Compare commits
122 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@@ -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,34 @@
|
|||||||
|
name: Lint & Format (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 .
|
||||||
@@ -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
|
||||||
+2
-1
@@ -1,4 +1,4 @@
|
|||||||
./__pycache__/
|
**/__pycache__/
|
||||||
./result/
|
./result/
|
||||||
.pyre/
|
.pyre/
|
||||||
.cache/
|
.cache/
|
||||||
@@ -12,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"
|
||||||
|
}
|
||||||
+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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
+27
-1
@@ -23,6 +23,7 @@ Singleton {
|
|||||||
property alias osd: adapter.osd
|
property alias osd: adapter.osd
|
||||||
property alias overview: adapter.overview
|
property alias overview: adapter.overview
|
||||||
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 +83,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 +98,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,
|
||||||
@@ -128,7 +134,8 @@ Singleton {
|
|||||||
background: serializeBackground(),
|
background: serializeBackground(),
|
||||||
launcher: serializeLauncher(),
|
launcher: serializeLauncher(),
|
||||||
colors: serializeColors(),
|
colors: serializeColors(),
|
||||||
dock: serializeDock()
|
dock: serializeDock(),
|
||||||
|
screenshot: serializeScreenshot()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +187,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 +241,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 +284,20 @@ Singleton {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 +453,8 @@ Singleton {
|
|||||||
}
|
}
|
||||||
property Overview overview: Overview {
|
property Overview overview: Overview {
|
||||||
}
|
}
|
||||||
|
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
|
||||||
@@ -79,10 +80,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 +116,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,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
|
||||||
|
|||||||
+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,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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+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
|
||||||
|
|
||||||
|
|||||||
+1
-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 {
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ Item {
|
|||||||
|
|
||||||
readonly property int padding: 6
|
readonly property int padding: 6
|
||||||
required property Item panels
|
required property Item panels
|
||||||
required property Item sidebarPanel
|
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
@@ -44,7 +43,7 @@ Item {
|
|||||||
|
|
||||||
return Math.min((QsWindow.window?.screen?.height ?? 0) - 1 * 2, height + padding * 2);
|
return Math.min((QsWindow.window?.screen?.height ?? 0) - 1 * 2, height + padding * 2);
|
||||||
}
|
}
|
||||||
implicitWidth: Math.max(sidebarPanel.width * (1 - sidebarPanel.offsetScale), Config.notifs.sizes.width + padding * 2)
|
implicitWidth: Config.notifs.sizes.width + padding * 2
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
Behavior on implicitHeight {
|
||||||
Anim {
|
Anim {
|
||||||
@@ -73,9 +72,8 @@ Item {
|
|||||||
required property NotifServer.Notif modelData
|
required property NotifServer.Notif modelData
|
||||||
readonly property alias nonAnimHeight: notif.nonAnimHeight
|
readonly property alias nonAnimHeight: notif.nonAnimHeight
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
implicitHeight: notif.implicitHeight + (idx === 0 ? 0 : 8)
|
implicitHeight: notif.implicitHeight + (idx === 0 ? 0 : 8)
|
||||||
|
implicitWidth: notif.implicitWidth
|
||||||
|
|
||||||
ListView.onRemove: removeAnim.start()
|
ListView.onRemove: removeAnim.start()
|
||||||
onIndexChanged: {
|
onIndexChanged: {
|
||||||
@@ -126,20 +124,16 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClippingRectangle {
|
ClippingRectangle {
|
||||||
// implicitWidth: notif.implicitWidth
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: wrapper.idx === 0 ? 0 : 8
|
anchors.topMargin: wrapper.idx === 0 ? 0 : 8
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
implicitHeight: notif.implicitHeight
|
implicitHeight: notif.implicitHeight
|
||||||
|
implicitWidth: notif.implicitWidth
|
||||||
radius: Appearance.rounding.smallest / 2
|
radius: Appearance.rounding.smallest / 2
|
||||||
|
|
||||||
Notification {
|
Notification {
|
||||||
id: notif
|
id: notif
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
modelData: wrapper.modelData
|
modelData: wrapper.modelData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ CustomRect {
|
|||||||
required property NotifServer.Notif modelData
|
required property NotifServer.Notif modelData
|
||||||
readonly property int nonAnimHeight: summary.implicitHeight + (root.expanded ? appName.height + body.height + actions.height + actions.anchors.topMargin : bodyPreview.height) + inner.anchors.margins * 2
|
readonly property int nonAnimHeight: summary.implicitHeight + (root.expanded ? appName.height + body.height + actions.height + actions.anchors.topMargin : bodyPreview.height) + inner.anchors.margins * 2
|
||||||
|
|
||||||
// implicitWidth: Config.notifs.sizes.width
|
|
||||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3secondaryContainer : DynamicColors.tPalette.m3surfaceContainer
|
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3secondaryContainer : DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: inner.implicitHeight
|
implicitHeight: inner.implicitHeight
|
||||||
|
implicitWidth: Config.notifs.sizes.width
|
||||||
radius: 6
|
radius: 6
|
||||||
x: Config.notifs.sizes.width
|
x: Config.notifs.sizes.width
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ Item {
|
|||||||
id: content
|
id: content
|
||||||
|
|
||||||
panels: root.panels
|
panels: root.panels
|
||||||
sidebarPanel: root.sidebarPanel
|
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,18 @@ Item {
|
|||||||
key: "launcher"
|
key: "launcher"
|
||||||
name: "Launcher"
|
name: "Launcher"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
icon: "screenshot_region"
|
||||||
|
key: "screenshot"
|
||||||
|
name: "Screenshot"
|
||||||
|
}
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
icon: "cached"
|
||||||
|
key: "updates"
|
||||||
|
name: "Updates"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomClippingRect {
|
CustomClippingRect {
|
||||||
@@ -171,9 +183,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 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,13 +32,11 @@ SettingsPage {
|
|||||||
step: 50
|
step: 50
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// WallpaperCropper {
|
WallpaperCropper {
|
||||||
// Layout.fillWidth: true
|
}
|
||||||
// Layout.preferredHeight: 300
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSection {
|
SettingsSection {
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,15 @@ SettingsPage {
|
|||||||
object: Config.general
|
object: Config.general
|
||||||
setting: "desktopIcons"
|
setting: "desktopIcons"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingInput {
|
||||||
|
name: "Date format"
|
||||||
|
object: Config.general
|
||||||
|
setting: "dateFormat"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSection {
|
SettingsSection {
|
||||||
|
|||||||
@@ -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,8 +95,8 @@ 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
|
||||||
|
|||||||
@@ -22,6 +22,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];
|
||||||
@@ -49,6 +56,9 @@ ColumnLayout {
|
|||||||
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,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
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,10 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
target: root
|
target: root
|
||||||
@@ -153,6 +158,7 @@ Item {
|
|||||||
id: background
|
id: background
|
||||||
|
|
||||||
Cat.Background {
|
Cat.Background {
|
||||||
|
screen: root.screen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,4 +231,18 @@ Item {
|
|||||||
Cat.Launcher {
|
Cat.Launcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: screenshot
|
||||||
|
|
||||||
|
Cat.Screenshot {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: updates
|
||||||
|
|
||||||
|
Cat.SystemUpdates {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,72 +28,11 @@ Item {
|
|||||||
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 +92,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 +102,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,7 +144,6 @@ 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
|
Layout.fillWidth: true
|
||||||
@@ -233,7 +151,7 @@ Item {
|
|||||||
|
|
||||||
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 +166,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 +184,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ Item {
|
|||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
||||||
signal addActiveActionRequested
|
signal addActiveActionRequested
|
||||||
|
signal deleteRequested(int index)
|
||||||
signal fieldEdited(string key, var value)
|
signal fieldEdited(string key, var value)
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -65,42 +66,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: {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ Item {
|
|||||||
Layout.preferredHeight: 42 * 6 + Appearance.padding.normal * 2 + Appearance.spacing.small * 5
|
Layout.preferredHeight: 42 * 6 + Appearance.padding.normal * 2 + Appearance.spacing.small * 5
|
||||||
Layout.preferredWidth: 500
|
Layout.preferredWidth: 500
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
radius: 21 + Appearance.padding.normal
|
radius: (21 + Appearance.padding.normal) * Appearance.rounding.scale
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
id: searchBox
|
id: searchBox
|
||||||
|
|||||||
@@ -1,102 +1,261 @@
|
|||||||
|
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)
|
|
||||||
|
|
||||||
Rectangle {
|
signal requestCrop
|
||||||
id: previewContainer
|
|
||||||
|
|
||||||
Layout.fillHeight: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredWidth: height * (Quickshell.screens.length > 0 ? (Quickshell.screens[0].height / Math.max(1, Quickshell.screens[0].width)) : 16 / 9)
|
Layout.preferredHeight: 400
|
||||||
clip: true
|
|
||||||
color: DynamicColors.palette.m3surfaceContainer
|
|
||||||
radius: Config.appearance.rounding.scale * 10
|
|
||||||
|
|
||||||
Image {
|
IconButton {
|
||||||
id: img
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
icon: "check"
|
||||||
|
opacity: wrapper.changesMade ? 1 : 0
|
||||||
|
scale: wrapper.changesMade ? 1 : 0
|
||||||
|
z: 2
|
||||||
|
|
||||||
anchors.fill: parent
|
Behavior on opacity {
|
||||||
asynchronous: true
|
Anim {
|
||||||
fillMode: Image.PreserveAspectFit
|
}
|
||||||
source: Wallpapers.current
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
onClicked: {
|
||||||
id: cropRect
|
wrapper.requestCrop();
|
||||||
|
wrapper.changesMade = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property real cropHeight: (imageAspect > screenAspect ? paintedHeight : paintedWidth / screenAspect) / Config.background.zoom
|
RowLayout {
|
||||||
property real cropWidth: (imageAspect > screenAspect ? paintedHeight * screenAspect : paintedWidth) / Config.background.zoom
|
id: root
|
||||||
property real imageAspect: Math.max(1, paintedWidth) / Math.max(1, paintedHeight)
|
|
||||||
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
|
anchors.fill: parent
|
||||||
border.width: 2
|
spacing: Appearance.spacing.normal
|
||||||
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 {
|
Repeater {
|
||||||
target: null
|
model: ScriptModel {
|
||||||
|
values: [...Quickshell.screens].sort((a, b) => {
|
||||||
|
return a.x - b.x;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
onActiveTranslationChanged: {
|
Item {
|
||||||
if (active) {
|
id: delegate
|
||||||
let newX = cropRect.x - cropRect.paintedX + translation.x;
|
|
||||||
let newY = cropRect.y - cropRect.paintedY + translation.y;
|
|
||||||
|
|
||||||
let rangeX = cropRect.paintedWidth - cropRect.width;
|
required property ShellScreen modelData
|
||||||
let rangeY = cropRect.paintedHeight - cropRect.height;
|
|
||||||
|
|
||||||
if (rangeX > 0) {
|
function applyCrop(): void {
|
||||||
let valX = newX / rangeX;
|
const croprect = cropRect.mapToItem(scaledImg, 0, 0, cropRect.width, cropRect.height);
|
||||||
Config.background.alignX = Math.max(0.0, Math.min(1.0, valX));
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rangeY > 0) {
|
function zoomClipRect(zoom: real): void {
|
||||||
let valY = newY / rangeY;
|
let oldCenterX = cropRect.x + cropRect.width * 0.5;
|
||||||
Config.background.alignY = Math.max(0.0, Math.min(1.0, valY));
|
let oldCenterY = cropRect.y + cropRect.height * 0.5;
|
||||||
Config.save();
|
|
||||||
}
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,26 +23,13 @@ GridView {
|
|||||||
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 +40,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 +85,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 +124,17 @@ 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"
|
|
||||||
radius: itemRadius - border.width
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ import QtQuick.Controls
|
|||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import "../../scripts/fuzzysort.js" as Fuzzy
|
import "../../scripts/fuzzysort.js" as Fuzzy
|
||||||
import "./SettingsIndex.mjs" as SettingsIndex
|
import "../../scripts/SettingsIndex.mjs" as SettingsIndex
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -53,11 +53,10 @@ Item {
|
|||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "/"
|
sequence: "/"
|
||||||
|
|
||||||
onActivated: searchField.forceActiveFocus()
|
onActivated: searchField.forceActiveFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: console.log(root.height)
|
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
id: resultsModel
|
id: resultsModel
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,45 +7,24 @@ import qs.Helpers
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property real offsetScale: shouldBeActive ? 0 : 1
|
||||||
required property var panels
|
required property var panels
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
|
readonly property bool shouldBeActive: visibilities.settings
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
implicitHeight: 0
|
anchors.topMargin: (-implicitHeight - 5) * offsetScale
|
||||||
|
implicitHeight: content.implicitHeight
|
||||||
implicitWidth: content.implicitWidth
|
implicitWidth: content.implicitWidth
|
||||||
visible: height > 0
|
opacity: 1 - offsetScale
|
||||||
|
visible: offsetScale < 1
|
||||||
|
|
||||||
states: State {
|
Behavior on offsetScale {
|
||||||
name: "visible"
|
Anim {
|
||||||
when: root.visibilities.settings
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||||
PropertyChanges {
|
|
||||||
root.implicitHeight: content.implicitHeight
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transitions: [
|
|
||||||
Transition {
|
|
||||||
from: ""
|
|
||||||
to: "visible"
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: MaterialEasing.expressiveEffectsTime
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
property: "implicitHeight"
|
|
||||||
target: root
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Transition {
|
|
||||||
from: "visible"
|
|
||||||
to: ""
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
property: "implicitHeight"
|
|
||||||
target: root
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
CustomClippingRect {
|
CustomClippingRect {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ Scope {
|
|||||||
description: "Toggle launcher"
|
description: "Toggle launcher"
|
||||||
name: "toggle-launcher"
|
name: "toggle-launcher"
|
||||||
|
|
||||||
onPressed: root.launcherInterrupted = false
|
onPressed: {
|
||||||
onReleased: {
|
root.launcherInterrupted = false;
|
||||||
if (!root.launcherInterrupted && !root.hasFullscreen) {
|
if (!root.launcherInterrupted && !root.hasFullscreen) {
|
||||||
const visibilities = Visibilities.getForActive();
|
const visibilities = Visibilities.getForActive();
|
||||||
visibilities.launcher = !visibilities.launcher;
|
visibilities.launcher = !visibilities.launcher;
|
||||||
|
|||||||
@@ -82,12 +82,14 @@ StackView {
|
|||||||
CustomRect {
|
CustomRect {
|
||||||
id: item
|
id: item
|
||||||
|
|
||||||
|
required property int index
|
||||||
required property QsMenuEntry modelData
|
required property QsMenuEntry modelData
|
||||||
|
|
||||||
color: modelData.isSeparator ? DynamicColors.palette.m3outlineVariant : "transparent"
|
color: modelData.isSeparator ? DynamicColors.palette.m3outlineVariant : "transparent"
|
||||||
implicitHeight: modelData.isSeparator ? 1 : children.implicitHeight
|
implicitHeight: modelData.isSeparator ? 1 : children.implicitHeight
|
||||||
implicitWidth: root.biggestWidth
|
implicitWidth: root.biggestWidth
|
||||||
radius: Appearance.rounding.smallest / 2
|
radius: Appearance.rounding.full
|
||||||
|
visible: index !== (menuOpener.children.values.length - 1) ? true : (modelData.isSeparator ? false : true)
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: children
|
id: children
|
||||||
@@ -201,18 +203,18 @@ StackView {
|
|||||||
asynchronous: true
|
asynchronous: true
|
||||||
|
|
||||||
sourceComponent: Item {
|
sourceComponent: Item {
|
||||||
implicitHeight: back.implicitHeight + 2 / 2
|
implicitHeight: 30
|
||||||
implicitWidth: back.implicitWidth
|
implicitWidth: back.implicitWidth
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
implicitHeight: back.implicitHeight
|
implicitHeight: 30
|
||||||
implicitWidth: back.implicitWidth + 10
|
implicitWidth: root.biggestWidth
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: DynamicColors.palette.m3secondaryContainer
|
color: DynamicColors.palette.m3secondaryContainer
|
||||||
radius: Appearance.rounding.smallest / 2
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
function onClicked(): void {
|
function onClicked(): void {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ Item {
|
|||||||
implicitHeight: Math.max(saver.implicitHeight, balance.implicitHeight, perf.implicitHeight) + 5 * 2 + saverLabel.contentHeight
|
implicitHeight: Math.max(saver.implicitHeight, balance.implicitHeight, perf.implicitHeight) + 5 * 2 + saverLabel.contentHeight
|
||||||
implicitWidth: saver.implicitHeight + balance.implicitHeight + perf.implicitHeight + 8 * 2 + saverLabel.contentWidth
|
implicitWidth: saver.implicitHeight + balance.implicitHeight + perf.implicitHeight + 8 * 2 + saverLabel.contentWidth
|
||||||
// color: "transparent"
|
// color: "transparent"
|
||||||
radius: 6
|
radius: (20 - Appearance.padding.small) * Appearance.rounding.scale
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
id: indicator
|
id: indicator
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.VectorImage
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Services.SystemTray
|
import Quickshell.Services.SystemTray
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
|
|
||||||
import Quickshell
|
|
||||||
import QtQuick
|
|
||||||
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
readonly property date date: clock.date
|
|
||||||
readonly property string dateStr: format("ddd d MMM - hh:mm:ss")
|
|
||||||
property alias enabled: clock.enabled
|
|
||||||
readonly property string hourStr: timeComponents[0] ?? ""
|
|
||||||
readonly property int hours: clock.hours
|
|
||||||
readonly property string minuteStr: timeComponents[1] ?? ""
|
|
||||||
readonly property int minutes: clock.minutes
|
|
||||||
readonly property string secondStr: timeComponents[2] ?? ""
|
|
||||||
readonly property int seconds: clock.seconds
|
|
||||||
readonly property list<string> timeComponents: timeStr.split(":")
|
|
||||||
readonly property string timeStr: format("hh:mm:ss")
|
|
||||||
|
|
||||||
function format(fmt: string): string {
|
|
||||||
return Qt.formatDateTime(clock.date, fmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemClock {
|
|
||||||
id: clock
|
|
||||||
|
|
||||||
precision: SystemClock.Seconds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -54,6 +54,8 @@ CustomClippingRect {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
contentHeight: childrenRect.height
|
contentHeight: childrenRect.height
|
||||||
contentWidth: 600
|
contentWidth: 600
|
||||||
|
displayMarginBeginning: root.itemHeight
|
||||||
|
displayMarginEnd: root.itemHeight
|
||||||
implicitHeight: Math.min(contentHeight, (root.itemHeight + spacing) * 5 - spacing)
|
implicitHeight: Math.min(contentHeight, (root.itemHeight + spacing) * 5 - spacing)
|
||||||
implicitWidth: contentWidth
|
implicitWidth: contentWidth
|
||||||
spacing: Appearance.spacing.normal
|
spacing: Appearance.spacing.normal
|
||||||
@@ -65,10 +67,11 @@ CustomClippingRect {
|
|||||||
required property var modelData
|
required property var modelData
|
||||||
readonly property list<string> sections: modelData.update.split(" ")
|
readonly property list<string> sections: modelData.update.split(" ")
|
||||||
|
|
||||||
anchors.left: parent.left
|
// anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
// anchors.right: parent.right
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: root.itemHeight
|
implicitHeight: root.itemHeight
|
||||||
|
implicitWidth: 600
|
||||||
radius: Appearance.rounding.small - Appearance.padding.small
|
radius: Appearance.rounding.small - Appearance.padding.small
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ CustomRect {
|
|||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
||||||
implicitWidth: contentRow.implicitWidth + Appearance.spacing.small * 2
|
implicitWidth: contentRow.implicitWidth + Appearance.spacing.small * 2
|
||||||
radius: height / 2
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: contentRow
|
id: contentRow
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.Components
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property Image current: one
|
||||||
|
property string source: Wallpapers.current
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (source)
|
||||||
|
Qt.callLater(() => one.update());
|
||||||
|
}
|
||||||
|
onSourceChanged: {
|
||||||
|
if (!source) {
|
||||||
|
current = null;
|
||||||
|
} else if (current === one) {
|
||||||
|
two.update();
|
||||||
|
} else {
|
||||||
|
one.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Img {
|
||||||
|
id: one
|
||||||
|
}
|
||||||
|
|
||||||
|
Img {
|
||||||
|
id: two
|
||||||
|
}
|
||||||
|
|
||||||
|
component Img: Image {
|
||||||
|
id: img
|
||||||
|
|
||||||
|
function update(): void {
|
||||||
|
if (source === root.source) {
|
||||||
|
root.current = this;
|
||||||
|
} else {
|
||||||
|
source = root.source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
opacity: 0
|
||||||
|
retainWhileLoading: true
|
||||||
|
scale: Wallpapers.showPreview ? 1 : 0.8
|
||||||
|
sourceClipRect: Qt.rect(Config.background.sourceClipX, Config.background.sourceClipY, Config.background.sourceClipW, Config.background.sourceClipH)
|
||||||
|
|
||||||
|
states: State {
|
||||||
|
name: "visible"
|
||||||
|
when: root.current === img
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
img.opacity: 1
|
||||||
|
img.scale: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transitions: Transition {
|
||||||
|
Anim {
|
||||||
|
duration: Config.background.wallFadeDuration
|
||||||
|
properties: "opacity,scale"
|
||||||
|
target: img
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onStatusChanged: {
|
||||||
|
if (status === Image.Ready) {
|
||||||
|
root.current = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
@@ -8,79 +10,76 @@ import qs.Config
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property Image current: one
|
required property ShellScreen screen
|
||||||
property string source: Wallpapers.current
|
property string source: Wallpapers.current
|
||||||
|
|
||||||
|
function refreshData(): void {
|
||||||
|
Hyprland.refreshMonitors();
|
||||||
|
const scale = Hyprland.monitorFor(root.screen).scale;
|
||||||
|
if (scale > 0 && img.resScale !== scale) {
|
||||||
|
img.resScale = scale;
|
||||||
|
img.sourceSize.width = root.screen.width * scale;
|
||||||
|
}
|
||||||
|
const displayData = Wallpapers.getCrop(root.screen.name);
|
||||||
|
const displayRect = Qt.rect(img.sourceSize.width * displayData.x, img.implicitHeight * displayData.y, img.sourceSize.width * displayData.width, img.implicitHeight * displayData.height);
|
||||||
|
img.anchors.fill = null;
|
||||||
|
img.zoom = displayData.zoom;
|
||||||
|
img.x = -(displayRect.x * displayData.zoom / img.resScale);
|
||||||
|
img.y = -(displayRect.y * displayData.zoom / img.resScale);
|
||||||
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
Component.onCompleted: {
|
Image {
|
||||||
if (source)
|
|
||||||
Qt.callLater(() => one.update());
|
|
||||||
}
|
|
||||||
onSourceChanged: {
|
|
||||||
if (!source) {
|
|
||||||
current = null;
|
|
||||||
} else if (current === one) {
|
|
||||||
two.update();
|
|
||||||
} else {
|
|
||||||
one.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Img {
|
|
||||||
id: one
|
|
||||||
}
|
|
||||||
|
|
||||||
Img {
|
|
||||||
id: two
|
|
||||||
}
|
|
||||||
|
|
||||||
component Img: CachingImage {
|
|
||||||
id: img
|
id: img
|
||||||
|
|
||||||
property real imageRatio: Math.max(1, sourceSize.width) / Math.max(1, sourceSize.height)
|
property int displayH
|
||||||
property bool isValid: sourceSize.width > 0 && sourceSize.height > 0 && root.width > 0 && root.height > 0
|
property int displayW
|
||||||
property real windowRatio: root.width / Math.max(1, root.height)
|
property real resScale
|
||||||
|
property real zoom: 1.0
|
||||||
|
|
||||||
function update(): void {
|
|
||||||
if (path === root.source) {
|
|
||||||
root.current = this;
|
|
||||||
} else {
|
|
||||||
path = root.source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.fill: undefined
|
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
height: isValid ? (imageRatio > windowRatio ? root.height : root.width / imageRatio) * Config.background.zoom : root.height
|
height: implicitHeight * zoom / resScale
|
||||||
opacity: 0
|
opacity: 1
|
||||||
scale: Wallpapers.showPreview ? 1 : 0.8
|
retainWhileLoading: true
|
||||||
width: isValid ? (imageRatio > windowRatio ? root.height * imageRatio : root.width) * Config.background.zoom : root.width
|
source: root.source
|
||||||
x: isValid ? (root.width - width) * Config.background.alignX : 0
|
sourceSize.width: root.screen.width * resScale
|
||||||
y: isValid ? (root.height - height) * Config.background.alignY : 0
|
width: implicitWidth * zoom / resScale
|
||||||
|
|
||||||
states: State {
|
Behavior on height {
|
||||||
name: "visible"
|
Anim {
|
||||||
when: root.current === img
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
img.opacity: 1
|
|
||||||
img.scale: 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transitions: Transition {
|
Behavior on width {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on x {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
Anim {
|
Anim {
|
||||||
duration: Config.background.wallFadeDuration
|
|
||||||
properties: "opacity,scale"
|
|
||||||
target: img
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
if (status === Image.Ready) {
|
if (img.status == Image.Ready) {
|
||||||
root.current = this;
|
root.refreshData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onAdapterUpdated(): void {
|
||||||
|
root.refreshData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onLoaded(): void {
|
||||||
|
root.refreshData();
|
||||||
|
}
|
||||||
|
|
||||||
|
target: Wallpapers.monitorCrops
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ Loader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WallBackground {
|
WallBackground {
|
||||||
|
screen: root.screen
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
|
|||||||
@@ -79,7 +79,8 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onPressed: {
|
onPressed: {
|
||||||
Hyprland.dispatch(`workspace ${button.modelData.name}`);
|
const ws = button.modelData.name;
|
||||||
|
Hyprland.dispatch(Hyprland.usingLua ? `hl.dsp.focus({ workspace= "${ws}"})` : `workspace ${ws}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ qml_module(ZShell-blobs
|
|||||||
|
|
||||||
qt_add_shaders(ZShell-blobs "blob_shaders"
|
qt_add_shaders(ZShell-blobs "blob_shaders"
|
||||||
BATCHABLE OPTIMIZED NOHLSL NOMSL
|
BATCHABLE OPTIMIZED NOHLSL NOMSL
|
||||||
|
GLSL "300es,330"
|
||||||
PREFIX "/"
|
PREFIX "/"
|
||||||
FILES
|
FILES
|
||||||
shaders/blob.frag
|
shaders/blob.frag
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
static_assert(sizeof(decltype(BlobRectData::excludeMask)) == sizeof(float),
|
||||||
|
"BlobMaterial packs excludeMask into a float slot via memcpy");
|
||||||
|
|
||||||
QSGMaterialType* BlobMaterial::type() const {
|
QSGMaterialType* BlobMaterial::type() const {
|
||||||
static QSGMaterialType s_type;
|
static QSGMaterialType s_type;
|
||||||
return &s_type;
|
return &s_type;
|
||||||
@@ -82,8 +85,11 @@ bool BlobMaterialShader::updateUniformData(RenderState& state, QSGMaterial* newM
|
|||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
const auto& r = mat->m_rects[i];
|
const auto& r = mat->m_rects[i];
|
||||||
const int base = 160 + i * 80;
|
const int base = 160 + i * 80;
|
||||||
|
// Pack excludeMask into props.x via bit-cast (read in shader with floatBitsToInt)
|
||||||
|
float maskAsFloat;
|
||||||
|
memcpy(&maskAsFloat, &r.excludeMask, sizeof(float));
|
||||||
const float d0[4] = { r.cx, r.cy, r.hw, r.hh };
|
const float d0[4] = { r.cx, r.cy, r.hw, r.hh };
|
||||||
const float d1[4] = { 0.0f, r.offsetX, r.offsetY, r.minEig };
|
const float d1[4] = { maskAsFloat, r.offsetX, r.offsetY, r.minEig };
|
||||||
const float d3[4] = { r.screenHalfX, r.screenHalfY, 0.0f, 0.0f };
|
const float d3[4] = { r.screenHalfX, r.screenHalfY, 0.0f, 0.0f };
|
||||||
memcpy(buf->data() + base, d0, 16);
|
memcpy(buf->data() + base, d0, 16);
|
||||||
memcpy(buf->data() + base + 16, d1, 16);
|
memcpy(buf->data() + base + 16, d1, 16);
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ struct BlobRectData {
|
|||||||
float screenHalfX = 0, screenHalfY = 0;
|
float screenHalfX = 0, screenHalfY = 0;
|
||||||
// Effective per-corner radii (tr, br, bl, tl), pre-computed on CPU
|
// Effective per-corner radii (tr, br, bl, tl), pre-computed on CPU
|
||||||
float radius[4] = { 0, 0, 0, 0 };
|
float radius[4] = { 0, 0, 0, 0 };
|
||||||
|
// Bitmask of indices in this rect's m_cachedRects that mutually exclude (or are excluded by) this rect.
|
||||||
|
// Used by the shader to skip smin between excluded pairs.
|
||||||
|
int excludeMask = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlobMaterial : public QSGMaterial {
|
class BlobMaterial : public QSGMaterial {
|
||||||
|
|||||||
@@ -72,11 +72,17 @@ void BlobShape::geometryChange(const QRectF& newGeometry, const QRectF& oldGeome
|
|||||||
// Accumulate sub-pixel drift so slow movements don't desync the shader
|
// Accumulate sub-pixel drift so slow movements don't desync the shader
|
||||||
m_pendingDx += static_cast<float>(newGeometry.x() - oldGeometry.x());
|
m_pendingDx += static_cast<float>(newGeometry.x() - oldGeometry.x());
|
||||||
m_pendingDy += static_cast<float>(newGeometry.y() - oldGeometry.y());
|
m_pendingDy += static_cast<float>(newGeometry.y() - oldGeometry.y());
|
||||||
const auto dw = std::abs(newGeometry.width() - oldGeometry.width());
|
// Accumulate size delta across multiple frames so incremental size
|
||||||
const auto dh = std::abs(newGeometry.height() - oldGeometry.height());
|
// changes that are each below the threshold still trigger a dirty
|
||||||
if (std::abs(m_pendingDx) > 0.5f || std::abs(m_pendingDy) > 0.5f || dw > 0.5 || dh > 0.5) {
|
// mark once their accumulated delta exceeds it.
|
||||||
|
m_pendingDw += static_cast<float>(newGeometry.width() - oldGeometry.width());
|
||||||
|
m_pendingDh += static_cast<float>(newGeometry.height() - oldGeometry.height());
|
||||||
|
if (std::abs(m_pendingDx) > 0.5f || std::abs(m_pendingDy) > 0.5f ||
|
||||||
|
std::abs(m_pendingDw) > 0.5f || std::abs(m_pendingDh) > 0.5f) {
|
||||||
m_pendingDx = 0;
|
m_pendingDx = 0;
|
||||||
m_pendingDy = 0;
|
m_pendingDy = 0;
|
||||||
|
m_pendingDw = 0;
|
||||||
|
m_pendingDh = 0;
|
||||||
m_group->markShapeDirty(this);
|
m_group->markShapeDirty(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,6 +155,10 @@ void BlobShape::updatePolish() {
|
|||||||
const QRectF myPadded(static_cast<double>(m_cachedPaddedX), static_cast<double>(m_cachedPaddedY),
|
const QRectF myPadded(static_cast<double>(m_cachedPaddedX), static_cast<double>(m_cachedPaddedY),
|
||||||
static_cast<double>(m_cachedPaddedW), static_cast<double>(m_cachedPaddedH));
|
static_cast<double>(m_cachedPaddedW), static_cast<double>(m_cachedPaddedH));
|
||||||
|
|
||||||
|
// Track shape pointers parallel to m_cachedRects for pairwise exclusion lookups
|
||||||
|
QVector<BlobShape*> rectShapes;
|
||||||
|
rectShapes.reserve(m_group->shapes().size());
|
||||||
|
|
||||||
for (BlobShape* other : m_group->shapes()) {
|
for (BlobShape* other : m_group->shapes()) {
|
||||||
if (other->isInvertedRect())
|
if (other->isInvertedRect())
|
||||||
continue;
|
continue;
|
||||||
@@ -210,12 +220,29 @@ void BlobShape::updatePolish() {
|
|||||||
r.screenHalfY = std::abs(b) * r.hw + std::abs(d) * r.hh;
|
r.screenHalfY = std::abs(b) * r.hw + std::abs(d) * r.hh;
|
||||||
|
|
||||||
m_cachedRects.append(r);
|
m_cachedRects.append(r);
|
||||||
|
rectShapes.append(other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInvertedRect())
|
if (isInvertedRect())
|
||||||
m_cachedMyIndex = -1;
|
m_cachedMyIndex = -1;
|
||||||
|
|
||||||
|
// Compute pairwise exclude masks. Bit j in entry i is set iff rect i excludes rect j
|
||||||
|
// or rect j excludes rect i. The shader uses this to avoid smin between excluded pairs.
|
||||||
|
const auto cachedCount = m_cachedRects.size();
|
||||||
|
for (qsizetype i = 0; i < cachedCount; ++i) {
|
||||||
|
int mask = 0;
|
||||||
|
BlobShape* si = rectShapes[i];
|
||||||
|
for (qsizetype j = 0; j < cachedCount; ++j) {
|
||||||
|
if (j == i)
|
||||||
|
continue;
|
||||||
|
BlobShape* sj = rectShapes[j];
|
||||||
|
if (si->isExcluded(sj) || sj->isExcluded(si))
|
||||||
|
mask |= (1 << j);
|
||||||
|
}
|
||||||
|
m_cachedRects[i].excludeMask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
// Cache inverted rect data
|
// Cache inverted rect data
|
||||||
m_cachedHasInverted = false;
|
m_cachedHasInverted = false;
|
||||||
m_cachedInvertedRadius = 0;
|
m_cachedInvertedRadius = 0;
|
||||||
@@ -270,6 +297,7 @@ void BlobShape::updatePolish() {
|
|||||||
const auto rectCount = m_cachedRects.size();
|
const auto rectCount = m_cachedRects.size();
|
||||||
for (qsizetype i = 0; i < rectCount; ++i) {
|
for (qsizetype i = 0; i < rectCount; ++i) {
|
||||||
auto& ri = m_cachedRects[i];
|
auto& ri = m_cachedRects[i];
|
||||||
|
const int riExcludeMask = ri.excludeMask;
|
||||||
float fTr = 1.0f, fBr = 1.0f, fBl = 1.0f, fTl = 1.0f;
|
float fTr = 1.0f, fBr = 1.0f, fBl = 1.0f, fTl = 1.0f;
|
||||||
|
|
||||||
const float cTrX = ri.cx + ri.hw, cTrY = ri.cy - ri.hh;
|
const float cTrX = ri.cx + ri.hw, cTrY = ri.cy - ri.hh;
|
||||||
@@ -280,6 +308,8 @@ void BlobShape::updatePolish() {
|
|||||||
for (qsizetype j = 0; j < rectCount; ++j) {
|
for (qsizetype j = 0; j < rectCount; ++j) {
|
||||||
if (j == i)
|
if (j == i)
|
||||||
continue;
|
continue;
|
||||||
|
if (riExcludeMask & (1 << j))
|
||||||
|
continue;
|
||||||
const auto& rj = m_cachedRects[j];
|
const auto& rj = m_cachedRects[j];
|
||||||
fTr = std::min(fTr, cpuSmoothstep(0.0f, smoothFactor, cpuSdBox(cTrX, cTrY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
fTr = std::min(fTr, cpuSmoothstep(0.0f, smoothFactor, cpuSdBox(cTrX, cTrY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
||||||
fBr = std::min(fBr, cpuSmoothstep(0.0f, smoothFactor, cpuSdBox(cBrX, cBrY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
fBr = std::min(fBr, cpuSmoothstep(0.0f, smoothFactor, cpuSdBox(cBrX, cBrY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
||||||
|
|||||||
@@ -84,8 +84,10 @@ QRectF m_localPaddedRect;
|
|||||||
QVector<BlobRectData> m_cachedRects;
|
QVector<BlobRectData> m_cachedRects;
|
||||||
int m_cachedMyIndex = -2;
|
int m_cachedMyIndex = -2;
|
||||||
float m_pendingDx = 0;
|
float m_pendingDx = 0;
|
||||||
float m_pendingDy = 0;
|
float m_pendingDy = 0;
|
||||||
bool m_cachedHasInverted = false;
|
float m_pendingDw = 0;
|
||||||
|
float m_pendingDh = 0;
|
||||||
|
bool m_cachedHasInverted = false;
|
||||||
float m_cachedInvertedRadius = 0;
|
float m_cachedInvertedRadius = 0;
|
||||||
float m_cachedInvertedOuter[4] = {};
|
float m_cachedInvertedOuter[4] = {};
|
||||||
float m_cachedInvertedInner[4] = {};
|
float m_cachedInvertedInner[4] = {};
|
||||||
|
|||||||
@@ -63,13 +63,17 @@ float smaxSharpA(float a, float b, float k) {
|
|||||||
void main() {
|
void main() {
|
||||||
vec2 pixel = vec2(paddedX, paddedY) + qt_TexCoord0 * vec2(paddedW, paddedH);
|
vec2 pixel = vec2(paddedX, paddedY) + qt_TexCoord0 * vec2(paddedW, paddedH);
|
||||||
|
|
||||||
float mergedSdf = 1e10;
|
// Phase 1: compute per-rect SDF, track owner. We can't smin yet because
|
||||||
|
// excluded pairs need to skip the smooth blend, which requires pairwise pass
|
||||||
|
// below.
|
||||||
|
float dArr[16];
|
||||||
int owner = -2;
|
int owner = -2;
|
||||||
float minDist = 1e10;
|
float minDist = 1e10;
|
||||||
|
|
||||||
for (int i = 0; i < rectCount; i++) {
|
for (int i = 0; i < rectCount; i++) {
|
||||||
vec4 rect = rectData[i * 5]; // cx, cy, hw, hh
|
vec4 rect = rectData[i * 5]; // cx, cy, hw, hh
|
||||||
vec4 props = rectData[i * 5 + 1]; // radius, offsetX, offsetY, minEig
|
vec4 props =
|
||||||
|
rectData[i * 5 + 1]; // excludeMask(int bits), offsetX, offsetY, minEig
|
||||||
vec4 invDm = rectData[i * 5 + 2]; // inverse deform matrix
|
vec4 invDm = rectData[i * 5 + 2]; // inverse deform matrix
|
||||||
vec4 sh = rectData[i * 5 + 3]; // screenHalfX, screenHalfY, 0, 0
|
vec4 sh = rectData[i * 5 + 3]; // screenHalfX, screenHalfY, 0, 0
|
||||||
vec4 radii =
|
vec4 radii =
|
||||||
@@ -81,8 +85,10 @@ void main() {
|
|||||||
// AABB early-out: skip rects far from this pixel
|
// AABB early-out: skip rects far from this pixel
|
||||||
vec2 extent = sh.xy + vec2(smoothFactor * 1.5);
|
vec2 extent = sh.xy + vec2(smoothFactor * 1.5);
|
||||||
if (abs(pixel.x - center.x) > extent.x ||
|
if (abs(pixel.x - center.x) > extent.x ||
|
||||||
abs(pixel.y - center.y) > extent.y)
|
abs(pixel.y - center.y) > extent.y) {
|
||||||
|
dArr[i] = 1e10;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Apply pre-computed inverse deformation to the evaluation point
|
// Apply pre-computed inverse deformation to the evaluation point
|
||||||
mat2 invDeform = mat2(invDm.xy, invDm.zw);
|
mat2 invDeform = mat2(invDm.xy, invDm.zw);
|
||||||
@@ -138,13 +144,38 @@ void main() {
|
|||||||
d *= scale;
|
d *= scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedSdf = smin(mergedSdf, d, smoothFactor);
|
dArr[i] = d;
|
||||||
if (d < smoothFactor && d < minDist) {
|
if (d < smoothFactor && d < minDist) {
|
||||||
minDist = d;
|
minDist = d;
|
||||||
owner = i;
|
owner = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Phase 2: hard-min baseline over all rects.
|
||||||
|
float mergedSdf = 1e10;
|
||||||
|
for (int i = 0; i < rectCount; i++) {
|
||||||
|
mergedSdf = min(mergedSdf, dArr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 3: pair-wise smin contributions, skipping excluded pairs. Pair smin
|
||||||
|
// <= min, so taking the min over all non-excluded pair smins gives the
|
||||||
|
// smoothly-merged SDF.
|
||||||
|
for (int i = 0; i < rectCount; i++) {
|
||||||
|
if (dArr[i] >= 1e9)
|
||||||
|
continue;
|
||||||
|
int excludeMask = floatBitsToInt(rectData[i * 5 + 1].x);
|
||||||
|
for (int j = i + 1; j < rectCount; j++) {
|
||||||
|
if (dArr[j] >= 1e9)
|
||||||
|
continue;
|
||||||
|
if ((excludeMask & (1 << j)) != 0)
|
||||||
|
continue;
|
||||||
|
// smin only deviates from min within smoothFactor
|
||||||
|
if (abs(dArr[i] - dArr[j]) >= smoothFactor)
|
||||||
|
continue;
|
||||||
|
mergedSdf = min(mergedSdf, smin(dArr[i], dArr[j], smoothFactor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hasInverted != 0) {
|
if (hasInverted != 0) {
|
||||||
float dOuter = sdBox(pixel, invertedOuter.xy, invertedOuter.zw) - 1.0;
|
float dOuter = sdBox(pixel, invertedOuter.xy, invertedOuter.zw) - 1.0;
|
||||||
float dInner =
|
float dInner =
|
||||||
|
|||||||
@@ -1,217 +1,384 @@
|
|||||||
#include "hyprextras.hpp"
|
#include "hyprextras.hpp"
|
||||||
|
#include "hyprdevices.hpp"
|
||||||
|
|
||||||
#include <qdir.h>
|
#include <qdir.h>
|
||||||
#include <qjsonarray.h>
|
#include <qjsonarray.h>
|
||||||
#include <qlocalsocket.h>
|
#include <qlocalsocket.h>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
|
#include <qmetatype.h>
|
||||||
|
#include <qregularexpression.h>
|
||||||
#include <qvariant.h>
|
#include <qvariant.h>
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(lcHypr, "ZShell.internal.hypr", QtInfoMsg)
|
||||||
|
|
||||||
namespace ZShell::internal::hypr {
|
namespace ZShell::internal::hypr {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static QString luaEscapeString(const QString& s) {
|
||||||
|
QString out;
|
||||||
|
out.reserve(s.size() + 2);
|
||||||
|
out += QLatin1Char('"');
|
||||||
|
|
||||||
|
for (const QChar c : s) {
|
||||||
|
switch (c.unicode()) {
|
||||||
|
case '\\':
|
||||||
|
out += QLatin1String(R"(\\)");
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
out += QLatin1String(R"(\")");
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
out += QLatin1String(R"(\n)");
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
out += QLatin1String(R"(\r)");
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
out += QLatin1String(R"(\t)");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out += c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out += QLatin1Char('"');
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString luaValue(const QVariant& v);
|
||||||
|
|
||||||
|
static QString luaArray(const QVariantList& list) {
|
||||||
|
QStringList parts;
|
||||||
|
parts.reserve(list.size());
|
||||||
|
|
||||||
|
for (const auto& item : list) {
|
||||||
|
parts << luaValue(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) + QLatin1String(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString luaArray(const QStringList& list) {
|
||||||
|
QStringList parts;
|
||||||
|
parts.reserve(list.size());
|
||||||
|
|
||||||
|
for (const auto& item : list) {
|
||||||
|
parts << luaEscapeString(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) + QLatin1String(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString luaMapFromHash(const QVariantHash& hash) {
|
||||||
|
QStringList parts;
|
||||||
|
parts.reserve(hash.size());
|
||||||
|
|
||||||
|
for (auto it = hash.cbegin(); it != hash.cend(); ++it) {
|
||||||
|
parts << luaEscapeString(it.key()) + QLatin1String(" = ") + luaValue(it.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) + QLatin1String(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString luaMap(const QVariantMap& map) {
|
||||||
|
QStringList parts;
|
||||||
|
parts.reserve(map.size());
|
||||||
|
|
||||||
|
for (auto it = map.cbegin(); it != map.cend(); ++it) {
|
||||||
|
parts << luaEscapeString(it.key()) + QLatin1String(" = ") + luaValue(it.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) + QLatin1String(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString luaValue(const QVariant& v) {
|
||||||
|
if (!v.isValid() || v.isNull()) {
|
||||||
|
return QLatin1String("nil");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (v.metaType().id()) {
|
||||||
|
case QMetaType::Bool:
|
||||||
|
return v.toBool() ? QLatin1String("true") : QLatin1String("false");
|
||||||
|
|
||||||
|
case QMetaType::Int:
|
||||||
|
case QMetaType::UInt:
|
||||||
|
case QMetaType::LongLong:
|
||||||
|
case QMetaType::ULongLong:
|
||||||
|
case QMetaType::Double:
|
||||||
|
return v.toString();
|
||||||
|
|
||||||
|
case QMetaType::QString:
|
||||||
|
return luaEscapeString(v.toString());
|
||||||
|
|
||||||
|
case QMetaType::QStringList:
|
||||||
|
return luaArray(v.toStringList());
|
||||||
|
|
||||||
|
case QMetaType::QVariantList:
|
||||||
|
return luaArray(v.toList());
|
||||||
|
|
||||||
|
case QMetaType::QVariantMap:
|
||||||
|
return luaMap(v.toMap());
|
||||||
|
|
||||||
|
case QMetaType::QVariantHash:
|
||||||
|
return luaMapFromHash(v.toHash());
|
||||||
|
|
||||||
|
default:
|
||||||
|
return luaEscapeString(v.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString normalizeOptionPath(QString key) {
|
||||||
|
key = key.trimmed();
|
||||||
|
key.replace(QLatin1Char(':'), QLatin1Char('.'));
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString buildHlConfigCall(const QString& key, const QVariant& value) {
|
||||||
|
const auto parts = normalizeOptionPath(key).split(QLatin1Char('.'), Qt::SkipEmptyParts);
|
||||||
|
if (parts.isEmpty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString out;
|
||||||
|
out.reserve(32 + key.size() + value.toString().size());
|
||||||
|
out += QLatin1String("hl.config({ ");
|
||||||
|
|
||||||
|
for (int i = 0; i < parts.size(); ++i) {
|
||||||
|
out += parts.at(i);
|
||||||
|
out += QLatin1String(" = ");
|
||||||
|
if (i + 1 < parts.size()) {
|
||||||
|
out += QLatin1String("{ ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out += luaValue(value);
|
||||||
|
|
||||||
|
for (int i = 0; i + 1 < parts.size(); ++i) {
|
||||||
|
out += QLatin1String(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
out += QLatin1String(" })");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
HyprExtras::HyprExtras(QObject* parent)
|
HyprExtras::HyprExtras(QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_requestSocket("")
|
, m_requestSocket("")
|
||||||
, m_eventSocket("")
|
, m_eventSocket("")
|
||||||
, m_socket(nullptr)
|
, m_socket(nullptr)
|
||||||
, m_socketValid(false)
|
, m_socketValid(false)
|
||||||
, m_devices(new HyprDevices(this)) {
|
, m_devices(new HyprDevices(this)) {
|
||||||
const auto his = qEnvironmentVariable("HYPRLAND_INSTANCE_SIGNATURE");
|
const auto his = qEnvironmentVariable("HYPRLAND_INSTANCE_SIGNATURE");
|
||||||
if (his.isEmpty()) {
|
if (his.isEmpty()) {
|
||||||
qWarning()
|
qCWarning(lcHypr) << "$HYPRLAND_INSTANCE_SIGNATURE is unset. Unable to connect to Hyprland socket.";
|
||||||
<< "HyprExtras::HyprExtras: $HYPRLAND_INSTANCE_SIGNATURE is unset. Unable to connect to Hyprland socket.";
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto hyprDir = QString("%1/hypr/%2").arg(qEnvironmentVariable("XDG_RUNTIME_DIR"), his);
|
auto hyprDir = QString("%1/hypr/%2").arg(qEnvironmentVariable("XDG_RUNTIME_DIR"), his);
|
||||||
if (!QDir(hyprDir).exists()) {
|
if (!QDir(hyprDir).exists()) {
|
||||||
hyprDir = "/tmp/hypr/" + his;
|
hyprDir = QStringLiteral("/tmp/hypr/") + his;
|
||||||
|
|
||||||
if (!QDir(hyprDir).exists()) {
|
if (!QDir(hyprDir).exists()) {
|
||||||
qWarning() << "HyprExtras::HyprExtras: Hyprland socket directory does not exist. Unable to connect to "
|
qCWarning(lcHypr) << "Hyprland socket directory does not exist. Unable to connect to Hyprland socket.";
|
||||||
"Hyprland socket.";
|
return;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
m_requestSocket = hyprDir + "/.socket.sock";
|
m_requestSocket = hyprDir + QStringLiteral("/.socket.sock");
|
||||||
m_eventSocket = hyprDir + "/.socket2.sock";
|
m_eventSocket = hyprDir + QStringLiteral("/.socket2.sock");
|
||||||
|
|
||||||
refreshOptions();
|
refreshOptions();
|
||||||
refreshDevices();
|
refreshDevices();
|
||||||
|
|
||||||
m_socket = new QLocalSocket(this);
|
m_socket = new QLocalSocket(this);
|
||||||
|
|
||||||
QObject::connect(m_socket, &QLocalSocket::errorOccurred, this, &HyprExtras::socketError);
|
QObject::connect(m_socket, &QLocalSocket::errorOccurred, this, &HyprExtras::socketError);
|
||||||
QObject::connect(m_socket, &QLocalSocket::stateChanged, this, &HyprExtras::socketStateChanged);
|
QObject::connect(m_socket, &QLocalSocket::stateChanged, this, &HyprExtras::socketStateChanged);
|
||||||
QObject::connect(m_socket, &QLocalSocket::readyRead, this, &HyprExtras::readEvent);
|
QObject::connect(m_socket, &QLocalSocket::readyRead, this, &HyprExtras::readEvent);
|
||||||
|
|
||||||
m_socket->connectToServer(m_eventSocket, QLocalSocket::ReadOnly);
|
m_socket->connectToServer(m_eventSocket, QLocalSocket::ReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantHash HyprExtras::options() const {
|
QVariantHash HyprExtras::options() const {
|
||||||
return m_options;
|
return m_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
HyprDevices* HyprExtras::devices() const {
|
HyprDevices* HyprExtras::devices() const {
|
||||||
return m_devices;
|
return m_devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprExtras::message(const QString& message) {
|
void HyprExtras::message(const QString& message) {
|
||||||
if (message.isEmpty()) {
|
if (message.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
makeRequest(message, [](bool success, const QByteArray& res) {
|
makeRequest(message, [](bool success, const QByteArray& res) {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
qWarning() << "HyprExtras::message: request error:" << QString::fromUtf8(res);
|
qCWarning(lcHypr) << "message: request error:" << QString::fromUtf8(res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprExtras::batchMessage(const QStringList& messages) {
|
void HyprExtras::batchMessage(const QStringList& messages) {
|
||||||
if (messages.isEmpty()) {
|
if (messages.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
makeRequest("[[BATCH]]" + messages.join(";"), [](bool success, const QByteArray& res) {
|
makeRequest(QStringLiteral("[[BATCH]]") + messages.join(QLatin1Char(';')),
|
||||||
if (!success) {
|
[](bool success, const QByteArray& res) {
|
||||||
qWarning() << "HyprExtras::batchMessage: request error:" << QString::fromUtf8(res);
|
if (!success) {
|
||||||
}
|
qCWarning(lcHypr) << "batchMessage: request error:" << QString::fromUtf8(res);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprExtras::applyOptions(const QVariantHash& options) {
|
void HyprExtras::applyOptions(const QVariantHash& options) {
|
||||||
if (options.isEmpty()) {
|
if (options.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString request = "[[BATCH]]";
|
QStringList calls;
|
||||||
for (auto it = options.constBegin(); it != options.constEnd(); ++it) {
|
calls.reserve(options.size());
|
||||||
request += QString("keyword %1 %2;").arg(it.key(), it.value().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
makeRequest(request, [this](bool success, const QByteArray& res) {
|
for (auto it = options.constBegin(); it != options.constEnd(); ++it) {
|
||||||
if (success) {
|
const auto call = buildHlConfigCall(it.key(), it.value());
|
||||||
refreshOptions();
|
if (!call.isEmpty()) {
|
||||||
} else {
|
calls << call;
|
||||||
qWarning() << "HyprExtras::applyOptions: request error" << QString::fromUtf8(res);
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
if (calls.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
makeRequest(QStringLiteral("eval ") + calls.join(QLatin1String("; ")), [this](bool success, const QByteArray& res) {
|
||||||
|
if (success) {
|
||||||
|
refreshOptions();
|
||||||
|
} else {
|
||||||
|
qCWarning(lcHypr) << "applyOptions: request error" << QString::fromUtf8(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprExtras::refreshOptions() {
|
void HyprExtras::refreshOptions() {
|
||||||
if (!m_optionsRefresh.isNull()) {
|
if (!m_optionsRefresh.isNull()) {
|
||||||
m_optionsRefresh->close();
|
m_optionsRefresh->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_optionsRefresh = makeRequestJson("descriptions", [this](bool success, const QJsonDocument& response) {
|
m_optionsRefresh = makeRequestJson(QStringLiteral("descriptions"), [this](bool success, const QJsonDocument& response) {
|
||||||
m_optionsRefresh.reset();
|
m_optionsRefresh.reset();
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto options = response.array();
|
const auto options = response.array();
|
||||||
bool dirty = false;
|
bool dirty = false;
|
||||||
|
|
||||||
for (const auto& o : std::as_const(options)) {
|
for (const auto& o : std::as_const(options)) {
|
||||||
const auto obj = o.toObject();
|
const auto obj = o.toObject();
|
||||||
const auto key = obj.value("value").toString();
|
const auto key = obj.value(QStringLiteral("value")).toString();
|
||||||
const auto value = obj.value("data").toObject().value("current").toVariant();
|
const auto value = obj.value(QStringLiteral("data")).toObject().value(QStringLiteral("current")).toVariant();
|
||||||
if (m_options.value(key) != value) {
|
|
||||||
dirty = true;
|
|
||||||
m_options.insert(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dirty) {
|
if (m_options.value(key) != value) {
|
||||||
emit optionsChanged();
|
dirty = true;
|
||||||
}
|
m_options.insert(key, value);
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirty) {
|
||||||
|
emit optionsChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprExtras::refreshDevices() {
|
void HyprExtras::refreshDevices() {
|
||||||
if (!m_devicesRefresh.isNull()) {
|
if (!m_devicesRefresh.isNull()) {
|
||||||
m_devicesRefresh->close();
|
m_devicesRefresh->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_devicesRefresh = makeRequestJson("devices", [this](bool success, const QJsonDocument& response) {
|
m_devicesRefresh = makeRequestJson(QStringLiteral("devices"), [this](bool success, const QJsonDocument& response) {
|
||||||
m_devicesRefresh.reset();
|
m_devicesRefresh.reset();
|
||||||
if (success) {
|
if (success) {
|
||||||
m_devices->updateLastIpcObject(response.object());
|
m_devices->updateLastIpcObject(response.object());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprExtras::socketError(QLocalSocket::LocalSocketError error) const {
|
void HyprExtras::socketError(QLocalSocket::LocalSocketError error) const {
|
||||||
if (!m_socketValid) {
|
if (!m_socketValid) {
|
||||||
qWarning() << "HyprExtras::socketError: unable to connect to Hyprland event socket:" << error;
|
qCWarning(lcHypr) << "socketError: unable to connect to Hyprland event socket:" << error;
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "HyprExtras::socketError: Hyprland event socket error:" << error;
|
qCWarning(lcHypr) << "socketError: Hyprland event socket error:" << error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprExtras::socketStateChanged(QLocalSocket::LocalSocketState state) {
|
void HyprExtras::socketStateChanged(QLocalSocket::LocalSocketState state) {
|
||||||
if (state == QLocalSocket::UnconnectedState && m_socketValid) {
|
if (state == QLocalSocket::UnconnectedState && m_socketValid) {
|
||||||
qWarning() << "HyprExtras::socketStateChanged: Hyprland event socket disconnected.";
|
qCWarning(lcHypr) << "socketStateChanged: Hyprland event socket disconnected.";
|
||||||
}
|
}
|
||||||
|
|
||||||
m_socketValid = state == QLocalSocket::ConnectedState;
|
m_socketValid = state == QLocalSocket::ConnectedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprExtras::readEvent() {
|
void HyprExtras::readEvent() {
|
||||||
while (true) {
|
while (true) {
|
||||||
auto rawEvent = m_socket->readLine();
|
auto rawEvent = m_socket->readLine();
|
||||||
if (rawEvent.isEmpty()) {
|
if (rawEvent.isEmpty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rawEvent.truncate(rawEvent.length() - 1); // Remove trailing \n
|
rawEvent.truncate(rawEvent.length() - 1);
|
||||||
const auto event = QByteArrayView(rawEvent.data(), rawEvent.indexOf(">>"));
|
const auto event = QByteArrayView(rawEvent.data(), rawEvent.indexOf(">>"));
|
||||||
handleEvent(QString::fromUtf8(event));
|
handleEvent(QString::fromUtf8(event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprExtras::handleEvent(const QString& event) {
|
void HyprExtras::handleEvent(const QString& event) {
|
||||||
if (event == "configreloaded") {
|
if (event == QStringLiteral("configreloaded")) {
|
||||||
refreshOptions();
|
refreshOptions();
|
||||||
} else if (event == "activelayout") {
|
} else if (event == QStringLiteral("activelayout")) {
|
||||||
refreshDevices();
|
refreshDevices();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HyprExtras::SocketPtr HyprExtras::makeRequestJson(
|
HyprExtras::SocketPtr HyprExtras::makeRequestJson(
|
||||||
const QString& request, const std::function<void(bool, QJsonDocument)>& callback) {
|
const QString& request, const std::function<void(bool, QJsonDocument)>& callback) {
|
||||||
return makeRequest("j/" + request, [callback](bool success, const QByteArray& response) {
|
return makeRequest(QStringLiteral("j/") + request, [callback](bool success, const QByteArray& response) {
|
||||||
callback(success, QJsonDocument::fromJson(response));
|
callback(success, QJsonDocument::fromJson(response));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
HyprExtras::SocketPtr HyprExtras::makeRequest(
|
HyprExtras::SocketPtr HyprExtras::makeRequest(
|
||||||
const QString& request, const std::function<void(bool, QByteArray)>& callback) {
|
const QString& request, const std::function<void(bool, QByteArray)>& callback) {
|
||||||
if (m_requestSocket.isEmpty()) {
|
if (m_requestSocket.isEmpty()) {
|
||||||
return SocketPtr();
|
return SocketPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto socket = SocketPtr::create(this);
|
auto socket = SocketPtr::create(this);
|
||||||
|
|
||||||
QObject::connect(socket.data(), &QLocalSocket::connected, this, [=, this]() {
|
QObject::connect(socket.data(), &QLocalSocket::connected, this, [=, this]() {
|
||||||
QObject::connect(socket.data(), &QLocalSocket::readyRead, this, [socket, callback]() {
|
QObject::connect(socket.data(), &QLocalSocket::readyRead, this, [socket, callback]() {
|
||||||
const auto response = socket->readAll();
|
const auto response = socket->readAll();
|
||||||
callback(true, std::move(response));
|
callback(true, std::move(response));
|
||||||
socket->close();
|
socket->close();
|
||||||
});
|
});
|
||||||
|
|
||||||
socket->write(request.toUtf8());
|
socket->write(request.toUtf8());
|
||||||
socket->flush();
|
socket->flush();
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(socket.data(), &QLocalSocket::errorOccurred, this, [=](QLocalSocket::LocalSocketError err) {
|
QObject::connect(socket.data(), &QLocalSocket::errorOccurred, this, [=](QLocalSocket::LocalSocketError err) {
|
||||||
qWarning() << "HyprExtras::makeRequest: error making request:" << err << "| request:" << request;
|
qCWarning(lcHypr) << "makeRequest: error making request:" << err << "| request:" << request;
|
||||||
callback(false, {});
|
callback(false, {});
|
||||||
socket->close();
|
socket->close();
|
||||||
});
|
});
|
||||||
|
|
||||||
socket->connectToServer(m_requestSocket);
|
socket->connectToServer(m_requestSocket);
|
||||||
|
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZShell::internal::hypr
|
} // namespace ZShell::internal::hypr
|
||||||
|
|||||||
@@ -1,56 +1,60 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "hyprdevices.hpp"
|
|
||||||
#include <qlocalsocket.h>
|
#include <qlocalsocket.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qqmlintegration.h>
|
#include <qqmlintegration.h>
|
||||||
|
#include <qsharedpointer.h>
|
||||||
|
#include <qvariant.h>
|
||||||
|
|
||||||
namespace ZShell::internal::hypr {
|
namespace ZShell::internal::hypr {
|
||||||
|
|
||||||
class HyprExtras : public QObject {
|
class HyprDevices;
|
||||||
Q_OBJECT
|
|
||||||
QML_ELEMENT
|
|
||||||
|
|
||||||
Q_PROPERTY(QVariantHash options READ options NOTIFY optionsChanged)
|
class HyprExtras : public QObject {
|
||||||
Q_PROPERTY(ZShell::internal::hypr::HyprDevices* devices READ devices CONSTANT)
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
Q_MOC_INCLUDE("hyprdevices.hpp")
|
||||||
|
|
||||||
|
Q_PROPERTY(QVariantHash options READ options NOTIFY optionsChanged)
|
||||||
|
Q_PROPERTY(ZShell::internal::hypr::HyprDevices* devices READ devices CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit HyprExtras(QObject* parent = nullptr);
|
explicit HyprExtras(QObject* parent = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] QVariantHash options() const;
|
[[nodiscard]] QVariantHash options() const;
|
||||||
[[nodiscard]] HyprDevices* devices() const;
|
[[nodiscard]] HyprDevices* devices() const;
|
||||||
|
|
||||||
Q_INVOKABLE void message(const QString& message);
|
Q_INVOKABLE void message(const QString& message);
|
||||||
Q_INVOKABLE void batchMessage(const QStringList& messages);
|
Q_INVOKABLE void batchMessage(const QStringList& messages);
|
||||||
Q_INVOKABLE void applyOptions(const QVariantHash& options);
|
Q_INVOKABLE void applyOptions(const QVariantHash& options);
|
||||||
|
|
||||||
Q_INVOKABLE void refreshOptions();
|
Q_INVOKABLE void refreshOptions();
|
||||||
Q_INVOKABLE void refreshDevices();
|
Q_INVOKABLE void refreshDevices();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void optionsChanged();
|
void optionsChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using SocketPtr = QSharedPointer<QLocalSocket>;
|
using SocketPtr = QSharedPointer<QLocalSocket>;
|
||||||
|
|
||||||
QString m_requestSocket;
|
QString m_requestSocket;
|
||||||
QString m_eventSocket;
|
QString m_eventSocket;
|
||||||
QLocalSocket* m_socket;
|
QLocalSocket* m_socket;
|
||||||
bool m_socketValid;
|
bool m_socketValid;
|
||||||
|
|
||||||
QVariantHash m_options;
|
QVariantHash m_options;
|
||||||
HyprDevices* const m_devices;
|
HyprDevices* const m_devices;
|
||||||
|
|
||||||
SocketPtr m_optionsRefresh;
|
SocketPtr m_optionsRefresh;
|
||||||
SocketPtr m_devicesRefresh;
|
SocketPtr m_devicesRefresh;
|
||||||
|
|
||||||
void socketError(QLocalSocket::LocalSocketError error) const;
|
void socketError(QLocalSocket::LocalSocketError error) const;
|
||||||
void socketStateChanged(QLocalSocket::LocalSocketState state);
|
void socketStateChanged(QLocalSocket::LocalSocketState state);
|
||||||
void readEvent();
|
void readEvent();
|
||||||
void handleEvent(const QString& event);
|
void handleEvent(const QString& event);
|
||||||
|
|
||||||
SocketPtr makeRequestJson(const QString& request, const std::function<void(bool, QJsonDocument)>& callback);
|
SocketPtr makeRequestJson(const QString& request, const std::function<void(bool, QJsonDocument)>& callback);
|
||||||
SocketPtr makeRequest(const QString& request, const std::function<void(bool, QByteArray)>& callback);
|
SocketPtr makeRequest(const QString& request, const std::function<void(bool, QByteArray)>& callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZShell::internal::hypr
|
} // namespace ZShell::internal::hypr
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ Defaults from `CMakeLists.txt`:
|
|||||||
|
|
||||||
### Nix Flake
|
### Nix Flake
|
||||||
|
|
||||||
|
_Note that Nix is not actively developed at this point. Things may be broken. Feel free to suggest fixes in a PR_
|
||||||
|
|
||||||
The flake exposes:
|
The flake exposes:
|
||||||
|
|
||||||
- `packages.<system>.zshell`
|
- `packages.<system>.zshell`
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"typer",
|
"typer",
|
||||||
"pillow",
|
"pillow",
|
||||||
"jinja2",
|
|
||||||
"materialyoucolor"
|
"materialyoucolor"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import typer
|
import typer
|
||||||
from zshell.subcommands import shell, scheme, screenshot, wallpaper, preset
|
from zshell.subcommands import shell, scheme, screenshot, wallpaper
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer()
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ app.add_typer(shell.app, name="shell")
|
|||||||
app.add_typer(scheme.app, name="scheme")
|
app.add_typer(scheme.app, name="scheme")
|
||||||
app.add_typer(screenshot.app, name="screenshot")
|
app.add_typer(screenshot.app, name="screenshot")
|
||||||
app.add_typer(wallpaper.app, name="wallpaper")
|
app.add_typer(wallpaper.app, name="wallpaper")
|
||||||
app.add_typer(preset.app, name="preset")
|
# app.add_typer(preset.app, name="preset")
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,544 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "catppuccin",
|
|
||||||
"name": "Catppuccin",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"author": "Catppuccin Org",
|
|
||||||
"description": "Soothing pastel theme for the high-spirited!",
|
|
||||||
"dark": {},
|
|
||||||
"light": {},
|
|
||||||
"variants": {
|
|
||||||
"type": "multi",
|
|
||||||
"defaults": {
|
|
||||||
"dark": { "flavor": "mocha", "accent": "mauve" },
|
|
||||||
"light": { "flavor": "latte", "accent": "mauve" }
|
|
||||||
},
|
|
||||||
"flavors": [
|
|
||||||
{
|
|
||||||
"id": "latte",
|
|
||||||
"name": "Latte",
|
|
||||||
"light": {
|
|
||||||
"surface": "#ccd0da",
|
|
||||||
"surfaceText": "#4c4f69",
|
|
||||||
"surfaceVariant": "#eff1f5",
|
|
||||||
"surfaceVariantText": "#6c6f85",
|
|
||||||
"background": "#eff1f5",
|
|
||||||
"backgroundText": "#4c4f69",
|
|
||||||
"outline": "#9ca0b0",
|
|
||||||
"surfaceContainer": "#eff1f5",
|
|
||||||
"surfaceContainerHigh": "#e6e9ef",
|
|
||||||
"surfaceContainerHighest": "#dce0e8",
|
|
||||||
"error": "#d20f39",
|
|
||||||
"warning": "#fe640b",
|
|
||||||
"info": "#1e66f5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "frappe",
|
|
||||||
"name": "Frappé",
|
|
||||||
"dark": {
|
|
||||||
"surface": "#414559",
|
|
||||||
"surfaceText": "#c6d0f5",
|
|
||||||
"surfaceVariant": "#303446",
|
|
||||||
"surfaceVariantText": "#a5adce",
|
|
||||||
"background": "#303446",
|
|
||||||
"backgroundText": "#c6d0f5",
|
|
||||||
"outline": "#737994",
|
|
||||||
"surfaceContainer": "#303446",
|
|
||||||
"surfaceContainerHigh": "#292c3c",
|
|
||||||
"surfaceContainerHighest": "#232634",
|
|
||||||
"error": "#e78284",
|
|
||||||
"warning": "#ef9f76",
|
|
||||||
"info": "#8caaee"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "macchiato",
|
|
||||||
"name": "Macchiato",
|
|
||||||
"dark": {
|
|
||||||
"surface": "#363a4f",
|
|
||||||
"surfaceText": "#cad3f5",
|
|
||||||
"surfaceVariant": "#24273a",
|
|
||||||
"surfaceVariantText": "#a5adcb",
|
|
||||||
"background": "#24273a",
|
|
||||||
"backgroundText": "#cad3f5",
|
|
||||||
"outline": "#6e738d",
|
|
||||||
"surfaceContainer": "#24273a",
|
|
||||||
"surfaceContainerHigh": "#1e2030",
|
|
||||||
"surfaceContainerHighest": "#181926",
|
|
||||||
"error": "#ed8796",
|
|
||||||
"warning": "#f5a97f",
|
|
||||||
"info": "#8aadf4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "mocha",
|
|
||||||
"name": "Mocha",
|
|
||||||
"dark": {
|
|
||||||
"surface": "#313244",
|
|
||||||
"surfaceText": "#cdd6f4",
|
|
||||||
"surfaceVariant": "#1e1e2e",
|
|
||||||
"surfaceVariantText": "#a6adc8",
|
|
||||||
"background": "#1e1e2e",
|
|
||||||
"backgroundText": "#cdd6f4",
|
|
||||||
"outline": "#6c7086",
|
|
||||||
"surfaceContainer": "#1e1e2e",
|
|
||||||
"surfaceContainerHigh": "#181825",
|
|
||||||
"surfaceContainerHighest": "#11111b",
|
|
||||||
"error": "#f38ba8",
|
|
||||||
"warning": "#fab387",
|
|
||||||
"info": "#89b4fa"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"accents": [
|
|
||||||
{
|
|
||||||
"id": "rosewater",
|
|
||||||
"name": "Rosewater",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#dc8a78",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#e1a99d",
|
|
||||||
"secondary": "#d8c7c4",
|
|
||||||
"surfaceTint": "#e1a99d"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#f2d5cf",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#b8a5a6",
|
|
||||||
"secondary": "#a2748b",
|
|
||||||
"surfaceTint": "#b8a5a6"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#f4dbd6",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#b6a6a7",
|
|
||||||
"secondary": "#9f6f8d",
|
|
||||||
"surfaceTint": "#b6a6a7"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#f5e0dc",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#b5a6a8",
|
|
||||||
"secondary": "#9d6d87",
|
|
||||||
"surfaceTint": "#b5a6a8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "flamingo",
|
|
||||||
"name": "Flamingo",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#dd7878",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#e29c9d",
|
|
||||||
"secondary": "#d7c3c4",
|
|
||||||
"surfaceTint": "#e29c9d"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#eebebe",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#b5949a",
|
|
||||||
"secondary": "#9d6b80",
|
|
||||||
"surfaceTint": "#b5949a"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#f0c6c6",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#b3979c",
|
|
||||||
"secondary": "#996780",
|
|
||||||
"surfaceTint": "#b3979c"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#f2cdcd",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#b3999e",
|
|
||||||
"secondary": "#98667c",
|
|
||||||
"surfaceTint": "#b3999e"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "pink",
|
|
||||||
"name": "Pink",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#ea76cb",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#eb9bd7",
|
|
||||||
"secondary": "#d9c7d5",
|
|
||||||
"surfaceTint": "#eb9bd7"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#f4b8e4",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#b990b5",
|
|
||||||
"secondary": "#996e9e",
|
|
||||||
"surfaceTint": "#b990b5"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#f5bde6",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#b791b2",
|
|
||||||
"secondary": "#95689a",
|
|
||||||
"surfaceTint": "#b791b2"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#f5c2e7",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#b591b0",
|
|
||||||
"secondary": "#966597",
|
|
||||||
"surfaceTint": "#b591b0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "mauve",
|
|
||||||
"name": "Mauve",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#8839ef",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#a670f1",
|
|
||||||
"secondary": "#c2b8d0",
|
|
||||||
"surfaceTint": "#a670f1"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#ca9ee6",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#9c7eb6",
|
|
||||||
"secondary": "#7d6799",
|
|
||||||
"surfaceTint": "#9c7eb6"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#c6a0f6",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#967cbe",
|
|
||||||
"secondary": "#766597",
|
|
||||||
"surfaceTint": "#967cbe"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#cba6f7",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#977ebb",
|
|
||||||
"secondary": "#756294",
|
|
||||||
"surfaceTint": "#977ebb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "red",
|
|
||||||
"name": "Red",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#d20f39",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#da5371",
|
|
||||||
"secondary": "#c0a0a8",
|
|
||||||
"surfaceTint": "#da5371"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#e78284",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#b06a72",
|
|
||||||
"secondary": "#8b5d66",
|
|
||||||
"surfaceTint": "#b06a72"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#ed8796",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#b16b7a",
|
|
||||||
"secondary": "#865a69",
|
|
||||||
"surfaceTint": "#b16b7a"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#f38ba8",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#b46b84",
|
|
||||||
"secondary": "#85596b",
|
|
||||||
"surfaceTint": "#b46b84"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "maroon",
|
|
||||||
"name": "Maroon",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#e64553",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#e87883",
|
|
||||||
"secondary": "#cfb7ba",
|
|
||||||
"surfaceTint": "#e87883"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#ea999c",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#b27a83",
|
|
||||||
"secondary": "#92626f",
|
|
||||||
"surfaceTint": "#b27a83"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#ee99a0",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#b27781",
|
|
||||||
"secondary": "#8c5e6c",
|
|
||||||
"surfaceTint": "#b27781"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#eba0ac",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#ae7987",
|
|
||||||
"secondary": "#895b6c",
|
|
||||||
"surfaceTint": "#ae7987"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "peach",
|
|
||||||
"name": "Peach",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#fe640b",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#f98e51",
|
|
||||||
"secondary": "#c9b7ad",
|
|
||||||
"surfaceTint": "#f98e51"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#ef9f76",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#b67f68",
|
|
||||||
"secondary": "#8f6a5f",
|
|
||||||
"surfaceTint": "#b67f68"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#f5a97f",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#b7836a",
|
|
||||||
"secondary": "#8c695e",
|
|
||||||
"surfaceTint": "#b7836a"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#fab387",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#b8876d",
|
|
||||||
"secondary": "#8b6a5d",
|
|
||||||
"surfaceTint": "#b8876d"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "yellow",
|
|
||||||
"name": "Yellow",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#df8e1d",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#e4ac5d",
|
|
||||||
"secondary": "#c6baaa",
|
|
||||||
"surfaceTint": "#e4ac5d"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#e5c890",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#af9b7a",
|
|
||||||
"secondary": "#948062",
|
|
||||||
"surfaceTint": "#af9b7a"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#eed49f",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#b2a181",
|
|
||||||
"secondary": "#947e62",
|
|
||||||
"surfaceTint": "#b2a181"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#f9e2af",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#b8a889",
|
|
||||||
"secondary": "#978265",
|
|
||||||
"surfaceTint": "#b8a889"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "green",
|
|
||||||
"name": "Green",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#40a02b",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#74b867",
|
|
||||||
"secondary": "#9fbd9b",
|
|
||||||
"surfaceTint": "#74b867"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#a6d189",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#83a275",
|
|
||||||
"secondary": "#648e5e",
|
|
||||||
"surfaceTint": "#83a275"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#a6da95",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#80a57a",
|
|
||||||
"secondary": "#5c8a61",
|
|
||||||
"surfaceTint": "#80a57a"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#a6e3a1",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#7ea87f",
|
|
||||||
"secondary": "#5b8964",
|
|
||||||
"surfaceTint": "#7ea87f"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "teal",
|
|
||||||
"name": "Teal",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#179299",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#57aeb4",
|
|
||||||
"secondary": "#93b4b7",
|
|
||||||
"surfaceTint": "#57aeb4"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#81c8be",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#699b9a",
|
|
||||||
"secondary": "#588084",
|
|
||||||
"surfaceTint": "#699b9a"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#8bd5ca",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#6da29f",
|
|
||||||
"secondary": "#577e83",
|
|
||||||
"surfaceTint": "#6da29f"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#94e2d5",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#71a8a4",
|
|
||||||
"secondary": "#588284",
|
|
||||||
"surfaceTint": "#71a8a4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "sky",
|
|
||||||
"name": "Sky",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#04a5e5",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#4abcea",
|
|
||||||
"secondary": "#a4b9c2",
|
|
||||||
"surfaceTint": "#4abcea"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#99d1db",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#79a2af",
|
|
||||||
"secondary": "#628494",
|
|
||||||
"surfaceTint": "#79a2af"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#91d7e3",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#71a3b0",
|
|
||||||
"secondary": "#5e7e8c",
|
|
||||||
"surfaceTint": "#71a3b0"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#89dceb",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#69a3b3",
|
|
||||||
"secondary": "#5a7b88",
|
|
||||||
"surfaceTint": "#69a3b3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "sapphire",
|
|
||||||
"name": "Sapphire",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#209fb5",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#5db8c8",
|
|
||||||
"secondary": "#9eb9be",
|
|
||||||
"surfaceTint": "#5db8c8"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#85c1dc",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#6b96af",
|
|
||||||
"secondary": "#5e7b8e",
|
|
||||||
"surfaceTint": "#6b96af"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#7dc4e4",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#6396b1",
|
|
||||||
"secondary": "#5a7486",
|
|
||||||
"surfaceTint": "#6396b1"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#74c7ec",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#5a95b4",
|
|
||||||
"secondary": "#567080",
|
|
||||||
"surfaceTint": "#5a95b4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "blue",
|
|
||||||
"name": "Blue",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#1e66f5",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#5c90f5",
|
|
||||||
"secondary": "#b1bacb",
|
|
||||||
"surfaceTint": "#5c90f5"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#8caaee",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#7086bc",
|
|
||||||
"secondary": "#637195",
|
|
||||||
"surfaceTint": "#7086bc"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#8aadf4",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#6c85bc",
|
|
||||||
"secondary": "#5f6d8f",
|
|
||||||
"surfaceTint": "#6c85bc"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#89b4fa",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#6987bd",
|
|
||||||
"secondary": "#5d6c8b",
|
|
||||||
"surfaceTint": "#6987bd"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "lavender",
|
|
||||||
"name": "Lavender",
|
|
||||||
"latte": {
|
|
||||||
"primary": "#7287fd",
|
|
||||||
"primaryText": "#eff1f5",
|
|
||||||
"primaryContainer": "#97a7fb",
|
|
||||||
"secondary": "#cdcfdd",
|
|
||||||
"surfaceTint": "#97a7fb"
|
|
||||||
},
|
|
||||||
"frappe": {
|
|
||||||
"primary": "#babbf1",
|
|
||||||
"primaryText": "#303446",
|
|
||||||
"primaryContainer": "#9192be",
|
|
||||||
"secondary": "#7175a1",
|
|
||||||
"surfaceTint": "#9192be"
|
|
||||||
},
|
|
||||||
"macchiato": {
|
|
||||||
"primary": "#b7bdf8",
|
|
||||||
"primaryText": "#24273a",
|
|
||||||
"primaryContainer": "#8b91bf",
|
|
||||||
"secondary": "#6b709d",
|
|
||||||
"surfaceTint": "#8b91bf"
|
|
||||||
},
|
|
||||||
"mocha": {
|
|
||||||
"primary": "#b4befe",
|
|
||||||
"primaryText": "#1e1e2e",
|
|
||||||
"primaryContainer": "#878ec0",
|
|
||||||
"secondary": "#676d99",
|
|
||||||
"surfaceTint": "#878ec0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,544 @@
|
|||||||
|
_data = {
|
||||||
|
"id": "catppuccin",
|
||||||
|
"name": "Catppuccin",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": "Catppuccin Org",
|
||||||
|
"description": "Soothing pastel theme for the high-spirited!",
|
||||||
|
"dark": {},
|
||||||
|
"light": {},
|
||||||
|
"variants": {
|
||||||
|
"type": "multi",
|
||||||
|
"defaults": {
|
||||||
|
"dark": {"m3flavor": "mocha", "m3accent": "mauve"},
|
||||||
|
"light": {"m3flavor": "latte", "m3accent": "mauve"},
|
||||||
|
},
|
||||||
|
"flavors": [
|
||||||
|
{
|
||||||
|
"id": "latte",
|
||||||
|
"name": "Latte",
|
||||||
|
"light": {
|
||||||
|
"m3surface": "#ccd0da",
|
||||||
|
"m3surfaceText": "#4c4f69",
|
||||||
|
"m3surfaceVariant": "#eff1f5",
|
||||||
|
"m3surfaceVariantText": "#6c6f85",
|
||||||
|
"m3background": "#eff1f5",
|
||||||
|
"m3backgroundText": "#4c4f69",
|
||||||
|
"m3outline": "#9ca0b0",
|
||||||
|
"m3surfaceContainer": "#eff1f5",
|
||||||
|
"m3surfaceContainerHigh": "#e6e9ef",
|
||||||
|
"m3surfaceContainerHighest": "#dce0e8",
|
||||||
|
"m3error": "#d20f39",
|
||||||
|
"m3warning": "#fe640b",
|
||||||
|
"m3info": "#1e66f5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "frappe",
|
||||||
|
"name": "Frappé",
|
||||||
|
"dark": {
|
||||||
|
"m3surface": "#414559",
|
||||||
|
"m3surfaceText": "#c6d0f5",
|
||||||
|
"m3surfaceVariant": "#303446",
|
||||||
|
"m3surfaceVariantText": "#a5adce",
|
||||||
|
"m3background": "#303446",
|
||||||
|
"m3backgroundText": "#c6d0f5",
|
||||||
|
"m3outline": "#737994",
|
||||||
|
"m3surfaceContainer": "#303446",
|
||||||
|
"m3surfaceContainerHigh": "#292c3c",
|
||||||
|
"m3surfaceContainerHighest": "#232634",
|
||||||
|
"m3error": "#e78284",
|
||||||
|
"m3warning": "#ef9f76",
|
||||||
|
"m3info": "#8caaee",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "macchiato",
|
||||||
|
"name": "Macchiato",
|
||||||
|
"dark": {
|
||||||
|
"m3surface": "#363a4f",
|
||||||
|
"m3surfaceText": "#cad3f5",
|
||||||
|
"m3surfaceVariant": "#24273a",
|
||||||
|
"m3surfaceVariantText": "#a5adcb",
|
||||||
|
"m3background": "#24273a",
|
||||||
|
"m3backgroundText": "#cad3f5",
|
||||||
|
"m3outline": "#6e738d",
|
||||||
|
"m3surfaceContainer": "#24273a",
|
||||||
|
"m3surfaceContainerHigh": "#1e2030",
|
||||||
|
"m3surfaceContainerHighest": "#181926",
|
||||||
|
"m3error": "#ed8796",
|
||||||
|
"m3warning": "#f5a97f",
|
||||||
|
"m3info": "#8aadf4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mocha",
|
||||||
|
"name": "Mocha",
|
||||||
|
"dark": {
|
||||||
|
"m3surface": "#313244",
|
||||||
|
"m3surfaceText": "#cdd6f4",
|
||||||
|
"m3surfaceVariant": "#1e1e2e",
|
||||||
|
"m3surfaceVariantText": "#a6adc8",
|
||||||
|
"m3background": "#1e1e2e",
|
||||||
|
"m3backgroundText": "#cdd6f4",
|
||||||
|
"m3outline": "#6c7086",
|
||||||
|
"m3surfaceContainer": "#1e1e2e",
|
||||||
|
"m3surfaceContainerHigh": "#181825",
|
||||||
|
"m3surfaceContainerHighest": "#11111b",
|
||||||
|
"m3error": "#f38ba8",
|
||||||
|
"m3warning": "#fab387",
|
||||||
|
"m3info": "#89b4fa",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"accents": [
|
||||||
|
{
|
||||||
|
"id": "rosewater",
|
||||||
|
"name": "Rosewater",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#dc8a78",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#e1a99d",
|
||||||
|
"m3secondary": "#d8c7c4",
|
||||||
|
"m3surfaceTint": "#e1a99d",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#f2d5cf",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#b8a5a6",
|
||||||
|
"m3secondary": "#a2748b",
|
||||||
|
"m3surfaceTint": "#b8a5a6",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#f4dbd6",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#b6a6a7",
|
||||||
|
"m3secondary": "#9f6f8d",
|
||||||
|
"m3surfaceTint": "#b6a6a7",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#f5e0dc",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#b5a6a8",
|
||||||
|
"m3secondary": "#9d6d87",
|
||||||
|
"m3surfaceTint": "#b5a6a8",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "flamingo",
|
||||||
|
"name": "Flamingo",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#dd7878",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#e29c9d",
|
||||||
|
"m3secondary": "#d7c3c4",
|
||||||
|
"m3surfaceTint": "#e29c9d",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#eebebe",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#b5949a",
|
||||||
|
"m3secondary": "#9d6b80",
|
||||||
|
"m3surfaceTint": "#b5949a",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#f0c6c6",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#b3979c",
|
||||||
|
"m3secondary": "#996780",
|
||||||
|
"m3surfaceTint": "#b3979c",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#f2cdcd",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#b3999e",
|
||||||
|
"m3secondary": "#98667c",
|
||||||
|
"m3surfaceTint": "#b3999e",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "pink",
|
||||||
|
"name": "Pink",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#ea76cb",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#eb9bd7",
|
||||||
|
"m3secondary": "#d9c7d5",
|
||||||
|
"m3surfaceTint": "#eb9bd7",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#f4b8e4",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#b990b5",
|
||||||
|
"m3secondary": "#996e9e",
|
||||||
|
"m3surfaceTint": "#b990b5",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#f5bde6",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#b791b2",
|
||||||
|
"m3secondary": "#95689a",
|
||||||
|
"m3surfaceTint": "#b791b2",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#f5c2e7",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#b591b0",
|
||||||
|
"m3secondary": "#966597",
|
||||||
|
"m3surfaceTint": "#b591b0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mauve",
|
||||||
|
"name": "Mauve",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#8839ef",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#a670f1",
|
||||||
|
"m3secondary": "#c2b8d0",
|
||||||
|
"m3surfaceTint": "#a670f1",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#ca9ee6",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#9c7eb6",
|
||||||
|
"m3secondary": "#7d6799",
|
||||||
|
"m3surfaceTint": "#9c7eb6",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#c6a0f6",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#967cbe",
|
||||||
|
"m3secondary": "#766597",
|
||||||
|
"m3surfaceTint": "#967cbe",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#cba6f7",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#977ebb",
|
||||||
|
"m3secondary": "#756294",
|
||||||
|
"m3surfaceTint": "#977ebb",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "red",
|
||||||
|
"name": "Red",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#d20f39",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#da5371",
|
||||||
|
"m3secondary": "#c0a0a8",
|
||||||
|
"m3surfaceTint": "#da5371",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#e78284",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#b06a72",
|
||||||
|
"m3secondary": "#8b5d66",
|
||||||
|
"m3surfaceTint": "#b06a72",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#ed8796",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#b16b7a",
|
||||||
|
"m3secondary": "#865a69",
|
||||||
|
"m3surfaceTint": "#b16b7a",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#f38ba8",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#b46b84",
|
||||||
|
"m3secondary": "#85596b",
|
||||||
|
"m3surfaceTint": "#b46b84",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "maroon",
|
||||||
|
"name": "Maroon",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#e64553",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#e87883",
|
||||||
|
"m3secondary": "#cfb7ba",
|
||||||
|
"m3surfaceTint": "#e87883",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#ea999c",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#b27a83",
|
||||||
|
"m3secondary": "#92626f",
|
||||||
|
"m3surfaceTint": "#b27a83",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#ee99a0",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#b27781",
|
||||||
|
"m3secondary": "#8c5e6c",
|
||||||
|
"m3surfaceTint": "#b27781",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#eba0ac",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#ae7987",
|
||||||
|
"m3secondary": "#895b6c",
|
||||||
|
"m3surfaceTint": "#ae7987",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "peach",
|
||||||
|
"name": "Peach",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#fe640b",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#f98e51",
|
||||||
|
"m3secondary": "#c9b7ad",
|
||||||
|
"m3surfaceTint": "#f98e51",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#ef9f76",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#b67f68",
|
||||||
|
"m3secondary": "#8f6a5f",
|
||||||
|
"m3surfaceTint": "#b67f68",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#f5a97f",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#b7836a",
|
||||||
|
"m3secondary": "#8c695e",
|
||||||
|
"m3surfaceTint": "#b7836a",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#fab387",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#b8876d",
|
||||||
|
"m3secondary": "#8b6a5d",
|
||||||
|
"m3surfaceTint": "#b8876d",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "yellow",
|
||||||
|
"name": "Yellow",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#df8e1d",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#e4ac5d",
|
||||||
|
"m3secondary": "#c6baaa",
|
||||||
|
"m3surfaceTint": "#e4ac5d",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#e5c890",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#af9b7a",
|
||||||
|
"m3secondary": "#948062",
|
||||||
|
"m3surfaceTint": "#af9b7a",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#eed49f",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#b2a181",
|
||||||
|
"m3secondary": "#947e62",
|
||||||
|
"m3surfaceTint": "#b2a181",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#f9e2af",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#b8a889",
|
||||||
|
"m3secondary": "#978265",
|
||||||
|
"m3surfaceTint": "#b8a889",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "green",
|
||||||
|
"name": "Green",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#40a02b",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#74b867",
|
||||||
|
"m3secondary": "#9fbd9b",
|
||||||
|
"m3surfaceTint": "#74b867",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#a6d189",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#83a275",
|
||||||
|
"m3secondary": "#648e5e",
|
||||||
|
"m3surfaceTint": "#83a275",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#a6da95",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#80a57a",
|
||||||
|
"m3secondary": "#5c8a61",
|
||||||
|
"m3surfaceTint": "#80a57a",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#a6e3a1",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#7ea87f",
|
||||||
|
"m3secondary": "#5b8964",
|
||||||
|
"m3surfaceTint": "#7ea87f",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "teal",
|
||||||
|
"name": "Teal",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#179299",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#57aeb4",
|
||||||
|
"m3secondary": "#93b4b7",
|
||||||
|
"m3surfaceTint": "#57aeb4",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#81c8be",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#699b9a",
|
||||||
|
"m3secondary": "#588084",
|
||||||
|
"m3surfaceTint": "#699b9a",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#8bd5ca",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#6da29f",
|
||||||
|
"m3secondary": "#577e83",
|
||||||
|
"m3surfaceTint": "#6da29f",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#94e2d5",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#71a8a4",
|
||||||
|
"m3secondary": "#588284",
|
||||||
|
"m3surfaceTint": "#71a8a4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sky",
|
||||||
|
"name": "Sky",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#04a5e5",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#4abcea",
|
||||||
|
"m3secondary": "#a4b9c2",
|
||||||
|
"m3surfaceTint": "#4abcea",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#99d1db",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#79a2af",
|
||||||
|
"m3secondary": "#628494",
|
||||||
|
"m3surfaceTint": "#79a2af",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#91d7e3",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#71a3b0",
|
||||||
|
"m3secondary": "#5e7e8c",
|
||||||
|
"m3surfaceTint": "#71a3b0",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#89dceb",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#69a3b3",
|
||||||
|
"m3secondary": "#5a7b88",
|
||||||
|
"m3surfaceTint": "#69a3b3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sapphire",
|
||||||
|
"name": "Sapphire",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#209fb5",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#5db8c8",
|
||||||
|
"m3secondary": "#9eb9be",
|
||||||
|
"m3surfaceTint": "#5db8c8",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#85c1dc",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#6b96af",
|
||||||
|
"m3secondary": "#5e7b8e",
|
||||||
|
"m3surfaceTint": "#6b96af",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#7dc4e4",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#6396b1",
|
||||||
|
"m3secondary": "#5a7486",
|
||||||
|
"m3surfaceTint": "#6396b1",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#74c7ec",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#5a95b4",
|
||||||
|
"m3secondary": "#567080",
|
||||||
|
"m3surfaceTint": "#5a95b4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "blue",
|
||||||
|
"name": "Blue",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#1e66f5",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#5c90f5",
|
||||||
|
"m3secondary": "#b1bacb",
|
||||||
|
"m3surfaceTint": "#5c90f5",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#8caaee",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#7086bc",
|
||||||
|
"m3secondary": "#637195",
|
||||||
|
"m3surfaceTint": "#7086bc",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#8aadf4",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#6c85bc",
|
||||||
|
"m3secondary": "#5f6d8f",
|
||||||
|
"m3surfaceTint": "#6c85bc",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#89b4fa",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#6987bd",
|
||||||
|
"m3secondary": "#5d6c8b",
|
||||||
|
"m3surfaceTint": "#6987bd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lavender",
|
||||||
|
"name": "Lavender",
|
||||||
|
"latte": {
|
||||||
|
"m3primary": "#7287fd",
|
||||||
|
"m3primaryText": "#eff1f5",
|
||||||
|
"m3primaryContainer": "#97a7fb",
|
||||||
|
"m3secondary": "#cdcfdd",
|
||||||
|
"m3surfaceTint": "#97a7fb",
|
||||||
|
},
|
||||||
|
"frappe": {
|
||||||
|
"m3primary": "#babbf1",
|
||||||
|
"m3primaryText": "#303446",
|
||||||
|
"m3primaryContainer": "#9192be",
|
||||||
|
"m3secondary": "#7175a1",
|
||||||
|
"m3surfaceTint": "#9192be",
|
||||||
|
},
|
||||||
|
"macchiato": {
|
||||||
|
"m3primary": "#b7bdf8",
|
||||||
|
"m3primaryText": "#24273a",
|
||||||
|
"m3primaryContainer": "#8b91bf",
|
||||||
|
"m3secondary": "#6b709d",
|
||||||
|
"m3surfaceTint": "#8b91bf",
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"m3primary": "#b4befe",
|
||||||
|
"m3primaryText": "#1e1e2e",
|
||||||
|
"m3primaryContainer": "#878ec0",
|
||||||
|
"m3secondary": "#676d99",
|
||||||
|
"m3surfaceTint": "#878ec0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user