Compare commits
168 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ad23da4eda | |||
| 06ebc4ffbf | |||
| f2f9fa1302 | |||
| b4020438f9 | |||
| 184ab20d11 | |||
| 5097e30a77 | |||
| ef71ae8afd | |||
| 6533533936 | |||
| 9688072e93 | |||
|
9c36f0de5b
|
|||
| 9ca46967d9 | |||
| 16e84ca998 | |||
|
c30128cf95
|
|||
| ba9926af18 | |||
| 78fcf33b3a | |||
| 5e9b373405 | |||
| b49165e7ea | |||
| d0cda51639 | |||
| ad57764636 | |||
| 96afbdb30b | |||
| 5df46160f6 | |||
| d118c02e75 | |||
| 21ed178bbc | |||
| 2934d863ca | |||
| 7c29921a6b | |||
| 0309fde3aa | |||
| f147969f37 | |||
| 90a1954658 | |||
| 2b550763e7 | |||
| 3037cfab53 | |||
| 5f92b6f6de | |||
| 67ae693d0c | |||
| fd620e7487 | |||
| 0ec426e0f0 | |||
| ec5e6d3995 | |||
| 41a129bb90 | |||
| 8c48ddbbe7 | |||
| 625d766719 | |||
| 88526b9e98 | |||
| a0d56b965c | |||
| 2342edcf66 | |||
| 9e75b593f4 | |||
| 4663c7d683 | |||
| 80683800eb | |||
| 57836f974c | |||
| 8dbb88e136 | |||
| 06c402c050 | |||
| e425a1701b | |||
| 41666d0150 | |||
| 853b683962 | |||
| b1bfcb3ed0 | |||
| 68662120ba | |||
| b8af60008d | |||
| b8524ff621 | |||
| ffde4063a0 | |||
| 96bf5f3365 | |||
| 053efb4aaf | |||
| c88aef2164 | |||
| 01b54ec5e1 | |||
| 7276ee28dc | |||
| a14ebe2016 | |||
| d3f6765819 | |||
| a3d0ee18cb | |||
| c9d6b95ca5 | |||
| 794a26a3fe | |||
| ca3a288eab | |||
| 902863e5ba | |||
| dd49198cf7 | |||
| ceca949535 | |||
| 24d5584b98 | |||
| 62ec1b9f33 | |||
| 9c6a1ce1a4 | |||
| b6ad180b6a | |||
| b20767c702 | |||
| 362b7bb8c2 | |||
| 405825518a | |||
| db7a822caf | |||
| 3bd9444e2f | |||
| d0e696c681 | |||
| 550630feaa | |||
| 8c22855dd8 | |||
| 015ee61885 | |||
| 8fba953f52 | |||
| 3d2fc0a3b1 | |||
| c060be79e8 | |||
| cb1df5078b | |||
| 5eb32fc30c | |||
| 0a84c822d5 | |||
| f89236f51e | |||
| 4b1316e887 | |||
| 63f4694322 | |||
| 51a8f1d5e1 | |||
| d57010a501 | |||
| d506d5ad27 | |||
| f6119072f7 | |||
| 00063309cd | |||
| c30891de83 | |||
| 55e9c0f267 | |||
| 3424df53e2 | |||
| 583c50f994 | |||
| ca53152630 | |||
| 0cd7df243b | |||
| 6a8ad4dbf2 | |||
| f57577fefd | |||
| 3a05cd339d | |||
| c67a498f8d | |||
| e7e772ebc6 | |||
| fb2c9c6a21 | |||
| 383671344f | |||
| beb1d96750 | |||
| 6f8af9028b | |||
| e874c19ee2 | |||
| af04e5d227 | |||
| 4ab19a8e37 | |||
| 783d05f815 | |||
| 17fb9c0fef | |||
| 39cbfa2c93 | |||
| 5c5018033d | |||
| d9afc6c7c7 | |||
| 17fef78672 | |||
| c120dcae41 | |||
| 64e65ca9df | |||
| 22a7993c07 | |||
| 24526ca2d1 | |||
| c5ee27bf62 | |||
| 7cec08d262 | |||
| 97b657ce9a | |||
| 33f6706658 | |||
| f6c4dc8ee1 | |||
| a53a4b32eb | |||
| e80ac202d0 | |||
| 6e6f6c28f6 | |||
| 26bfa952d7 | |||
| 611abdf028 | |||
| 37a112a04b | |||
| bfc09c71a8 | |||
| c7fabf9fc5 | |||
| 0bae21c891 | |||
| 53733c7fe0 | |||
| 836b92cc5f | |||
| bcc75abc54 | |||
| 11c185baa6 | |||
| 7cc056c327 | |||
| f657741551 | |||
| 073e1dd8b1 | |||
| 8fa447c63d | |||
| e4113994dc | |||
| 8a2eeb6c31 | |||
| 10340a83dd | |||
| c2bd45db4a | |||
| d5256a3952 | |||
| abd85388f6 | |||
| 2bad732592 | |||
| 47120db391 | |||
| d568cd34ab | |||
| a3a55ba8d1 | |||
| 8db28ec3a0 | |||
| 9688e99a8e | |||
| cbc81a1af8 | |||
| 14ec888269 | |||
| 2eb0529e98 | |||
| 7a2786af66 | |||
| 1eb2bbda00 | |||
| 6b8ae3f291 | |||
| 4a18eda37c | |||
| 85c126ad1e | |||
| 6316e788b9 | |||
| 3cf206ea43 |
@@ -0,0 +1,42 @@
|
|||||||
|
name: Lint & Format (JS/TS)
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint-format:
|
||||||
|
runs-on: alpine
|
||||||
|
container: node:26-alpine
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install tools
|
||||||
|
run: |
|
||||||
|
apk add --no-cache \
|
||||||
|
git
|
||||||
|
|
||||||
|
- name: Prettier
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
if [ -n "$(find . \( -iname "*.js" -o -iname "*.jsx" -o -iname "*.ts" -o -iname "*.tsx" -o -iname "*.mjs" -o -iname "*.cjs" \) -print -quit)" ]; then
|
||||||
|
npx --yes prettier --check "**/*.{js,jsx,ts,tsx,mjs,cjs}" --ignore-path .prettierignore
|
||||||
|
else
|
||||||
|
echo "No JS/TS files found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- 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
|
||||||
|
if [ -f package.json ]; then
|
||||||
|
npm install --no-audit --no-fund
|
||||||
|
fi
|
||||||
|
if [ -f eslint.config.js ] || [ -f eslint.config.mjs ] || [ -f eslint.config.cjs ] || [ -f .eslintrc ] || [ -f .eslintrc.js ] || [ -f .eslintrc.cjs ] || [ -f .eslintrc.json ] || [ -f .eslintrc.yaml ] || [ -f .eslintrc.yml ]; then
|
||||||
|
npx --yes eslint . && echo "ESLint passed" || echo "ESLint failed"
|
||||||
|
else
|
||||||
|
echo "No eslint config found"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "No JS/TS files found"
|
||||||
|
fi
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
name: Python
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint-format:
|
||||||
|
runs-on: alpine
|
||||||
|
container: node:26-alpine
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install tools
|
||||||
|
run: |
|
||||||
|
apk add --no-cache \
|
||||||
|
git \
|
||||||
|
python3 \
|
||||||
|
py3-pip
|
||||||
|
python3 -m venv .venv
|
||||||
|
. .venv/bin/activate
|
||||||
|
pip install --no-cache-dir ruff
|
||||||
|
|
||||||
|
- name: Format check
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
. .venv/bin/activate
|
||||||
|
ruff format --check .
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: |
|
||||||
|
. .venv/bin/activate
|
||||||
|
ruff check .
|
||||||
|
|
||||||
|
test:
|
||||||
|
runs-on: alpine
|
||||||
|
container: node:26-alpine
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install tools
|
||||||
|
run: |
|
||||||
|
apk add --no-cache \
|
||||||
|
git \
|
||||||
|
python3 \
|
||||||
|
py3-pip \
|
||||||
|
py3-pillow \
|
||||||
|
build-base
|
||||||
|
python3 -m venv .venv
|
||||||
|
. .venv/bin/activate
|
||||||
|
pip install --no-cache-dir \
|
||||||
|
typer \
|
||||||
|
pillow \
|
||||||
|
materialyoucolor \
|
||||||
|
jinja2 \
|
||||||
|
pytest
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
. .venv/bin/activate
|
||||||
|
cd cli
|
||||||
|
python -m pytest tests/ -v
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
name: Lint & Format (Rust)
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint-format:
|
||||||
|
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-${{ runner.os }}-build-${{ 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 \
|
||||||
|
rust-clippy
|
||||||
|
|
||||||
|
- name: Format check
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
|
||||||
|
for manifest in $(find . -name "Cargo.toml"); do
|
||||||
|
cargo fmt --manifest-path "$manifest" --check && \
|
||||||
|
echo "$manifest: formatting OK" || \
|
||||||
|
echo "$manifest: needs formatting"
|
||||||
|
done
|
||||||
|
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
|
||||||
|
|
||||||
|
- name: Clippy
|
||||||
|
run: |
|
||||||
|
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
|
||||||
|
status=0
|
||||||
|
for manifest in $(find . -name "Cargo.toml"); do
|
||||||
|
cargo clippy --manifest-path "$manifest" --all-targets --all-features -- -D warnings && \
|
||||||
|
echo "$manifest: Clippy passed" || \
|
||||||
|
{ echo "$manifest: Clippy failed"; 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
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
**/__pycache__/
|
||||||
./result/
|
./result/
|
||||||
.pyre/
|
.pyre/
|
||||||
.cache/
|
.cache/
|
||||||
@@ -11,3 +12,4 @@ pkg/
|
|||||||
uv.lock
|
uv.lock
|
||||||
.qtcreator/
|
.qtcreator/
|
||||||
dist/
|
dist/
|
||||||
|
**/target/
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.venv/
|
||||||
|
scripts/fzf.js
|
||||||
|
scripts/fuzzysort.js
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": false,
|
||||||
|
"jsxSingleQuote": false,
|
||||||
|
"tabWidth": 4,
|
||||||
|
"printWidth": 80,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"bracketSameLine": false,
|
||||||
|
"arrowParens": "always",
|
||||||
|
"endOfLine": "lf",
|
||||||
|
"proseWrap": "preserve"
|
||||||
|
}
|
||||||
+8
-1
@@ -31,6 +31,13 @@ if("shell" IN_LIST ENABLE_MODULES)
|
|||||||
foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths)
|
foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths)
|
||||||
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
|
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
|
||||||
endforeach()
|
endforeach()
|
||||||
install(FILES shell.qml DESTINATION "${INSTALL_QSCONFDIR}")
|
|
||||||
|
# Disable watching for changes
|
||||||
|
file(READ shell.qml SHELL_QML)
|
||||||
|
string(REPLACE "settings.watchFiles: true" "settings.watchFiles: false" SHELL_QML "${SHELL_QML}")
|
||||||
|
file(WRITE "${CMAKE_BINARY_DIR}/qml/shell.qml" "${SHELL_QML}")
|
||||||
|
install(FILES "${CMAKE_BINARY_DIR}/qml/shell.qml" DESTINATION "${INSTALL_QSCONFDIR}")
|
||||||
|
|
||||||
|
# Greeter
|
||||||
install(DIRECTORY Greeter/ DESTINATION "${INSTALL_GREETERCONFDIR}")
|
install(DIRECTORY Greeter/ DESTINATION "${INSTALL_GREETERCONFDIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@ import QtQuick
|
|||||||
import qs.Config
|
import qs.Config
|
||||||
|
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: MaterialEasing.standardTime
|
duration: Appearance.anim.durations.normal
|
||||||
easing.bezierCurve: MaterialEasing.standard
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,20 +8,34 @@ Item {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property alias active: splitButton.active
|
property alias active: splitButton.active
|
||||||
|
property alias buttonAlias: splitButton
|
||||||
property bool enabled: true
|
property bool enabled: true
|
||||||
property alias expanded: splitButton.expanded
|
property alias expanded: splitButton.expanded
|
||||||
property int expandedZ: 100
|
property int expandedZ: 100
|
||||||
required property string label
|
required property string label
|
||||||
property alias menuItems: splitButton.menuItems
|
property alias menuItems: splitButton.menuItems
|
||||||
|
property bool shouldBeActive: true
|
||||||
property alias type: splitButton.type
|
property alias type: splitButton.type
|
||||||
|
|
||||||
signal selected(item: MenuItem)
|
signal selected(item: MenuItem)
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
|
anchors.right: parent.right
|
||||||
clip: false
|
clip: false
|
||||||
|
implicitHeight: row.implicitHeight + Appearance.padding.smaller * 2
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
z: root.expanded ? expandedZ : -1
|
z: root.expanded ? expandedZ : -1
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: row
|
id: row
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Text {
|
|||||||
color: DynamicColors.palette.m3onSurface
|
color: DynamicColors.palette.m3onSurface
|
||||||
font.family: Appearance.font.family.sans
|
font.family: Appearance.font.family.sans
|
||||||
font.pointSize: Appearance.font.size.normal
|
font.pointSize: Appearance.font.size.normal
|
||||||
|
linkColor: DynamicColors.palette.m3onPrimaryFixedVariant
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
textFormat: Text.PlainText
|
textFormat: Text.PlainText
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property bool shouldBeVisible
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
scale: 0
|
||||||
|
visible: root.scale > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.small
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onShouldBeVisibleChanged: {
|
||||||
|
if (root.shouldBeVisible) {
|
||||||
|
root.opacity = 1;
|
||||||
|
root.scale = 1;
|
||||||
|
} else {
|
||||||
|
root.opacity = 0;
|
||||||
|
root.scale = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,12 +41,11 @@ CustomRect {
|
|||||||
color: type === IconButton.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour
|
color: type === IconButton.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour
|
||||||
implicitHeight: label.implicitHeight + padding * 2
|
implicitHeight: label.implicitHeight + padding * 2
|
||||||
implicitWidth: implicitHeight
|
implicitWidth: implicitHeight
|
||||||
radius: internalChecked ? 6 : implicitHeight / 2 * Math.min(1, 1)
|
radius: internalChecked ? 6 : (implicitHeight / 2 * Math.min(1, 1)) * Appearance.rounding.scale
|
||||||
|
|
||||||
Behavior on radius {
|
Behavior on radius {
|
||||||
Anim {
|
Anim {
|
||||||
id: radiusAnim
|
id: radiusAnim
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,4 +7,8 @@ JsonObject {
|
|||||||
property real alignX: 0.5
|
property real alignX: 0.5
|
||||||
property real alignY: 0.5
|
property real alignY: 0.5
|
||||||
property real zoom: 1.0
|
property real zoom: 1.0
|
||||||
|
property real sourceClipX: 0
|
||||||
|
property real sourceClipY: 0
|
||||||
|
property real sourceClipW: 0
|
||||||
|
property real sourceClipH: 0
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-12
@@ -8,10 +8,6 @@ JsonObject {
|
|||||||
id: "workspaces",
|
id: "workspaces",
|
||||||
enabled: true
|
enabled: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "audio",
|
|
||||||
enabled: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "media",
|
id: "media",
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -24,10 +20,6 @@ JsonObject {
|
|||||||
id: "updates",
|
id: "updates",
|
||||||
enabled: true
|
enabled: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "dash",
|
|
||||||
enabled: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "spacer",
|
id: "spacer",
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -48,10 +40,6 @@ JsonObject {
|
|||||||
id: "tray",
|
id: "tray",
|
||||||
enabled: true
|
enabled: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "upower",
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "network",
|
id: "network",
|
||||||
enabled: false
|
enabled: false
|
||||||
@@ -70,6 +58,7 @@ JsonObject {
|
|||||||
property Popouts popouts: Popouts {
|
property Popouts popouts: Popouts {
|
||||||
}
|
}
|
||||||
property int rounding: 8
|
property int rounding: 8
|
||||||
|
property int smoothing: 32
|
||||||
|
|
||||||
component Popouts: JsonObject {
|
component Popouts: JsonObject {
|
||||||
property bool activeWindow: true
|
property bool activeWindow: true
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
|
||||||
JsonObject {
|
JsonObject {
|
||||||
|
property Presets presets: Presets {
|
||||||
|
}
|
||||||
property string schemeType: "vibrant"
|
property string schemeType: "vibrant"
|
||||||
|
|
||||||
|
component Presets: JsonObject {
|
||||||
|
property string accent: ""
|
||||||
|
property string name: ""
|
||||||
|
property string variant: ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-2
@@ -22,7 +22,9 @@ Singleton {
|
|||||||
property alias notifs: adapter.notifs
|
property alias notifs: adapter.notifs
|
||||||
property alias osd: adapter.osd
|
property alias osd: adapter.osd
|
||||||
property alias overview: adapter.overview
|
property alias overview: adapter.overview
|
||||||
|
property alias plugins: adapter.plugins
|
||||||
property bool recentlySaved: false
|
property bool recentlySaved: false
|
||||||
|
property alias screenshot: adapter.screenshot
|
||||||
property alias services: adapter.services
|
property alias services: adapter.services
|
||||||
property alias sidebar: adapter.sidebar
|
property alias sidebar: adapter.sidebar
|
||||||
property alias utilities: adapter.utilities
|
property alias utilities: adapter.utilities
|
||||||
@@ -82,6 +84,10 @@ Singleton {
|
|||||||
wallFadeDuration: background.wallFadeDuration,
|
wallFadeDuration: background.wallFadeDuration,
|
||||||
enabled: background.enabled,
|
enabled: background.enabled,
|
||||||
alignX: background.alignX,
|
alignX: background.alignX,
|
||||||
|
sourceClipX: background.sourceClipX,
|
||||||
|
sourceClipY: background.sourceClipY,
|
||||||
|
sourceClipW: background.sourceClipW,
|
||||||
|
sourceClipH: background.sourceClipH,
|
||||||
alignY: background.alignY,
|
alignY: background.alignY,
|
||||||
zoom: background.zoom
|
zoom: background.zoom
|
||||||
};
|
};
|
||||||
@@ -93,6 +99,7 @@ Singleton {
|
|||||||
hideWhenNotif: barConfig.hideWhenNotif,
|
hideWhenNotif: barConfig.hideWhenNotif,
|
||||||
rounding: barConfig.rounding,
|
rounding: barConfig.rounding,
|
||||||
border: barConfig.border,
|
border: barConfig.border,
|
||||||
|
smoothing: barConfig.smoothing,
|
||||||
height: barConfig.height,
|
height: barConfig.height,
|
||||||
popouts: {
|
popouts: {
|
||||||
tray: barConfig.popouts.tray,
|
tray: barConfig.popouts.tray,
|
||||||
@@ -109,7 +116,12 @@ Singleton {
|
|||||||
|
|
||||||
function serializeColors(): var {
|
function serializeColors(): var {
|
||||||
return {
|
return {
|
||||||
schemeType: colors.schemeType
|
schemeType: colors.schemeType,
|
||||||
|
presets: {
|
||||||
|
name: colors.presets.name,
|
||||||
|
variant: colors.presets.variant,
|
||||||
|
accent: colors.presets.accent
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +140,9 @@ Singleton {
|
|||||||
background: serializeBackground(),
|
background: serializeBackground(),
|
||||||
launcher: serializeLauncher(),
|
launcher: serializeLauncher(),
|
||||||
colors: serializeColors(),
|
colors: serializeColors(),
|
||||||
dock: serializeDock()
|
dock: serializeDock(),
|
||||||
|
screenshot: serializeScreenshot(),
|
||||||
|
plugins: serializePlugins()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +194,7 @@ Singleton {
|
|||||||
logo: general.logo,
|
logo: general.logo,
|
||||||
wallpaperPath: general.wallpaperPath,
|
wallpaperPath: general.wallpaperPath,
|
||||||
desktopIcons: general.desktopIcons,
|
desktopIcons: general.desktopIcons,
|
||||||
|
dateFormat: general.dateFormat,
|
||||||
color: {
|
color: {
|
||||||
mode: general.color.mode,
|
mode: general.color.mode,
|
||||||
smart: general.color.smart,
|
smart: general.color.smart,
|
||||||
@@ -233,6 +248,8 @@ Singleton {
|
|||||||
return {
|
return {
|
||||||
recolorLogo: lock.recolorLogo,
|
recolorLogo: lock.recolorLogo,
|
||||||
enableFprint: lock.enableFprint,
|
enableFprint: lock.enableFprint,
|
||||||
|
showNotifContent: lock.showNotifContent,
|
||||||
|
showNotifIcon: lock.showNotifIcon,
|
||||||
maxFprintTries: lock.maxFprintTries,
|
maxFprintTries: lock.maxFprintTries,
|
||||||
blurAmount: lock.blurAmount,
|
blurAmount: lock.blurAmount,
|
||||||
sizes: {
|
sizes: {
|
||||||
@@ -274,6 +291,27 @@ Singleton {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function serializePlugins(): var {
|
||||||
|
return {
|
||||||
|
enabled: plugins.enabled,
|
||||||
|
entries: plugins.entries
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeScreenshot(): var {
|
||||||
|
return {
|
||||||
|
enable_pp: screenshot.enable_pp,
|
||||||
|
mode: screenshot.mode,
|
||||||
|
corner_radius: screenshot.corner_radius,
|
||||||
|
drop_shadow: screenshot.drop_shadow,
|
||||||
|
rounded_corners: screenshot.rounded_corners,
|
||||||
|
shadow_blur_radius: screenshot.shadow_blur_radius,
|
||||||
|
shadow_color: screenshot.shadow_color,
|
||||||
|
shadow_offset_x: screenshot.shadow_offset_x,
|
||||||
|
shadow_offset_y: screenshot.shadow_offset_y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function serializeServices(): var {
|
function serializeServices(): var {
|
||||||
return {
|
return {
|
||||||
weatherLocation: services.weatherLocation,
|
weatherLocation: services.weatherLocation,
|
||||||
@@ -429,6 +467,10 @@ Singleton {
|
|||||||
}
|
}
|
||||||
property Overview overview: Overview {
|
property Overview overview: Overview {
|
||||||
}
|
}
|
||||||
|
property PluginConfig plugins: PluginConfig {
|
||||||
|
}
|
||||||
|
property Screenshot screenshot: Screenshot {
|
||||||
|
}
|
||||||
property Services services: Services {
|
property Services services: Services {
|
||||||
}
|
}
|
||||||
property SidebarConfig sidebar: SidebarConfig {
|
property SidebarConfig sidebar: SidebarConfig {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
|
|||||||
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import Quickshell.Hyprland
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import ZShell
|
import ZShell
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
@@ -29,9 +30,10 @@ Singleton {
|
|||||||
readonly property alias wallLuminance: analyser.luminance
|
readonly property alias wallLuminance: analyser.luminance
|
||||||
|
|
||||||
function alterColor(c: color, a: real, layer: int): color {
|
function alterColor(c: color, a: real, layer: int): color {
|
||||||
const luminance = getLuminance(c);
|
const initLuminance = getLuminance(c);
|
||||||
|
const luminance = Math.max(initLuminance, 0.001);
|
||||||
|
|
||||||
const offset = (!light || layer == 1 ? 1 : -layer / 2) * (light ? 0.2 : 0.3) * (1 - transparency.base) * (1 + wallLuminance * (light ? (layer == 1 ? 3 : 1) : 2.5));
|
const offset = (!light || layer == 1 ? 1 : -layer / 2) * (light ? 0.2 : 0.3) * (0.2 + 0.3 * (1 - transparency.base)) * (1 + wallLuminance * (light ? (layer == 1 ? 3 : 1) : 2.5));
|
||||||
const scale = (luminance + offset) / luminance;
|
const scale = (luminance + offset) / luminance;
|
||||||
const r = Math.max(0, Math.min(1, c.r * scale));
|
const r = Math.max(0, Math.min(1, c.r * scale));
|
||||||
const g = Math.max(0, Math.min(1, c.g * scale));
|
const g = Math.max(0, Math.min(1, c.g * scale));
|
||||||
@@ -79,10 +81,32 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reloadHyprRules(): void {
|
function reloadHyprRules(): void {
|
||||||
const barStr = "keyword layerrule %1 %2, match:namespace ZShell-Bar";
|
const blur = transparency.enabled ? 1 : 0;
|
||||||
const authStr = "keyword layerrule %1 %2, match:namespace ZShell-Auth";
|
const alpha = transparency.base - 0.03;
|
||||||
Hypr.extras.batchMessage([barStr.arg("blur").arg(transparency.enabled ? 1 : 0), barStr.arg("ignore_alpha").arg(transparency.base - 0.03)]);
|
|
||||||
Hypr.extras.batchMessage([authStr.arg("blur").arg(transparency.enabled ? 1 : 0), authStr.arg("ignore_alpha").arg(transparency.base - 0.03)]);
|
const rules = `
|
||||||
|
hl.layer_rule({
|
||||||
|
match = { namespace = "ZShell-Bar" },
|
||||||
|
blur = ${blur}
|
||||||
|
})
|
||||||
|
|
||||||
|
hl.layer_rule({
|
||||||
|
match = { namespace = "ZShell-Bar" },
|
||||||
|
ignore_alpha = ${alpha}
|
||||||
|
})
|
||||||
|
|
||||||
|
hl.layer_rule({
|
||||||
|
match = { namespace = "ZShell-Auth" },
|
||||||
|
blur = ${blur}
|
||||||
|
})
|
||||||
|
|
||||||
|
hl.layer_rule({
|
||||||
|
match = { namespace = "ZShell-Auth" },
|
||||||
|
ignore_alpha = ${alpha}
|
||||||
|
})
|
||||||
|
`;
|
||||||
|
|
||||||
|
Hypr.extras.message(`eval ${rules}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMode(mode: string): void {
|
function setMode(mode: string): void {
|
||||||
@@ -93,6 +117,14 @@ Singleton {
|
|||||||
|
|
||||||
Component.onCompleted: debounceTimer.triggered()
|
Component.onCompleted: debounceTimer.triggered()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onUsingLuaChanged(): void {
|
||||||
|
root.reloadHyprRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
target: Hyprland
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
function onConfigReloaded(): void {
|
function onConfigReloaded(): void {
|
||||||
root.reloadHyprRules();
|
root.reloadHyprRules();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ JsonObject {
|
|||||||
}
|
}
|
||||||
property Color color: Color {
|
property Color color: Color {
|
||||||
}
|
}
|
||||||
|
property string dateFormat: "ddd d MMM - hh:mm:ss"
|
||||||
property bool desktopIcons: false
|
property bool desktopIcons: false
|
||||||
property Idle idle: Idle {
|
property Idle idle: Idle {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ JsonObject {
|
|||||||
property bool enableFprint: true
|
property bool enableFprint: true
|
||||||
property int maxFprintTries: 3
|
property int maxFprintTries: 3
|
||||||
property bool recolorLogo: false
|
property bool recolorLogo: false
|
||||||
|
property bool showNotifContent: false
|
||||||
|
property bool showNotifIcon: true
|
||||||
property Sizes sizes: Sizes {
|
property Sizes sizes: Sizes {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
JsonObject {
|
||||||
|
property bool enabled: false
|
||||||
|
property list<var> entries: [
|
||||||
|
{
|
||||||
|
id: "Plugin",
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
JsonObject {
|
||||||
|
property real corner_radius: 12.0
|
||||||
|
property bool drop_shadow: true
|
||||||
|
property bool enable_pp: true
|
||||||
|
property string mode: "manual"
|
||||||
|
property bool rounded_corners: false
|
||||||
|
property real shadow_blur_radius: 22.0
|
||||||
|
property list<int> shadow_color: [0, 0, 0, 160]
|
||||||
|
property real shadow_offset_x: 5.0
|
||||||
|
property real shadow_offset_y: 5.0
|
||||||
|
}
|
||||||
+23
-174
@@ -3,184 +3,33 @@ import QtQuick
|
|||||||
Canvas {
|
Canvas {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property rect dirtyRect: Qt.rect(0, 0, 0, 0)
|
|
||||||
property bool frameQueued: false
|
|
||||||
property bool fullRepaintPending: true
|
|
||||||
property point lastPoint: Qt.point(0, 0)
|
|
||||||
property real minPointDistance: 2.0
|
|
||||||
property color penColor: "white"
|
property color penColor: "white"
|
||||||
property real penWidth: 4
|
property real penWidth: 4
|
||||||
property var pendingSegments: []
|
property var points: []
|
||||||
property bool strokeActive: false
|
|
||||||
property var strokes: []
|
|
||||||
|
|
||||||
function appendPoint(x, y) {
|
function clear(): void {
|
||||||
if (!strokeActive || strokes.length === 0)
|
var ctx = getContext('2d');
|
||||||
|
root.points = [];
|
||||||
|
ctx.reset();
|
||||||
|
root.requestPaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStrategy: Canvas.Cooperative
|
||||||
|
|
||||||
|
onPaint: {
|
||||||
|
if (points.length < 2)
|
||||||
return;
|
return;
|
||||||
const dx = x - lastPoint.x;
|
var ctx = root.getContext('2d');
|
||||||
const dy = y - lastPoint.y;
|
ctx.save();
|
||||||
|
ctx.lineWidth = root.penWidth;
|
||||||
if ((dx * dx + dy * dy) < (minPointDistance * minPointDistance))
|
ctx.strokeStyle = root.penColor;
|
||||||
return;
|
|
||||||
const x1 = lastPoint.x;
|
|
||||||
const y1 = lastPoint.y;
|
|
||||||
const x2 = x;
|
|
||||||
const y2 = y;
|
|
||||||
|
|
||||||
strokes[strokes.length - 1].push(Qt.point(x2, y2));
|
|
||||||
|
|
||||||
pendingSegments.push({
|
|
||||||
dot: false,
|
|
||||||
x1: x1,
|
|
||||||
y1: y1,
|
|
||||||
x2: x2,
|
|
||||||
y2: y2
|
|
||||||
});
|
|
||||||
|
|
||||||
lastPoint = Qt.point(x2, y2);
|
|
||||||
queueDirty(segmentDirtyRect(x1, y1, x2, y2));
|
|
||||||
}
|
|
||||||
|
|
||||||
function beginStroke(x, y) {
|
|
||||||
const p = Qt.point(x, y);
|
|
||||||
strokes.push([p]);
|
|
||||||
lastPoint = p;
|
|
||||||
strokeActive = true;
|
|
||||||
|
|
||||||
pendingSegments.push({
|
|
||||||
dot: true,
|
|
||||||
x: x,
|
|
||||||
y: y
|
|
||||||
});
|
|
||||||
|
|
||||||
queueDirty(pointDirtyRect(x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
function clear() {
|
|
||||||
strokes = [];
|
|
||||||
pendingSegments = [];
|
|
||||||
dirtyRect = Qt.rect(0, 0, 0, 0);
|
|
||||||
fullRepaintPending = true;
|
|
||||||
markDirty(Qt.rect(0, 0, width, height));
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawDot(ctx, x, y) {
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(x, y, penWidth / 2, 0, Math.PI * 2);
|
|
||||||
ctx.fill();
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawSegment(ctx, x1, y1, x2, y2) {
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(x1, y1);
|
|
||||||
ctx.lineTo(x2, y2);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
function endStroke() {
|
|
||||||
strokeActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pointDirtyRect(x, y) {
|
|
||||||
const pad = penWidth + 2;
|
|
||||||
return Qt.rect(x - pad, y - pad, pad * 2, pad * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function queueDirty(r) {
|
|
||||||
dirtyRect = unionRects(dirtyRect, r);
|
|
||||||
|
|
||||||
if (frameQueued)
|
|
||||||
return;
|
|
||||||
frameQueued = true;
|
|
||||||
|
|
||||||
requestAnimationFrame(function () {
|
|
||||||
frameQueued = false;
|
|
||||||
|
|
||||||
if (dirtyRect.width > 0 && dirtyRect.height > 0) {
|
|
||||||
markDirty(dirtyRect);
|
|
||||||
dirtyRect = Qt.rect(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function replayAll(ctx) {
|
|
||||||
ctx.clearRect(0, 0, width, height);
|
|
||||||
|
|
||||||
for (const stroke of strokes) {
|
|
||||||
if (!stroke || stroke.length === 0)
|
|
||||||
continue;
|
|
||||||
if (stroke.length === 1) {
|
|
||||||
const p = stroke[0];
|
|
||||||
drawDot(ctx, p.x, p.y);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(stroke[0].x, stroke[0].y);
|
|
||||||
for (let i = 1; i < stroke.length; ++i)
|
|
||||||
ctx.lineTo(stroke[i].x, stroke[i].y);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function requestFullRepaint() {
|
|
||||||
fullRepaintPending = true;
|
|
||||||
markDirty(Qt.rect(0, 0, width, height));
|
|
||||||
}
|
|
||||||
|
|
||||||
function segmentDirtyRect(x1, y1, x2, y2) {
|
|
||||||
const pad = penWidth + 2;
|
|
||||||
const left = Math.min(x1, x2) - pad;
|
|
||||||
const top = Math.min(y1, y2) - pad;
|
|
||||||
const right = Math.max(x1, x2) + pad;
|
|
||||||
const bottom = Math.max(y1, y2) + pad;
|
|
||||||
return Qt.rect(left, top, right - left, bottom - top);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unionRects(a, b) {
|
|
||||||
if (a.width <= 0 || a.height <= 0)
|
|
||||||
return b;
|
|
||||||
if (b.width <= 0 || b.height <= 0)
|
|
||||||
return a;
|
|
||||||
|
|
||||||
const left = Math.min(a.x, b.x);
|
|
||||||
const top = Math.min(a.y, b.y);
|
|
||||||
const right = Math.max(a.x + a.width, b.x + b.width);
|
|
||||||
const bottom = Math.max(a.y + a.height, b.y + b.height);
|
|
||||||
|
|
||||||
return Qt.rect(left, top, right - left, bottom - top);
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
contextType: "2d"
|
|
||||||
renderStrategy: Canvas.Threaded
|
|
||||||
renderTarget: Canvas.Image
|
|
||||||
|
|
||||||
onHeightChanged: requestFullRepaint()
|
|
||||||
onPaint: region => {
|
|
||||||
const ctx = getContext("2d");
|
|
||||||
|
|
||||||
ctx.lineCap = "round";
|
ctx.lineCap = "round";
|
||||||
ctx.lineJoin = "round";
|
ctx.beginPath();
|
||||||
ctx.lineWidth = penWidth;
|
ctx.moveTo(points[0].x, points[0].y);
|
||||||
ctx.strokeStyle = penColor;
|
for (var i = 1; i < points.length; i++)
|
||||||
ctx.fillStyle = penColor;
|
ctx.lineTo(points[i].x, points[i].y);
|
||||||
|
ctx.stroke();
|
||||||
if (fullRepaintPending) {
|
points = points.slice(points.length - 2);
|
||||||
fullRepaintPending = false;
|
ctx.restore();
|
||||||
replayAll(ctx);
|
|
||||||
pendingSegments = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const seg of pendingSegments) {
|
|
||||||
if (seg.dot)
|
|
||||||
drawDot(ctx, seg.x, seg.y);
|
|
||||||
else
|
|
||||||
drawSegment(ctx, seg.x1, seg.y1, seg.x2, seg.y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingSegments = [];
|
|
||||||
}
|
}
|
||||||
onWidthChanged: requestFullRepaint()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ CustomMouseArea {
|
|||||||
const x = event.x;
|
const x = event.x;
|
||||||
const y = event.y;
|
const y = event.y;
|
||||||
|
|
||||||
if (event.buttons & Qt.LeftButton)
|
if (root.visibilities.isDrawing && (event.buttons & Qt.LeftButton)) {
|
||||||
root.drawing.appendPoint(x, y);
|
root.drawing.points.push(Qt.point(x, y));
|
||||||
|
root.drawing.requestPaint();
|
||||||
|
}
|
||||||
|
|
||||||
if (root.inLeftPanel(root.popout, x, y)) {
|
if (root.inLeftPanel(root.popout, x, y)) {
|
||||||
root.z = -2;
|
root.z = -2;
|
||||||
@@ -44,7 +46,8 @@ CustomMouseArea {
|
|||||||
|
|
||||||
if (root.visibilities.isDrawing && (event.buttons & Qt.LeftButton)) {
|
if (root.visibilities.isDrawing && (event.buttons & Qt.LeftButton)) {
|
||||||
root.panels.drawing.expanded = false;
|
root.panels.drawing.expanded = false;
|
||||||
root.drawing.beginStroke(x, y);
|
root.drawing.points.push(Qt.point(x, y));
|
||||||
|
root.drawing.requestPaint();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +55,6 @@ CustomMouseArea {
|
|||||||
root.drawing.clear();
|
root.drawing.clear();
|
||||||
}
|
}
|
||||||
onReleased: {
|
onReleased: {
|
||||||
if (root.visibilities.isDrawing)
|
root.drawing.points = [];
|
||||||
root.drawing.endStroke();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,22 +12,37 @@ Scope {
|
|||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
|
|
||||||
ExclusionZone {
|
ExclusionZone {
|
||||||
|
id: top
|
||||||
|
|
||||||
anchors.top: true
|
anchors.top: true
|
||||||
exclusiveZone: root.bar.exclusiveZone
|
exclusiveZone: root.bar.exclusiveZone
|
||||||
}
|
}
|
||||||
|
|
||||||
ExclusionZone {
|
ExclusionZone {
|
||||||
|
id: left
|
||||||
|
|
||||||
anchors.left: true
|
anchors.left: true
|
||||||
}
|
}
|
||||||
|
|
||||||
ExclusionZone {
|
ExclusionZone {
|
||||||
|
id: right
|
||||||
|
|
||||||
anchors.right: true
|
anchors.right: true
|
||||||
}
|
}
|
||||||
|
|
||||||
ExclusionZone {
|
ExclusionZone {
|
||||||
|
id: bottom
|
||||||
|
|
||||||
anchors.bottom: true
|
anchors.bottom: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 5000
|
||||||
|
running: true
|
||||||
|
|
||||||
|
onTriggered: console.log("top height:", top.exclusiveZone, "left width:", left.exclusiveZone, "right width:", right.exclusiveZone, "bottom height:", bottom.exclusiveZone)
|
||||||
|
}
|
||||||
|
|
||||||
component ExclusionZone: CustomWindow {
|
component ExclusionZone: CustomWindow {
|
||||||
exclusiveZone: Config.barConfig.border
|
exclusiveZone: Config.barConfig.border
|
||||||
implicitHeight: 1
|
implicitHeight: 1
|
||||||
|
|||||||
+18
-18
@@ -78,7 +78,7 @@ CustomMouseArea {
|
|||||||
const dragY = y - dragStart.y;
|
const dragY = y - dragStart.y;
|
||||||
|
|
||||||
if (root.visibilities.isDrawing && !root.inLeftPanel(root.panels.drawing, x, y)) {
|
if (root.visibilities.isDrawing && !root.inLeftPanel(root.panels.drawing, x, y)) {
|
||||||
root.input.z = 2;
|
// root.input.z = 2;
|
||||||
root.panels.drawing.expanded = false;
|
root.panels.drawing.expanded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,25 +96,25 @@ CustomMouseArea {
|
|||||||
if (dragY < -10)
|
if (dragY < -10)
|
||||||
visibilities.dock = true;
|
visibilities.dock = true;
|
||||||
|
|
||||||
if (panels.sidebar.width === 0) {
|
if (panels.sidebar.width === 0) {
|
||||||
const showOsd = inRightPanel(panels.osdWrapper, x, y);
|
const showOsd = inRightPanel(panels.osdWrapper, x, y);
|
||||||
|
|
||||||
if (showOsd) {
|
if (showOsd) {
|
||||||
osdShortcutActive = false;
|
osdShortcutActive = false;
|
||||||
root.panels.osd.hovered = true;
|
root.panels.osd.hovered = true;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const outOfSidebar = x < width - panels.sidebar.width;
|
|
||||||
const showOsd = outOfSidebar && inRightPanel(panels.osdWrapper, x, y);
|
|
||||||
|
|
||||||
if (!osdShortcutActive) {
|
|
||||||
visibilities.osd = showOsd;
|
|
||||||
root.panels.osd.hovered = showOsd;
|
|
||||||
} else if (showOsd) {
|
|
||||||
osdShortcutActive = false;
|
|
||||||
root.panels.osd.hovered = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
const outOfSidebar = x < width - panels.sidebar.width;
|
||||||
|
const showOsd = outOfSidebar && inRightPanel(panels.osdWrapper, x, y);
|
||||||
|
|
||||||
|
if (!osdShortcutActive) {
|
||||||
|
visibilities.osd = showOsd;
|
||||||
|
root.panels.osd.hovered = showOsd;
|
||||||
|
} else if (showOsd) {
|
||||||
|
osdShortcutActive = false;
|
||||||
|
root.panels.osd.hovered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Config.dock.enable && !Config.dock.hoverToReveal && !visibilities.dock && !visibilities.launcher && inBottomPanel(panels.dock, x, y))
|
if (Config.dock.enable && !Config.dock.hoverToReveal && !visibilities.dock && !visibilities.launcher && inBottomPanel(panels.dock, x, y))
|
||||||
visibilities.dock = true;
|
visibilities.dock = true;
|
||||||
|
|||||||
+17
-6
@@ -34,6 +34,7 @@ Item {
|
|||||||
readonly property alias resourcesWrapper: resourcesWrapper
|
readonly property alias resourcesWrapper: resourcesWrapper
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
readonly property alias settings: settings
|
readonly property alias settings: settings
|
||||||
|
readonly property alias settingsWrapper: settingsWrapper
|
||||||
readonly property alias sidebar: sidebar
|
readonly property alias sidebar: sidebar
|
||||||
readonly property alias toasts: toasts
|
readonly property alias toasts: toasts
|
||||||
readonly property alias utilities: utilities
|
readonly property alias utilities: utilities
|
||||||
@@ -176,15 +177,25 @@ Item {
|
|||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings.Wrapper {
|
Item {
|
||||||
id: settings
|
id: settingsWrapper
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
// anchors.centerIn: parent
|
clip: true
|
||||||
panels: root
|
implicitHeight: settings.implicitHeight * (1 - settings.offsetScale)
|
||||||
screen: root.screen
|
implicitWidth: settings.implicitWidth
|
||||||
visibilities: root.visibilities
|
|
||||||
|
Settings.Wrapper {
|
||||||
|
id: settings
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
// anchors.centerIn: parent
|
||||||
|
panels: root
|
||||||
|
screen: root.screen
|
||||||
|
visibilities: root.visibilities
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dock.Wrapper {
|
Dock.Wrapper {
|
||||||
|
|||||||
+40
-18
@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import ZShell.Blobs
|
import ZShell.Blobs
|
||||||
@@ -127,6 +128,14 @@ Variants {
|
|||||||
Component.onCompleted: Visibilities.load(scope.modelData, this)
|
Component.onCompleted: Visibilities.load(scope.modelData, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
function toggleLauncher(fix: string): void {
|
||||||
|
visibilities.launcher = !visibilities.launcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
target: "visibilities"
|
||||||
|
}
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
property: "bar"
|
property: "bar"
|
||||||
target: visibilities
|
target: visibilities
|
||||||
@@ -149,6 +158,7 @@ Variants {
|
|||||||
id: blobGroup
|
id: blobGroup
|
||||||
|
|
||||||
color: DynamicColors.palette.m3surface
|
color: DynamicColors.palette.m3surface
|
||||||
|
smoothing: Config.barConfig.smoothing
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
CAnim {
|
CAnim {
|
||||||
@@ -170,28 +180,34 @@ Variants {
|
|||||||
PanelBg {
|
PanelBg {
|
||||||
id: dashBg
|
id: dashBg
|
||||||
|
|
||||||
deformAmount: 0.08 * Config.appearance.deform.scale
|
property real extraHeight: 0.2
|
||||||
implicitHeight: panels.dashboard.height
|
|
||||||
|
deformAmount: 0.06
|
||||||
|
implicitHeight: panels.dashboard.height * (1 + extraHeight)
|
||||||
implicitWidth: panels.dashboard.width
|
implicitWidth: panels.dashboard.width
|
||||||
panel: panels.dashboard
|
panel: panels.dashboardWrapper
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
x: panels.dashboardWrapper.x + panels.dashboard.x + Config.barConfig.border
|
x: panels.dashboardWrapper.x + panels.dashboard.x + Config.barConfig.border
|
||||||
y: panels.dashboardWrapper.y + panels.dashboard.y + bar.implicitHeight
|
y: panels.dashboardWrapper.y + panels.dashboard.y + bar.implicitHeight - panels.dashboard.height * extraHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelBg {
|
PanelBg {
|
||||||
id: launcherBg
|
id: launcherBg
|
||||||
|
|
||||||
deformAmount: 0.08 * Config.appearance.deform.scale
|
property real extraHeight: 0.2
|
||||||
|
|
||||||
|
deformAmount: 0.06
|
||||||
|
implicitHeight: panels.launcher.height * (1 + extraHeight)
|
||||||
panel: panels.launcher
|
panel: panels.launcher
|
||||||
radius: Appearance.rounding.smallest + 5
|
radius: Appearance.rounding.smallest + 5
|
||||||
|
y: panels.launcher.y + bar.implicitHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelBg {
|
PanelBg {
|
||||||
id: sidebarBg
|
id: sidebarBg
|
||||||
|
|
||||||
bottomLeftRadius: 0
|
bottomLeftRadius: 0
|
||||||
deformAmount: 0.08 * Config.appearance.deform.scale
|
deformAmount: 0.04
|
||||||
exclude: panels.sidebar.offsetScale > 0.08 ? [] : [utilsBg]
|
exclude: panels.sidebar.offsetScale > 0.08 ? [] : [utilsBg]
|
||||||
implicitHeight: panel.height * (1 / rawDeformMatrix.m22) + 2
|
implicitHeight: panel.height * (1 / rawDeformMatrix.m22) + 2
|
||||||
panel: panels.sidebar
|
panel: panels.sidebar
|
||||||
@@ -200,10 +216,10 @@ Variants {
|
|||||||
PanelBg {
|
PanelBg {
|
||||||
id: osdBg
|
id: osdBg
|
||||||
|
|
||||||
deformAmount: 0.1 * Config.appearance.deform.scale
|
deformAmount: 0.1
|
||||||
implicitHeight: panels.osd.height
|
implicitHeight: panels.osd.height
|
||||||
implicitWidth: panels.osd.width
|
implicitWidth: panels.osd.width
|
||||||
panel: panels.osd
|
panel: panels.osdWrapper
|
||||||
radius: 20
|
radius: 20
|
||||||
x: panels.osdWrapper.x + panels.osd.x + Config.barConfig.border
|
x: panels.osdWrapper.x + panels.osd.x + Config.barConfig.border
|
||||||
y: panels.osdWrapper.y + panels.osd.y + bar.implicitHeight
|
y: panels.osdWrapper.y + panels.osd.y + bar.implicitHeight
|
||||||
@@ -218,7 +234,7 @@ Variants {
|
|||||||
PanelBg {
|
PanelBg {
|
||||||
id: utilsBg
|
id: utilsBg
|
||||||
|
|
||||||
deformAmount: panels.sidebar.visible ? (0.1 * Config.appearance.deform.scale) : (0.1 * Config.appearance.deform.scale)
|
deformAmount: panels.sidebar.visible ? (0.1) : (0.1)
|
||||||
exclude: panels.sidebar.offsetScale > 0.08 ? [] : [sidebarBg]
|
exclude: panels.sidebar.offsetScale > 0.08 ? [] : [sidebarBg]
|
||||||
panel: panels.utilities
|
panel: panels.utilities
|
||||||
topLeftRadius: 0
|
topLeftRadius: 0
|
||||||
@@ -229,11 +245,11 @@ Variants {
|
|||||||
|
|
||||||
property real extraHeight: panels.popouts.isDetached ? 0 : 0.2
|
property real extraHeight: panels.popouts.isDetached ? 0 : 0.2
|
||||||
|
|
||||||
deformAmount: panels.popouts.isDetached ? 0.05 * Config.appearance.deform.scale : panels.popouts.hasCurrent ? 0.15 * Config.appearance.deform.scale : 0.1 * Config.appearance.deform.scale
|
deformAmount: panels.popouts.isDetached ? 0.05 : panels.popouts.hasCurrent ? 0.15 : 0.1
|
||||||
implicitHeight: panels.popouts.height * (1 + extraHeight)
|
implicitHeight: panels.popouts.height * (1 + extraHeight)
|
||||||
implicitWidth: panels.popouts.width
|
implicitWidth: panels.popouts.width
|
||||||
panel: panels.popouts
|
panel: panels.popoutsWrapper
|
||||||
radius: (panels.popouts.currentName.startsWith("audio") || panels.popouts.currentName.startsWith("updates")) ? Appearance.rounding.normal : Appearance.rounding.smallest
|
radius: (panels.popouts.currentName.startsWith("audio") || panels.popouts.currentName.startsWith("updates")) ? Appearance.rounding.normal : 20 * Appearance.rounding.scale
|
||||||
x: panels.popoutsWrapper.x + panels.popouts.x + Config.barConfig.border
|
x: panels.popoutsWrapper.x + panels.popouts.x + Config.barConfig.border
|
||||||
y: panels.popoutsWrapper.y + panels.popouts.y + bar.implicitHeight - panels.popouts.height * extraHeight
|
y: panels.popoutsWrapper.y + panels.popouts.y + bar.implicitHeight - panels.popouts.height * extraHeight
|
||||||
|
|
||||||
@@ -246,10 +262,10 @@ Variants {
|
|||||||
PanelBg {
|
PanelBg {
|
||||||
id: resourcesBg
|
id: resourcesBg
|
||||||
|
|
||||||
deformAmount: 0.08 * Config.appearance.deform.scale
|
deformAmount: 0.05
|
||||||
implicitHeight: panels.resources.height
|
implicitHeight: panels.resources.height
|
||||||
implicitWidth: panels.resources.width
|
implicitWidth: panels.resources.width
|
||||||
panel: panels.resources
|
panel: panels.resourcesWrapper
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
x: panels.resourcesWrapper.x + panels.resources.x + Config.barConfig.border
|
x: panels.resourcesWrapper.x + panels.resources.x + Config.barConfig.border
|
||||||
y: panels.resourcesWrapper.y + panels.resources.y + bar.implicitHeight
|
y: panels.resourcesWrapper.y + panels.resources.y + bar.implicitHeight
|
||||||
@@ -258,17 +274,23 @@ Variants {
|
|||||||
PanelBg {
|
PanelBg {
|
||||||
id: settingsBg
|
id: settingsBg
|
||||||
|
|
||||||
deformAmount: 0.08 * Config.appearance.deform.scale
|
property real extraHeight: 0.2
|
||||||
|
|
||||||
|
deformAmount: 0.03
|
||||||
|
implicitHeight: panels.settings.height * (1 + extraHeight)
|
||||||
|
implicitWidth: panels.settings.width
|
||||||
panel: panels.settings
|
panel: panels.settings
|
||||||
radius: Appearance.rounding.large
|
radius: Appearance.rounding.large
|
||||||
topLeftRadius: Appearance.rounding.large + Appearance.padding.smaller
|
topLeftRadius: Appearance.rounding.large + Appearance.padding.smaller
|
||||||
topRightRadius: Appearance.rounding.large + Appearance.padding.smaller
|
topRightRadius: Appearance.rounding.large + Appearance.padding.smaller
|
||||||
|
x: panels.settingsWrapper.x + panels.settings.x + Config.barConfig.border
|
||||||
|
y: panels.settingsWrapper.y + panels.settings.y + bar.implicitHeight - panels.settings.height * extraHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelBg {
|
PanelBg {
|
||||||
id: dockBg
|
id: dockBg
|
||||||
|
|
||||||
deformAmount: 0.08 * Config.appearance.deform.scale
|
deformAmount: 0.08
|
||||||
panel: panels.dock
|
panel: panels.dock
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
}
|
}
|
||||||
@@ -276,7 +298,7 @@ Variants {
|
|||||||
PanelBg {
|
PanelBg {
|
||||||
id: drawingBg
|
id: drawingBg
|
||||||
|
|
||||||
deformAmount: 0.08 * Config.appearance.deform.scale
|
deformAmount: 0.08
|
||||||
panel: panels.drawing
|
panel: panels.drawing
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
}
|
}
|
||||||
@@ -371,7 +393,7 @@ Variants {
|
|||||||
property real deformAmount: 0.15
|
property real deformAmount: 0.15
|
||||||
required property Item panel
|
required property Item panel
|
||||||
|
|
||||||
deformScale: deformAmount / 10000
|
deformScale: (deformAmount * Config.appearance.deform.scale) / 10000
|
||||||
group: blobGroup
|
group: blobGroup
|
||||||
implicitHeight: panel.height
|
implicitHeight: panel.height
|
||||||
implicitWidth: panel.width
|
implicitWidth: panel.width
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import ZShell.Models
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias plugins: plugins.entries
|
||||||
|
|
||||||
|
FileSystemModel {
|
||||||
|
id: plugins
|
||||||
|
|
||||||
|
nameFilters: ["*.qml"]
|
||||||
|
path: Quickshell.env("HOME") + "/.config/zshell"
|
||||||
|
recursive: false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import ZShell.Models
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: FetchPlugins.plugins
|
||||||
|
|
||||||
|
LazyLoader {
|
||||||
|
required property FileSystemEntry modelData
|
||||||
|
|
||||||
|
activeAsync: Config.plugins.entries.some(p => {
|
||||||
|
return p.id === modelData.baseName && p.enabled;
|
||||||
|
})
|
||||||
|
source: modelData.path
|
||||||
|
}
|
||||||
|
}
|
||||||
+20
-20
@@ -16,27 +16,14 @@ Scope {
|
|||||||
property bool launching: false
|
property bool launching: false
|
||||||
property string promptMessage: ""
|
property string promptMessage: ""
|
||||||
readonly property var selectedSession: sessionIndex >= 0 ? sessions[sessionIndex] : null
|
readonly property var selectedSession: sessionIndex >= 0 ? sessions[sessionIndex] : null
|
||||||
|
readonly property var selectedUser: Users.selectedUser
|
||||||
property int sessionIndex: sessions.length > 0 ? 0 : -1
|
property int sessionIndex: sessions.length > 0 ? 0 : -1
|
||||||
property var sessions: []
|
property var sessions: []
|
||||||
|
readonly property string userFace: selectedUser ? selectedUser.face : ""
|
||||||
|
readonly property string username: Users.selectedUsername
|
||||||
|
|
||||||
// User handling - now uses the Users singleton
|
// User handling - now uses the Users singleton
|
||||||
readonly property var users: Users.users
|
readonly property var users: Users.users
|
||||||
readonly property var selectedUser: Users.selectedUser
|
|
||||||
readonly property string username: Users.selectedUsername
|
|
||||||
readonly property string userFace: selectedUser ? selectedUser.face : ""
|
|
||||||
|
|
||||||
// User selection functions (delegate to Users singleton)
|
|
||||||
function selectUser(username: string): bool {
|
|
||||||
return Users.selectUser(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectNextUser(): void {
|
|
||||||
Users.selectNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectPreviousUser(): void {
|
|
||||||
Users.selectPrevious();
|
|
||||||
}
|
|
||||||
|
|
||||||
signal flashMsg
|
signal flashMsg
|
||||||
|
|
||||||
@@ -58,11 +45,11 @@ Scope {
|
|||||||
|
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
return;
|
return;
|
||||||
}
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
buffer = "";
|
||||||
if (event.text && !/[\r\n]/.test(event.text)) {
|
} else if (" abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) {
|
||||||
|
// No illegal characters (you are insane if you use unicode in your password)
|
||||||
buffer += event.text;
|
buffer += event.text;
|
||||||
event.accepted = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +68,19 @@ Scope {
|
|||||||
Greetd.launch(selectedSession.command, [], true);
|
Greetd.launch(selectedSession.command, [], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectNextUser(): void {
|
||||||
|
Users.selectNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPreviousUser(): void {
|
||||||
|
Users.selectPrevious();
|
||||||
|
}
|
||||||
|
|
||||||
|
// User selection functions (delegate to Users singleton)
|
||||||
|
function selectUser(username: string): bool {
|
||||||
|
return Users.selectUser(username);
|
||||||
|
}
|
||||||
|
|
||||||
function submit(): void {
|
function submit(): void {
|
||||||
errorMessage = "";
|
errorMessage = "";
|
||||||
|
|
||||||
|
|||||||
@@ -346,7 +346,6 @@ Singleton {
|
|||||||
|
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
onStreamFinished: {
|
onStreamFinished: {
|
||||||
console.log("this is running");
|
|
||||||
if (root.gpuType === "GENERIC") {
|
if (root.gpuType === "GENERIC") {
|
||||||
const percs = text.trim().split("\n");
|
const percs = text.trim().split("\n");
|
||||||
const sum = percs.reduce((acc, d) => acc + parseInt(d, 10), 0);
|
const sum = percs.reduce((acc, d) => acc + parseInt(d, 10), 0);
|
||||||
|
|||||||
+20
-44
@@ -7,23 +7,30 @@ import QtQuick
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// The list of users that can log in graphically
|
readonly property string defaultUserFile: "/etc/zshell-greeter/default-user"
|
||||||
// Each user object has: username, uid, home, shell, gecos (full name), face (avatar path)
|
property int selectedIndex: 0
|
||||||
|
readonly property var selectedUser: selectedIndex >= 0 && selectedIndex < users.length ? users[selectedIndex] : null
|
||||||
|
readonly property string selectedUsername: selectedUser ? selectedUser.username : ""
|
||||||
property var users: []
|
property var users: []
|
||||||
|
|
||||||
// The currently selected user index
|
function saveDefaultUser(): void {
|
||||||
property int selectedIndex: 0
|
if (selectedUser) {
|
||||||
|
defaultUserStorage.setText(selectedUser.username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The currently selected user object (or null if none)
|
function selectNext(): void {
|
||||||
readonly property var selectedUser: selectedIndex >= 0 && selectedIndex < users.length ? users[selectedIndex] : null
|
if (users.length === 0)
|
||||||
|
return;
|
||||||
|
selectedIndex = (selectedIndex + 1) % users.length;
|
||||||
|
}
|
||||||
|
|
||||||
// Convenience property for the selected username
|
function selectPrevious(): void {
|
||||||
readonly property string selectedUsername: selectedUser ? selectedUser.username : ""
|
if (users.length === 0)
|
||||||
|
return;
|
||||||
|
selectedIndex = (selectedIndex - 1 + users.length) % users.length;
|
||||||
|
}
|
||||||
|
|
||||||
// Path to store the default user preference
|
|
||||||
readonly property string defaultUserFile: "/etc/zshell-greeter/default-user"
|
|
||||||
|
|
||||||
// Select a user by username
|
|
||||||
function selectUser(username: string): bool {
|
function selectUser(username: string): bool {
|
||||||
for (let i = 0; i < users.length; i++) {
|
for (let i = 0; i < users.length; i++) {
|
||||||
if (users[i].username === username) {
|
if (users[i].username === username) {
|
||||||
@@ -34,28 +41,6 @@ Singleton {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select the next user in the list (wraps around)
|
|
||||||
function selectNext(): void {
|
|
||||||
if (users.length === 0)
|
|
||||||
return;
|
|
||||||
selectedIndex = (selectedIndex + 1) % users.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select the previous user in the list (wraps around)
|
|
||||||
function selectPrevious(): void {
|
|
||||||
if (users.length === 0)
|
|
||||||
return;
|
|
||||||
selectedIndex = (selectedIndex - 1 + users.length) % users.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the current user as the default for next login
|
|
||||||
function saveDefaultUser(): void {
|
|
||||||
if (selectedUser) {
|
|
||||||
defaultUserStorage.setText(selectedUser.username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process to fetch the list of graphical users
|
|
||||||
Process {
|
Process {
|
||||||
id: userLister
|
id: userLister
|
||||||
|
|
||||||
@@ -67,13 +52,10 @@ Singleton {
|
|||||||
try {
|
try {
|
||||||
root.users = JSON.parse(text);
|
root.users = JSON.parse(text);
|
||||||
|
|
||||||
// If we have users and no selection yet, try to select the default user
|
|
||||||
if (root.users.length > 0) {
|
if (root.users.length > 0) {
|
||||||
// Try to load the default user
|
|
||||||
if (defaultUserStorage.loaded) {
|
if (defaultUserStorage.loaded) {
|
||||||
const defaultUsername = defaultUserStorage.text().trim();
|
const defaultUsername = defaultUserStorage.text().trim();
|
||||||
if (defaultUsername && !root.selectUser(defaultUsername)) {
|
if (defaultUsername && !root.selectUser(defaultUsername)) {
|
||||||
// Default user not found, select first user
|
|
||||||
root.selectedIndex = 0;
|
root.selectedIndex = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -87,15 +69,14 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileView for persisting the default user
|
|
||||||
FileView {
|
FileView {
|
||||||
id: defaultUserStorage
|
id: defaultUserStorage
|
||||||
|
|
||||||
path: root.defaultUserFile
|
path: root.defaultUserFile
|
||||||
preload: true
|
preload: true
|
||||||
|
|
||||||
|
onLoadFailed: {}
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
// If users are already loaded, try to select the default user
|
|
||||||
if (root.users.length > 0) {
|
if (root.users.length > 0) {
|
||||||
const defaultUsername = text().trim();
|
const defaultUsername = text().trim();
|
||||||
if (defaultUsername) {
|
if (defaultUsername) {
|
||||||
@@ -103,10 +84,5 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoadFailed: {
|
|
||||||
// File doesn't exist yet, that's fine - we'll create it on first save
|
|
||||||
console.log("No default user file found, will use first user");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
// FetchPresets.qml
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var parsedPresets: ({})
|
||||||
|
readonly property var presets: parsedPresets
|
||||||
|
property bool ready: false
|
||||||
|
|
||||||
|
function accents(presetName, variantName) {
|
||||||
|
const variant = parsedPresets[presetName]?.variants?.[variantName];
|
||||||
|
|
||||||
|
return variant?.accents ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultAccent(presetName, variantName) {
|
||||||
|
const variant = parsedPresets[presetName]?.variants?.[variantName];
|
||||||
|
|
||||||
|
return variant?.default_accent ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function modes(presetName, variantName) {
|
||||||
|
const variant = parsedPresets[presetName]?.variants?.[variantName];
|
||||||
|
|
||||||
|
return variant?.modes ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function presetNames() {
|
||||||
|
return Object.keys(parsedPresets);
|
||||||
|
}
|
||||||
|
|
||||||
|
function variantNames(presetName) {
|
||||||
|
const preset = parsedPresets[presetName];
|
||||||
|
|
||||||
|
if (!preset || !preset.variants)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
return Object.keys(preset.variants);
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
command: ["zshell-cli", "scheme", "list-presets", "--json"]
|
||||||
|
running: true
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(text);
|
||||||
|
|
||||||
|
root.parsedPresets = parsed.presets ?? {};
|
||||||
|
root.ready = true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to parse presets JSON:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import ZShell
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias enabled: props.enabled
|
||||||
|
|
||||||
|
function setHyprConf(): void {
|
||||||
|
Hypr.extras.applyOptions({
|
||||||
|
"animations.enabled": 0,
|
||||||
|
"decoration.shadow.enabled": 0,
|
||||||
|
"decoration.blur.enabled": 0,
|
||||||
|
"general.border_size": 0,
|
||||||
|
"decoration.rounding": 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnabledChanged: {
|
||||||
|
if (enabled) {
|
||||||
|
setHyprConf();
|
||||||
|
if (Config.utilities.toasts.gameModeChanged)
|
||||||
|
Toaster.toast(qsTr("Game mode enabled"), qsTr("Disabled Hyprland animations, blur, shadows and corner radius"), "gamepad");
|
||||||
|
} else {
|
||||||
|
Hypr.extras.message("reload");
|
||||||
|
if (Config.utilities.toasts.gameModeChanged)
|
||||||
|
Toaster.toast(qsTr("Game mode disabled"), qsTr("Hyprland settings restored"), "gamepad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistentProperties {
|
||||||
|
id: props
|
||||||
|
|
||||||
|
property bool enabled: Hypr.options["animations:enabled"] === 0
|
||||||
|
|
||||||
|
reloadableId: "gamemode"
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onConfigReloaded(): void {
|
||||||
|
if (props.enabled)
|
||||||
|
root.setHyprConf();
|
||||||
|
}
|
||||||
|
|
||||||
|
target: Hypr
|
||||||
|
}
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
function disable(): void {
|
||||||
|
props.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function enable(): void {
|
||||||
|
props.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isEnabled(): bool {
|
||||||
|
return props.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle(): void {
|
||||||
|
props.enabled = !props.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
target: "gameMode"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ Singleton {
|
|||||||
|
|
||||||
readonly property int darkEnd: Config.general.color.scheduleDarkEnd
|
readonly property int darkEnd: Config.general.color.scheduleDarkEnd
|
||||||
readonly property int darkStart: Config.general.color.scheduleDarkStart
|
readonly property int darkStart: Config.general.color.scheduleDarkStart
|
||||||
readonly property bool enabled: Config.general.color.scheduleDark
|
readonly property bool enabled: Config.general.color.scheduleDark && Config.general.color.schemeGeneration
|
||||||
|
|
||||||
function applyDarkMode() {
|
function applyDarkMode() {
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", "dark"]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", "dark"]);
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Networking
|
|
||||||
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property NetworkDevice activeDevice: devices.find(d => d.connected)
|
|
||||||
property list<NetworkDevice> devices: Networking.devices.values
|
|
||||||
}
|
|
||||||
+2
-1
@@ -66,7 +66,8 @@ MouseArea {
|
|||||||
|
|
||||||
function save(): void {
|
function save(): void {
|
||||||
const tmpfile = Qt.resolvedUrl(`/tmp/zshell-picker-${Quickshell.processId}-${Date.now()}.png`);
|
const tmpfile = Qt.resolvedUrl(`/tmp/zshell-picker-${Quickshell.processId}-${Date.now()}.png`);
|
||||||
ZShellIo.saveItem(screencopy, tmpfile, Qt.rect(Math.ceil(rsx), Math.ceil(rsy), Math.floor(sw), Math.floor(sh)), path => Quickshell.execDetached(["swappy", "-f", path]));
|
const cmd = Config.screenshot.enable_pp ? ["zshell-img-tools", "--image"] : ["swappy", "-f"];
|
||||||
|
ZShellIo.saveItem(screencopy, tmpfile, Qt.rect(Math.ceil(rsx), Math.ceil(rsy), Math.floor(sw), Math.floor(sh)), path => Quickshell.execDetached([...cmd, path]));
|
||||||
closeAnim.start();
|
closeAnim.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property alias elapsed: props.elapsed
|
||||||
|
property bool needsPause
|
||||||
|
property bool needsStart
|
||||||
|
property bool needsStop
|
||||||
|
readonly property alias paused: props.paused
|
||||||
|
readonly property alias running: props.running
|
||||||
|
property list<string> startArgs
|
||||||
|
|
||||||
|
function start(extraArgs = []): void {
|
||||||
|
needsStart = true;
|
||||||
|
startArgs = extraArgs;
|
||||||
|
checkProc.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stop(): void {
|
||||||
|
needsStop = true;
|
||||||
|
checkProc.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function togglePause(): void {
|
||||||
|
needsPause = true;
|
||||||
|
checkProc.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistentProperties {
|
||||||
|
id: props
|
||||||
|
|
||||||
|
property real elapsed: 0
|
||||||
|
property bool paused: false
|
||||||
|
property bool running: false
|
||||||
|
|
||||||
|
reloadableId: "recorder"
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: checkProc
|
||||||
|
|
||||||
|
command: ["pidof", "gpu-screen-recorder"]
|
||||||
|
running: true
|
||||||
|
|
||||||
|
onExited: code => {
|
||||||
|
props.running = code === 0;
|
||||||
|
|
||||||
|
if (code === 0) {
|
||||||
|
if (root.needsStop) {
|
||||||
|
Quickshell.execDetached(["zshell-cli", "record", "record"]);
|
||||||
|
props.running = false;
|
||||||
|
props.paused = false;
|
||||||
|
} else if (root.needsPause) {
|
||||||
|
Quickshell.execDetached(["zshell-cli", "record", "record", "-p"]);
|
||||||
|
props.paused = !props.paused;
|
||||||
|
}
|
||||||
|
} else if (root.needsStart) {
|
||||||
|
Quickshell.execDetached(["zshell-cli", "record", "record", ...root.startArgs]);
|
||||||
|
props.running = true;
|
||||||
|
props.paused = false;
|
||||||
|
props.elapsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.needsStart = false;
|
||||||
|
root.needsStop = false;
|
||||||
|
root.needsPause = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onSecondsChanged(): void {
|
||||||
|
props.elapsed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
target: Time // qmllint disable incompatible-type
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import Quickshell
|
|
||||||
import "../scripts/fzf.js" as Fzf
|
import "../scripts/fzf.js" as Fzf
|
||||||
import "../scripts/fuzzysort.js" as Fuzzy
|
import "../scripts/fuzzysort.js" as Fuzzy
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
property var extraOpts: ({})
|
property var extraOpts: ({})
|
||||||
|
|||||||
+7
-2
@@ -1,18 +1,23 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
readonly property string amPmStr: timeComponents[2] ?? ""
|
id: root
|
||||||
|
|
||||||
readonly property date date: clock.date
|
readonly property date date: clock.date
|
||||||
|
readonly property string dateStr: format(Config.general.dateFormat)
|
||||||
property alias enabled: clock.enabled
|
property alias enabled: clock.enabled
|
||||||
readonly property string hourStr: timeComponents[0] ?? ""
|
readonly property string hourStr: timeComponents[0] ?? ""
|
||||||
readonly property int hours: clock.hours
|
readonly property int hours: clock.hours
|
||||||
readonly property string minuteStr: timeComponents[1] ?? ""
|
readonly property string minuteStr: timeComponents[1] ?? ""
|
||||||
readonly property int minutes: clock.minutes
|
readonly property int minutes: clock.minutes
|
||||||
|
readonly property string secondStr: timeComponents[2] ?? ""
|
||||||
readonly property int seconds: clock.seconds
|
readonly property int seconds: clock.seconds
|
||||||
readonly property list<string> timeComponents: timeStr.split(":")
|
readonly property list<string> timeComponents: timeStr.split(":")
|
||||||
readonly property string timeStr: format("hh:mm")
|
readonly property string timeStr: format("hh:mm:ss")
|
||||||
|
|
||||||
function format(fmt: string): string {
|
function format(fmt: string): string {
|
||||||
return Qt.formatDateTime(clock.date, fmt);
|
return Qt.formatDateTime(clock.date, fmt);
|
||||||
|
|||||||
@@ -6,7 +6,21 @@ import Quickshell.Services.UPower
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
readonly property real batteryPercent: UPower.displayDevice.percentage
|
||||||
readonly property list<UPowerDevice> devices: UPower.devices.values
|
readonly property list<UPowerDevice> devices: UPower.devices.values
|
||||||
readonly property UPowerDevice displayDevice: UPower.displayDevice
|
readonly property UPowerDevice displayDevice: UPower.displayDevice
|
||||||
readonly property bool onBattery: UPower.onBattery
|
readonly property bool onBattery: UPower.onBattery
|
||||||
|
// property bool toastShown
|
||||||
|
//
|
||||||
|
// Connections {
|
||||||
|
// target: UPower
|
||||||
|
//
|
||||||
|
// function onPercentageChanged(): {
|
||||||
|
// if (root.batteryPercent >= 0.2 && toastShown)
|
||||||
|
// return;
|
||||||
|
//
|
||||||
|
// root.toastShown = true;
|
||||||
|
// Toaster.toast(qsTr("Battery "))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,13 @@ Singleton {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property int availableUpdates: 0
|
property int availableUpdates: 0
|
||||||
|
property string cmd: ""
|
||||||
property bool commandReady
|
property bool commandReady
|
||||||
property bool loaded
|
property bool loaded
|
||||||
property double now: Date.now()
|
property double now: Date.now()
|
||||||
property var updates: ({})
|
property var updates: ({})
|
||||||
|
property bool updating
|
||||||
|
property string updatingPackage: ""
|
||||||
|
|
||||||
function formatUpdateTime(timestamp) {
|
function formatUpdateTime(timestamp) {
|
||||||
const diffMs = root.now - timestamp;
|
const diffMs = root.now - timestamp;
|
||||||
@@ -34,6 +37,22 @@ Singleton {
|
|||||||
return Qt.formatDateTime(new Date(timestamp), "dd hh:mm");
|
return Qt.formatDateTime(new Date(timestamp), "dd hh:mm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function performPackageUpdate(pkg: string): void {
|
||||||
|
if (root.cmd === "pacman")
|
||||||
|
pkgUpdateProc.command = ["pkexec", root.cmd, "--noconfirm", "-Sy", pkg];
|
||||||
|
else
|
||||||
|
pkgUpdateProc.command = [root.cmd, "--noconfirm", "--sudo", "pkexec", "-Sy", pkg];
|
||||||
|
pkgUpdateProc.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function performSystemUpdate(): void {
|
||||||
|
if (root.cmd === "pacman")
|
||||||
|
sysUpdateProc.command = ["pkexec", root.cmd, "--noconfirm", "-Syu"];
|
||||||
|
else
|
||||||
|
sysUpdateProc.command = [root.cmd, "--noconfirm", "--sudo", "pkexec", "-Syu"];
|
||||||
|
sysUpdateProc.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
onUpdatesChanged: {
|
onUpdatesChanged: {
|
||||||
if (!root.loaded)
|
if (!root.loaded)
|
||||||
return;
|
return;
|
||||||
@@ -92,6 +111,28 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: updateCmdDetect
|
||||||
|
|
||||||
|
command: ["sh", "-c", "command -v yay || command -v paru"]
|
||||||
|
running: true
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
const cmd = this.text.trim();
|
||||||
|
let helper;
|
||||||
|
|
||||||
|
if (cmd.length > 0) {
|
||||||
|
helper = cmd.split("/").pop();
|
||||||
|
} else {
|
||||||
|
helper = "pacman";
|
||||||
|
}
|
||||||
|
|
||||||
|
root.cmd = helper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: updatesProc
|
id: updatesProc
|
||||||
|
|
||||||
@@ -115,6 +156,44 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: sysUpdateProc
|
||||||
|
|
||||||
|
command: []
|
||||||
|
running: false
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
root.updating = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onRunningChanged: {
|
||||||
|
if (running)
|
||||||
|
root.updating = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: pkgUpdateProc
|
||||||
|
|
||||||
|
command: []
|
||||||
|
running: false
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
root.updating = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onRunningChanged: {
|
||||||
|
if (running) {
|
||||||
|
root.updatingPackage = command[command.length - 1];
|
||||||
|
root.updating = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: saveTimer
|
id: saveTimer
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import QtQuick
|
||||||
import ZShell.Models
|
import ZShell.Models
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
@@ -12,10 +14,17 @@ Searcher {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string actualCurrent: WallpaperPath.currentWallpaperPath
|
property string actualCurrent: WallpaperPath.currentWallpaperPath
|
||||||
|
property alias crops: adapter.monitorCrops
|
||||||
readonly property string current: showPreview ? previewPath : actualCurrent
|
readonly property string current: showPreview ? previewPath : actualCurrent
|
||||||
|
property alias monitorCrops: monitorCrops
|
||||||
property string previewPath
|
property string previewPath
|
||||||
|
property bool recentlyChanged
|
||||||
property bool showPreview: false
|
property bool showPreview: false
|
||||||
|
|
||||||
|
function getCrop(screen: string): var {
|
||||||
|
return root.crops[screen];
|
||||||
|
}
|
||||||
|
|
||||||
function preview(path: string): void {
|
function preview(path: string): void {
|
||||||
previewPath = path;
|
previewPath = path;
|
||||||
if (Config.general.color.schemeGeneration)
|
if (Config.general.color.schemeGeneration)
|
||||||
@@ -23,9 +32,35 @@ Searcher {
|
|||||||
showPreview = true;
|
showPreview = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setCrop(screen: string, rect: rect, scaledRect: rect, zoom: real): void {
|
||||||
|
let updated = Object.assign({}, root.crops);
|
||||||
|
|
||||||
|
if (zoom <= 0)
|
||||||
|
zoom = 1.0;
|
||||||
|
else if (zoom > 5.0)
|
||||||
|
zoom = 5.0;
|
||||||
|
|
||||||
|
updated[screen] = {
|
||||||
|
x: rect.x,
|
||||||
|
y: rect.y,
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
scaledX: scaledRect.x,
|
||||||
|
scaledY: scaledRect.y,
|
||||||
|
scaledWidth: scaledRect.width,
|
||||||
|
scaledHeight: scaledRect.height,
|
||||||
|
zoom: zoom
|
||||||
|
};
|
||||||
|
|
||||||
|
root.crops = updated;
|
||||||
|
monitorCrops.writeAdapter();
|
||||||
|
monitorCrops.reload();
|
||||||
|
}
|
||||||
|
|
||||||
function setWallpaper(path: string): void {
|
function setWallpaper(path: string): void {
|
||||||
actualCurrent = path;
|
actualCurrent = path;
|
||||||
WallpaperPath.currentWallpaperPath = path;
|
WallpaperPath.currentWallpaperPath = path;
|
||||||
|
Quickshell.screens.forEach(n => setCrop(n.name, Qt.rect(0, 0, 0, 0), Qt.rect(0, 0, 0, 0), 1.0));
|
||||||
Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]);
|
Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]);
|
||||||
if (Config.general.color.schemeGeneration)
|
if (Config.general.color.schemeGeneration)
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.general.color.mode}`]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.general.color.mode}`]);
|
||||||
@@ -52,6 +87,22 @@ Searcher {
|
|||||||
target: "wallpaper"
|
target: "wallpaper"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
id: monitorCrops
|
||||||
|
|
||||||
|
path: `${Paths.state}/wallpaper-crops.json`
|
||||||
|
watchChanges: true
|
||||||
|
|
||||||
|
onAdapterUpdated: writeAdapter()
|
||||||
|
onFileChanged: reload()
|
||||||
|
|
||||||
|
JsonAdapter {
|
||||||
|
id: adapter
|
||||||
|
|
||||||
|
property var monitorCrops: ({})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FileSystemModel {
|
FileSystemModel {
|
||||||
id: wallpapers
|
id: wallpapers
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -3,7 +3,7 @@ import QtQuick
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
import qs.Helpers as Helpers
|
import qs.Helpers
|
||||||
import qs.Components
|
import qs.Components
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
@@ -23,6 +23,7 @@ CustomRect {
|
|||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
color: root.visibilities.dashboard ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
|
color: root.visibilities.dashboard ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
|
||||||
|
font: Appearance.font.family.mono
|
||||||
text: Time.dateStr
|
text: Time.dateStr
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import QtQuick
|
|
||||||
import qs.Config
|
|
||||||
import qs.Helpers
|
|
||||||
import qs.Components
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property PersistentProperties visibilities
|
|
||||||
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.bottomMargin: 6
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 6
|
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
|
||||||
implicitWidth: 40
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
|
|
||||||
StateLayer {
|
|
||||||
onClicked: {
|
|
||||||
root.visibilities.dashboard = !root.visibilities.dashboard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
color: DynamicColors.palette.m3onSurface
|
|
||||||
text: "widgets"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+25
-77
@@ -12,90 +12,29 @@ Item {
|
|||||||
|
|
||||||
required property Canvas drawing
|
required property Canvas drawing
|
||||||
property bool expanded: true
|
property bool expanded: true
|
||||||
|
property real offsetScale: shouldBeActive ? 0 : 1
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
readonly property bool shouldBeActive: visibilities.isDrawing
|
readonly property bool shouldBeActive: visibilities.isDrawing
|
||||||
required property var visibilities
|
required property var visibilities
|
||||||
|
|
||||||
|
anchors.leftMargin: (-implicitWidth - 5) * offsetScale
|
||||||
implicitHeight: content.implicitHeight
|
implicitHeight: content.implicitHeight
|
||||||
implicitWidth: 0
|
implicitWidth: root.expanded ? content.implicitWidth : icon.implicitWidth
|
||||||
visible: width > 0
|
opacity: 1 - offsetScale
|
||||||
|
visible: offsetScale < 1
|
||||||
|
|
||||||
states: [
|
Behavior on implicitWidth {
|
||||||
State {
|
Anim {
|
||||||
name: "hidden"
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||||
when: !root.shouldBeActive
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
root.implicitWidth: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
icon.opacity: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
content.opacity: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "collapsed"
|
|
||||||
when: root.shouldBeActive && !root.expanded
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
root.implicitWidth: icon.implicitWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
icon.opacity: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
content.opacity: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "visible"
|
|
||||||
when: root.shouldBeActive && root.expanded
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
root.implicitWidth: content.implicitWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
icon.opacity: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
content.opacity: 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
transitions: [
|
Behavior on offsetScale {
|
||||||
Transition {
|
Anim {
|
||||||
from: "*"
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||||
to: "*"
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||||
|
|
||||||
ParallelAnimation {
|
|
||||||
Anim {
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
property: "implicitWidth"
|
|
||||||
target: root
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.small
|
|
||||||
property: "opacity"
|
|
||||||
target: icon
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.small
|
|
||||||
property: "opacity"
|
|
||||||
target: content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (!visible)
|
if (!visible)
|
||||||
@@ -109,8 +48,12 @@ Item {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
height: content.contentItem.height
|
height: content.contentItem.height
|
||||||
opacity: 1
|
opacity: root.expanded ? 0 : 1
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
sourceComponent: MaterialIcon {
|
sourceComponent: MaterialIcon {
|
||||||
font.pointSize: Appearance.font.size.larger
|
font.pointSize: Appearance.font.size.larger
|
||||||
text: "arrow_forward_ios"
|
text: "arrow_forward_ios"
|
||||||
@@ -122,7 +65,12 @@ Item {
|
|||||||
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
opacity: root.expanded ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
sourceComponent: Content {
|
sourceComponent: Content {
|
||||||
drawing: root.drawing
|
drawing: root.drawing
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ Searcher {
|
|||||||
|
|
||||||
function launch(entry: DesktopEntry): void {
|
function launch(entry: DesktopEntry): void {
|
||||||
appDb.incrementFrequency(entry.id);
|
appDb.incrementFrequency(entry.id);
|
||||||
console.log(root.command);
|
|
||||||
|
|
||||||
if (entry.runInTerminal)
|
if (entry.runInTerminal)
|
||||||
Quickshell.execDetached({
|
Quickshell.execDetached({
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Searcher {
|
|||||||
description: qsTr("Pastel palette with a low chroma.")
|
description: qsTr("Pastel palette with a low chroma.")
|
||||||
icon: "android"
|
icon: "android"
|
||||||
name: qsTr("Tonal Spot")
|
name: qsTr("Tonal Spot")
|
||||||
variant: "tonalspot"
|
variant: "tonal-spot"
|
||||||
},
|
},
|
||||||
Variant {
|
Variant {
|
||||||
description: qsTr("Hue-shifted, artistic or playful colors.")
|
description: qsTr("Hue-shifted, artistic or playful colors.")
|
||||||
|
|||||||
@@ -8,21 +8,25 @@ import qs.Helpers
|
|||||||
Scope {
|
Scope {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
readonly property bool enabled: !Players.list.some(p => p.isPlaying)
|
||||||
required property Lock lock
|
required property Lock lock
|
||||||
readonly property bool enabled: !Players.list.some( p => p.isPlaying )
|
|
||||||
|
|
||||||
function handleIdleAction( action: var ): void {
|
function handleIdleAction(action: var): void {
|
||||||
if ( !action )
|
if (!action)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( action === "lock" )
|
if (action === "lock")
|
||||||
lock.lock.locked = true;
|
lock.lock.locked = true;
|
||||||
else if ( action === "unlock" )
|
else if (action === "unlock")
|
||||||
lock.lock.locked = false;
|
lock.lock.locked = false;
|
||||||
else if ( typeof action === "string" )
|
else if (action === "dpms on")
|
||||||
Hypr.dispatch( action );
|
Hypr.dispatch('hl.dsp.dpms({ action = "enable" })');
|
||||||
|
else if (action === "dpms off")
|
||||||
|
Hypr.dispatch('hl.dsp.dpms({ action = "disable" })');
|
||||||
|
else if (typeof action === "string")
|
||||||
|
Hypr.dispatch(action);
|
||||||
else
|
else
|
||||||
Quickshell.execDetached( action );
|
Quickshell.execDetached(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
Variants {
|
Variants {
|
||||||
@@ -33,7 +37,8 @@ Scope {
|
|||||||
|
|
||||||
enabled: root.enabled && modelData.timeout > 0 ? true : false
|
enabled: root.enabled && modelData.timeout > 0 ? true : false
|
||||||
timeout: modelData.timeout
|
timeout: modelData.timeout
|
||||||
onIsIdleChanged: root.handleIdleAction( isIdle ? modelData.idleAction : modelData.activeAction )
|
|
||||||
|
onIsIdleChanged: root.handleIdleAction(isIdle ? modelData.idleAction : modelData.activeAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ WlSessionLockSurface {
|
|||||||
id: background
|
id: background
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
source: WallpaperPath.lockscreenBg
|
source: WallpaperPath.lockscreenBg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ CustomRect {
|
|||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
height: Config.notifs.sizes.image
|
height: Config.notifs.sizes.image
|
||||||
source: Qt.resolvedUrl(root.image)
|
source: Qt.resolvedUrl(root.image)
|
||||||
|
visible: Config.lock.showNotifIcon
|
||||||
width: Config.notifs.sizes.image
|
width: Config.notifs.sizes.image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,6 +285,8 @@ CustomRect {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
color: root.urgency === "critical" ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface
|
color: root.urgency === "critical" ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface
|
||||||
text: {
|
text: {
|
||||||
|
if (!Config.lock.showNotifContent)
|
||||||
|
return "Unlock to view";
|
||||||
const summary = modelData.summary.replace(/\n/g, " ");
|
const summary = modelData.summary.replace(/\n/g, " ");
|
||||||
const body = modelData.body.replace(/\n/g, " ");
|
const body = modelData.body.replace(/\n/g, " ");
|
||||||
const color = root.urgency === "critical" ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3outline;
|
const color = root.urgency === "critical" ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3outline;
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ Scope {
|
|||||||
} else {
|
} else {
|
||||||
buffer = buffer.slice(0, -1);
|
buffer = buffer.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
buffer = "";
|
||||||
} else if (" abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) {
|
} else if (" abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) {
|
||||||
// No illegal characters (you are insane if you use unicode in your password)
|
// No illegal characters (you are insane if you use unicode in your password)
|
||||||
buffer += event.text;
|
buffer += event.text;
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ Item {
|
|||||||
height += list.itemAtIndex(i)?.nonAnimHeight ?? 0;
|
height += list.itemAtIndex(i)?.nonAnimHeight ?? 0;
|
||||||
|
|
||||||
if (visibilities && panels) {
|
if (visibilities && panels) {
|
||||||
|
if (panels.popouts.hasCurrent && (panels.popouts.currentCenter + (panels.popouts.current?.width / 2)) > panels.notifications.x || visibilities.dashboard)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (visibilities.osd) {
|
if (visibilities.osd) {
|
||||||
const h = panels.osd.y - 8 * 2 - padding * 2;
|
const h = panels.osd.y - 8 * 2 - padding * 2;
|
||||||
if (height > h)
|
if (height > h)
|
||||||
@@ -194,8 +197,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
component Anim: NumberAnimation {
|
component Anim: NumberAnimation {
|
||||||
duration: MaterialEasing.expressiveEffectsTime
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||||
easing.type: Easing.BezierSpline
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,10 @@ CustomRect {
|
|||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
|
|
||||||
onLinkActivated: link => {
|
onLinkActivated: link => {
|
||||||
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
if (Config.launcher.uwsm)
|
||||||
|
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
||||||
|
else
|
||||||
|
Quickshell.execDetached(["xdg-open", link]);
|
||||||
root.visibilities.sidebar = false;
|
root.visibilities.sidebar = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ LazyListView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDoubleClicked: event => {
|
||||||
|
if (event.button === Qt.LeftButton)
|
||||||
|
notifInner.toggleExpand(!notifInner.expanded);
|
||||||
|
}
|
||||||
onPositionChanged: event => {
|
onPositionChanged: event => {
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
const diffY = event.y - startY;
|
const diffY = event.y - startY;
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ LazyListView {
|
|||||||
|
|
||||||
Component.onCompleted: modelData?.lock(this)
|
Component.onCompleted: modelData?.lock(this)
|
||||||
Component.onDestruction: modelData?.unlock(this)
|
Component.onDestruction: modelData?.unlock(this)
|
||||||
|
onDoubleClicked: event => {
|
||||||
|
if (event.button === Qt.LeftButton)
|
||||||
|
root.requestToggleExpand(!root.expanded);
|
||||||
|
}
|
||||||
onPositionChanged: event => {
|
onPositionChanged: event => {
|
||||||
if (pressed && !root.expanded) {
|
if (pressed && !root.expanded) {
|
||||||
const diffY = event.y - startY;
|
const diffY = event.y - startY;
|
||||||
|
|||||||
@@ -0,0 +1,290 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var props
|
||||||
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
|
||||||
|
radius: Appearance.rounding.smallest
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: layout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Appearance.padding.large
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
z: 1
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
color: Recorder.running ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3secondaryContainer
|
||||||
|
implicitHeight: {
|
||||||
|
const h = icon.implicitHeight + Appearance.padding.smaller * 2;
|
||||||
|
return h - (h % 2);
|
||||||
|
}
|
||||||
|
implicitWidth: implicitHeight
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.horizontalCenterOffset: -0.5
|
||||||
|
anchors.verticalCenterOffset: 1.5
|
||||||
|
color: Recorder.running ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSecondaryContainer
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: "screen_record"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.normal
|
||||||
|
text: qsTr("Screen Recorder")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: Recorder.paused ? qsTr("Recording paused") : Recorder.running ? qsTr("Recording running") : qsTr("Recording off")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomSplitButton {
|
||||||
|
active: menuItems.find(m => root.props.recordingMode === m.icon + m.text) ?? menuItems[0]
|
||||||
|
disabled: Recorder.running
|
||||||
|
|
||||||
|
menuItems: [
|
||||||
|
MenuItem {
|
||||||
|
activeText: qsTr("Fullscreen")
|
||||||
|
icon: "fullscreen"
|
||||||
|
text: qsTr("Record fullscreen")
|
||||||
|
|
||||||
|
onClicked: Recorder.start()
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
activeText: qsTr("Region")
|
||||||
|
icon: "screenshot_region"
|
||||||
|
text: qsTr("Record region")
|
||||||
|
|
||||||
|
onClicked: Recorder.start(["-r"])
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
activeText: qsTr("Fullscreen")
|
||||||
|
icon: "select_to_speak"
|
||||||
|
text: qsTr("Record fullscreen with sound")
|
||||||
|
|
||||||
|
onClicked: Recorder.start(["-s"])
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
activeText: qsTr("Region")
|
||||||
|
icon: "volume_up"
|
||||||
|
text: qsTr("Record region with sound")
|
||||||
|
|
||||||
|
onClicked: Recorder.start(["-s", "-r"])
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
menu.onItemSelected: item => root.props.recordingMode = item.icon + item.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: listOrControls
|
||||||
|
|
||||||
|
property bool running: Recorder.running
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: implicitHeight
|
||||||
|
asynchronous: true
|
||||||
|
sourceComponent: running ? recordingControls : recordingList
|
||||||
|
|
||||||
|
Behavior on Layout.preferredHeight {
|
||||||
|
id: locHeightAnim
|
||||||
|
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on running {
|
||||||
|
SequentialAnimation {
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.small
|
||||||
|
easing: Appearance.anim.curves.standardAccel
|
||||||
|
property: "scale"
|
||||||
|
target: listOrControls
|
||||||
|
to: 0.7
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.small
|
||||||
|
easing: Appearance.anim.curves.standardAccel
|
||||||
|
property: "opacity"
|
||||||
|
target: listOrControls
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
property: "enabled"
|
||||||
|
target: locHeightAnim
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
property: "enabled"
|
||||||
|
target: locHeightAnim
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.small
|
||||||
|
easing: Appearance.anim.curves.standardDecel
|
||||||
|
property: "scale"
|
||||||
|
target: listOrControls
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.small
|
||||||
|
easing: Appearance.anim.curves.standardDecel
|
||||||
|
property: "opacity"
|
||||||
|
target: listOrControls
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: recordingList
|
||||||
|
|
||||||
|
RecordingList {
|
||||||
|
props: root.props
|
||||||
|
visibilities: root.visibilities
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: recordingControls
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
color: Recorder.paused ? DynamicColors.palette.m3tertiary : DynamicColors.palette.m3error
|
||||||
|
implicitHeight: recText.implicitHeight + Appearance.padding.smaller * 2
|
||||||
|
implicitWidth: recText.implicitWidth + Appearance.padding.normal * 2
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SequentialAnimation on opacity {
|
||||||
|
alwaysRunToEnd: true
|
||||||
|
loops: Animation.Infinite
|
||||||
|
running: !Recorder.paused
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.large
|
||||||
|
easing: Appearance.anim.curves.emphasizedAccel
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.extraLarge
|
||||||
|
easing: Appearance.anim.curves.emphasizedDecel
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: recText
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
animate: true
|
||||||
|
color: Recorder.paused ? DynamicColors.palette.m3onTertiary : DynamicColors.palette.m3onError
|
||||||
|
font.family: Appearance.font.family.mono
|
||||||
|
text: Recorder.paused ? "PAUSED" : "REC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
font.pointSize: Appearance.font.size.normal
|
||||||
|
text: {
|
||||||
|
const elapsed = Recorder.elapsed;
|
||||||
|
|
||||||
|
const hours = Math.floor(elapsed / 3600);
|
||||||
|
const mins = Math.floor((elapsed % 3600) / 60);
|
||||||
|
const secs = Math.floor(elapsed % 60).toString().padStart(2, "0");
|
||||||
|
|
||||||
|
let time;
|
||||||
|
if (hours > 0)
|
||||||
|
time = `${hours}:${mins.toString().padStart(2, "0")}:${secs}`;
|
||||||
|
else
|
||||||
|
time = `${mins}:${secs}`;
|
||||||
|
|
||||||
|
return qsTr("Recording for %1").arg(time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
checked: Recorder.paused
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
icon: Recorder.paused ? "play_arrow" : "pause"
|
||||||
|
label.animate: true
|
||||||
|
toggle: true
|
||||||
|
type: IconButton.Tonal
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
Recorder.togglePause();
|
||||||
|
internalChecked = Recorder.paused;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
icon: "stop"
|
||||||
|
inactiveColour: DynamicColors.palette.m3error
|
||||||
|
inactiveOnColour: DynamicColors.palette.m3onError
|
||||||
|
|
||||||
|
onClicked: Recorder.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import ZShell.Models
|
||||||
|
import qs.Components
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Paths
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var props
|
||||||
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
WrapperMouseArea {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
|
||||||
|
onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: Appearance.spacing.smaller
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: "list"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: Appearance.font.size.normal
|
||||||
|
text: qsTr("Recordings")
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: root.props.recordingListExpanded ? "unfold_less" : "unfold_more"
|
||||||
|
label.animate: true
|
||||||
|
type: IconButton.Text
|
||||||
|
|
||||||
|
onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomListView {
|
||||||
|
id: list
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: -Appearance.spacing.small
|
||||||
|
clip: true
|
||||||
|
implicitHeight: (Appearance.font.size.larger + Appearance.padding.small) * (root.props.recordingListExpanded ? 10 : 3)
|
||||||
|
|
||||||
|
CustomScrollBar.vertical: CustomScrollBar {
|
||||||
|
flickable: list
|
||||||
|
}
|
||||||
|
add: Transition {
|
||||||
|
Anim {
|
||||||
|
from: 0
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
from: 0.5
|
||||||
|
property: "scale"
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delegate: RowLayout {
|
||||||
|
id: recording
|
||||||
|
|
||||||
|
property string baseName
|
||||||
|
required property FileSystemEntry modelData
|
||||||
|
|
||||||
|
anchors.left: list.contentItem.left
|
||||||
|
anchors.right: list.contentItem.right
|
||||||
|
anchors.rightMargin: Appearance.spacing.small
|
||||||
|
spacing: Appearance.spacing.small / 2
|
||||||
|
|
||||||
|
Component.onCompleted: baseName = modelData.baseName
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: Appearance.spacing.small / 2
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
elide: Text.ElideRight
|
||||||
|
text: {
|
||||||
|
const time = recording.baseName;
|
||||||
|
const matches = time.match(/^recording_(\d{4})(\d{2})(\d{2})_(\d{2})-(\d{2})-(\d{2})/);
|
||||||
|
if (!matches)
|
||||||
|
return time;
|
||||||
|
const date = new Date(...matches.slice(1));
|
||||||
|
date.setMonth(date.getMonth() - 1);
|
||||||
|
return qsTr("Recording at %1").arg(Qt.formatDateTime(date, Qt.locale()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: "play_arrow"
|
||||||
|
type: IconButton.Text
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.visibilities.sidebar = false;
|
||||||
|
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: "folder"
|
||||||
|
type: IconButton.Text
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.visibilities.sidebar = false;
|
||||||
|
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displaced: Transition {
|
||||||
|
Anim {
|
||||||
|
properties: "opacity,scale"
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
property: "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model: FileSystemModel {
|
||||||
|
nameFilters: ["recording_*.mp4"]
|
||||||
|
path: Paths.recsdir
|
||||||
|
sortReverse: true
|
||||||
|
}
|
||||||
|
remove: Transition {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
property: "scale"
|
||||||
|
to: 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
active: opacity > 0
|
||||||
|
anchors.centerIn: parent
|
||||||
|
asynchronous: true
|
||||||
|
opacity: list.count === 0 ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sourceComponent: ColumnLayout {
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.preferredHeight: root.props.recordingListExpanded ? implicitHeight : 0
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
opacity: root.props.recordingListExpanded ? 1 : 0
|
||||||
|
scale: root.props.recordingListExpanded ? 1 : 0
|
||||||
|
text: "scan_delete"
|
||||||
|
|
||||||
|
Behavior on Layout.preferredHeight {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: Appearance.spacing.smaller
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.preferredWidth: !root.props.recordingListExpanded ? implicitWidth : 0
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
opacity: !root.props.recordingListExpanded ? 1 : 0
|
||||||
|
scale: !root.props.recordingListExpanded ? 1 : 0
|
||||||
|
text: "scan_delete"
|
||||||
|
|
||||||
|
Behavior on Layout.preferredWidth {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
text: qsTr("No recordings found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import QtQuick.Layouts
|
|||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
|
import qs.Helpers
|
||||||
import qs.Daemons
|
import qs.Daemons
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
@@ -32,7 +33,7 @@ CustomRect {
|
|||||||
Toggle {
|
Toggle {
|
||||||
checked: Network.wifiEnabled
|
checked: Network.wifiEnabled
|
||||||
icon: Network.wifiEnabled ? "wifi" : "wifi_off"
|
icon: Network.wifiEnabled ? "wifi" : "wifi_off"
|
||||||
visible: QSNetwork.Networking.devices.values.length > 0
|
visible: QSNetwork.Networking.devices.values.some(n => n.type === QSNetwork.DeviceType.Wifi)
|
||||||
|
|
||||||
onClicked: Network.toggleWifi()
|
onClicked: Network.toggleWifi()
|
||||||
}
|
}
|
||||||
@@ -79,6 +80,13 @@ CustomRect {
|
|||||||
adapter.enabled = !adapter.enabled;
|
adapter.enabled = !adapter.enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Toggle {
|
||||||
|
checked: GameMode.enabled
|
||||||
|
icon: GameMode.enabled ? "videogame_asset" : "videogame_asset_off"
|
||||||
|
|
||||||
|
onClicked: GameMode.enabled = !GameMode.enabled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import qs.Modules.Notifications.Sidebar.Utils.Cards
|
import Quickshell
|
||||||
import qs.Config
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import qs.Modules.Notifications.Sidebar.Utils.Cards
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Item popouts
|
required property Item popouts
|
||||||
required property var props
|
required property PersistentProperties props
|
||||||
required property var visibilities
|
required property var visibilities
|
||||||
|
|
||||||
implicitHeight: layout.implicitHeight
|
implicitHeight: layout.implicitHeight
|
||||||
@@ -22,6 +23,12 @@ Item {
|
|||||||
IdleInhibit {
|
IdleInhibit {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Record {
|
||||||
|
props: root.props
|
||||||
|
visibilities: root.visibilities
|
||||||
|
z: 1
|
||||||
|
}
|
||||||
|
|
||||||
Toggles {
|
Toggles {
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
|
|||||||
@@ -7,18 +7,17 @@ import QtQuick
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property real offsetScale: shouldBeActive ? 0 : 1
|
||||||
required property var panels
|
required property var panels
|
||||||
readonly property Props props: Props {
|
readonly property Props props: Props {
|
||||||
}
|
}
|
||||||
|
readonly property bool shouldBeActive: root.visibilities.sidebar && Config.sidebar.enabled
|
||||||
required property var visibilities
|
required property var visibilities
|
||||||
|
|
||||||
readonly property bool shouldBeActive: root.visibilities.sidebar && Config.sidebar.enabled
|
|
||||||
property real offsetScale: shouldBeActive ? 0 : 1
|
|
||||||
|
|
||||||
visible: offsetScale < 1
|
|
||||||
anchors.rightMargin: (-implicitWidth - 5) * offsetScale
|
anchors.rightMargin: (-implicitWidth - 5) * offsetScale
|
||||||
implicitWidth: Config.sidebar.sizes.width
|
implicitWidth: Config.sidebar.sizes.width
|
||||||
opacity: 1 - offsetScale
|
opacity: 1 - offsetScale
|
||||||
|
visible: offsetScale < 1
|
||||||
|
|
||||||
Behavior on offsetScale {
|
Behavior on offsetScale {
|
||||||
Anim {
|
Anim {
|
||||||
@@ -30,16 +29,15 @@ Item {
|
|||||||
Loader {
|
Loader {
|
||||||
id: content
|
id: content
|
||||||
|
|
||||||
|
active: root.shouldBeActive || root.visible
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: 0
|
anchors.bottomMargin: 0
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.margins: 8
|
anchors.margins: 8
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
|
||||||
active: root.shouldBeActive || root.visible
|
|
||||||
|
|
||||||
sourceComponent: Content {
|
sourceComponent: Content {
|
||||||
implicitWidth: Config.sidebar.sizes.width - 8 * 2
|
implicitWidth: Config.sidebar.sizes.width - Appearance.padding.smaller * 2
|
||||||
props: root.props
|
props: root.props
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,26 +10,9 @@ Item {
|
|||||||
required property var visibilities
|
required property var visibilities
|
||||||
|
|
||||||
implicitHeight: content.implicitHeight
|
implicitHeight: content.implicitHeight
|
||||||
implicitWidth: content.implicitWidth
|
implicitWidth: Math.max(sidebarPanel.width * (1 - sidebarPanel.offsetScale), content.implicitWidth)
|
||||||
visible: height > 0
|
visible: height > 0
|
||||||
|
|
||||||
states: State {
|
|
||||||
name: "hidden"
|
|
||||||
when: root.visibilities.sidebar || root.visibilities.dashboard || (root.panels.popouts.hasCurrent && root.panels.popouts.currentName.startsWith("traymenu"))
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
root.implicitHeight: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
transitions: Transition {
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
|
||||||
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
|
||||||
property: "implicitHeight"
|
|
||||||
target: root
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Content {
|
Content {
|
||||||
id: content
|
id: content
|
||||||
|
|
||||||
|
|||||||
@@ -100,12 +100,14 @@ Item {
|
|||||||
icon: `brightness_${(Math.round(value * 6) + 1)}`
|
icon: `brightness_${(Math.round(value * 6) + 1)}`
|
||||||
value: root.brightness
|
value: root.brightness
|
||||||
|
|
||||||
onMoved: {
|
onPressedChanged: {
|
||||||
if (Config.osd.allMonBrightness) {
|
if (!pressed) {
|
||||||
root.monitor?.setBrightness(value);
|
if (Config.osd.allMonBrightness) {
|
||||||
} else {
|
for (const mon of Brightness.monitors) {
|
||||||
for (const mon of Brightness.monitors) {
|
mon.setBrightness(value);
|
||||||
mon.setBrightness(value);
|
}
|
||||||
|
} else {
|
||||||
|
root.monitor?.setBrightness(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ CustomRect {
|
|||||||
color: visibilities.resources ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
|
color: visibilities.resources ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
||||||
implicitWidth: rowLayout.implicitWidth + Appearance.padding.normal * 2
|
implicitWidth: rowLayout.implicitWidth + Appearance.padding.normal * 2
|
||||||
radius: height / 2
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
onClicked: root.visibilities.resources = !root.visibilities.resources
|
onClicked: root.visibilities.resources = !root.visibilities.resources
|
||||||
|
|||||||
@@ -104,6 +104,24 @@ Item {
|
|||||||
key: "launcher"
|
key: "launcher"
|
||||||
name: "Launcher"
|
name: "Launcher"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
icon: "screenshot_region"
|
||||||
|
key: "screenshot"
|
||||||
|
name: "Screenshot"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
icon: "cached"
|
||||||
|
key: "updates"
|
||||||
|
name: "Updates"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
icon: "extension"
|
||||||
|
key: "plugins"
|
||||||
|
name: "Extensions"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomClippingRect {
|
CustomClippingRect {
|
||||||
@@ -153,7 +171,7 @@ Item {
|
|||||||
required property string name
|
required property string name
|
||||||
|
|
||||||
implicitHeight: 42
|
implicitHeight: 42
|
||||||
implicitWidth: 200
|
implicitWidth: 250
|
||||||
radius: Appearance.rounding.normal - Appearance.padding.smaller
|
radius: Appearance.rounding.normal - Appearance.padding.smaller
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -171,9 +189,15 @@ Item {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.preferredWidth: icon.contentWidth
|
Layout.preferredWidth: icon.contentWidth
|
||||||
color: categoryItem.index === clayout.currentIndex ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
|
color: categoryItem.index === clayout.currentIndex ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
|
||||||
|
fill: categoryItem.index === clayout.currentIndex ? 1 : 0
|
||||||
font.pointSize: Appearance.font.size.small * 2
|
font.pointSize: Appearance.font.size.small * 2
|
||||||
text: categoryItem.icon
|
text: categoryItem.icon
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|
||||||
|
Behavior on fill {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import QtQuick
|
||||||
import qs.Modules.Settings.Controls
|
import qs.Modules.Settings.Controls
|
||||||
import qs.Config
|
import qs.Config
|
||||||
|
|
||||||
@@ -76,37 +77,21 @@ SettingsPage {
|
|||||||
name: "Fonts"
|
name: "Fonts"
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingInput {
|
SettingListView {
|
||||||
name: "Sans family"
|
name: "Sans family"
|
||||||
object: Config.appearance.font.family
|
object: Config.appearance.font.family
|
||||||
setting: "sans"
|
setting: "sans"
|
||||||
|
stringList: Qt.fontFamilies()
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingInput {
|
SettingListView {
|
||||||
name: "Monospace family"
|
name: "Monospace family"
|
||||||
object: Config.appearance.font.family
|
object: Config.appearance.font.family
|
||||||
setting: "mono"
|
setting: "mono"
|
||||||
}
|
stringList: Qt.fontFamilies()
|
||||||
|
|
||||||
Separator {
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingInput {
|
|
||||||
name: "Material family"
|
|
||||||
object: Config.appearance.font.family
|
|
||||||
setting: "material"
|
|
||||||
}
|
|
||||||
|
|
||||||
Separator {
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingInput {
|
|
||||||
name: "Clock family"
|
|
||||||
object: Config.appearance.font.family
|
|
||||||
setting: "clock"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import Quickshell
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Modules.Settings.Controls
|
import qs.Modules.Settings.Controls
|
||||||
import qs.Config
|
import qs.Config
|
||||||
@@ -5,6 +6,8 @@ import qs.Config
|
|||||||
SettingsPage {
|
SettingsPage {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
required property ShellScreen screen
|
||||||
|
|
||||||
SettingsSection {
|
SettingsSection {
|
||||||
sectionId: "Wallpaper"
|
sectionId: "Wallpaper"
|
||||||
|
|
||||||
@@ -29,20 +32,17 @@ SettingsPage {
|
|||||||
step: 50
|
step: 50
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// WallpaperCropper {
|
WallpaperCropper {
|
||||||
// Layout.fillWidth: true
|
}
|
||||||
// Layout.preferredHeight: 300
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSection {
|
SettingsSection {
|
||||||
sectionId: "Wallpapers"
|
sectionId: "Wallpapers"
|
||||||
|
|
||||||
WallpaperGrid {
|
WallpaperGrid {
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Height"
|
|
||||||
min: 1
|
min: 1
|
||||||
|
name: "Height"
|
||||||
object: Config.barConfig
|
object: Config.barConfig
|
||||||
setting: "height"
|
setting: "height"
|
||||||
}
|
}
|
||||||
@@ -29,8 +29,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Rounding"
|
|
||||||
min: 0
|
min: 0
|
||||||
|
name: "Rounding"
|
||||||
object: Config.barConfig
|
object: Config.barConfig
|
||||||
setting: "rounding"
|
setting: "rounding"
|
||||||
}
|
}
|
||||||
@@ -39,11 +39,21 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Border"
|
|
||||||
min: 0
|
min: 0
|
||||||
|
name: "Border"
|
||||||
object: Config.barConfig
|
object: Config.barConfig
|
||||||
setting: "border"
|
setting: "border"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSpinBox {
|
||||||
|
min: 0
|
||||||
|
name: "Smoothing"
|
||||||
|
object: Config.barConfig
|
||||||
|
setting: "smoothing"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSection {
|
SettingsSection {
|
||||||
@@ -145,8 +155,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Dock height"
|
|
||||||
min: 1
|
min: 1
|
||||||
|
name: "Dock height"
|
||||||
object: Config.dock
|
object: Config.dock
|
||||||
setting: "height"
|
setting: "height"
|
||||||
}
|
}
|
||||||
@@ -173,8 +183,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingStringList {
|
SettingStringList {
|
||||||
name: "Pinned apps"
|
|
||||||
addLabel: qsTr("Add pinned app")
|
addLabel: qsTr("Add pinned app")
|
||||||
|
name: "Pinned apps"
|
||||||
object: Config.dock
|
object: Config.dock
|
||||||
setting: "pinnedApps"
|
setting: "pinnedApps"
|
||||||
}
|
}
|
||||||
@@ -183,8 +193,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingStringList {
|
SettingStringList {
|
||||||
name: "Ignored app regexes"
|
|
||||||
addLabel: qsTr("Add ignored regex")
|
addLabel: qsTr("Add ignored regex")
|
||||||
|
name: "Ignored app regexes"
|
||||||
object: Config.dock
|
object: Config.dock
|
||||||
setting: "ignoredAppRegexes"
|
setting: "ignoredAppRegexes"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Media update interval"
|
|
||||||
min: 0
|
min: 0
|
||||||
|
name: "Media update interval"
|
||||||
object: Config.dashboard
|
object: Config.dashboard
|
||||||
setting: "mediaUpdateInterval"
|
setting: "mediaUpdateInterval"
|
||||||
step: 50
|
step: 50
|
||||||
@@ -30,8 +30,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Resource update interval"
|
|
||||||
min: 0
|
min: 0
|
||||||
|
name: "Resource update interval"
|
||||||
object: Config.dashboard
|
object: Config.dashboard
|
||||||
setting: "resourceUpdateInterval"
|
setting: "resourceUpdateInterval"
|
||||||
step: 50
|
step: 50
|
||||||
@@ -41,8 +41,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Drag threshold"
|
|
||||||
min: 0
|
min: 0
|
||||||
|
name: "Drag threshold"
|
||||||
object: Config.dashboard
|
object: Config.dashboard
|
||||||
setting: "dragThreshold"
|
setting: "dragThreshold"
|
||||||
}
|
}
|
||||||
@@ -107,112 +107,112 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSection {
|
// SettingsSection {
|
||||||
sectionId: "Layout Sizes"
|
// sectionId: "Layout Sizes"
|
||||||
|
//
|
||||||
SettingsHeader {
|
// SettingsHeader {
|
||||||
name: "Layout Sizes"
|
// name: "Layout Sizes"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Tab indicator height"
|
// name: "Tab indicator height"
|
||||||
value: String(Config.dashboard.sizes.tabIndicatorHeight)
|
// value: String(Config.dashboard.sizes.tabIndicatorHeight)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Tab indicator spacing"
|
// name: "Tab indicator spacing"
|
||||||
value: String(Config.dashboard.sizes.tabIndicatorSpacing)
|
// value: String(Config.dashboard.sizes.tabIndicatorSpacing)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Info width"
|
// name: "Info width"
|
||||||
value: String(Config.dashboard.sizes.infoWidth)
|
// value: String(Config.dashboard.sizes.infoWidth)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Info icon size"
|
// name: "Info icon size"
|
||||||
value: String(Config.dashboard.sizes.infoIconSize)
|
// value: String(Config.dashboard.sizes.infoIconSize)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Date time width"
|
// name: "Date time width"
|
||||||
value: String(Config.dashboard.sizes.dateTimeWidth)
|
// value: String(Config.dashboard.sizes.dateTimeWidth)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Media width"
|
// name: "Media width"
|
||||||
value: String(Config.dashboard.sizes.mediaWidth)
|
// value: String(Config.dashboard.sizes.mediaWidth)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Media progress sweep"
|
// name: "Media progress sweep"
|
||||||
value: String(Config.dashboard.sizes.mediaProgressSweep)
|
// value: String(Config.dashboard.sizes.mediaProgressSweep)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Media progress thickness"
|
// name: "Media progress thickness"
|
||||||
value: String(Config.dashboard.sizes.mediaProgressThickness)
|
// value: String(Config.dashboard.sizes.mediaProgressThickness)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Resource progress thickness"
|
// name: "Resource progress thickness"
|
||||||
value: String(Config.dashboard.sizes.resourceProgessThickness)
|
// value: String(Config.dashboard.sizes.resourceProgessThickness)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Weather width"
|
// name: "Weather width"
|
||||||
value: String(Config.dashboard.sizes.weatherWidth)
|
// value: String(Config.dashboard.sizes.weatherWidth)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Media cover art size"
|
// name: "Media cover art size"
|
||||||
value: String(Config.dashboard.sizes.mediaCoverArtSize)
|
// value: String(Config.dashboard.sizes.mediaCoverArtSize)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Media visualiser size"
|
// name: "Media visualiser size"
|
||||||
value: String(Config.dashboard.sizes.mediaVisualiserSize)
|
// value: String(Config.dashboard.sizes.mediaVisualiserSize)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingReadOnly {
|
// SettingReadOnly {
|
||||||
name: "Resource size"
|
// name: "Resource size"
|
||||||
value: String(Config.dashboard.sizes.resourceSize)
|
// value: String(Config.dashboard.sizes.resourceSize)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
import qs.Modules.Settings.Controls
|
import qs.Modules.Settings.Controls
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Components
|
import qs.Components
|
||||||
@@ -47,6 +49,15 @@ SettingsPage {
|
|||||||
object: Config.general
|
object: Config.general
|
||||||
setting: "desktopIcons"
|
setting: "desktopIcons"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingInput {
|
||||||
|
name: "Date format"
|
||||||
|
object: Config.general
|
||||||
|
setting: "dateFormat"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSection {
|
SettingsSection {
|
||||||
@@ -58,6 +69,7 @@ SettingsPage {
|
|||||||
|
|
||||||
CustomSplitButtonRow {
|
CustomSplitButtonRow {
|
||||||
active: Config.general.color.mode === "light" ? menuItems[0] : menuItems[1]
|
active: Config.general.color.mode === "light" ? menuItems[0] : menuItems[1]
|
||||||
|
buttonAlias.disabled: !Config.general.color.schemeGeneration
|
||||||
label: qsTr("Scheme mode")
|
label: qsTr("Scheme mode")
|
||||||
|
|
||||||
menuItems: [
|
menuItems: [
|
||||||
@@ -91,6 +103,7 @@ SettingsPage {
|
|||||||
id: schemeType
|
id: schemeType
|
||||||
|
|
||||||
active: root.schemeTypeItem(menuItems, Config.colors.schemeType)
|
active: root.schemeTypeItem(menuItems, Config.colors.schemeType)
|
||||||
|
buttonAlias.disabled: !Config.general.color.schemeGeneration
|
||||||
label: qsTr("Scheme type")
|
label: qsTr("Scheme type")
|
||||||
z: 2
|
z: 2
|
||||||
|
|
||||||
@@ -118,7 +131,7 @@ SettingsPage {
|
|||||||
MenuItem {
|
MenuItem {
|
||||||
icon: "gradient"
|
icon: "gradient"
|
||||||
text: qsTr("Tonal spot")
|
text: qsTr("Tonal spot")
|
||||||
value: "tonalSpot"
|
value: "tonal-spot"
|
||||||
},
|
},
|
||||||
MenuItem {
|
MenuItem {
|
||||||
icon: "target"
|
icon: "target"
|
||||||
@@ -138,7 +151,7 @@ SettingsPage {
|
|||||||
MenuItem {
|
MenuItem {
|
||||||
icon: "nutrition"
|
icon: "nutrition"
|
||||||
text: qsTr("Fruit salad")
|
text: qsTr("Fruit salad")
|
||||||
value: "fruitSalad"
|
value: "fruit-salad"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -146,12 +159,7 @@ SettingsPage {
|
|||||||
Config.colors.schemeType = item.value;
|
Config.colors.schemeType = item.value;
|
||||||
Config.save();
|
Config.save();
|
||||||
|
|
||||||
if (item.value === "tonalSpot")
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--scheme", item.value]);
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--scheme", "tonal-spot"]);
|
|
||||||
else if (item.value === "fruitSalad")
|
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--scheme", "fruit-salad"]);
|
|
||||||
else
|
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--scheme", item.value]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,21 +173,69 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
|
shouldBeActive: Config.general.color.schemeGeneration ? 0 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
SchemesListView {
|
||||||
|
name: "Color scheme presets"
|
||||||
|
object: Config.colors.presets
|
||||||
|
setting: "name"
|
||||||
|
shouldBeActive: Config.general.color.schemeGeneration ? 0 : 1
|
||||||
|
stringList: FetchPresets.presetNames()
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
shouldBeActive: Config.colors.presets.name !== "" && !Config.general.color.schemeGeneration
|
||||||
|
}
|
||||||
|
|
||||||
|
SchemesListView {
|
||||||
|
name: "Preset variant"
|
||||||
|
object: Config.colors.presets
|
||||||
|
setting: "variant"
|
||||||
|
shouldBeActive: Config.colors.presets.name !== "" && !Config.general.color.schemeGeneration
|
||||||
|
stringList: FetchPresets.variantNames(Config.colors.presets.name)
|
||||||
|
|
||||||
|
onOptionSet: item => {
|
||||||
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--preset", `${Config.colors.presets.name.toLowerCase()}:${item}`]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
shouldBeActive: Config.colors.presets.variant !== "" && FetchPresets.accents(Config.colors.presets.name, Config.colors.presets.variant).length > 0 && !Config.general.color.schemeGeneration
|
||||||
|
}
|
||||||
|
|
||||||
|
SchemesListView {
|
||||||
|
name: "Preset accent"
|
||||||
|
object: Config.colors.presets
|
||||||
|
setting: "accent"
|
||||||
|
shouldBeActive: Config.colors.presets.variant !== "" && FetchPresets.accents(Config.colors.presets.name, Config.colors.presets.variant).length > 0 && !Config.general.color.schemeGeneration
|
||||||
|
stringList: FetchPresets.accents(Config.colors.presets.name, Config.colors.presets.variant)
|
||||||
|
|
||||||
|
onOptionSet: item => {
|
||||||
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--preset", `${Config.colors.presets.name.toLowerCase()}:${Config.colors.presets.variant}`, "--accent", `${item}`]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
shouldBeActive: Config.general.color.schemeGeneration ? 1 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Smart color scheme"
|
name: "Smart color scheme"
|
||||||
object: Config.general.color
|
object: Config.general.color
|
||||||
setting: "smart"
|
setting: "smart"
|
||||||
|
shouldBeActive: Config.general.color.schemeGeneration ? 1 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
|
shouldBeActive: Config.general.color.schemeGeneration ? 1 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinner {
|
SettingSpinner {
|
||||||
name: "Schedule dark mode"
|
name: "Schedule dark mode"
|
||||||
object: Config.general.color
|
object: Config.general.color
|
||||||
settings: ["scheduleDarkStart", "scheduleDarkEnd", "scheduleDark"]
|
settings: ["scheduleDarkStart", "scheduleDarkEnd", "scheduleDark"]
|
||||||
|
shouldBeActive: Config.general.color.schemeGeneration ? 1 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Max fingerprint tries"
|
|
||||||
min: 1
|
min: 1
|
||||||
|
name: "Max fingerprint tries"
|
||||||
object: Config.lock
|
object: Config.lock
|
||||||
setting: "maxFprintTries"
|
setting: "maxFprintTries"
|
||||||
step: 1
|
step: 1
|
||||||
@@ -41,9 +41,27 @@ SettingsPage {
|
|||||||
Separator {
|
Separator {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Show notification details"
|
||||||
|
object: Config.lock
|
||||||
|
setting: "showNotifContent"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Show notification icon"
|
||||||
|
object: Config.lock
|
||||||
|
setting: "showNotifIcon"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Blur amount"
|
|
||||||
min: 0
|
min: 0
|
||||||
|
name: "Blur amount"
|
||||||
object: Config.lock
|
object: Config.lock
|
||||||
setting: "blurAmount"
|
setting: "blurAmount"
|
||||||
step: 1
|
step: 1
|
||||||
@@ -53,9 +71,9 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Height multiplier"
|
|
||||||
max: 2
|
max: 2
|
||||||
min: 0.1
|
min: 0.1
|
||||||
|
name: "Height multiplier"
|
||||||
object: Config.lock.sizes
|
object: Config.lock.sizes
|
||||||
setting: "heightMult"
|
setting: "heightMult"
|
||||||
step: 0.05
|
step: 0.05
|
||||||
@@ -65,9 +83,9 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Aspect ratio"
|
|
||||||
max: 4
|
max: 4
|
||||||
min: 0.5
|
min: 0.5
|
||||||
|
name: "Aspect ratio"
|
||||||
object: Config.lock.sizes
|
object: Config.lock.sizes
|
||||||
setting: "ratio"
|
setting: "ratio"
|
||||||
step: 0.05
|
step: 0.05
|
||||||
@@ -77,14 +95,26 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Center width"
|
|
||||||
min: 100
|
min: 100
|
||||||
|
name: "Center width"
|
||||||
object: Config.lock.sizes
|
object: Config.lock.sizes
|
||||||
setting: "centerWidth"
|
setting: "centerWidth"
|
||||||
step: 10
|
step: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsSection {
|
||||||
|
sectionId: "Greeter"
|
||||||
|
|
||||||
|
SettingsHeader {
|
||||||
|
name: "Greeter"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsIconButton {
|
||||||
|
name: "Install wallpaper and color scheme to greeter"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SettingsSection {
|
SettingsSection {
|
||||||
sectionId: "Idle"
|
sectionId: "Idle"
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import qs.Modules.Settings.Controls
|
|||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
function addTimeoutEntry() {
|
function addTimeoutEntry() {
|
||||||
let list = [...Config.general.idle.timeouts];
|
let list = [...Config.general.idle.timeouts];
|
||||||
|
|
||||||
@@ -22,6 +24,13 @@ ColumnLayout {
|
|||||||
Config.save();
|
Config.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteTimeoutEntry(index) {
|
||||||
|
let list = [...Config.general.idle.timeouts];
|
||||||
|
list.splice(index, 1);
|
||||||
|
Config.general.idle.timeouts = list;
|
||||||
|
Config.save();
|
||||||
|
}
|
||||||
|
|
||||||
function updateTimeoutEntry(i, key, value) {
|
function updateTimeoutEntry(i, key, value) {
|
||||||
const list = [...Config.general.idle.timeouts];
|
const list = [...Config.general.idle.timeouts];
|
||||||
let entry = list[i];
|
let entry = list[i];
|
||||||
@@ -33,8 +42,26 @@ ColumnLayout {
|
|||||||
Config.save();
|
Config.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: shouldBeActive ? implicitHeight : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
spacing: Appearance.spacing.smaller
|
spacing: Appearance.spacing.smaller
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
name: "Idle Monitors"
|
name: "Idle Monitors"
|
||||||
@@ -45,10 +72,15 @@ ColumnLayout {
|
|||||||
|
|
||||||
SettingList {
|
SettingList {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
anchors.left: undefined
|
||||||
|
anchors.right: undefined
|
||||||
|
|
||||||
onAddActiveActionRequested: {
|
onAddActiveActionRequested: {
|
||||||
root.updateTimeoutEntry(index, "activeAction", "");
|
root.updateTimeoutEntry(index, "activeAction", "");
|
||||||
}
|
}
|
||||||
|
onDeleteRequested: function (index) {
|
||||||
|
root.deleteTimeoutEntry(index);
|
||||||
|
}
|
||||||
onFieldEdited: function (key, value) {
|
onFieldEdited: function (key, value) {
|
||||||
root.updateTimeoutEntry(index, key, value);
|
root.updateTimeoutEntry(index, key, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import qs.Modules.Settings.Controls
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
SettingsPage {
|
||||||
|
SettingsSection {
|
||||||
|
sectionId: "Plugins"
|
||||||
|
|
||||||
|
SettingsHeader {
|
||||||
|
name: "Plugins"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingBarEntryList {
|
||||||
|
name: "Enable or disable plugins"
|
||||||
|
object: Config.plugins
|
||||||
|
setting: "entries"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import qs.Modules.Settings.Controls
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
|
||||||
|
SettingsPage {
|
||||||
|
SettingsSection {
|
||||||
|
sectionId: "Screenshot"
|
||||||
|
|
||||||
|
SettingsHeader {
|
||||||
|
name: "Screenshot"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Enable effects"
|
||||||
|
object: Config.screenshot
|
||||||
|
setting: "enable_pp"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomSplitButtonRow {
|
||||||
|
// active: true
|
||||||
|
label: qsTr("Effects mode")
|
||||||
|
|
||||||
|
menuItems: [
|
||||||
|
MenuItem {
|
||||||
|
icon: "build"
|
||||||
|
text: qsTr("Manual")
|
||||||
|
value: "manual"
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
icon: "rotate_auto"
|
||||||
|
text: qsTr("Auto")
|
||||||
|
value: "auto"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
onSelected: item => {
|
||||||
|
Config.screenshot.mode = item.value;
|
||||||
|
Config.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSpinBox {
|
||||||
|
min: 0
|
||||||
|
name: "Corner radius"
|
||||||
|
object: Config.screenshot
|
||||||
|
setting: "corner_radius"
|
||||||
|
step: 1
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Enable drop shadow"
|
||||||
|
object: Config.screenshot
|
||||||
|
setting: "drop_shadow"
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Enable rounded corners"
|
||||||
|
object: Config.screenshot
|
||||||
|
setting: "rounded_corners"
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSpinBox {
|
||||||
|
min: 0
|
||||||
|
name: "Shadow blur radius"
|
||||||
|
object: Config.screenshot
|
||||||
|
setting: "shadow_blur_radius"
|
||||||
|
step: 1
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Shadow color broken atm"
|
||||||
|
object: Config.Screenshot
|
||||||
|
setting: "shadow_color"
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSpinBox {
|
||||||
|
min: 0
|
||||||
|
name: "Shadow offset X"
|
||||||
|
object: Config.screenshot
|
||||||
|
setting: "shadow_offset_x"
|
||||||
|
step: 1
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSpinBox {
|
||||||
|
min: 0
|
||||||
|
name: "Shadow offset Y"
|
||||||
|
object: Config.screenshot
|
||||||
|
setting: "shadow_offset_y"
|
||||||
|
step: 1
|
||||||
|
visible: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick
|
||||||
|
import qs.Config
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.Settings.Controls
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
radius: Appearance.rounding.normal - Appearance.padding.smaller
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: Appearance.padding.large
|
||||||
|
spacing: Appearance.spacing.large
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
font.pointSize: Appearance.font.size.larger * 4
|
||||||
|
text: "update"
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
CustomText {
|
||||||
|
font.pointSize: Appearance.font.size.large * 2
|
||||||
|
text: "System updates"
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: text
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
text: `${Updates.availableUpdates} available updates`
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
Layout.preferredHeight: 40
|
||||||
|
Layout.preferredWidth: 150
|
||||||
|
color: Updates.updating ? DynamicColors.layer(DynamicColors.palette.m3outline, 2) : DynamicColors.palette.m3primary
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
animate: true
|
||||||
|
color: DynamicColors.palette.m3onPrimary
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: Updates.updating ? "update" : "download"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
color: Updates.updating ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onPrimary
|
||||||
|
text: "Update all"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
color: DynamicColors.palette.m3onPrimary
|
||||||
|
disabled: Updates.updating
|
||||||
|
|
||||||
|
onClicked: Updates.performSystemUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomListView {
|
||||||
|
id: view
|
||||||
|
|
||||||
|
readonly property int itemHeight: 50 + Appearance.padding.smaller * 2
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
clip: true
|
||||||
|
contentHeight: height
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
delegate: CustomRect {
|
||||||
|
id: update
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
readonly property list<string> sections: modelData.update.split(" ")
|
||||||
|
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: view.itemHeight
|
||||||
|
implicitWidth: parent.width
|
||||||
|
radius: Appearance.rounding.small - Appearance.padding.small
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.smaller
|
||||||
|
anchors.rightMargin: Appearance.padding.smaller
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
font.pointSize: Appearance.font.size.large * 2
|
||||||
|
text: "package_2"
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 25
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: update.sections[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
text: Updates.formatUpdateTime(update.modelData.timestamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
|
||||||
|
MarqueeText {
|
||||||
|
id: versionFrom
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: 225
|
||||||
|
animate: true
|
||||||
|
color: DynamicColors.palette.m3tertiary
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
marqueeEnabled: true
|
||||||
|
pauseMs: 4000
|
||||||
|
text: update.sections[1]
|
||||||
|
width: 225
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
color: DynamicColors.palette.m3secondary
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: "arrow_right_alt"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
MarqueeText {
|
||||||
|
id: versionTo
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: 225
|
||||||
|
animate: true
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
marqueeEnabled: true
|
||||||
|
pauseMs: 4000
|
||||||
|
text: update.sections[3]
|
||||||
|
width: 225
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
Layout.preferredHeight: width
|
||||||
|
icon: "download"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
Updates.performPackageUpdate(update.sections[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model: ScriptModel {
|
||||||
|
id: script
|
||||||
|
|
||||||
|
objectProp: "update"
|
||||||
|
values: Object.entries(Updates.updates).sort((a, b) => b[1] - a[1]).map(([update, timestamp]) => ({
|
||||||
|
update,
|
||||||
|
timestamp
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,8 +19,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Max toasts"
|
|
||||||
min: 1
|
min: 1
|
||||||
|
name: "Max toasts"
|
||||||
object: Config.utilities
|
object: Config.utilities
|
||||||
setting: "maxToasts"
|
setting: "maxToasts"
|
||||||
}
|
}
|
||||||
@@ -29,8 +29,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Panel width"
|
|
||||||
min: 1
|
min: 1
|
||||||
|
name: "Panel width"
|
||||||
object: Config.utilities.sizes
|
object: Config.utilities.sizes
|
||||||
setting: "width"
|
setting: "width"
|
||||||
}
|
}
|
||||||
@@ -39,8 +39,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Toast width"
|
|
||||||
min: 1
|
min: 1
|
||||||
|
name: "Toast width"
|
||||||
object: Config.utilities.sizes
|
object: Config.utilities.sizes
|
||||||
setting: "toastWidth"
|
setting: "toastWidth"
|
||||||
}
|
}
|
||||||
@@ -77,100 +77,100 @@ SettingsPage {
|
|||||||
setting: "gameModeChanged"
|
setting: "gameModeChanged"
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingSwitch {
|
// SettingSwitch {
|
||||||
name: "Do not disturb changed"
|
// name: "Do not disturb changed"
|
||||||
object: Config.utilities.toasts
|
// object: Config.utilities.toasts
|
||||||
setting: "dndChanged"
|
// setting: "dndChanged"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingSwitch {
|
// SettingSwitch {
|
||||||
name: "Audio output changed"
|
// name: "Audio output changed"
|
||||||
object: Config.utilities.toasts
|
// object: Config.utilities.toasts
|
||||||
setting: "audioOutputChanged"
|
// setting: "audioOutputChanged"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingSwitch {
|
// SettingSwitch {
|
||||||
name: "Audio input changed"
|
// name: "Audio input changed"
|
||||||
object: Config.utilities.toasts
|
// object: Config.utilities.toasts
|
||||||
setting: "audioInputChanged"
|
// setting: "audioInputChanged"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingSwitch {
|
// SettingSwitch {
|
||||||
name: "Caps lock changed"
|
// name: "Caps lock changed"
|
||||||
object: Config.utilities.toasts
|
// object: Config.utilities.toasts
|
||||||
setting: "capsLockChanged"
|
// setting: "capsLockChanged"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingSwitch {
|
// SettingSwitch {
|
||||||
name: "Num lock changed"
|
// name: "Num lock changed"
|
||||||
object: Config.utilities.toasts
|
// object: Config.utilities.toasts
|
||||||
setting: "numLockChanged"
|
// setting: "numLockChanged"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingSwitch {
|
// SettingSwitch {
|
||||||
name: "Keyboard layout changed"
|
// name: "Keyboard layout changed"
|
||||||
object: Config.utilities.toasts
|
// object: Config.utilities.toasts
|
||||||
setting: "kbLayoutChanged"
|
// setting: "kbLayoutChanged"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingSwitch {
|
// SettingSwitch {
|
||||||
name: "VPN changed"
|
// name: "VPN changed"
|
||||||
object: Config.utilities.toasts
|
// object: Config.utilities.toasts
|
||||||
setting: "vpnChanged"
|
// setting: "vpnChanged"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingSwitch {
|
// SettingSwitch {
|
||||||
name: "Now playing"
|
// name: "Now playing"
|
||||||
object: Config.utilities.toasts
|
// object: Config.utilities.toasts
|
||||||
setting: "nowPlaying"
|
// setting: "nowPlaying"
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSection {
|
// SettingsSection {
|
||||||
sectionId: "VPN"
|
// sectionId: "VPN"
|
||||||
|
//
|
||||||
SettingsHeader {
|
// SettingsHeader {
|
||||||
name: "VPN"
|
// name: "VPN"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingSwitch {
|
// SettingSwitch {
|
||||||
name: "Enable VPN integration"
|
// name: "Enable VPN integration"
|
||||||
object: Config.utilities.vpn
|
// object: Config.utilities.vpn
|
||||||
setting: "enabled"
|
// setting: "enabled"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
Separator {
|
// Separator {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SettingStringList {
|
// SettingStringList {
|
||||||
name: "Provider"
|
// name: "Provider"
|
||||||
addLabel: qsTr("Add VPN provider")
|
// addLabel: qsTr("Add VPN provider")
|
||||||
object: Config.utilities.vpn
|
// object: Config.utilities.vpn
|
||||||
setting: "provider"
|
// setting: "provider"
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -20,7 +22,6 @@ Item {
|
|||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
function scrollToSetting(section: string, settingName: string) {
|
function scrollToSetting(section: string, settingName: string) {
|
||||||
// Wait for the StackView transition to complete, then scroll
|
|
||||||
root.pendingSection = section;
|
root.pendingSection = section;
|
||||||
root.pendingSetting = settingName;
|
root.pendingSetting = settingName;
|
||||||
scrollTimer.restart();
|
scrollTimer.restart();
|
||||||
@@ -74,6 +75,12 @@ Item {
|
|||||||
stack.push(osd);
|
stack.push(osd);
|
||||||
else if (currentCategory === "launcher")
|
else if (currentCategory === "launcher")
|
||||||
stack.push(launcher);
|
stack.push(launcher);
|
||||||
|
else if (currentCategory === "screenshot")
|
||||||
|
stack.push(screenshot);
|
||||||
|
else if (currentCategory === "updates")
|
||||||
|
stack.push(updates);
|
||||||
|
else if (currentCategory === "plugins")
|
||||||
|
stack.push(plugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
target: root
|
target: root
|
||||||
@@ -129,7 +136,7 @@ Item {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: searchBar.bottom
|
anchors.top: searchBar.bottom
|
||||||
anchors.topMargin: Appearance.spacing.smaller
|
anchors.topMargin: Appearance.spacing.smaller
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainerLowest
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
|
|
||||||
StackView {
|
StackView {
|
||||||
@@ -153,6 +160,7 @@ Item {
|
|||||||
id: background
|
id: background
|
||||||
|
|
||||||
Cat.Background {
|
Cat.Background {
|
||||||
|
screen: root.screen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,4 +233,25 @@ Item {
|
|||||||
Cat.Launcher {
|
Cat.Launcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: screenshot
|
||||||
|
|
||||||
|
Cat.Screenshot {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: updates
|
||||||
|
|
||||||
|
Cat.SystemUpdates {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: plugins
|
||||||
|
|
||||||
|
Cat.Plugins {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property string name
|
||||||
|
required property var object
|
||||||
|
property alias row: row
|
||||||
|
required property string setting
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
required property list<var> stringList
|
||||||
|
|
||||||
|
signal optionSet(option: string)
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? row.height : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.small
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: text
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
text: root.name
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
Layout.preferredHeight: 42 * 6 + Appearance.padding.normal * 2 + Appearance.spacing.small * 5
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
radius: (21 + Appearance.padding.normal) * Appearance.rounding.scale
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: searchBox
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: 42
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: searchIcon
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Appearance.padding.large
|
||||||
|
anchors.top: parent.top
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: "search"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: textSearch
|
||||||
|
|
||||||
|
anchors.left: searchIcon.right
|
||||||
|
anchors.leftMargin: Appearance.spacing.small
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Appearance.spacing.normal
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
placeholderText: "Search..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: searchBox.bottom
|
||||||
|
bottomLeftRadius: 21
|
||||||
|
bottomRightRadius: 21
|
||||||
|
|
||||||
|
CustomListView {
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
delegate: CustomRect {
|
||||||
|
id: delegate
|
||||||
|
|
||||||
|
required property string modelData
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
implicitHeight: 42
|
||||||
|
radius: Appearance.rounding.smallest
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.normal
|
||||||
|
text: modelData
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.rightMargin: Appearance.padding.normal
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
text: "check_circle"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
visible: root.object[root.setting] === delegate.modelData
|
||||||
|
}
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
onClicked: {
|
||||||
|
root.object[root.setting] = delegate.modelData;
|
||||||
|
root.optionSet(delegate.modelData);
|
||||||
|
Config.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model: ScriptModel {
|
||||||
|
values: {
|
||||||
|
const values = root.stringList;
|
||||||
|
const search = textSearch.text;
|
||||||
|
var regex = new RegExp(search, "i");
|
||||||
|
|
||||||
|
return values.filter(n => regex.test(n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,26 @@ import qs.Config
|
|||||||
CustomRect {
|
CustomRect {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
Layout.fillWidth: true
|
property bool shouldBeActive: true
|
||||||
Layout.preferredHeight: 1
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
color: DynamicColors.tPalette.m3outlineVariant
|
color: DynamicColors.tPalette.m3outlineVariant
|
||||||
|
implicitHeight: shouldBeActive ? 1 : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ ColumnLayout {
|
|||||||
required property string name
|
required property string name
|
||||||
required property var object
|
required property var object
|
||||||
required property string setting
|
required property string setting
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
function addAction() {
|
function addAction() {
|
||||||
const list = [...root.object[root.setting]];
|
const list = [...root.object[root.setting]];
|
||||||
@@ -44,8 +45,26 @@ ColumnLayout {
|
|||||||
Config.save();
|
Config.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: shouldBeActive ? implicitHeight : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
spacing: Appearance.spacing.smaller
|
spacing: Appearance.spacing.smaller
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -108,6 +127,9 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
anchors.left: undefined
|
||||||
|
anchors.right: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -188,6 +210,8 @@ ColumnLayout {
|
|||||||
StringListEditor {
|
StringListEditor {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
addLabel: qsTr("Add command argument")
|
addLabel: qsTr("Add command argument")
|
||||||
|
anchors.left: undefined
|
||||||
|
anchors.right: undefined
|
||||||
values: [...(modelData.command ?? [])]
|
values: [...(modelData.command ?? [])]
|
||||||
|
|
||||||
onListEdited: function (values) {
|
onListEdited: function (values) {
|
||||||
@@ -196,6 +220,9 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
anchors.left: undefined
|
||||||
|
anchors.right: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -214,6 +241,9 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
anchors.left: undefined
|
||||||
|
anchors.right: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ import qs.Components
|
|||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
|
|
||||||
ColumnLayout {
|
CustomRect {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
|
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
|
||||||
required property string name
|
required property string name
|
||||||
required property var object
|
required property var object
|
||||||
required property string setting
|
required property string setting
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
function addAlias() {
|
function addAlias() {
|
||||||
const list = [...root.object[root.setting]];
|
const list = [...root.object[root.setting]];
|
||||||
@@ -40,8 +41,25 @@ ColumnLayout {
|
|||||||
Config.save();
|
Config.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
spacing: Appearance.spacing.smaller
|
anchors.right: parent.right
|
||||||
|
height: shouldBeActive ? layout.implicitHeight : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -58,115 +76,128 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomText {
|
ColumnLayout {
|
||||||
Layout.fillWidth: true
|
id: layout
|
||||||
font.pointSize: Appearance.font.size.larger
|
|
||||||
text: root.name
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
anchors.left: parent.left
|
||||||
model: [...root.object[root.setting]]
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
Item {
|
spacing: Appearance.spacing.smaller
|
||||||
required property int index
|
|
||||||
required property var modelData
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: layout.implicitHeight + Appearance.padding.smaller * 2
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: -(Appearance.spacing.smaller / 2)
|
|
||||||
color: DynamicColors.tPalette.m3outlineVariant
|
|
||||||
implicitHeight: 1
|
|
||||||
visible: index !== 0
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: layout
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.margins: Appearance.padding.small
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Appearance.spacing.small
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: qsTr("From")
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 33
|
|
||||||
color: DynamicColors.tPalette.m3surfaceContainerHigh
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
|
|
||||||
CustomTextField {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: Appearance.padding.normal
|
|
||||||
anchors.rightMargin: Appearance.padding.normal
|
|
||||||
text: modelData.from ?? ""
|
|
||||||
|
|
||||||
onEditingFinished: root.updateAlias(index, "from", text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
font.pointSize: Appearance.font.size.large
|
|
||||||
icon: "delete"
|
|
||||||
type: IconButton.Tonal
|
|
||||||
|
|
||||||
onClicked: root.removeAlias(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: qsTr("To")
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 33
|
|
||||||
color: DynamicColors.tPalette.m3surface
|
|
||||||
radius: Appearance.rounding.small
|
|
||||||
|
|
||||||
CustomTextField {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: Appearance.padding.normal
|
|
||||||
anchors.rightMargin: Appearance.padding.normal
|
|
||||||
text: modelData.to ?? ""
|
|
||||||
|
|
||||||
onEditingFinished: root.updateAlias(index, "to", text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
font.pointSize: Appearance.font.size.large
|
|
||||||
icon: "add"
|
|
||||||
|
|
||||||
onClicked: root.addAlias()
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: qsTr("Add alias")
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
text: root.name
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: [...root.object[root.setting]]
|
||||||
|
|
||||||
|
Item {
|
||||||
|
required property int index
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: layout.implicitHeight + Appearance.padding.smaller * 2
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: -(Appearance.spacing.smaller / 2)
|
||||||
|
color: DynamicColors.tPalette.m3outlineVariant
|
||||||
|
implicitHeight: 1
|
||||||
|
visible: index !== 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: layout
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.small
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: qsTr("From")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
Layout.preferredHeight: 33
|
||||||
|
Layout.preferredWidth: Math.max(Math.min(fromTextField.contentWidth + Appearance.padding.large * 2, 550), 50)
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainerHigh
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: fromTextField
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, 550)
|
||||||
|
text: modelData.from ?? ""
|
||||||
|
|
||||||
|
onEditingFinished: root.updateAlias(index, "from", text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
icon: "delete"
|
||||||
|
type: IconButton.Tonal
|
||||||
|
|
||||||
|
onClicked: root.removeAlias(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: qsTr("To")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
Layout.preferredHeight: 33
|
||||||
|
Layout.preferredWidth: Math.max(Math.min(toTextField.contentWidth + Appearance.padding.large * 2, 550), 50)
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainerHigh
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: toTextField
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, 550)
|
||||||
|
text: modelData.to ?? ""
|
||||||
|
|
||||||
|
onEditingFinished: root.updateAlias(index, "to", text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
icon: "add"
|
||||||
|
|
||||||
|
onClicked: root.addAlias()
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: qsTr("Add alias")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,75 +25,15 @@ Item {
|
|||||||
required property var object
|
required property var object
|
||||||
property var pendingCommitEntries: []
|
property var pendingCommitEntries: []
|
||||||
required property string setting
|
required property string setting
|
||||||
|
property bool shouldBeActive: true
|
||||||
property int uidCounter: 0
|
property int uidCounter: 0
|
||||||
property var visualEntries: []
|
property var visualEntries: []
|
||||||
|
|
||||||
function beginVisualDrag(uid, modelData, item) {
|
|
||||||
const pos = item.mapToItem(root, 0, 0);
|
|
||||||
|
|
||||||
root.draggedUid = uid;
|
|
||||||
root.draggedModelData = modelData;
|
|
||||||
root.dragHeight = item.height;
|
|
||||||
root.dragStartX = pos.x;
|
|
||||||
root.dragStartY = pos.y;
|
|
||||||
root.dragX = pos.x;
|
|
||||||
root.dragY = pos.y;
|
|
||||||
root.dragActive = true;
|
|
||||||
root.dropAnimating = false;
|
|
||||||
root.pendingCommitEntries = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function commitVisualOrder(entries) {
|
|
||||||
const list = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < entries.length; i++)
|
|
||||||
list.push(entries[i].entry);
|
|
||||||
|
|
||||||
root.object[root.setting] = list;
|
|
||||||
Config.save();
|
|
||||||
root.rebuildVisualEntries();
|
|
||||||
}
|
|
||||||
|
|
||||||
function endVisualDrag() {
|
|
||||||
const entries = root.visualEntries.slice();
|
|
||||||
const finalIndex = root.indexForUid(root.draggedUid);
|
|
||||||
const finalItem = listView.itemAtIndex(finalIndex);
|
|
||||||
|
|
||||||
root.dragActive = false;
|
|
||||||
|
|
||||||
if (!finalItem) {
|
|
||||||
root.pendingCommitEntries = entries;
|
|
||||||
root.finishVisualDrag();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pos = finalItem.mapToItem(root, 0, 0);
|
|
||||||
|
|
||||||
root.pendingCommitEntries = entries;
|
|
||||||
root.dropAnimating = true;
|
|
||||||
settleX.to = pos.x;
|
|
||||||
settleY.to = pos.y;
|
|
||||||
settleAnim.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensureVisualEntries() {
|
function ensureVisualEntries() {
|
||||||
if (!root.dragActive && !root.dropAnimating)
|
if (!root.dragActive && !root.dropAnimating)
|
||||||
root.rebuildVisualEntries();
|
root.rebuildVisualEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishVisualDrag() {
|
|
||||||
const entries = root.pendingCommitEntries.slice();
|
|
||||||
|
|
||||||
root.dragActive = false;
|
|
||||||
root.dropAnimating = false;
|
|
||||||
root.draggedUid = "";
|
|
||||||
root.draggedModelData = null;
|
|
||||||
root.pendingCommitEntries = [];
|
|
||||||
root.dragHeight = 0;
|
|
||||||
|
|
||||||
root.commitVisualOrder(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
function iconForId(id) {
|
function iconForId(id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case "workspaces":
|
case "workspaces":
|
||||||
@@ -153,7 +93,7 @@ Item {
|
|||||||
case "spacer":
|
case "spacer":
|
||||||
return qsTr("Spacer");
|
return qsTr("Spacer");
|
||||||
case "activeWindow":
|
case "activeWindow":
|
||||||
return qsTr("Active window");
|
return qsTr("Title");
|
||||||
case "tray":
|
case "tray":
|
||||||
return qsTr("Tray");
|
return qsTr("Tray");
|
||||||
case "upower":
|
case "upower":
|
||||||
@@ -163,34 +103,14 @@ Item {
|
|||||||
case "clock":
|
case "clock":
|
||||||
return qsTr("Clock");
|
return qsTr("Clock");
|
||||||
case "notifBell":
|
case "notifBell":
|
||||||
return qsTr("Notification bell");
|
return qsTr("Notifs");
|
||||||
|
case "hyprsunset":
|
||||||
|
return qsTr("Night light");
|
||||||
default:
|
default:
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveArrayItem(list, from, to) {
|
|
||||||
const next = list.slice();
|
|
||||||
const [item] = next.splice(from, 1);
|
|
||||||
next.splice(to, 0, item);
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
function previewVisualMove(from, hovered, before) {
|
|
||||||
let to = hovered + (before ? 0 : 1);
|
|
||||||
|
|
||||||
if (to > from)
|
|
||||||
to -= 1;
|
|
||||||
|
|
||||||
to = Math.max(0, Math.min(visualModel.items.count - 1, to));
|
|
||||||
|
|
||||||
if (from === to)
|
|
||||||
return;
|
|
||||||
|
|
||||||
visualModel.items.move(from, to);
|
|
||||||
root.visualEntries = root.moveArrayItem(root.visualEntries, from, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
function rebuildVisualEntries() {
|
function rebuildVisualEntries() {
|
||||||
const entries = root.object[root.setting] ?? [];
|
const entries = root.object[root.setting] ?? [];
|
||||||
const next = [];
|
const next = [];
|
||||||
@@ -225,15 +145,31 @@ Item {
|
|||||||
list[index] = entry;
|
list[index] = entry;
|
||||||
root.object[root.setting] = list;
|
root.object[root.setting] = list;
|
||||||
Config.save();
|
Config.save();
|
||||||
root.ensureVisualEntries();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
implicitHeight: layout.implicitHeight
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? layout.implicitHeight : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: root.rebuildVisualEntries()
|
Component.onCompleted: root.rebuildVisualEntries()
|
||||||
|
|
||||||
Rectangle {
|
CustomRect {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: -Appearance.padding.smaller
|
anchors.margins: -Appearance.padding.smaller
|
||||||
color: DynamicColors.palette.m3primaryContainer
|
color: DynamicColors.palette.m3primaryContainer
|
||||||
@@ -248,39 +184,12 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParallelAnimation {
|
RowLayout {
|
||||||
id: settleAnim
|
|
||||||
|
|
||||||
onFinished: root.finishVisualDrag()
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
id: settleX
|
|
||||||
|
|
||||||
duration: Appearance.anim.durations.normal
|
|
||||||
property: "dragX"
|
|
||||||
target: root
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
id: settleY
|
|
||||||
|
|
||||||
duration: Appearance.anim.durations.normal
|
|
||||||
property: "dragY"
|
|
||||||
target: root
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: layout
|
id: layout
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: Appearance.spacing.smaller
|
|
||||||
|
|
||||||
CustomText {
|
// spacing: Appearance.spacing.smaller
|
||||||
Layout.fillWidth: true
|
|
||||||
font.pointSize: Appearance.font.size.larger
|
|
||||||
text: root.name
|
|
||||||
}
|
|
||||||
|
|
||||||
DelegateModel {
|
DelegateModel {
|
||||||
id: visualModel
|
id: visualModel
|
||||||
@@ -293,248 +202,40 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
Repeater {
|
||||||
id: listView
|
delegate: entryDelegate
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: contentHeight
|
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
|
||||||
clip: false
|
|
||||||
implicitHeight: contentHeight
|
|
||||||
implicitWidth: width
|
|
||||||
interactive: !(root.dragActive || root.dropAnimating)
|
|
||||||
model: visualModel
|
model: visualModel
|
||||||
spacing: Appearance.spacing.small
|
|
||||||
|
|
||||||
add: Transition {
|
|
||||||
Anim {
|
|
||||||
properties: "opacity,scale"
|
|
||||||
to: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addDisplaced: Transition {
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.normal
|
|
||||||
property: "y"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
displaced: Transition {
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.normal
|
|
||||||
property: "y"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
move: Transition {
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.normal
|
|
||||||
property: "y"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removeDisplaced: Transition {
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.normal
|
|
||||||
property: "y"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
active: root.dragActive || root.dropAnimating
|
|
||||||
asynchronous: false
|
|
||||||
|
|
||||||
sourceComponent: Item {
|
|
||||||
Drag.active: root.dragActive
|
|
||||||
Drag.hotSpot.x: width / 2
|
|
||||||
Drag.hotSpot.y: height / 2
|
|
||||||
height: proxyRect.implicitHeight
|
|
||||||
implicitHeight: proxyRect.implicitHeight
|
|
||||||
implicitWidth: listView.width
|
|
||||||
visible: root.draggedModelData !== null
|
|
||||||
width: listView.width
|
|
||||||
x: root.dragX
|
|
||||||
y: root.dragY
|
|
||||||
z: 100
|
|
||||||
|
|
||||||
Drag.source: QtObject {
|
|
||||||
property string uid: root.draggedUid
|
|
||||||
property int visualIndex: root.indexForUid(root.draggedUid)
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: proxyRect
|
|
||||||
|
|
||||||
color: DynamicColors.tPalette.m3surface
|
|
||||||
implicitHeight: proxyRow.implicitHeight + Appearance.padding.small * 2
|
|
||||||
implicitWidth: parent.width
|
|
||||||
opacity: 0.95
|
|
||||||
radius: Appearance.rounding.normal
|
|
||||||
width: parent.width
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: proxyRow
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Appearance.padding.small
|
|
||||||
spacing: Appearance.spacing.normal
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
color: Qt.alpha(DynamicColors.palette.m3onSurface, 0.12)
|
|
||||||
implicitHeight: 32
|
|
||||||
implicitWidth: implicitHeight
|
|
||||||
radius: Appearance.rounding.small
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
color: DynamicColors.palette.m3onSurfaceVariant
|
|
||||||
text: "drag_indicator"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
color: DynamicColors.palette.m3onSurfaceVariant
|
|
||||||
text: root.iconForId(root.draggedModelData?.entry?.id ?? "")
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
font.pointSize: Appearance.font.size.larger
|
|
||||||
text: root.labelForId(root.draggedModelData?.entry?.id ?? "")
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomSwitch {
|
|
||||||
checked: root.draggedModelData?.entry?.enabled ?? true
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: entryDelegate
|
id: entryDelegate
|
||||||
|
|
||||||
DropArea {
|
IconButton {
|
||||||
id: slot
|
required property int index
|
||||||
|
|
||||||
readonly property var entryData: modelData.entry
|
|
||||||
required property var modelData
|
required property var modelData
|
||||||
readonly property string uid: modelData.uid
|
|
||||||
|
|
||||||
function previewReorder(drag) {
|
Layout.fillWidth: true
|
||||||
const source = drag.source;
|
Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? 18 : internalChecked ? 7 : 0)
|
||||||
if (!source || !source.uid || source.uid === slot.uid)
|
checked: modelData.entry.enabled ?? true
|
||||||
return;
|
font: Appearance.font.family.sans
|
||||||
|
// icon: root.iconForId(modelData.entry.id)
|
||||||
|
icon: root.labelForId(modelData.entry.id)
|
||||||
|
inactiveColour: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 2)
|
||||||
|
radius: stateLayer.pressed ? 6 / 2 : internalChecked ? 6 : 8
|
||||||
|
radiusAnim.duration: MaterialEasing.expressiveEffectsTime
|
||||||
|
radiusAnim.easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||||
|
toggle: true
|
||||||
|
visible: !["spacer", "upower", "dash", "audio"].some(prefix => modelData.entry.id.startsWith(prefix))
|
||||||
|
|
||||||
const from = source.visualIndex;
|
Behavior on Layout.preferredWidth {
|
||||||
const hovered = slot.DelegateModel.itemsIndex;
|
Anim {
|
||||||
|
duration: MaterialEasing.expressiveEffectsTime
|
||||||
if (from < 0 || hovered < 0)
|
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||||
return;
|
|
||||||
|
|
||||||
root.previewVisualMove(from, hovered, drag.y < height / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
height: entryRow.implicitHeight
|
|
||||||
implicitHeight: entryRow.implicitHeight
|
|
||||||
implicitWidth: listView.width
|
|
||||||
width: ListView.view ? ListView.view.width : listView.width
|
|
||||||
|
|
||||||
onEntered: drag => previewReorder(drag)
|
|
||||||
onPositionChanged: drag => previewReorder(drag)
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: entryRow
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
color: DynamicColors.tPalette.m3surface
|
|
||||||
implicitHeight: entryLayout.implicitHeight + Appearance.padding.small * 2
|
|
||||||
implicitWidth: parent.width
|
|
||||||
opacity: root.draggedUid === slot.uid ? 0 : 1
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: entryLayout
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Appearance.padding.small
|
|
||||||
spacing: Appearance.spacing.normal
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: handle
|
|
||||||
|
|
||||||
color: Qt.alpha(DynamicColors.palette.m3onSurface, handleDrag.active ? 0.12 : handleHover.hovered ? 0.09 : 0.06)
|
|
||||||
implicitHeight: 32
|
|
||||||
implicitWidth: implicitHeight
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
CAnim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
color: DynamicColors.palette.m3onSurfaceVariant
|
|
||||||
text: "drag_indicator"
|
|
||||||
}
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
id: handleHover
|
|
||||||
|
|
||||||
cursorShape: handleDrag.active ? Qt.ClosedHandCursor : Qt.OpenHandCursor
|
|
||||||
}
|
|
||||||
|
|
||||||
DragHandler {
|
|
||||||
id: handleDrag
|
|
||||||
|
|
||||||
enabled: true
|
|
||||||
grabPermissions: PointerHandler.CanTakeOverFromAnything
|
|
||||||
target: null
|
|
||||||
xAxis.enabled: false
|
|
||||||
yAxis.enabled: true
|
|
||||||
|
|
||||||
onActiveChanged: {
|
|
||||||
if (active) {
|
|
||||||
root.beginVisualDrag(slot.uid, slot.modelData, entryRow);
|
|
||||||
} else if (root.draggedUid === slot.uid) {
|
|
||||||
root.endVisualDrag();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onActiveTranslationChanged: {
|
|
||||||
if (!active || root.draggedUid !== slot.uid)
|
|
||||||
return;
|
|
||||||
|
|
||||||
root.dragX = root.dragStartX;
|
|
||||||
root.dragY = root.dragStartY + activeTranslation.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
color: DynamicColors.palette.m3onSurfaceVariant
|
|
||||||
text: root.iconForId(slot.entryData.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
font.pointSize: Appearance.font.size.larger
|
|
||||||
text: root.labelForId(slot.entryData.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomSwitch {
|
|
||||||
Layout.rightMargin: Appearance.padding.small
|
|
||||||
checked: slot.entryData.enabled ?? true
|
|
||||||
|
|
||||||
onToggled: root.updateEntry(slot.DelegateModel.itemsIndex, checked)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClicked: root.updateEntry(index, internalChecked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Item {
|
|||||||
required property string name
|
required property string name
|
||||||
required property var object
|
required property var object
|
||||||
required property list<string> settings
|
required property list<string> settings
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
function commitChoice(choice: int, setting: string): void {
|
function commitChoice(choice: int, setting: string): void {
|
||||||
root.object[setting] = choice;
|
root.object[setting] = choice;
|
||||||
@@ -32,8 +33,25 @@ Item {
|
|||||||
return Qt.formatTime(d, "h AP");
|
return Qt.formatTime(d, "h AP");
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Item {
|
|||||||
required property string name
|
required property string name
|
||||||
required property var object
|
required property var object
|
||||||
required property string setting
|
required property string setting
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
function formattedValue(): string {
|
function formattedValue(): string {
|
||||||
const value = root.object[root.setting];
|
const value = root.object[root.setting];
|
||||||
@@ -21,8 +22,25 @@ Item {
|
|||||||
return String(value);
|
return String(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -59,7 +77,7 @@ Item {
|
|||||||
id: rect
|
id: rect
|
||||||
|
|
||||||
Layout.preferredHeight: 33
|
Layout.preferredHeight: 33
|
||||||
Layout.preferredWidth: Math.max(Math.min(textField.contentWidth + Appearance.padding.normal * 2, 550), 50)
|
Layout.preferredWidth: Math.max(Math.min(textField.contentWidth + Appearance.padding.large * 2, 550), 50)
|
||||||
color: DynamicColors.tPalette.m3surfaceContainerHigh
|
color: DynamicColors.tPalette.m3surfaceContainerHigh
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
@@ -68,7 +86,7 @@ Item {
|
|||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
implicitWidth: Math.min(contentWidth, 550)
|
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, 550)
|
||||||
text: root.formattedValue()
|
text: root.formattedValue()
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
|
|||||||
@@ -8,12 +8,31 @@ Item {
|
|||||||
|
|
||||||
required property int index
|
required property int index
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
signal addActiveActionRequested
|
signal addActiveActionRequested
|
||||||
|
signal deleteRequested(int index)
|
||||||
signal fieldEdited(string key, var value)
|
signal fieldEdited(string key, var value)
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -65,42 +84,64 @@ Item {
|
|||||||
|
|
||||||
HoverHandler {
|
HoverHandler {
|
||||||
id: nameHover
|
id: nameHover
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverIconButton {
|
||||||
|
id: editButton
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
icon: "edit"
|
||||||
|
shouldBeVisible: nameHover.hovered && !nameCell.editing
|
||||||
|
|
||||||
|
onClicked: nameCell.beginEdit()
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: editButton.left
|
anchors.leftMargin: nameHover.hovered ? editButton.width + Appearance.spacing.smaller * 2 : 0
|
||||||
|
anchors.right: deleteButton.left
|
||||||
anchors.rightMargin: Appearance.spacing.small
|
anchors.rightMargin: Appearance.spacing.small
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
elide: Text.ElideRight // enable if CustomText supports it
|
elide: Text.ElideRight // enable if CustomText supports it
|
||||||
font.pointSize: Appearance.font.size.larger
|
font.pointSize: Appearance.font.size.larger
|
||||||
text: root.modelData.name
|
text: root.modelData.name
|
||||||
visible: !nameCell.editing
|
visible: !nameCell.editing
|
||||||
|
|
||||||
|
Behavior on anchors.leftMargin {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton {
|
HoverIconButton {
|
||||||
id: editButton
|
id: deleteButton
|
||||||
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
font.pointSize: Appearance.font.size.large
|
font.pointSize: Appearance.font.size.large
|
||||||
icon: "edit"
|
icon: "delete"
|
||||||
visible: nameHover.hovered && !nameCell.editing
|
shouldBeVisible: nameHover.hovered && !nameCell.editing
|
||||||
|
|
||||||
onClicked: nameCell.beginEdit()
|
onClicked: root.deleteRequested(root.index)
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
anchors.fill: parent
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
color: DynamicColors.tPalette.m3surface
|
color: DynamicColors.tPalette.m3surface
|
||||||
|
implicitHeight: nameEditor.implicitHeight + (Appearance.padding.normal * 2)
|
||||||
|
implicitWidth: Math.min(nameEditor.contentWidth + (Appearance.padding.normal * 2), parent.width - Appearance.padding.normal)
|
||||||
radius: Appearance.rounding.small
|
radius: Appearance.rounding.small
|
||||||
visible: nameCell.editing
|
visible: nameCell.editing
|
||||||
|
|
||||||
CustomTextField {
|
CustomTextField {
|
||||||
id: nameEditor
|
id: nameEditor
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.centerIn: parent
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, nameCell.width - Appearance.padding.normal)
|
||||||
text: nameCell.draftName
|
text: nameCell.draftName
|
||||||
|
|
||||||
Keys.onEscapePressed: {
|
Keys.onEscapePressed: {
|
||||||
@@ -153,6 +194,9 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
anchors.left: undefined
|
||||||
|
anchors.right: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -184,6 +228,9 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
anchors.left: undefined
|
||||||
|
anchors.right: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property string name
|
||||||
|
required property var object
|
||||||
|
property alias row: row
|
||||||
|
required property string setting
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
required property list<var> stringList
|
||||||
|
|
||||||
|
signal optionSet
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? row.height : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.small
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: text
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
text: root.name
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
id: fontArea
|
||||||
|
|
||||||
|
Layout.preferredHeight: 42 * 6 + Appearance.padding.normal * 2 + Appearance.spacing.small * 5
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
radius: (21 + Appearance.padding.normal) * Appearance.rounding.scale
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: searchBox
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: 42
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: searchIcon
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Appearance.padding.large
|
||||||
|
anchors.top: parent.top
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: "search"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: fontSearch
|
||||||
|
|
||||||
|
anchors.left: searchIcon.right
|
||||||
|
anchors.leftMargin: Appearance.spacing.small
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Appearance.spacing.normal
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
placeholderText: "Search..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: searchBox.bottom
|
||||||
|
bottomLeftRadius: 21
|
||||||
|
bottomRightRadius: 21
|
||||||
|
|
||||||
|
CustomListView {
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
delegate: CustomRect {
|
||||||
|
id: fontDelegate
|
||||||
|
|
||||||
|
required property string modelData
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
implicitHeight: 42
|
||||||
|
radius: Appearance.rounding.smallest
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.normal
|
||||||
|
text: modelData
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.rightMargin: Appearance.padding.normal
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
text: "check_circle"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
visible: root.object[root.setting] === fontDelegate.modelData
|
||||||
|
}
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
onClicked: {
|
||||||
|
root.object[root.setting] = fontDelegate.modelData;
|
||||||
|
root.optionSet();
|
||||||
|
Config.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model: ScriptModel {
|
||||||
|
values: {
|
||||||
|
const values = root.stringList;
|
||||||
|
const search = fontSearch.text;
|
||||||
|
var regex = new RegExp(search, "i");
|
||||||
|
|
||||||
|
return values.filter(n => regex.test(n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,10 +9,28 @@ Item {
|
|||||||
|
|
||||||
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
|
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
|
||||||
required property string name
|
required property string name
|
||||||
|
property bool shouldBeActive: true
|
||||||
required property string value
|
required property string value
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -13,10 +13,28 @@ Item {
|
|||||||
required property string name
|
required property string name
|
||||||
required property var object
|
required property var object
|
||||||
required property string setting
|
required property string setting
|
||||||
|
property bool shouldBeActive: true
|
||||||
property real step: 1
|
property real step: 1
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Item {
|
|||||||
required property string name
|
required property string name
|
||||||
required property var object
|
required property var object
|
||||||
required property list<string> settings
|
required property list<string> settings
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
function commitChoice(choice: int, setting: string): void {
|
function commitChoice(choice: int, setting: string): void {
|
||||||
root.object[setting] = choice;
|
root.object[setting] = choice;
|
||||||
@@ -32,8 +33,25 @@ Item {
|
|||||||
return Qt.formatTime(d, "h AP");
|
return Qt.formatTime(d, "h AP");
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -12,9 +12,27 @@ Item {
|
|||||||
required property string name
|
required property string name
|
||||||
required property var object
|
required property var object
|
||||||
required property string setting
|
required property string setting
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: layout.implicitHeight
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? layout.implicitHeight : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -46,6 +64,9 @@ Item {
|
|||||||
StringListEditor {
|
StringListEditor {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
addLabel: root.addLabel
|
addLabel: root.addLabel
|
||||||
|
anchors.left: undefined
|
||||||
|
anchors.right: undefined
|
||||||
|
anchors.verticalCenter: undefined
|
||||||
values: [...(root.object[root.setting] ?? [])]
|
values: [...(root.object[root.setting] ?? [])]
|
||||||
|
|
||||||
onListEdited: function (values) {
|
onListEdited: function (values) {
|
||||||
|
|||||||
@@ -11,9 +11,27 @@ Item {
|
|||||||
required property string name
|
required property string name
|
||||||
required property var object
|
required property var object
|
||||||
required property string setting
|
required property string setting
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -7,9 +7,13 @@ CustomRect {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property string name
|
required property string name
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
Layout.preferredHeight: 60
|
implicitHeight: 60
|
||||||
Layout.preferredWidth: 200
|
implicitWidth: 200
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Paths
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias button: iButton
|
||||||
|
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
|
||||||
|
required property string name
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -Appearance.padding.smaller
|
||||||
|
color: DynamicColors.palette.m3primaryContainer
|
||||||
|
opacity: root.highlighted ? 0.5 : 0
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.small
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: text
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
text: root.name
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
id: iButton
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
icon: "download"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
const lockBg = `${Paths.state}/lockscreen_bg.png`;
|
||||||
|
const scheme = `${Paths.state}/scheme.json`;
|
||||||
|
const face = `${Paths.home}/.face`;
|
||||||
|
const destination = "/etc/zshell-greeter/images";
|
||||||
|
Quickshell.execDetached(["pkexec", "sh", "-c", `mkdir -p ${destination}; cp ${lockBg} ${destination}; cp ${scheme} /etc/zshell-greeter; cp ${face} ${destination}`]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,12 +60,18 @@ CustomClippingRect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
Column {
|
||||||
id: clayout
|
id: clayout
|
||||||
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
spacing: Appearance.spacing.small
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
// move: Transition {
|
||||||
|
// Anim {
|
||||||
|
// properties: "y"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,18 +10,39 @@ CustomRect {
|
|||||||
property real contentPadding: Appearance.padding.large
|
property real contentPadding: Appearance.padding.large
|
||||||
property string sectionId: ""
|
property string sectionId: ""
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.preferredHeight: layout.implicitHeight + contentPadding * 2
|
anchors.right: parent.right
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: layout.height + contentPadding * 2
|
||||||
radius: Appearance.rounding.normal - Appearance.padding.smaller
|
radius: Appearance.rounding.normal - Appearance.padding.smaller
|
||||||
|
|
||||||
ColumnLayout {
|
Behavior on implicitHeight {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
id: layout
|
id: layout
|
||||||
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.margins: root.contentPadding
|
anchors.margins: root.contentPadding
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.top: parent.top
|
||||||
|
// anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Appearance.spacing.normal
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
move: Transition {
|
||||||
|
Anim {
|
||||||
|
properties: "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,29 @@ CustomRect {
|
|||||||
property alias expanded: menu.expanded
|
property alias expanded: menu.expanded
|
||||||
property alias label: label
|
property alias label: label
|
||||||
property alias menu: menu
|
property alias menu: menu
|
||||||
|
property bool shouldBeActive: true
|
||||||
property alias text: label.text
|
property alias text: label.text
|
||||||
|
|
||||||
color: enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
|
color: enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
z: expanded ? 100 : 0
|
z: expanded ? 100 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
id: label
|
id: label
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ ColumnLayout {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string addLabel: qsTr("Add entry")
|
property string addLabel: qsTr("Add entry")
|
||||||
|
property bool shouldBeActive: true
|
||||||
property var values: []
|
property var values: []
|
||||||
|
|
||||||
signal listEdited(var values)
|
signal listEdited(var values)
|
||||||
@@ -31,8 +32,26 @@ ColumnLayout {
|
|||||||
root.listEdited(list);
|
root.listEdited(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: shouldBeActive ? implicitHeight : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
spacing: Appearance.spacing.smaller
|
spacing: Appearance.spacing.smaller
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: [...root.values]
|
model: [...root.values]
|
||||||
|
|||||||
@@ -1,102 +1,279 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import ZShell.Internal
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
|
|
||||||
ColumnLayout {
|
Item {
|
||||||
id: root
|
id: wrapper
|
||||||
|
|
||||||
spacing: 15
|
property bool changesMade: false
|
||||||
width: Math.min(parent ? parent.width : 600, 600)
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
Rectangle {
|
signal requestCrop
|
||||||
id: previewContainer
|
|
||||||
|
|
||||||
Layout.fillHeight: true
|
anchors.left: parent.left
|
||||||
Layout.preferredWidth: height * (Quickshell.screens.length > 0 ? (Quickshell.screens[0].height / Math.max(1, Quickshell.screens[0].width)) : 16 / 9)
|
anchors.right: parent.right
|
||||||
clip: true
|
implicitHeight: shouldBeActive ? 400 : 0
|
||||||
color: DynamicColors.palette.m3surfaceContainer
|
opacity: shouldBeActive ? 1 : 0
|
||||||
radius: Config.appearance.rounding.scale * 10
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
Image {
|
Behavior on opacity {
|
||||||
id: img
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
IconButton {
|
||||||
asynchronous: true
|
anchors.margins: Appearance.padding.normal
|
||||||
fillMode: Image.PreserveAspectFit
|
anchors.right: parent.right
|
||||||
source: Wallpapers.current
|
anchors.top: parent.top
|
||||||
|
icon: "check"
|
||||||
|
opacity: wrapper.changesMade ? 1 : 0
|
||||||
|
scale: wrapper.changesMade ? 1 : 0
|
||||||
|
z: 2
|
||||||
|
|
||||||
Rectangle {
|
Behavior on opacity {
|
||||||
id: cropRect
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property real cropHeight: (imageAspect > screenAspect ? paintedHeight : paintedWidth / screenAspect) / Config.background.zoom
|
onClicked: {
|
||||||
property real cropWidth: (imageAspect > screenAspect ? paintedHeight * screenAspect : paintedWidth) / Config.background.zoom
|
wrapper.requestCrop();
|
||||||
property real imageAspect: Math.max(1, paintedWidth) / Math.max(1, paintedHeight)
|
wrapper.changesMade = false;
|
||||||
property real paintedHeight: img.paintedHeight > 0 ? img.paintedHeight : img.height
|
}
|
||||||
property real paintedWidth: img.paintedWidth > 0 ? img.paintedWidth : img.width
|
}
|
||||||
property real paintedX: (img.width - paintedWidth) / 2
|
|
||||||
property real paintedY: (img.height - paintedHeight) / 2
|
|
||||||
property real screenAspect: Quickshell.screens.length > 0 ? (Quickshell.screens[0].width / Math.max(1, Quickshell.screens[0].height)) : 16 / 9
|
|
||||||
|
|
||||||
border.color: DynamicColors.palette.m3primary
|
RowLayout {
|
||||||
border.width: 2
|
id: root
|
||||||
color: Qt.alpha(DynamicColors.palette.m3primaryContainer, 0.3)
|
|
||||||
height: cropHeight
|
|
||||||
width: cropWidth
|
|
||||||
x: paintedX + (paintedWidth - width) * Config.background.alignX
|
|
||||||
y: paintedY + (paintedHeight - height) * Config.background.alignY
|
|
||||||
|
|
||||||
DragHandler {
|
anchors.fill: parent
|
||||||
target: null
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
onActiveTranslationChanged: {
|
Repeater {
|
||||||
if (active) {
|
model: ScriptModel {
|
||||||
let newX = cropRect.x - cropRect.paintedX + translation.x;
|
values: [...Quickshell.screens].sort((a, b) => {
|
||||||
let newY = cropRect.y - cropRect.paintedY + translation.y;
|
return a.x - b.x;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let rangeX = cropRect.paintedWidth - cropRect.width;
|
Item {
|
||||||
let rangeY = cropRect.paintedHeight - cropRect.height;
|
id: delegate
|
||||||
|
|
||||||
if (rangeX > 0) {
|
required property ShellScreen modelData
|
||||||
let valX = newX / rangeX;
|
|
||||||
Config.background.alignX = Math.max(0.0, Math.min(1.0, valX));
|
|
||||||
Config.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rangeY > 0) {
|
function applyCrop(): void {
|
||||||
let valY = newY / rangeY;
|
const croprect = cropRect.mapToItem(scaledImg, 0, 0, cropRect.width, cropRect.height);
|
||||||
Config.background.alignY = Math.max(0.0, Math.min(1.0, valY));
|
const upscaledRect = Qt.rect((croprect.x - cropRect.imageX) / scaledImg.paintedWidth, (croprect.y - cropRect.imageY) / scaledImg.paintedHeight, croprect.width / scaledImg.paintedWidth, croprect.height / scaledImg.paintedHeight);
|
||||||
Config.save();
|
Wallpapers.setCrop(delegate.modelData.name, upscaledRect, croprect, cropRect.zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zoomClipRect(zoom: real): void {
|
||||||
|
let oldCenterX = cropRect.x + cropRect.width * 0.5;
|
||||||
|
let oldCenterY = cropRect.y + cropRect.height * 0.5;
|
||||||
|
|
||||||
|
cropRect.zoom = zoom;
|
||||||
|
|
||||||
|
cropRect.x = oldCenterX - cropRect.width * 0.5;
|
||||||
|
cropRect.y = oldCenterY - cropRect.height * 0.5;
|
||||||
|
|
||||||
|
cropRect.clampToBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onRequestCrop(): void {
|
||||||
|
delegate.applyCrop();
|
||||||
|
}
|
||||||
|
|
||||||
|
target: wrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: sliderLayout
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
implicitHeight: 30
|
||||||
|
spacing: Appearance.spacing.large
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
text: qsTr("Crop scale")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomSlider {
|
||||||
|
id: zoomSlider
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 10
|
||||||
|
from: 1.0
|
||||||
|
to: 5.0
|
||||||
|
value: cropRect.zoom
|
||||||
|
|
||||||
|
onMoved: {
|
||||||
|
delegate.zoomClipRect(value);
|
||||||
|
wrapper.changesMade = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PinchHandler {
|
CachingImage {
|
||||||
maximumScale: 5.0
|
id: scaledImg
|
||||||
minimumScale: 1.0
|
|
||||||
target: null
|
|
||||||
|
|
||||||
onActiveScaleChanged: {
|
property var displayData
|
||||||
if (active) {
|
property real monitorScale: 1.0
|
||||||
let newZoom = Config.background.zoom * (1 / (1 + (activeScale - 1) * 0.1));
|
|
||||||
Config.background.zoom = Math.max(1.0, Math.min(newZoom, 5.0));
|
anchors.bottom: sliderLayout.top
|
||||||
|
anchors.bottomMargin: Appearance.spacing.normal
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
// retainWhileLoading: true
|
||||||
|
source: Wallpapers.current
|
||||||
|
sourceSize.height: parent.height
|
||||||
|
sourceSize.width: parent.width
|
||||||
|
|
||||||
|
onPaintedWidthChanged: {
|
||||||
|
if (paintedWidth > 0) {
|
||||||
|
scaledImg.displayData = Wallpapers.getCrop(delegate.modelData.name);
|
||||||
|
cropRect.zoom = Wallpapers.getCrop(delegate.modelData.name).zoom;
|
||||||
|
cropRect.restoreFromData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSourceChanged: cropRect.clampToBounds()
|
||||||
|
onStatusChanged: if (scaledImg.status == Image.Ready)
|
||||||
|
cropRect.clampToBounds()
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: monitorId
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: Qt.alpha(DynamicColors.palette.m3surface, 0.85)
|
||||||
|
font.pointSize: Appearance.font.size.large * 4
|
||||||
|
style: Text.Outline
|
||||||
|
styleColor: DynamicColors.palette.m3onSurface
|
||||||
|
text: delegate.modelData.name
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: cropRect
|
||||||
|
|
||||||
|
property real aspectRatio: delegate.modelData.width / delegate.modelData.height
|
||||||
|
readonly property real baseHeight: baseWidth / aspectRatio
|
||||||
|
readonly property real baseWidth: {
|
||||||
|
let fittedHeight = scaledImg.paintedHeight;
|
||||||
|
let fittedWidth = fittedHeight * aspectRatio;
|
||||||
|
|
||||||
|
if (fittedWidth > scaledImg.paintedWidth) {
|
||||||
|
fittedWidth = scaledImg.paintedWidth;
|
||||||
|
fittedHeight = fittedWidth / aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fittedWidth;
|
||||||
|
}
|
||||||
|
readonly property real imageX: (scaledImg.width - scaledImg.paintedWidth) / 2
|
||||||
|
readonly property real imageY: (scaledImg.height - scaledImg.paintedHeight) / 2
|
||||||
|
property real imgAspectRatio: scaledImg.paintedWidth / scaledImg.paintedHeight
|
||||||
|
property real zoom: scaledImg.displayData.zoom
|
||||||
|
|
||||||
|
function centerInImage() {
|
||||||
|
x = imageX + (scaledImg.paintedWidth - width) / 2;
|
||||||
|
y = imageY + (scaledImg.paintedHeight - height) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clampToBounds() {
|
||||||
|
x = Math.max(imageX, Math.min(x, imageX + scaledImg.paintedWidth - width));
|
||||||
|
|
||||||
|
y = Math.max(imageY, Math.min(y, imageY + scaledImg.paintedHeight - height));
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreFromData() {
|
||||||
|
let data = scaledImg.displayData;
|
||||||
|
|
||||||
|
if (data && data.scaledX !== 0 || data.scaledY !== 0 || data.scaledWidth !== 0 || data.scaledHeight !== 0) {
|
||||||
|
x = data.scaledX;
|
||||||
|
y = data.scaledY;
|
||||||
|
|
||||||
|
clampToBounds();
|
||||||
|
} else {
|
||||||
|
zoom = 1.0;
|
||||||
|
centerInImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
border.color: DynamicColors.palette.m3primary
|
||||||
|
border.width: 2
|
||||||
|
height: baseHeight / zoom
|
||||||
|
opacity: 1
|
||||||
|
width: baseWidth / zoom
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: clampToBounds()
|
||||||
|
onHeightChanged: clampToBounds()
|
||||||
|
onWidthChanged: clampToBounds()
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouse
|
||||||
|
|
||||||
|
function updateCrop(mouseX, mouseY) {
|
||||||
|
let nx = mouseX - cropRect.width * 0.5;
|
||||||
|
let ny = mouseY - cropRect.height * 0.5;
|
||||||
|
|
||||||
|
nx = Math.max(cropRect.imageX, Math.min(nx, cropRect.imageX + scaledImg.paintedWidth - cropRect.width));
|
||||||
|
|
||||||
|
ny = Math.max(cropRect.imageY, Math.min(ny, cropRect.imageY + scaledImg.paintedHeight - cropRect.height));
|
||||||
|
|
||||||
|
cropRect.x = nx;
|
||||||
|
cropRect.y = ny;
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
preventStealing: true
|
||||||
|
|
||||||
|
onPositionChanged: mouse => {
|
||||||
|
if (pressed) {
|
||||||
|
updateCrop(mouse.x, mouse.y);
|
||||||
|
wrapper.changesMade = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onPressed: mouse => {
|
||||||
|
updateCrop(mouse.x, mouse.y);
|
||||||
|
wrapper.changesMade = true;
|
||||||
|
}
|
||||||
|
onReleased: {
|
||||||
|
wrapper.changesMade = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
|
||||||
max: 5.0
|
|
||||||
min: 1.0
|
|
||||||
name: "Zoom"
|
|
||||||
object: Config.background
|
|
||||||
setting: "zoom"
|
|
||||||
step: 0.1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,37 +12,30 @@ GridView {
|
|||||||
|
|
||||||
readonly property int columnsCount: Math.max(1, Math.floor(width / minCellWidth))
|
readonly property int columnsCount: Math.max(1, Math.floor(width / minCellWidth))
|
||||||
readonly property int minCellWidth: 200 + Appearance.spacing.normal
|
readonly property int minCellWidth: 200 + Appearance.spacing.normal
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
Layout.preferredHeight: contentHeight
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
cellHeight: 140 + Appearance.spacing.normal
|
cellHeight: 140 + Appearance.spacing.normal
|
||||||
cellWidth: width / columnsCount
|
cellWidth: width / columnsCount
|
||||||
clip: true
|
clip: true
|
||||||
|
implicitHeight: shouldBeActive ? contentHeight : 0
|
||||||
interactive: false
|
interactive: false
|
||||||
model: Wallpapers.list
|
model: Wallpapers.list
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
required property int index
|
required property int index
|
||||||
readonly property bool isCurrent: modelData && modelData.path === Wallpapers.actualCurrent
|
readonly property bool isCurrent: modelData && modelData.path === Wallpapers.actualCurrent
|
||||||
readonly property real itemMargin: Appearance.spacing.normal / 2
|
readonly property real itemMargin: Appearance.spacing.normal
|
||||||
readonly property real itemRadius: Appearance.rounding.normal
|
readonly property real itemRadius: Appearance.rounding.small
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
||||||
height: root.cellHeight
|
height: root.cellHeight
|
||||||
width: root.cellWidth
|
width: root.cellWidth
|
||||||
|
|
||||||
StateLayer {
|
|
||||||
function onClicked(): void {
|
|
||||||
Wallpapers.setWallpaper(modelData.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.bottomMargin: itemMargin
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: itemMargin
|
|
||||||
anchors.rightMargin: itemMargin
|
|
||||||
anchors.topMargin: itemMargin
|
|
||||||
radius: itemRadius
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomClippingRect {
|
CustomClippingRect {
|
||||||
id: image
|
id: image
|
||||||
|
|
||||||
@@ -53,8 +46,6 @@ GridView {
|
|||||||
anchors.topMargin: itemMargin
|
anchors.topMargin: itemMargin
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
layer.enabled: true
|
|
||||||
layer.smooth: true
|
|
||||||
radius: itemRadius
|
radius: itemRadius
|
||||||
|
|
||||||
CachingImage {
|
CachingImage {
|
||||||
@@ -100,6 +91,33 @@ GridView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
antialiasing: true
|
||||||
|
border.color: DynamicColors.palette.m3primary
|
||||||
|
border.width: isCurrent ? 2 : 0
|
||||||
|
color: "transparent"
|
||||||
|
radius: itemRadius + 2
|
||||||
|
smooth: true
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 150
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
anchors.margins: Appearance.padding.small
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: "check_circle"
|
||||||
|
visible: isCurrent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: fallbackTimer
|
id: fallbackTimer
|
||||||
|
|
||||||
@@ -112,35 +130,29 @@ GridView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
StateLayer {
|
||||||
|
function onClicked(): void {
|
||||||
|
Wallpapers.setWallpaper(modelData.path);
|
||||||
|
}
|
||||||
|
|
||||||
anchors.bottomMargin: itemMargin
|
anchors.bottomMargin: itemMargin
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.leftMargin: itemMargin
|
anchors.leftMargin: itemMargin
|
||||||
anchors.rightMargin: itemMargin
|
anchors.rightMargin: itemMargin
|
||||||
anchors.topMargin: itemMargin
|
anchors.topMargin: itemMargin
|
||||||
antialiasing: true
|
radius: itemRadius
|
||||||
border.color: DynamicColors.palette.m3primary
|
}
|
||||||
border.width: isCurrent ? 2 : 0
|
}
|
||||||
color: "transparent"
|
Behavior on opacity {
|
||||||
radius: itemRadius - border.width
|
Anim {
|
||||||
smooth: true
|
}
|
||||||
|
}
|
||||||
Behavior on border.width {
|
Behavior on scale {
|
||||||
NumberAnimation {
|
Anim {
|
||||||
duration: 150
|
}
|
||||||
easing.type: Easing.OutQuad
|
}
|
||||||
}
|
Behavior on y {
|
||||||
}
|
Anim {
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
anchors.margins: Appearance.padding.small
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
color: DynamicColors.palette.m3primary
|
|
||||||
font.pointSize: Appearance.font.size.large
|
|
||||||
text: "check_circle"
|
|
||||||
visible: isCurrent
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user