Compare commits
7
Commits
e28f276209
...
cc88356099
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc88356099
|
||
|
|
0136c8b23c
|
||
|
|
6fe9e8844d
|
||
|
|
14ad33de7c
|
||
|
|
7b3e155389
|
||
|
|
697d784044
|
||
|
|
e35c87b3f2 |
@@ -18,7 +18,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Docker CLI
|
||||
run: apk add --no-cache docker-cli
|
||||
run: apk add --no-cache docker-cli docker-cli-buildx
|
||||
|
||||
- name: Login to registry
|
||||
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.aramjonghu.dev --username aramjonghu --password-stdin
|
||||
|
||||
@@ -20,28 +20,10 @@ jobs:
|
||||
-exec clang-format -i --style=file {} +
|
||||
git diff --exit-code && echo "clang-format: passed"
|
||||
|
||||
build:
|
||||
build & lint:
|
||||
runs-on: alpine
|
||||
container:
|
||||
image: git.aramjonghu.dev/aramjonghu/zshell-ci:latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure
|
||||
run: cmake -B build -G Ninja -DENABLE_MODULES=plugin -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
- name: Build
|
||||
run: ninja -C build
|
||||
|
||||
clang-tidy:
|
||||
runs-on: alpine
|
||||
container:
|
||||
image: git.aramjonghu.dev/aramjonghu/zshell-ci:latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -4,7 +4,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
fmt:
|
||||
fmt & lint:
|
||||
runs-on: alpine
|
||||
container: node:26-alpine
|
||||
|
||||
@@ -24,20 +24,6 @@ jobs:
|
||||
else
|
||||
echo "No JS/TS files found"
|
||||
fi
|
||||
|
||||
lint:
|
||||
runs-on: alpine
|
||||
container: node:26-alpine
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
apk add --no-cache \
|
||||
git
|
||||
|
||||
- name: ESLint
|
||||
run: |
|
||||
if [ -n "$(find . \( -iname "*.js" -o -iname "*.jsx" -o -iname "*.ts" -o -iname "*.tsx" -o -iname "*.mjs" -o -iname "*.cjs" \) -print -quit)" ]; then
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
static:
|
||||
fmt & lint:
|
||||
runs-on: debian
|
||||
container: node:26-trixie-slim
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
. .venv/bin/activate
|
||||
ruff check .
|
||||
|
||||
verify:
|
||||
test & nuitka build:
|
||||
if: always()
|
||||
runs-on: debian
|
||||
container: node:26-trixie-slim
|
||||
@@ -64,4 +64,4 @@ jobs:
|
||||
- name: Nuitka module check
|
||||
run: |
|
||||
. .venv/bin/activate
|
||||
nuitka --module --include-package=zshell cli/src/zshell/
|
||||
nuitka --module --include-package=zshell cli/src/zshell/
|
||||
|
||||
+21
-86
@@ -3,8 +3,9 @@ name: Rust
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
# jobs can be separated if we integrate tests
|
||||
jobs:
|
||||
build:
|
||||
build, clippy & fmt:
|
||||
runs-on: alpine
|
||||
container: node:26-alpine
|
||||
env:
|
||||
@@ -34,7 +35,9 @@ jobs:
|
||||
apk add --no-cache \
|
||||
git \
|
||||
cargo \
|
||||
rust
|
||||
rust \
|
||||
rust-clippy \
|
||||
rustfmt
|
||||
|
||||
- name: Cargo check
|
||||
run: |
|
||||
@@ -50,90 +53,6 @@ jobs:
|
||||
else
|
||||
echo "No Rust project found"
|
||||
fi
|
||||
|
||||
fmt:
|
||||
runs-on: alpine
|
||||
container: node:26-alpine
|
||||
env:
|
||||
CARGO_HOME: ${{ github.workspace }}/.cargo
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache cargo packages
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-cargo-packages
|
||||
with:
|
||||
path: |
|
||||
.cargo/registry
|
||||
.cargo/git
|
||||
target
|
||||
key: rust-fmt-${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
rust-${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
rust-${{ runner.os }}-build-
|
||||
rust-
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
apk add --no-cache \
|
||||
git \
|
||||
cargo \
|
||||
rust \
|
||||
rustfmt
|
||||
|
||||
- name: Format check
|
||||
run: |
|
||||
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
|
||||
status=0
|
||||
for manifest in $(find . -name "Cargo.toml"); do
|
||||
cargo fmt --manifest-path "$manifest" --check && \
|
||||
echo "$manifest: formatting OK" || \
|
||||
{ echo "$manifest: needs formatting"; status=1; }
|
||||
done
|
||||
exit $status
|
||||
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
|
||||
echo "Rust files found but no Cargo.toml"
|
||||
exit 1
|
||||
else
|
||||
echo "No Rust project found"
|
||||
fi
|
||||
|
||||
clippy:
|
||||
runs-on: alpine
|
||||
container: node:26-alpine
|
||||
env:
|
||||
CARGO_HOME: ${{ github.workspace }}/.cargo
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache cargo packages
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-cargo-packages
|
||||
with:
|
||||
path: |
|
||||
.cargo/registry
|
||||
.cargo/git
|
||||
target
|
||||
key: rust-clippy-${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
rust-${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
rust-${{ runner.os }}-build-
|
||||
rust-
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
apk add --no-cache \
|
||||
git \
|
||||
cargo \
|
||||
rust \
|
||||
rust-clippy
|
||||
|
||||
- name: Clippy
|
||||
run: |
|
||||
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
|
||||
@@ -150,3 +69,19 @@ jobs:
|
||||
else
|
||||
echo "No Rust project found"
|
||||
fi
|
||||
- name: Format check
|
||||
run: |
|
||||
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
|
||||
status=0
|
||||
for manifest in $(find . -name "Cargo.toml"); do
|
||||
cargo fmt --manifest-path "$manifest" --check && \
|
||||
echo "$manifest: formatting OK" || \
|
||||
{ echo "$manifest: needs formatting"; status=1; }
|
||||
done
|
||||
exit $status
|
||||
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
|
||||
echo "Rust files found but no Cargo.toml"
|
||||
exit 1
|
||||
else
|
||||
echo "No Rust project found"
|
||||
fi
|
||||
|
||||
@@ -2,55 +2,57 @@ import QtQuick
|
||||
import ZShell.Config
|
||||
import qs.Services
|
||||
|
||||
CustomClippingRect {
|
||||
Item {
|
||||
id: track
|
||||
|
||||
required property var scrollBar
|
||||
required property var mouseArea
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
implicitHeight: handle.implicitHeight
|
||||
radius: Tokens.rounding.full
|
||||
|
||||
CustomRect {
|
||||
id: handle
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
color: Colors.palette.m3secondary
|
||||
implicitWidth: track.scrollBar.width * track.scrollBar.effectiveSize
|
||||
implicitHeight: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall
|
||||
opacity: {
|
||||
if (!track.scrollBar.enabled)
|
||||
return 0;
|
||||
if (track.scrollBar.size === 1)
|
||||
return 0;
|
||||
if (track.mouseArea.pressed)
|
||||
return 1;
|
||||
if (track.mouseArea.containsMouse)
|
||||
return 0.8;
|
||||
if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive)
|
||||
return 0.6;
|
||||
return 0;
|
||||
}
|
||||
ClipRect {
|
||||
radius: Tokens.rounding.full
|
||||
x: track.scrollBar.reversed ? track.scrollBar.width * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.width * track.scrollBar.nonAnimY * track.scrollBar.travelScale
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
implicitHeight: handle.implicitHeight
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
CustomRect {
|
||||
id: handle
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
color: Colors.palette.m3secondary
|
||||
implicitWidth: track.scrollBar.width * track.scrollBar.effectiveSize
|
||||
implicitHeight: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall
|
||||
opacity: {
|
||||
if (!track.scrollBar.enabled)
|
||||
return 0;
|
||||
if (track.scrollBar.size === 1)
|
||||
return 0;
|
||||
if (track.mouseArea.pressed)
|
||||
return 1;
|
||||
if (track.mouseArea.containsMouse)
|
||||
return 0.8;
|
||||
if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive)
|
||||
return 0.6;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
radius: Tokens.rounding.full
|
||||
x: track.scrollBar.reversed ? track.scrollBar.width * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.width * track.scrollBar.nonAnimY * track.scrollBar.travelScale
|
||||
|
||||
MouseArea {
|
||||
acceptedButtons: Qt.NoButton
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
Behavior on implicitHeight {
|
||||
Anim {}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
acceptedButtons: Qt.NoButton
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ CustomFlickable {
|
||||
type: Anim.SlowEffects
|
||||
}
|
||||
}
|
||||
// layer.textureSize: Qt.size(width * dpr, height * dpr)
|
||||
layer.textureSize: Qt.size(width * dpr, height * dpr)
|
||||
layer.effect: Mask {
|
||||
maskSource: mask
|
||||
|
||||
|
||||
@@ -2,55 +2,57 @@ import QtQuick
|
||||
import ZShell.Config
|
||||
import qs.Services
|
||||
|
||||
CustomClippingRect {
|
||||
Item {
|
||||
id: track
|
||||
|
||||
required property var scrollBar
|
||||
required property var mouseArea
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
implicitWidth: handle.implicitWidth
|
||||
radius: Tokens.rounding.full
|
||||
|
||||
CustomRect {
|
||||
id: handle
|
||||
|
||||
ClipRect {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
color: Colors.palette.m3secondary
|
||||
implicitHeight: track.scrollBar.height * track.scrollBar.effectiveSize
|
||||
implicitWidth: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall
|
||||
opacity: {
|
||||
if (!track.scrollBar.enabled)
|
||||
return 0;
|
||||
if (track.scrollBar.size === 1)
|
||||
return 0;
|
||||
if (track.mouseArea.pressed)
|
||||
return 1;
|
||||
if (track.mouseArea.containsMouse)
|
||||
return 0.8;
|
||||
if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive)
|
||||
return 0.6;
|
||||
return 0;
|
||||
}
|
||||
anchors.top: parent.top
|
||||
radius: Tokens.rounding.full
|
||||
y: track.scrollBar.reversed ? track.scrollBar.height * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.height * track.scrollBar.nonAnimY * track.scrollBar.travelScale
|
||||
implicitWidth: handle.implicitWidth
|
||||
|
||||
Behavior on implicitWidth {
|
||||
Anim {}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
CustomRect {
|
||||
id: handle
|
||||
|
||||
anchors.right: parent.right
|
||||
color: Colors.palette.m3secondary
|
||||
implicitHeight: track.scrollBar.height * track.scrollBar.effectiveSize
|
||||
implicitWidth: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall
|
||||
opacity: {
|
||||
if (!track.scrollBar.enabled)
|
||||
return 0;
|
||||
if (track.scrollBar.size === 1)
|
||||
return 0;
|
||||
if (track.mouseArea.pressed)
|
||||
return 1;
|
||||
if (track.mouseArea.containsMouse)
|
||||
return 0.8;
|
||||
if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive)
|
||||
return 0.6;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
radius: Tokens.rounding.full
|
||||
y: track.scrollBar.reversed ? track.scrollBar.height * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.height * track.scrollBar.nonAnimY * track.scrollBar.travelScale
|
||||
|
||||
MouseArea {
|
||||
acceptedButtons: Qt.NoButton
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
Behavior on implicitWidth {
|
||||
Anim {}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
acceptedButtons: Qt.NoButton
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ Scope {
|
||||
name: "Bar-Exclusion"
|
||||
screen: root.screen
|
||||
|
||||
mask: Region {
|
||||
}
|
||||
mask: Region {}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -19,15 +19,11 @@ import ZShell.Config
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property Item bar
|
||||
required property real borderThickness
|
||||
readonly property alias clipboard: clipboard
|
||||
readonly property alias dashboard: dashboard
|
||||
readonly property alias dashboardWrapper: dashboardWrapper
|
||||
readonly property alias dock: dock
|
||||
readonly property alias drawing: drawing
|
||||
required property var drawingItem
|
||||
required property EdgeGeometry geometry
|
||||
readonly property alias launcher: launcher
|
||||
readonly property alias notifications: notifications
|
||||
readonly property alias osd: osd
|
||||
@@ -36,14 +32,19 @@ Item {
|
||||
readonly property alias popoutsWrapper: popouts
|
||||
readonly property alias resources: resources
|
||||
readonly property alias resourcesWrapper: resourcesWrapper
|
||||
required property ShellScreen screen
|
||||
required property ScreenState screenState
|
||||
readonly property alias settings: settings
|
||||
readonly property alias settingsWrapper: settingsWrapper
|
||||
readonly property alias sidebar: sidebar
|
||||
readonly property alias toasts: toasts
|
||||
readonly property alias utilities: utilities
|
||||
|
||||
required property Item bar
|
||||
required property real borderThickness
|
||||
required property var drawingItem
|
||||
required property EdgeGeometry geometry
|
||||
required property ShellScreen screen
|
||||
required property ScreenState screenState
|
||||
|
||||
anchors.bottomMargin: geometry.insetBottom(borderThickness)
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: geometry.insetLeft(borderThickness)
|
||||
|
||||
+12
-28
@@ -27,27 +27,21 @@ ColumnLayout {
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: Colors.palette.m3secondary
|
||||
font.bold: true
|
||||
font.family: Config.appearance.font.family.clock
|
||||
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
|
||||
font: Tokens.font.headline.builders.large.scale(3 * root.centerScale).weight(Font.Bold).width(30).build()
|
||||
text: Time.hourStr
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: Colors.palette.m3primary
|
||||
font.bold: true
|
||||
font.family: Config.appearance.font.family.clock
|
||||
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
|
||||
font: Tokens.font.headline.builders.large.scale(3 * root.centerScale).weight(Font.Bold).width(30).build()
|
||||
text: ":"
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: Colors.palette.m3secondary
|
||||
font.bold: true
|
||||
font.family: Config.appearance.font.family.clock
|
||||
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
|
||||
font: Tokens.font.headline.builders.large.scale(3 * root.centerScale).weight(Font.Bold).width(30).build()
|
||||
text: Time.minuteStr
|
||||
}
|
||||
}
|
||||
@@ -56,13 +50,11 @@ ColumnLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: -Tokens.padding.large * 2
|
||||
color: Colors.palette.m3tertiary
|
||||
font.bold: true
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.pointSize: Math.floor(Tokens.font.size.extraLarge * root.centerScale)
|
||||
font: Tokens.font.title.builders.medium.weight(Font.DemiBold).build()
|
||||
text: Time.format("dddd, d MMMM yyyy")
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: Tokens.spacing.largeIncreased * 2
|
||||
color: Colors.tPalette.m3surfaceContainer
|
||||
@@ -73,7 +65,7 @@ ColumnLayout {
|
||||
MaterialIcon {
|
||||
anchors.centerIn: parent
|
||||
color: Colors.palette.m3onSurfaceVariant
|
||||
font.pointSize: Math.floor(root.centerWidth / 4)
|
||||
fontStyle: Tokens.font.icon.size(root.centerWidth / 4).build()
|
||||
text: "person"
|
||||
}
|
||||
|
||||
@@ -88,9 +80,7 @@ ColumnLayout {
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: Colors.palette.m3onSurfaceVariant
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.pointSize: Tokens.font.size.normal
|
||||
font.weight: 600
|
||||
font: Tokens.font.body.large
|
||||
text: root.greeter.username
|
||||
visible: text.length > 0
|
||||
}
|
||||
@@ -155,8 +145,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +180,6 @@ ColumnLayout {
|
||||
|
||||
anchors.centerIn: parent
|
||||
color: root.greeter.buffer && !root.greeter.launching ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||
font.weight: 500
|
||||
text: root.greeter.launching ? "hourglass_top" : "arrow_forward"
|
||||
}
|
||||
}
|
||||
@@ -204,8 +192,7 @@ ColumnLayout {
|
||||
implicitHeight: Math.max(message.implicitHeight, stateMessage.implicitHeight)
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
@@ -245,12 +232,10 @@ ColumnLayout {
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
Behavior on scale {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
|
||||
onMsgChanged: {
|
||||
@@ -292,8 +277,7 @@ ColumnLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: isError ? Colors.palette.m3error : Colors.palette.m3primary
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.pointSize: Tokens.font.size.small
|
||||
font: Tokens.font.mono.medium
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
opacity: 0
|
||||
scale: 0.7
|
||||
|
||||
@@ -20,7 +20,7 @@ BusyIndicator {
|
||||
property int animState
|
||||
property color bgColor: Colors.palette.m3secondaryContainer
|
||||
property color fgColor: Colors.palette.m3primary
|
||||
property real implicitSize: Tokens.font.size.normal * 3
|
||||
property real implicitSize: Tokens.font.body.medium.pointSize * 3
|
||||
property real internalStrokeWidth: strokeWidth
|
||||
readonly property alias progress: manager.progress
|
||||
property real strokeWidth: Tokens.padding.extraSmall * 0.8
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import QtQuick
|
||||
import ZShell.Components
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property real radius
|
||||
property real topLeftRadius: radius
|
||||
property real topRightRadius: radius
|
||||
property real bottomRightRadius: radius
|
||||
property real bottomLeftRadius: radius
|
||||
property color color: "transparent"
|
||||
default property alias contentData: contentItem.data
|
||||
|
||||
Item {
|
||||
id: contentItem
|
||||
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
ShaderEffectSource {
|
||||
id: source
|
||||
|
||||
hideSource: true
|
||||
sourceItem: contentItem
|
||||
}
|
||||
|
||||
RoundedMask {
|
||||
anchors.fill: parent
|
||||
source: source
|
||||
topLeftRadius: root.topLeftRadius
|
||||
topRightRadius: root.topRightRadius
|
||||
bottomRightRadius: root.bottomRightRadius
|
||||
bottomLeftRadius: root.bottomLeftRadius
|
||||
color: root.color
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,36 @@
|
||||
import QtQuick
|
||||
import qs.Services
|
||||
|
||||
Flickable {
|
||||
id: root
|
||||
|
||||
property bool doneFakeFlick
|
||||
|
||||
interactive: !ShellState.forActive().isDrawing
|
||||
maximumFlickVelocity: 3000
|
||||
|
||||
rebound: Transition {
|
||||
onRunningChanged: {
|
||||
if (!running && !root.doneFakeFlick) {
|
||||
root.doneFakeFlick = true;
|
||||
root.flick(1, 1);
|
||||
root.flick(-1, -1);
|
||||
Qt.callLater(() => root.cancelFlick());
|
||||
}
|
||||
}
|
||||
|
||||
Anim {
|
||||
properties: "x,y"
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 10
|
||||
running: root.doneFakeFlick
|
||||
|
||||
onTriggered: {
|
||||
root.doneFakeFlick = false;
|
||||
root.returnToBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,36 @@
|
||||
import QtQuick
|
||||
import qs.Services
|
||||
|
||||
ListView {
|
||||
id: root
|
||||
|
||||
property bool doneFakeFlick
|
||||
|
||||
interactive: !ShellState.forActive()?.isDrawing
|
||||
maximumFlickVelocity: 3000
|
||||
|
||||
rebound: Transition {
|
||||
// onRunningChanged: {
|
||||
// if (!running && !root.doneFakeFlick) {
|
||||
// root.doneFakeFlick = true;
|
||||
// root.flick(1, 1);
|
||||
// root.flick(-1, -1);
|
||||
// Qt.callLater(() => root.cancelFlick());
|
||||
// }
|
||||
// }
|
||||
|
||||
Anim {
|
||||
properties: "x,y"
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
|
||||
// Timer {
|
||||
// interval: 10
|
||||
// running: root.doneFakeFlick
|
||||
//
|
||||
// onTriggered: {
|
||||
// root.doneFakeFlick = false;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ MouseArea {
|
||||
property int scrollAccumulatedY: 0
|
||||
|
||||
function onWheel(event: WheelEvent): void {
|
||||
event.accepted = false;
|
||||
}
|
||||
|
||||
onWheel: event => {
|
||||
|
||||
@@ -6,7 +6,6 @@ Rectangle {
|
||||
color: "transparent"
|
||||
|
||||
Behavior on color {
|
||||
CAnim {
|
||||
}
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,9 @@ Text {
|
||||
property real animateTo: 1
|
||||
|
||||
color: Colors.palette.m3onSurface
|
||||
font.family: Config.appearance.font.family.sans
|
||||
font.pointSize: Tokens.font.size.normal
|
||||
font: Tokens.font.body.small
|
||||
linkColor: Colors.palette.m3onPrimaryFixedVariant
|
||||
renderType: Text.NativeRendering
|
||||
renderType: Text.QtRendering
|
||||
textFormat: Text.PlainText
|
||||
|
||||
Behavior on color {
|
||||
@@ -28,22 +27,25 @@ Text {
|
||||
enabled: root.animate
|
||||
|
||||
SequentialAnimation {
|
||||
Anim {
|
||||
TAnim {
|
||||
target: root
|
||||
to: root.animateFrom
|
||||
type: Anim.FastEffects
|
||||
}
|
||||
|
||||
PropertyAction {
|
||||
}
|
||||
|
||||
Anim {
|
||||
TAnim {
|
||||
target: root
|
||||
to: root.animateTo
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component Anim: NumberAnimation {
|
||||
component TAnim: Anim {
|
||||
duration: root.animateDuration / 2
|
||||
easing.type: Easing.BezierSpline
|
||||
properties: root.animateProp.split(",").length > 1 ? root.animateProp : ""
|
||||
property: root.animateProp.split(",").length === 1 ? root.animateProp : ""
|
||||
target: root
|
||||
|
||||
@@ -1,76 +1,305 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Shapes
|
||||
import ZShell.Config
|
||||
import qs.Services
|
||||
|
||||
TextField {
|
||||
TextFieldBase {
|
||||
id: root
|
||||
|
||||
background: null
|
||||
color: Colors.palette.m3onSurface
|
||||
cursorVisible: !readOnly
|
||||
font.family: Config.appearance.font.family.sans
|
||||
font.pointSize: Tokens.font.size.smaller
|
||||
placeholderTextColor: Colors.palette.m3outline
|
||||
renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering
|
||||
enum TextFieldType {
|
||||
Outlined,
|
||||
Filled
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
CAnim {
|
||||
readonly property int clampedRadius: Math.min(horizontalPadding, Math.min(width, height) / 2, radius)
|
||||
readonly property string effectiveSupportingText: isError && errorText ? errorText : supportingText
|
||||
readonly property int filledOffset: type === CustomTextField.Filled ? Tokens.spacing.small : 0
|
||||
readonly property int leadingOffset: leadingIcon ? leadingIconLoader.width + leadingIconLoader.anchors.leftMargin : 0
|
||||
readonly property real smallFontScale: smallFontSize / font.pointSize
|
||||
readonly property int supportingTextOffset: effectiveSupportingText ? supportingTextLoader.height + Tokens.spacing.extraSmall : 0
|
||||
readonly property int trailingOffset: trailingIcon ? trailingIconLoader.width + trailingIconLoader.anchors.rightMargin : 0
|
||||
readonly property bool valid: !validate || (!text && emptyIsValid) || (validate instanceof RegExp ? validate.test(text) : !!validate(text))
|
||||
|
||||
property int horizontalPadding: Tokens.padding.large
|
||||
property int verticalPadding: Tokens.padding.large
|
||||
|
||||
property int radius: Tokens.rounding.small
|
||||
|
||||
property string supportingText
|
||||
property string trailingIcon
|
||||
property int smallFontSize: Tokens.font.label.small.pointSize
|
||||
|
||||
property int type: CustomTextField.Outlined
|
||||
property var validate // Regex or function
|
||||
property bool emptyIsValid: true
|
||||
property string errorText
|
||||
property bool isError
|
||||
property string leadingIcon
|
||||
|
||||
bottomPadding: verticalPadding + supportingTextOffset - filledOffset
|
||||
leftPadding: horizontalPadding + leadingOffset
|
||||
rightPadding: horizontalPadding + trailingOffset
|
||||
topPadding: verticalPadding + filledOffset
|
||||
|
||||
background: Loader {
|
||||
anchors.bottomMargin: root.supportingTextOffset
|
||||
anchors.fill: parent
|
||||
sourceComponent: root.type === CustomTextField.Filled ? filledComp : outlineComp
|
||||
|
||||
StateLayer {
|
||||
id: stateLayer
|
||||
|
||||
cursorShape: Qt.IBeamCursor
|
||||
enabled: !root.activeFocus
|
||||
manualPressOverride: tapHandler.pressed
|
||||
radius: root.type === CustomTextField.Outlined ? root.clampedRadius : 0
|
||||
topLeftRadius: root.clampedRadius
|
||||
topRightRadius: root.clampedRadius
|
||||
|
||||
onClicked: root.focus = true
|
||||
}
|
||||
}
|
||||
cursorDelegate: CustomRect {
|
||||
id: cursor
|
||||
|
||||
property bool disableBlink
|
||||
onEditingFinished: {
|
||||
if (!valid)
|
||||
isError = true;
|
||||
}
|
||||
onPressed: {
|
||||
if (stateLayer.enabled)
|
||||
stateLayer.press(stateLayer.mouseX, stateLayer.mouseY);
|
||||
}
|
||||
onTextEdited: {
|
||||
if (isError)
|
||||
isError = false;
|
||||
}
|
||||
|
||||
color: Colors.palette.m3primary
|
||||
implicitWidth: 2
|
||||
radius: Tokens.rounding.medium
|
||||
Item {
|
||||
id: contentWrapper
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: Tokens.anim.durations.small
|
||||
}
|
||||
}
|
||||
anchors.bottomMargin: root.supportingTextOffset
|
||||
anchors.fill: parent
|
||||
|
||||
Connections {
|
||||
function onCursorPositionChanged(): void {
|
||||
if (root.activeFocus && root.cursorVisible) {
|
||||
cursor.opacity = 1;
|
||||
cursor.disableBlink = true;
|
||||
enableBlink.restart();
|
||||
CustomText {
|
||||
id: placeholder
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.leftPadding
|
||||
anchors.topMargin: Tokens.padding.extraSmall
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : root.text ? Colors.palette.m3outline : root.placeholderTextColor)
|
||||
font.family: root.font.family
|
||||
font.pointSize: root.font.pointSize
|
||||
font.variableAxes: root.font.variableAxes
|
||||
font.weight: root.font.weight
|
||||
renderType: Text.QtRendering
|
||||
text: root.placeholderText
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "smallOutlined"
|
||||
when: root.type === CustomTextField.Outlined && (root.activeFocus || root.text)
|
||||
|
||||
PropertyChanges {
|
||||
placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding
|
||||
placeholder.scale: root.smallFontScale
|
||||
}
|
||||
|
||||
AnchorChanges {
|
||||
anchors.verticalCenter: contentWrapper.top
|
||||
target: placeholder
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "smallFilled"
|
||||
when: root.type === CustomTextField.Filled && (root.activeFocus || root.text)
|
||||
|
||||
PropertyChanges {
|
||||
placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding + root.leadingOffset
|
||||
placeholder.scale: root.smallFontScale
|
||||
}
|
||||
|
||||
AnchorChanges {
|
||||
anchors.top: contentWrapper.top
|
||||
anchors.verticalCenter: undefined
|
||||
target: placeholder
|
||||
}
|
||||
}
|
||||
]
|
||||
transitions: Transition {
|
||||
Anim {
|
||||
properties: "scale,leftMargin"
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
|
||||
AnchorAnim {
|
||||
duration: Tokens.anim.durations.expressiveDefaultEffects
|
||||
easing: Tokens.anim.expressiveDefaultEffects
|
||||
}
|
||||
}
|
||||
|
||||
target: root
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: enableBlink
|
||||
Loader {
|
||||
id: leadingIconLoader
|
||||
|
||||
interval: 100
|
||||
active: root.leadingIcon
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Tokens.padding.small
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
onTriggered: cursor.disableBlink = false
|
||||
sourceComponent: MaterialIcon {
|
||||
color: Colors.palette.m3onSurfaceVariant
|
||||
text: root.leadingIcon
|
||||
fontStyle: Tokens.font.icon.builders.medium.scale(0.9).build()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 500
|
||||
repeat: true
|
||||
running: root.activeFocus && root.cursorVisible && !cursor.disableBlink
|
||||
triggeredOnStart: true
|
||||
Loader {
|
||||
id: trailingIconLoader
|
||||
|
||||
onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1
|
||||
}
|
||||
active: root.trailingIcon
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Tokens.padding.small
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Binding {
|
||||
cursor.opacity: 0
|
||||
when: !root.activeFocus || !root.cursorVisible
|
||||
sourceComponent: MaterialIcon {
|
||||
color: Colors.palette.m3onSurfaceVariant
|
||||
text: root.trailingIcon
|
||||
fontStyle: Tokens.font.icon.builders.medium.scale(0.9).build()
|
||||
}
|
||||
}
|
||||
}
|
||||
Behavior on placeholderTextColor {
|
||||
CAnim {
|
||||
|
||||
Loader {
|
||||
id: supportingTextLoader
|
||||
|
||||
active: root.effectiveSupportingText
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.horizontalPadding
|
||||
|
||||
sourceComponent: CustomText {
|
||||
color: root.isError ? Colors.palette.m3error : Colors.palette.m3onSurfaceVariant
|
||||
font: Tokens.font.label.small
|
||||
text: root.effectiveSupportingText
|
||||
}
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
id: tapHandler
|
||||
}
|
||||
|
||||
Component {
|
||||
id: outlineComp
|
||||
|
||||
Shape {
|
||||
id: bg
|
||||
|
||||
asynchronous: true
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
|
||||
ShapePath {
|
||||
id: path
|
||||
|
||||
readonly property real inset: strokeWidth / 2
|
||||
readonly property real outlineGap: placeholder.width * root.smallFontScale + Tokens.spacing.small * 2
|
||||
property real outlineGapScale: root.activeFocus || root.text ? 1 : 0
|
||||
|
||||
capStyle: ShapePath.RoundCap
|
||||
fillColor: "transparent"
|
||||
startX: path.inset + root.horizontalPadding - root.clampedRadius + path.outlineGap * (1 - path.outlineGapScale) / 2 + path.outlineGap * path.outlineGapScale
|
||||
startY: path.inset
|
||||
strokeColor: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : Colors.palette.m3outline)
|
||||
strokeWidth: root.activeFocus ? 2 : 1
|
||||
|
||||
Behavior on outlineGapScale {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
Behavior on strokeColor {
|
||||
CAnim {}
|
||||
}
|
||||
Behavior on strokeWidth {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: bg.width - path.inset - root.clampedRadius
|
||||
y: path.inset
|
||||
}
|
||||
|
||||
PathArc {
|
||||
radiusX: root.clampedRadius
|
||||
radiusY: root.clampedRadius
|
||||
x: bg.width - path.inset
|
||||
y: path.inset + root.clampedRadius
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: bg.width - path.inset
|
||||
y: bg.height - path.inset - root.clampedRadius
|
||||
}
|
||||
|
||||
PathArc {
|
||||
radiusX: root.clampedRadius
|
||||
radiusY: root.clampedRadius
|
||||
x: bg.width - path.inset - root.clampedRadius
|
||||
y: bg.height - path.inset
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: path.inset + root.clampedRadius
|
||||
y: bg.height - path.inset
|
||||
}
|
||||
|
||||
PathArc {
|
||||
radiusX: root.clampedRadius
|
||||
radiusY: root.clampedRadius
|
||||
x: path.inset
|
||||
y: bg.height - path.inset - root.clampedRadius
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: path.inset
|
||||
y: path.inset + root.clampedRadius
|
||||
}
|
||||
|
||||
PathArc {
|
||||
radiusX: root.clampedRadius
|
||||
radiusY: root.clampedRadius
|
||||
x: path.inset + root.clampedRadius
|
||||
y: path.inset
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: path.inset + root.horizontalPadding - root.clampedRadius / 2 + path.outlineGap * (1 - path.outlineGapScale) / 2
|
||||
y: path.inset
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: filledComp
|
||||
|
||||
CustomRect {
|
||||
color: root.activeFocus ? Colors.tPalette.m3surfaceContainerHighest : Colors.tPalette.m3surfaceContainerHigh
|
||||
topLeftRadius: root.clampedRadius
|
||||
topRightRadius: root.clampedRadius
|
||||
|
||||
CustomRect {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : Colors.palette.m3outline)
|
||||
implicitHeight: root.activeFocus ? 2 : 1
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import ZShell.Config
|
||||
import qs.Services
|
||||
|
||||
TextInput {
|
||||
renderType: Text.NativeRendering
|
||||
selectedTextColor: Colors.palette.m3onSecondaryContainer
|
||||
selectionColor: Colors.tPalette.m3onSecondaryContainer
|
||||
selectionColor: Colors.tPalette.colSecondaryContainer
|
||||
|
||||
font {
|
||||
family: Config.appearance?.font.family.sans ?? "sans-serif"
|
||||
hintingPreference: Font.PreferFullHinting
|
||||
pixelSize: Tokens?.font.size.normal ?? 15
|
||||
pixelSize: Config.appearance?.font.size.normal ?? 15
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import ZShell.Config
|
||||
|
||||
Image {
|
||||
id: root
|
||||
|
||||
property int fadeInAnim: Anim.DefaultEffects
|
||||
property int fadeInLargeAnim: Anim.StandardLarge
|
||||
property int fadeOutAnim: Anim.FastEffects
|
||||
property bool fadingOut
|
||||
property bool hadPrevious
|
||||
property bool preventInit
|
||||
|
||||
function maybeStartInAnim(): void {
|
||||
if (!preventInit && !opacityInAnim.running && status === Image.Ready) {
|
||||
opacityInAnim.type = hadPrevious ? fadeInAnim : fadeInLargeAnim;
|
||||
opacityInAnim.start();
|
||||
}
|
||||
}
|
||||
|
||||
asynchronous: true
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
opacity: 0
|
||||
retainWhileLoading: true
|
||||
sourceSize: {
|
||||
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
|
||||
return Qt.size(width * dpr, height * dpr);
|
||||
}
|
||||
|
||||
Anim on opacity {
|
||||
id: opacityInAnim
|
||||
|
||||
running: false
|
||||
to: 1
|
||||
}
|
||||
Behavior on source {
|
||||
SequentialAnimation {
|
||||
ScriptAction {
|
||||
script: opacityInAnim.stop()
|
||||
}
|
||||
|
||||
PropertyAction {
|
||||
property: "fadingOut"
|
||||
target: root
|
||||
value: true
|
||||
}
|
||||
|
||||
Anim {
|
||||
property: "opacity"
|
||||
target: root
|
||||
to: 0
|
||||
type: root.fadeOutAnim
|
||||
}
|
||||
|
||||
PropertyAction {
|
||||
property: "fadingOut"
|
||||
target: root
|
||||
value: false
|
||||
}
|
||||
|
||||
PropertyAction {
|
||||
property: "hadPrevious"
|
||||
target: root
|
||||
value: root.source
|
||||
}
|
||||
|
||||
PropertyAction {
|
||||
}
|
||||
|
||||
ScriptAction {
|
||||
script: root.maybeStartInAnim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPreventInitChanged: maybeStartInAnim()
|
||||
onStatusChanged: maybeStartInAnim()
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import M3Shapes
|
||||
import ZShell.Config
|
||||
import qs.Services
|
||||
|
||||
MaterialShape {
|
||||
id: root
|
||||
|
||||
property bool animated: true
|
||||
property real cRotation
|
||||
property bool containsIcon
|
||||
property real dampingRatio: 0.6
|
||||
property real lRotation
|
||||
property int morphAnimRotation: 60
|
||||
property real morphScale: 0.14
|
||||
property alias rotateAnimDuration: rotateAnim.duration
|
||||
property int shapeIndex
|
||||
property list<int> shapes: {
|
||||
if (containsIcon)
|
||||
return [MaterialShape.SoftBurst, MaterialShape.Cookie9Sided, MaterialShape.Pill, MaterialShape.Sunny, MaterialShape.Cookie4Sided, MaterialShape.Oval];
|
||||
return [MaterialShape.SoftBurst, MaterialShape.Cookie9Sided, MaterialShape.Pentagon, MaterialShape.Pill, MaterialShape.Sunny, MaterialShape.Cookie4Sided, MaterialShape.Oval];
|
||||
}
|
||||
readonly property real springDuration: {
|
||||
const wn = Math.sqrt(stiffness);
|
||||
const r = -dampingRatio * wn;
|
||||
const c = 1 / Math.sqrt(1 - dampingRatio * dampingRatio);
|
||||
return Math.log(visibilityThreshold / c) / r;
|
||||
}
|
||||
readonly property real springMaxVelocity: {
|
||||
const wn = Math.sqrt(stiffness);
|
||||
const factor = Math.exp(-z * Math.acos(z) / Math.sqrt(1 - z * z));
|
||||
return wn * factor;
|
||||
}
|
||||
property bool springSettled: true
|
||||
property real stiffness: 180
|
||||
property real thisLRotation
|
||||
property real visibilityThreshold: 0.075
|
||||
|
||||
function spring(t: real): var {
|
||||
const wn = Math.sqrt(stiffness);
|
||||
const za = dampingRatio * wn;
|
||||
|
||||
const wd = wn * Math.sqrt(1 - dampingRatio * dampingRatio);
|
||||
const r = za / wd;
|
||||
const pos = 1 - Math.exp(-za * t) * (Math.cos(wd * t) + r * Math.sin(wd * t));
|
||||
const vel = Math.exp(-za * t) * (wn * wn / wd) * Math.sin(wd * t);
|
||||
|
||||
return [pos, vel];
|
||||
}
|
||||
|
||||
color: Colors.palette.m3primary
|
||||
implicitSize: 38
|
||||
toShape: shapes[0]
|
||||
|
||||
RotationAnimation on cRotation {
|
||||
id: rotateAnim
|
||||
|
||||
duration: 4666
|
||||
easing.type: Easing.Linear
|
||||
from: 0
|
||||
loops: Animation.Infinite
|
||||
running: root.animated
|
||||
to: 360
|
||||
}
|
||||
Behavior on color {
|
||||
CAnim {
|
||||
}
|
||||
}
|
||||
|
||||
ElapsedTimer {
|
||||
id: timer
|
||||
}
|
||||
|
||||
FrameAnimation {
|
||||
running: root.animated && !root.springSettled
|
||||
|
||||
onTriggered: {
|
||||
const t = timer.elapsed();
|
||||
|
||||
if (t >= root.springDuration) {
|
||||
root.springSettled = true;
|
||||
} else {
|
||||
const [pos, vel] = root.spring(t);
|
||||
root.morphProgress = Math.min(1, pos); // Overshooting the morph looks weird
|
||||
root.thisLRotation = pos * root.morphAnimRotation;
|
||||
root.scale = 1 + vel * root.morphScale / root.springMaxVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 650
|
||||
repeat: true
|
||||
running: root.animated
|
||||
triggeredOnStart: true
|
||||
|
||||
onTriggered: {
|
||||
root.beginBatchUpdate();
|
||||
root.fromShape = root.toShape;
|
||||
root.shapeIndex = (root.shapeIndex + 1) % root.shapes.length;
|
||||
root.toShape = root.shapes[root.shapeIndex];
|
||||
root.morphProgress = 0;
|
||||
|
||||
root.rotation = root.rotation;
|
||||
root.lRotation = (root.lRotation + root.thisLRotation) % 360;
|
||||
root.thisLRotation = 0;
|
||||
root.rotation = Qt.binding(() => root.cRotation + root.lRotation + root.thisLRotation);
|
||||
|
||||
root.springSettled = false;
|
||||
timer.restart();
|
||||
root.endBatchUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
import QtQuick
|
||||
import ZShell.Config
|
||||
import qs.Services
|
||||
|
||||
CustomText {
|
||||
property real fill
|
||||
property int grade: Colors.light ? 0 : -25
|
||||
id: root
|
||||
|
||||
font.family: "Material Symbols Rounded"
|
||||
font.pointSize: Tokens.font.size.larger
|
||||
font.variableAxes: ({
|
||||
FILL: fill.toFixed(1),
|
||||
GRAD: grade,
|
||||
opsz: fontInfo.pixelSize,
|
||||
wght: fontInfo.weight
|
||||
})
|
||||
property real fill: 0
|
||||
property int grade: Colors.light ? 0 : -25
|
||||
property font fontStyle: Tokens.font.icon.small
|
||||
|
||||
renderType: Text.NativeRendering
|
||||
font: Tokens.font.icon.size(fontStyle.pointSize).weight(fontStyle.weight).vaxes(fontStyle.variableAxes).fill(fill.toFixed(1)).grade(grade).build()
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import ZShell
|
||||
import ZShell.Components
|
||||
import qs.Helpers
|
||||
import ZShell.Config
|
||||
import qs.Services
|
||||
|
||||
@@ -13,7 +11,6 @@ MouseArea {
|
||||
property alias bottomRightRadius: base.bottomRightRadius
|
||||
property real circleRadius
|
||||
property alias color: base.color
|
||||
property bool disabled
|
||||
readonly property real endRadius: {
|
||||
const d1 = distSq(0, 0);
|
||||
const d2 = distSq(width, 0);
|
||||
@@ -22,6 +19,7 @@ MouseArea {
|
||||
return (Math.sqrt(Math.max(d1, d2, d3, d4)) + (shapeMorph ? 24 : 0)) * 1.3;
|
||||
}
|
||||
property real endRadiusAtPress
|
||||
property bool manualHoverOverride
|
||||
property bool manualPressOverride
|
||||
property real pressX: width / 2
|
||||
property real pressY: height / 2
|
||||
@@ -29,7 +27,7 @@ MouseArea {
|
||||
readonly property alias rect: base
|
||||
property bool shapeMorph
|
||||
property bool showHoverBackground: true
|
||||
property real stateOpacity: containsMouse ? 0.08 : 0
|
||||
property real stateOpacity: containsMouse || manualHoverOverride ? 0.08 : 0
|
||||
property alias topLeftRadius: base.topLeftRadius
|
||||
property alias topRightRadius: base.topRightRadius
|
||||
|
||||
@@ -52,8 +50,8 @@ MouseArea {
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
cursorShape: disabled ? undefined : Qt.PointingHandCursor
|
||||
enabled: !disabled
|
||||
cursorShape: !enabled ? undefined : Qt.PointingHandCursor
|
||||
enabled: parent.enabled
|
||||
hoverEnabled: true
|
||||
|
||||
Behavior on stateOpacity {
|
||||
@@ -100,13 +98,13 @@ MouseArea {
|
||||
id: base
|
||||
|
||||
anchors.fill: parent
|
||||
bottomLeftRadius: root.parent?.bottomLeftRadius ?? radius ?? 0
|
||||
bottomRightRadius: root.parent?.bottomRightRadius ?? radius ?? 0
|
||||
color: Colors.palette.m3onSurface
|
||||
opacity: root.stateOpacity
|
||||
// Pick up radius from parent if it has one (parent can be anything with radius props)
|
||||
// qmllint disable missing-property
|
||||
radius: root.parent?.radius ?? 0
|
||||
bottomLeftRadius: root.parent?.bottomLeftRadius ?? radius ?? 0
|
||||
bottomRightRadius: root.parent?.bottomRightRadius ?? radius ?? 0
|
||||
topLeftRadius: root.parent?.topLeftRadius ?? radius ?? 0
|
||||
topRightRadius: root.parent?.topRightRadius ?? radius ?? 0
|
||||
// qmllint enable missing-property
|
||||
|
||||
+16
-39
@@ -13,34 +13,16 @@ RowLayout {
|
||||
|
||||
spacing: Tokens.spacing.largeIncreased * 2
|
||||
|
||||
ColumnLayout {
|
||||
CustomRect {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
spacing: Tokens.spacing.medium
|
||||
topLeftRadius: Tokens.rounding.largeIncreased
|
||||
bottomLeftRadius: Tokens.rounding.largeIncreased
|
||||
color: Colors.tPalette.m3surfaceContainer
|
||||
radius: Tokens.rounding.small
|
||||
|
||||
CustomRect {
|
||||
Layout.fillWidth: true
|
||||
color: Colors.tPalette.m3surfaceContainer
|
||||
implicitHeight: weather.implicitHeight
|
||||
radius: Tokens.rounding.small
|
||||
topLeftRadius: Tokens.rounding.largeIncreased
|
||||
|
||||
WeatherInfo {
|
||||
id: weather
|
||||
|
||||
rootHeight: root.height
|
||||
}
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
bottomLeftRadius: Tokens.rounding.largeIncreased
|
||||
color: Colors.tPalette.m3surfaceContainer
|
||||
radius: Tokens.rounding.small
|
||||
|
||||
UserDock {
|
||||
greeter: root.greeter
|
||||
}
|
||||
UserDock {
|
||||
greeter: root.greeter
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,21 +31,16 @@ RowLayout {
|
||||
screenHeight: root.screenHeight
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
CustomRect {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
spacing: Tokens.spacing.medium
|
||||
bottomRightRadius: Tokens.rounding.largeIncreased
|
||||
color: Colors.tPalette.m3surfaceContainer
|
||||
radius: Tokens.rounding.small
|
||||
topRightRadius: Tokens.rounding.largeIncreased
|
||||
|
||||
CustomRect {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
bottomRightRadius: Tokens.rounding.largeIncreased
|
||||
color: Colors.tPalette.m3surfaceContainer
|
||||
radius: Tokens.rounding.small
|
||||
topRightRadius: Tokens.rounding.largeIncreased
|
||||
|
||||
SessionDock {
|
||||
greeter: root.greeter
|
||||
}
|
||||
SessionDock {
|
||||
greeter: root.greeter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,8 +134,7 @@ Scope {
|
||||
id: lockIcon
|
||||
|
||||
anchors.centerIn: parent
|
||||
font.bold: true
|
||||
font.pointSize: Tokens.font.size.extraLarge * 4
|
||||
fontStyle: Tokens.font.icon.builders.extraLarge.size(Tokens.font.icon.extraLarge.pointSize * 3).build()
|
||||
text: "lock"
|
||||
}
|
||||
|
||||
|
||||
+8
-15
@@ -39,8 +39,7 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
animate: true
|
||||
color: root.greeter.launching ? Colors.palette.m3secondary : Colors.palette.m3outline
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.pointSize: Tokens.font.size.normal
|
||||
font: Tokens.font.mono.medium
|
||||
opacity: root.buffer ? 0 : 1
|
||||
text: {
|
||||
if (root.greeter.launching)
|
||||
@@ -51,8 +50,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,15 +62,13 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: Colors.palette.m3onSurface
|
||||
elide: Text.ElideLeft
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.pointSize: Tokens.font.size.normal
|
||||
font: Tokens.font.mono.medium
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
opacity: root.greeter.echoResponse && root.buffer ? 1 : 0
|
||||
text: root.buffer
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +85,7 @@ Item {
|
||||
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenterOffset: implicitWidth > root.width ? -(implicitWidth - root.width) / 2 : 0
|
||||
implicitHeight: Tokens.font.size.normal
|
||||
implicitHeight: Tokens.font.body.medium
|
||||
implicitWidth: fullWidth
|
||||
interactive: false
|
||||
opacity: root.greeter.echoResponse ? 0 : 1
|
||||
@@ -107,8 +103,7 @@ Item {
|
||||
scale: 0
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
Behavior on scale {
|
||||
Anim {
|
||||
@@ -156,15 +151,13 @@ Item {
|
||||
Behavior on implicitWidth {
|
||||
id: imWidthBehavior
|
||||
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
model: ScriptModel {
|
||||
values: root.buffer.split("")
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-17
@@ -13,22 +13,19 @@ ColumnLayout {
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Tokens.padding.large
|
||||
spacing: Tokens.spacing.small
|
||||
spacing: Tokens.spacing.large
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
color: Colors.palette.m3outline
|
||||
elide: Text.ElideRight
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.weight: 500
|
||||
font: Tokens.font.mono.builders.small.weight(Font.Medium).build()
|
||||
text: root.greeter.sessions.length > 0 ? qsTr("%1 session%2").arg(root.greeter.sessions.length).arg(root.greeter.sessions.length === 1 ? "" : "s") : qsTr("Sessions")
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
color: "transparent"
|
||||
radius: Tokens.rounding.small
|
||||
|
||||
Loader {
|
||||
active: opacity > 0
|
||||
@@ -46,16 +43,14 @@ ColumnLayout {
|
||||
MaterialIcon {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: Colors.palette.m3outlineVariant
|
||||
font.pointSize: Tokens.font.size.extraLarge * 2
|
||||
fontStyle: Tokens.font.icon.large
|
||||
text: "desktop_windows"
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: Colors.palette.m3outlineVariant
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.pointSize: Tokens.font.size.large
|
||||
font.weight: 500
|
||||
font: Tokens.font.headline.builders.small.width(90).build()
|
||||
text: qsTr("No Sessions Found")
|
||||
}
|
||||
}
|
||||
@@ -68,6 +63,7 @@ ColumnLayout {
|
||||
clip: true
|
||||
currentIndex: root.greeter.sessionIndex
|
||||
highlightFollowsCurrentItem: false
|
||||
boundsBehavior: ListView.StopAtBounds
|
||||
model: root.greeter.sessions
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
@@ -80,7 +76,7 @@ ColumnLayout {
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
implicitHeight: row.implicitHeight + Tokens.padding.small * 2
|
||||
radius: Tokens.rounding.medium - Tokens.padding.small
|
||||
radius: Tokens.rounding.large
|
||||
|
||||
StateLayer {
|
||||
onClicked: {
|
||||
@@ -97,7 +93,7 @@ ColumnLayout {
|
||||
|
||||
MaterialIcon {
|
||||
color: session.index === sessions.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurfaceVariant
|
||||
font.pointSize: Tokens.font.size.extraLarge
|
||||
fontStyle: Tokens.font.icon.extraLarge
|
||||
text: modelData.kind === "x11" ? "tv" : "desktop_windows"
|
||||
}
|
||||
|
||||
@@ -109,8 +105,7 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
color: session.index === sessions.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: Tokens.font.size.normal
|
||||
font.weight: 600
|
||||
font: Tokens.font.body.builders.medium.weight(Font.Bold).build()
|
||||
text: modelData.name
|
||||
}
|
||||
|
||||
@@ -118,8 +113,7 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
color: session.index === sessions.currentIndex ? Colors.palette.m3onPrimaryFixedVariant : Colors.palette.m3onSurfaceVariant
|
||||
elide: Text.ElideRight
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.pointSize: Tokens.font.size.small
|
||||
font: Tokens.font.mono.small
|
||||
text: modelData.kind
|
||||
}
|
||||
}
|
||||
@@ -129,7 +123,7 @@ ColumnLayout {
|
||||
color: Colors.palette.m3primary
|
||||
implicitHeight: sessions.currentItem?.implicitHeight ?? 0
|
||||
implicitWidth: sessions.width
|
||||
radius: Tokens.rounding.medium - Tokens.padding.small
|
||||
radius: Tokens.rounding.large
|
||||
y: sessions.currentItem?.y ?? 0
|
||||
|
||||
Behavior on y {
|
||||
|
||||
+11
-16
@@ -14,22 +14,19 @@ ColumnLayout {
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Tokens.padding.large
|
||||
spacing: Tokens.spacing.small
|
||||
spacing: Tokens.spacing.large
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
color: Colors.palette.m3outline
|
||||
elide: Text.ElideRight
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.weight: 500
|
||||
font: Tokens.font.mono.builders.small.weight(Font.Medium).build()
|
||||
text: root.greeter.users.length > 0 ? qsTr("%1 user%2").arg(root.greeter.users.length).arg(root.greeter.users.length === 1 ? "" : "s") : qsTr("Users")
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
color: "transparent"
|
||||
radius: Tokens.rounding.small
|
||||
|
||||
Loader {
|
||||
active: opacity > 0
|
||||
@@ -48,16 +45,14 @@ ColumnLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: Colors.palette.m3outlineVariant
|
||||
fill: 1
|
||||
font.pointSize: Tokens.font.size.extraLarge * 2
|
||||
fontStyle: Tokens.font.icon.large
|
||||
text: "account_circle"
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: Colors.palette.m3outlineVariant
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.pointSize: Tokens.font.size.large
|
||||
font.weight: 500
|
||||
font: Tokens.font.headline.builders.small.width(90).build()
|
||||
text: qsTr("No Users Found")
|
||||
}
|
||||
}
|
||||
@@ -70,6 +65,7 @@ ColumnLayout {
|
||||
clip: true
|
||||
currentIndex: root.greeter.selectedUser ? root.greeter.users.indexOf(root.greeter.selectedUser) : -1
|
||||
highlightFollowsCurrentItem: false
|
||||
boundsBehavior: ListView.StopAtBounds
|
||||
model: root.greeter.users
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
@@ -82,7 +78,7 @@ ColumnLayout {
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
implicitHeight: row.implicitHeight + Tokens.padding.small * 2
|
||||
radius: Tokens.rounding.medium - Tokens.padding.small
|
||||
radius: Tokens.rounding.large
|
||||
|
||||
StateLayer {
|
||||
onClicked: {
|
||||
@@ -97,7 +93,7 @@ ColumnLayout {
|
||||
anchors.margins: Tokens.padding.small
|
||||
spacing: Tokens.spacing.medium
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
Layout.preferredHeight: 50
|
||||
Layout.preferredWidth: 50
|
||||
radius: Tokens.rounding.full
|
||||
@@ -106,7 +102,7 @@ ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
color: user.index === users.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurfaceVariant
|
||||
fill: 1
|
||||
font.pointSize: Tokens.font.size.extraLarge
|
||||
fontStyle: Tokens.font.icon.extraLarge
|
||||
text: modelData.kind === "x11" ? "tv" : "account_circle"
|
||||
}
|
||||
|
||||
@@ -124,8 +120,7 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
color: user.index === users.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: Tokens.font.size.normal
|
||||
font.weight: 600
|
||||
font: Tokens.font.body.builders.medium.weight(Font.Bold).build()
|
||||
text: modelData.username
|
||||
}
|
||||
}
|
||||
@@ -135,7 +130,7 @@ ColumnLayout {
|
||||
color: Colors.palette.m3primary
|
||||
implicitHeight: users.currentItem?.implicitHeight ?? 0
|
||||
implicitWidth: users.width
|
||||
radius: Tokens.rounding.medium - Tokens.padding.small
|
||||
radius: Tokens.rounding.large
|
||||
y: users.currentItem?.y ?? 0
|
||||
|
||||
Behavior on y {
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import ZShell.Config
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Services
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
required property int rootHeight
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.margins: Tokens.padding.large * 2
|
||||
anchors.right: parent.right
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
Loader {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.bottomMargin: -Tokens.padding.large
|
||||
Layout.topMargin: Tokens.padding.large * 2
|
||||
active: root.rootHeight > 610
|
||||
visible: active
|
||||
|
||||
sourceComponent: CustomText {
|
||||
color: Colors.palette.m3primary
|
||||
font.pointSize: Tokens.font.size.extraLarge
|
||||
font.weight: 500
|
||||
text: qsTr("Weather")
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Tokens.spacing.largeIncreased
|
||||
|
||||
MaterialIcon {
|
||||
animate: true
|
||||
color: Colors.palette.m3secondary
|
||||
font.pointSize: Tokens.font.size.extraLarge * 2.5
|
||||
text: Weather.icon
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
animate: true
|
||||
color: Colors.palette.m3secondary
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: Tokens.font.size.large
|
||||
font.weight: 500
|
||||
text: Weather.description
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
animate: true
|
||||
color: Colors.palette.m3onSurfaceVariant
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: Tokens.font.size.normal
|
||||
text: qsTr("Humidity: %1%").arg(Weather.humidity)
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
Layout.rightMargin: Tokens.padding.small
|
||||
active: root.width > 400
|
||||
visible: active
|
||||
|
||||
sourceComponent: ColumnLayout {
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
animate: true
|
||||
color: Colors.palette.m3primary
|
||||
elide: Text.ElideLeft
|
||||
font.pointSize: Tokens.font.size.extraLarge
|
||||
font.weight: 500
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: Weather.temp
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
animate: true
|
||||
color: Colors.palette.m3outline
|
||||
elide: Text.ElideLeft
|
||||
font.pointSize: Tokens.font.size.smaller
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: qsTr("Feels like: %1").arg(Weather.feelsLike)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: forecastLoader
|
||||
|
||||
Layout.bottomMargin: Tokens.padding.large * 2
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Tokens.spacing.small
|
||||
active: root.rootHeight > 820
|
||||
visible: active
|
||||
|
||||
sourceComponent: RowLayout {
|
||||
spacing: Tokens.spacing.largeIncreased
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
const forecast = Weather.hourlyForecast;
|
||||
const count = root.width < 320 ? 3 : root.width < 400 ? 4 : 5;
|
||||
if (!forecast)
|
||||
return Array.from({
|
||||
length: count
|
||||
}, () => null);
|
||||
|
||||
const start = Math.max(0, Weather.currentHourIndex);
|
||||
return forecast.slice(start, start + count);
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: forecastHour
|
||||
|
||||
required property var modelData
|
||||
|
||||
Layout.fillWidth: true
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
color: Colors.palette.m3outline
|
||||
font.pointSize: Tokens.font.size.larger
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: {
|
||||
const hour = forecastHour.modelData?.hour ?? 0;
|
||||
return hour > 12 ? `${(hour - 12).toString().padStart(2, "0")} PM` : `${hour.toString().padStart(2, "0")} AM`;
|
||||
}
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
font.pointSize: Tokens.font.size.extraLarge * 1.5
|
||||
font.weight: 500
|
||||
text: forecastHour.modelData?.icon ?? "cloud_alert"
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: Colors.palette.m3secondary
|
||||
font.pointSize: Tokens.font.size.larger
|
||||
text: Config.services.useFahrenheit ? `${forecastHour.modelData?.tempF ?? 0}°F` : `${forecastHour.modelData?.tempC ?? 0}°C`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 900000 // 15 minutes
|
||||
repeat: true
|
||||
running: true
|
||||
triggeredOnStart: true
|
||||
|
||||
onTriggered: Weather.reload()
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import ZShell.Config
|
||||
import qs.Components
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property Item bar
|
||||
required property ScreenState screenState
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
CustomRect {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -1
|
||||
color: Colors.palette.m3surface
|
||||
layer.enabled: true
|
||||
|
||||
layer.effect: MultiEffect {
|
||||
maskEnabled: true
|
||||
maskInverted: true
|
||||
maskSource: mask
|
||||
maskSpreadAtMin: 1
|
||||
maskThresholdMin: 0.5
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: mask
|
||||
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
visible: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Config.bar.border + 1
|
||||
anchors.topMargin: root.bar.implicitHeight + 1
|
||||
radius: Config.bar.border > 0 ? Config.bar.rounding : 0
|
||||
topLeftRadius: Config.bar.rounding
|
||||
topRightRadius: Config.bar.rounding
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ Item {
|
||||
node: Audio.source
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
|
||||
@@ -249,7 +249,7 @@ Item {
|
||||
node: appBox.modelData
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ Item {
|
||||
searchField.forceActiveFocus();
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: search
|
||||
|
||||
anchors.left: parent.left
|
||||
@@ -54,7 +54,7 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: preview
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
@@ -228,7 +228,7 @@ Item {
|
||||
anchors.fill: parent
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: textRect
|
||||
|
||||
Layout.fillHeight: true
|
||||
|
||||
@@ -14,7 +14,7 @@ Row {
|
||||
padding: 20
|
||||
spacing: 12
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
|
||||
implicitHeight: info.implicitHeight
|
||||
implicitWidth: info.implicitHeight
|
||||
|
||||
@@ -16,7 +16,7 @@ Item {
|
||||
implicitWidth: 1000
|
||||
implicitHeight: 320
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
anchors.fill: parent
|
||||
radius: root.radius
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ CustomListView {
|
||||
anchors.bottom: parent.bottom
|
||||
spacing: Tokens.spacing.extraSmall / 2
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: iconClip
|
||||
|
||||
Layout.fillHeight: true
|
||||
|
||||
@@ -25,7 +25,7 @@ Item {
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: popupBackground
|
||||
readonly property real padding: 4
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ Item {
|
||||
visible: false
|
||||
z: 999
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: popupBackground
|
||||
|
||||
readonly property real padding: Tokens.padding.extraSmall
|
||||
|
||||
@@ -19,7 +19,7 @@ Item {
|
||||
implicitHeight: tileHeight + Tokens.padding.large * 2
|
||||
implicitWidth: tileWidth
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: image
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -55,7 +55,7 @@ ColumnLayout {
|
||||
text: Time.format("dddd, d MMMM yyyy")
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: Tokens.spacing.largeIncreased * 2
|
||||
color: Colors.tPalette.m3surfaceContainer
|
||||
|
||||
@@ -5,7 +5,7 @@ import qs.Helpers
|
||||
import ZShell.Config
|
||||
import qs.Services
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: root
|
||||
|
||||
required property var lock
|
||||
|
||||
@@ -2,12 +2,12 @@ import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import ZShell.Components
|
||||
import qs.Components
|
||||
import ZShell.Config
|
||||
import qs.Components
|
||||
import qs.Helpers
|
||||
import qs.Services
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: root
|
||||
|
||||
required property var lock
|
||||
|
||||
@@ -24,12 +24,11 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
color: Colors.palette.m3outline
|
||||
elide: Text.ElideRight
|
||||
font.family: Config.appearance.font.family.mono
|
||||
font.weight: 500
|
||||
font: Tokens.font.mono.builders.small.weight(Font.Medium).build()
|
||||
text: NotifServer.list.length > 0 ? qsTr("%1 notification%2").arg(NotifServer.list.length).arg(NotifServer.list.length === 1 ? "" : "s") : qsTr("Notifications")
|
||||
}
|
||||
|
||||
ClippingRectangle {
|
||||
ClipRect {
|
||||
id: clipRect
|
||||
|
||||
Layout.fillHeight: true
|
||||
|
||||
@@ -85,7 +85,7 @@ CustomRect {
|
||||
}
|
||||
}
|
||||
|
||||
ClippingRectangle {
|
||||
ClipRect {
|
||||
anchors.fill: parent
|
||||
color: root.urgency === "critical" ? Colors.palette.m3error : root.urgency === "low" ? Colors.layer(Colors.palette.m3surfaceContainerHighest, 3) : Colors.palette.m3secondaryContainer
|
||||
radius: Tokens.rounding.full
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
import qs.Components
|
||||
import qs.Paths
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
ClippingRectangle {
|
||||
ClipRect {
|
||||
anchors.fill: parent
|
||||
radius: Tokens.rounding.full
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ CustomRect {
|
||||
visible: root.hasImage || root.hasAppIcon
|
||||
width: Config.notifs.sizes.image
|
||||
|
||||
sourceComponent: CustomClippingRect {
|
||||
sourceComponent: ClipRect {
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? Colors.palette.m3error : root.modelData.urgency === NotificationUrgency.Low ? Colors.layer(Colors.palette.m3surfaceContainerHighest, 2) : Colors.palette.m3secondaryContainer
|
||||
implicitHeight: Config.notifs.sizes.image
|
||||
implicitWidth: Config.notifs.sizes.image
|
||||
|
||||
@@ -5,7 +5,7 @@ import ZShell.Config
|
||||
import qs.Components
|
||||
import qs.Services
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: root
|
||||
|
||||
property real animPerc: UPower.displayDevice.percentage
|
||||
|
||||
@@ -19,7 +19,7 @@ CustomRect {
|
||||
implicitWidth: 450
|
||||
radius: Tokens.rounding.largeIncreased
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
Flickable {
|
||||
CustomFlickable {
|
||||
id: flickable
|
||||
|
||||
Layout.fillHeight: true
|
||||
|
||||
@@ -25,7 +25,7 @@ Item {
|
||||
anchors.fill: parent
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: imgWrapper
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -100,16 +100,13 @@ Item {
|
||||
visible: opacity > 0
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
Behavior on scale {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
Behavior on y {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
@@ -120,9 +117,8 @@ Item {
|
||||
Qt.callLater(syncCropToScreen);
|
||||
}
|
||||
|
||||
ButtonRow {
|
||||
id: screenSelector
|
||||
|
||||
Loader {
|
||||
id: selectorLoader
|
||||
anchors.bottom: imageSlot.top
|
||||
anchors.bottomMargin: Tokens.spacing.medium
|
||||
anchors.left: parent.left
|
||||
@@ -130,25 +126,32 @@ Item {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Tokens.padding.extraLarge * 2
|
||||
anchors.top: parent.top
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
Repeater {
|
||||
model: wrapper.screens
|
||||
active: wrapper.screens.length > 1
|
||||
|
||||
delegate: TextButton {
|
||||
required property int index
|
||||
readonly property bool isCurrent: wrapper.selectedScreenIndex === index
|
||||
required property var modelData
|
||||
sourceComponent: ButtonRow {
|
||||
id: screenSelector
|
||||
|
||||
fillWidth: true
|
||||
font: Tokens.font.body.builders.large.weight(Font.DemiBold).build()
|
||||
inactiveColor: isCurrent ? Colors.palette.m3primary : Qt.alpha(Colors.palette.m3surfaceContainer, 0.7)
|
||||
inactiveOnColor: isCurrent ? Colors.palette.m3onPrimary : Qt.alpha(Colors.palette.m3onSurface, 0.7)
|
||||
isRound: true
|
||||
shapeMorph: true
|
||||
text: modelData.name
|
||||
spacing: Tokens.spacing.small
|
||||
|
||||
onClicked: wrapper.selectScreen(index)
|
||||
Repeater {
|
||||
model: wrapper.screens
|
||||
|
||||
delegate: TextButton {
|
||||
required property int index
|
||||
readonly property bool isCurrent: wrapper.selectedScreenIndex === index
|
||||
required property var modelData
|
||||
|
||||
fillWidth: true
|
||||
font: Tokens.font.body.builders.large.weight(Font.DemiBold).build()
|
||||
inactiveColor: isCurrent ? Colors.palette.m3primary : Qt.alpha(Colors.palette.m3surfaceContainer, 0.7)
|
||||
inactiveOnColor: isCurrent ? Colors.palette.m3onPrimary : Qt.alpha(Colors.palette.m3onSurface, 0.7)
|
||||
isRound: true
|
||||
shapeMorph: true
|
||||
text: modelData.name
|
||||
|
||||
onClicked: wrapper.selectScreen(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,9 +225,9 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: wrapper.buttonRowHeight + Tokens.spacing.medium
|
||||
anchors.topMargin: selectorLoader.active ? wrapper.buttonRowHeight + Tokens.spacing.medium : Tokens.spacing.medium
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: fitBox
|
||||
|
||||
readonly property real aspect: scaledImg.implicitHeight > 0 ? scaledImg.implicitWidth / scaledImg.implicitHeight : 1
|
||||
@@ -357,8 +360,7 @@ Item {
|
||||
width: Math.round(baseWidth / zoom)
|
||||
|
||||
Behavior on color {
|
||||
CAnim {
|
||||
}
|
||||
CAnim {}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
||||
@@ -38,6 +38,7 @@ Item {
|
||||
}
|
||||
|
||||
BlobInvertedRect {
|
||||
id: blobRect
|
||||
anchors.fill: parent
|
||||
borderBottom: Tokens.padding.small
|
||||
borderLeft: navPane.width + navPane.anchors.margins * 2
|
||||
@@ -65,6 +66,7 @@ Item {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: navPane.right
|
||||
anchors.leftMargin: navPane.anchors.margins + anchors.margins
|
||||
anchors.bottomMargin: blobRect.borderBottom
|
||||
anchors.margins: Tokens.padding.extraLarge
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
|
||||
@@ -436,7 +436,7 @@ Item {
|
||||
width: attachments.cellWidth
|
||||
height: width
|
||||
opacity: modelData ? 1 : 0
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Tokens.spacing.extraSmall
|
||||
|
||||
|
||||
@@ -337,7 +337,7 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: expandedTool
|
||||
|
||||
anchors.top: collapsedRow.bottom
|
||||
|
||||
@@ -252,7 +252,7 @@ CustomRect {
|
||||
}
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
CustomRect {
|
||||
id: codeRect
|
||||
|
||||
anchors.left: parent.left
|
||||
@@ -265,6 +265,7 @@ CustomRect {
|
||||
implicitWidth: codeText.implicitWidth + codeFlick.anchors.margins * 2
|
||||
implicitHeight: codeText.implicitHeight + codeFlick.anchors.margins * 2
|
||||
color: CodeColors.active.bg
|
||||
clip: true
|
||||
|
||||
Flickable {
|
||||
id: codeFlick
|
||||
@@ -272,6 +273,9 @@ CustomRect {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Tokens.padding.small
|
||||
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
contentWidth: codeText.implicitWidth
|
||||
|
||||
CustomScrollBar.horizontal: CustomScrollBar {
|
||||
flickable: codeFlick
|
||||
parent: codeFlick.parent
|
||||
@@ -280,16 +284,13 @@ CustomRect {
|
||||
anchors.right: parent.right
|
||||
}
|
||||
|
||||
TextAreaBase.flickable: TextAreaBase {
|
||||
CustomText {
|
||||
id: codeText
|
||||
|
||||
color: CodeColors.active.normal
|
||||
layer.enabled: true
|
||||
clip: false
|
||||
font: Tokens.font.mono.small
|
||||
textFormat: root.colored ? Text.RichText : Text.PlainText
|
||||
textFormat: Text.RichText
|
||||
text: root.colored ? root.html : root.plainForDisplay(root.code)
|
||||
readOnly: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ Item {
|
||||
current: root.current
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
id: expandedRect
|
||||
|
||||
anchors.left: parent.left
|
||||
|
||||
@@ -86,7 +86,7 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: invertedRect.borderLeft
|
||||
anchors.topMargin: invertedRect.borderTop
|
||||
|
||||
@@ -17,76 +17,6 @@ Item {
|
||||
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: flickable.contentHeight
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
|
||||
layer.effect: Mask {
|
||||
maskSource: gradientMask
|
||||
}
|
||||
|
||||
Item {
|
||||
id: gradientMask
|
||||
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
visible: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
||||
gradient: Gradient {
|
||||
orientation: Gradient.Horizontal
|
||||
|
||||
GradientStop {
|
||||
color: Qt.rgba(0, 0, 0, 0)
|
||||
position: 0
|
||||
}
|
||||
|
||||
GradientStop {
|
||||
color: Qt.rgba(0, 0, 0, 1)
|
||||
position: 0.1
|
||||
}
|
||||
|
||||
GradientStop {
|
||||
color: Qt.rgba(0, 0, 0, 1)
|
||||
position: 0.9
|
||||
}
|
||||
|
||||
GradientStop {
|
||||
color: Qt.rgba(0, 0, 0, 0)
|
||||
position: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
implicitWidth: parent.width / 2
|
||||
opacity: flickable.contentX > 0 ? 0 : 1
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
implicitWidth: parent.width / 2
|
||||
opacity: flickable.contentX < flickable.contentWidth - parent.width ? 0 : 1
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.DefaultEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomFlickable {
|
||||
id: flickable
|
||||
|
||||
@@ -112,7 +112,7 @@ CustomRect {
|
||||
}
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
ClipRect {
|
||||
anchors.fill: parent
|
||||
color: root.urgency === NotificationUrgency.Critical ? Colors.palette.m3error : root.urgency === NotificationUrgency.Low ? Colors.layer(Colors.palette.m3surfaceContainerHigh, 3) : Colors.palette.m3secondaryContainer
|
||||
radius: Tokens.rounding.full
|
||||
|
||||
@@ -218,7 +218,7 @@ void BlobInvertedRect::outerCornerRadii(float out[4]) const {
|
||||
const auto base = std::min(static_cast<float>(m_outerRadius), maxR);
|
||||
out[0] = std::min(
|
||||
m_outerTopRightRadius >= 0 ? static_cast<float>(m_outerTopRightRadius)
|
||||
: base,
|
||||
: base,
|
||||
maxR);
|
||||
out[1] = std::min(
|
||||
m_outerBottomRightRadius >= 0
|
||||
|
||||
@@ -60,11 +60,15 @@ class BlobInvertedRect : public BlobShape {
|
||||
void setOuterRadius(qreal v);
|
||||
|
||||
// Per-corner outer radii. -1 falls back to outerRadius (mirrors BlobRect).
|
||||
[[nodiscard]] qreal outerTopLeftRadius() const { return m_outerTopLeftRadius; }
|
||||
[[nodiscard]] qreal outerTopLeftRadius() const {
|
||||
return m_outerTopLeftRadius;
|
||||
}
|
||||
|
||||
void setOuterTopLeftRadius(qreal v);
|
||||
|
||||
[[nodiscard]] qreal outerTopRightRadius() const { return m_outerTopRightRadius; }
|
||||
[[nodiscard]] qreal outerTopRightRadius() const {
|
||||
return m_outerTopRightRadius;
|
||||
}
|
||||
|
||||
void setOuterTopRightRadius(qreal v);
|
||||
|
||||
|
||||
@@ -240,8 +240,7 @@ void BlobShape::updatePolish() {
|
||||
m_cachedInvertedRadius = 0;
|
||||
memset(m_cachedInvertedOuter, 0, sizeof(m_cachedInvertedOuter));
|
||||
memset(m_cachedInvertedInner, 0, sizeof(m_cachedInvertedInner));
|
||||
memset(
|
||||
m_cachedInvertedOuterRadii, 0, sizeof(m_cachedInvertedOuterRadii));
|
||||
memset(m_cachedInvertedOuterRadii, 0, sizeof(m_cachedInvertedOuterRadii));
|
||||
|
||||
auto* inv = m_group->invertedRect();
|
||||
if (inv) {
|
||||
|
||||
@@ -662,6 +662,17 @@ void WallpaperService::drawSurface(WallpaperSurface* surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Release the context when this scope ends (see FrameService::drawSurface).
|
||||
// Holding it across the draw loop's sleep serializes the two raw-EGL clients on
|
||||
// NVIDIA, which makes eglSwapBuffers fail and starves other processes' contexts.
|
||||
struct ContextRelease {
|
||||
EGLDisplay display;
|
||||
~ContextRelease() {
|
||||
eglMakeCurrent(
|
||||
display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
} contextRelease{m_eglDisplay};
|
||||
|
||||
QVariantMap crops;
|
||||
QSize size;
|
||||
bool upload = false;
|
||||
@@ -701,7 +712,9 @@ void WallpaperService::drawSurface(WallpaperSurface* surface) {
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
if (!eglSwapBuffers(m_eglDisplay, target))
|
||||
qWarning() << "WallpaperService: eglSwapBuffers failed";
|
||||
qWarning()
|
||||
<< "WallpaperService: eglSwapBuffers failed, eglGetError = 0x"
|
||||
<< QString::number(unsigned(eglGetError()), 16);
|
||||
}
|
||||
|
||||
void WallpaperService::addSurface(const QString& screen) {
|
||||
|
||||
+25
-53
@@ -1,56 +1,28 @@
|
||||
FROM archlinux:latest
|
||||
|
||||
RUN pacman -Syyu --noconfirm
|
||||
RUN pacman -Syu --noconfirm \
|
||||
&& pacman -S --needed --noconfirm \
|
||||
base-devel cmake ninja clang lld nodejs tree-sitter \
|
||||
jkqtplotter cmark-gfm git wayland-protocols \
|
||||
qt6-base qt6-declarative qt6-shadertools qt6-5compat \
|
||||
qt6-canvaspainter qt6-wayland qt5-wayland\
|
||||
libqalculate pipewire aubio cava lm_sensors glib2 \
|
||||
&& pacman -Scc --noconfirm
|
||||
|
||||
# Build toolchain
|
||||
RUN pacman -S --noconfirm \
|
||||
base-devel \
|
||||
cmake \
|
||||
ninja \
|
||||
clang \
|
||||
lld \
|
||||
nodejs \
|
||||
tree-sitter \
|
||||
jkqtplotter \
|
||||
cmark-gfm \
|
||||
git
|
||||
|
||||
# Qt6
|
||||
RUN pacman -S --noconfirm \
|
||||
qt6-base \
|
||||
qt6-declarative \
|
||||
qt6-shadertools \
|
||||
qt6-5compat \
|
||||
qt6-canvaspainter
|
||||
|
||||
# Project-specific dependencies
|
||||
RUN pacman -S --noconfirm \
|
||||
libqalculate \
|
||||
pipewire \
|
||||
aubio \
|
||||
cava \
|
||||
lm_sensors \
|
||||
glib2
|
||||
|
||||
# AUR: libcava (provides development headers for cava)
|
||||
RUN pacman -Syu --noconfirm && \
|
||||
pacman -S --needed --noconfirm \
|
||||
sudo \
|
||||
meson \
|
||||
autoconf-archive \
|
||||
python-tqdm && \
|
||||
useradd -m builder && \
|
||||
echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||
|
||||
RUN for i in 1 2 3 4 5; do \
|
||||
rm -rf /tmp/libcava && \
|
||||
git clone --depth 1 https://aur.archlinux.org/libcava.git /tmp/libcava && \
|
||||
break || sleep 5; \
|
||||
done && \
|
||||
test -d /tmp/libcava/.git && \
|
||||
chown -R builder /tmp/libcava
|
||||
|
||||
RUN su builder -c "cd /tmp/libcava && makepkg -si --noconfirm" && \
|
||||
rm -rf /tmp/libcava && \
|
||||
userdel -r builder && \
|
||||
sed -i '/^builder/d' /etc/sudoers
|
||||
RUN pacman -Syu --noconfirm \
|
||||
&& pacman -S --needed --noconfirm \
|
||||
sudo meson autoconf-archive python-tqdm \
|
||||
&& useradd -m builder \
|
||||
&& printf '%s\n' 'builder ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/builder \
|
||||
&& chmod 0440 /etc/sudoers.d/builder \
|
||||
&& for i in 1 2 3 4 5; do \
|
||||
rm -rf /tmp/libcava; \
|
||||
if git clone --depth 1 https://aur.archlinux.org/libcava.git /tmp/libcava; then break; fi; \
|
||||
sleep 5; \
|
||||
done \
|
||||
&& test -d /tmp/libcava/.git \
|
||||
&& chown -R builder:builder /tmp/libcava \
|
||||
&& su builder -c "cd /tmp/libcava && makepkg -si --noconfirm" \
|
||||
&& rm -rf /tmp/libcava /etc/sudoers.d/builder \
|
||||
&& userdel -r builder \
|
||||
&& pacman -Scc --noconfirm
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
BUILD ?= cmake -B build -G Ninja
|
||||
NINJA ?= ninja -C build
|
||||
COMPILE ?= $(BUILD) && $(NINJA)
|
||||
INSTALL ?= $(BUILD) && $(NINJA) && sudo ninja -C build install
|
||||
|
||||
CPPFMT ?= find . \( -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) -not -path './build/*' -exec clang-format -i --style=file {} +
|
||||
|
||||
NUITKA ?= nuitka --module --include-package=zshell cli/src/zshell/ --output-dir=cli/
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
# string is misaligned to align when run in terminal
|
||||
help:
|
||||
@echo "build cmake builds into build directory"
|
||||
@echo "install cmake builds, compiles and installs into filesystem"
|
||||
@echo "compile cmake builds and compiles C++ code"
|
||||
@echo "cpp-fmt format C++ code with clang-format"
|
||||
@echo "cpp-lint lint check C++ code with clang-tidy"
|
||||
@echo "cpp-compile alias to make compile"
|
||||
@echo "py-fmt format Python code with ruff"
|
||||
@echo "py-lint lint check Python code with ruff"
|
||||
@echo "py-check lsp and typecheck all Python code using Basedpyright"
|
||||
@echo "py-test run all Python tests using Pytest"
|
||||
@echo "py-compile compiles Python code using Nuitka"
|
||||
@echo "rs-compile compiles Rust code"
|
||||
@echo "rs-format formats Rust code with Rustfmt"
|
||||
@echo "rs-lint lint check Rust code with Clippy"
|
||||
@echo "rs-test runs all Rust tests"
|
||||
@echo "check-cpp runs all C++ checks"
|
||||
@echo "check-py runs all Python checks"
|
||||
@echo "check-rs runs all Rust checks"
|
||||
|
||||
build:
|
||||
$(BUILD)
|
||||
|
||||
install:
|
||||
$(INSTALL)
|
||||
|
||||
compile:
|
||||
$(COMPILE)
|
||||
|
||||
# TODO: Anything below is not ready
|
||||
|
||||
# C++
|
||||
cpp-fmt:
|
||||
$(CPPFMT)
|
||||
|
||||
# cpp-lint needs adjustments in ci and here
|
||||
|
||||
cpp-compile:
|
||||
$(COMPILE)
|
||||
|
||||
# Python
|
||||
py-fmt:
|
||||
ruff format --check
|
||||
|
||||
py-lint:
|
||||
ruff check ./cli
|
||||
|
||||
py-check:
|
||||
basedpyright
|
||||
|
||||
py-test:
|
||||
python -m pytest ./cli/tests/ -v
|
||||
|
||||
# Want to use gcc, clang or zig C compiler instead? Output directory?
|
||||
py-compile:
|
||||
$(NUITKA)
|
||||
|
||||
# Rust
|
||||
rs-compile:
|
||||
cd ./zshell-img-tools/ && cargo run
|
||||
|
||||
rs-fmt:
|
||||
cd ./zshell-img-tools/ && cargo fmt && echo "formatted!"
|
||||
|
||||
rs-lint:
|
||||
cd ./zshell-img-tools/ && cargo clippy
|
||||
|
||||
rs-test:
|
||||
cd ./zshell-img-tools/ && cargo test
|
||||
|
||||
# Qml
|
||||
|
||||
|
||||
# Full checks
|
||||
check-cpp:
|
||||
$(MAKE) cpp-fmt
|
||||
$(MAKE) cpp-lint
|
||||
$(MAKE) install
|
||||
|
||||
check-rs:
|
||||
$(MAKE) rs-fmt
|
||||
$(MAKE) rs-lint
|
||||
$(MAKE) rs-test
|
||||
$(MAKE) rs-compile
|
||||
|
||||
check-py:
|
||||
$(MAKE) py-fmt
|
||||
$(MAKE) py-lint
|
||||
$(MAKE) py-test
|
||||
$(MAKE) py-check
|
||||
$(MAKE) py-compile
|
||||
@@ -1,7 +1,5 @@
|
||||
//@ pragma UseQApplication
|
||||
//@ pragma DefaultEnv QSG_RENDER_LOOP=threaded
|
||||
// @ pragma DefaultEnv QSG_RHI_BACKEND=vulkan
|
||||
//@ pragma DefaultEnv QSG_NO_VSYNC=1
|
||||
//@ pragma DefaultEnv QS_NO_RELOAD_POPUP=1
|
||||
//@ pragma DefaultEnv QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000
|
||||
//@ pragma DropExpensiveFonts
|
||||
|
||||
Reference in New Issue
Block a user