4 Commits

217 changed files with 4511 additions and 14810 deletions
-42
View File
@@ -1,42 +0,0 @@
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
-65
View File
@@ -1,65 +0,0 @@
name: Python
on:
pull_request:
jobs:
lint-format:
runs-on: alpine
container: node:26-alpine
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install tools
run: |
apk add --no-cache \
git \
python3 \
py3-pip
python3 -m venv .venv
. .venv/bin/activate
pip install --no-cache-dir ruff
- name: Format check
continue-on-error: true
run: |
. .venv/bin/activate
ruff format --check .
- name: Lint
run: |
. .venv/bin/activate
ruff check .
test:
runs-on: alpine
container: node:26-alpine
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install tools
run: |
apk add --no-cache \
git \
python3 \
py3-pip \
py3-pillow \
build-base
python3 -m venv .venv
. .venv/bin/activate
pip install --no-cache-dir \
typer \
pillow \
materialyoucolor \
jinja2 \
pytest
- name: Test
run: |
. .venv/bin/activate
cd cli
python -m pytest tests/ -v
-72
View File
@@ -1,72 +0,0 @@
name: Lint & Format (Rust)
on:
pull_request:
jobs:
lint-format:
runs-on: alpine
container: node:26-alpine
env:
CARGO_HOME: ${{ github.workspace }}/.cargo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache cargo packages
uses: actions/cache@v4
env:
cache-name: cache-cargo-packages
with:
path: |
.cargo/registry
.cargo/git
target
key: rust-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
rust-${{ runner.os }}-build-${{ env.cache-name }}-
rust-${{ runner.os }}-build-
rust-
- name: Install tools
run: |
apk add --no-cache \
git \
cargo \
rust \
rustfmt \
rust-clippy
- name: Format check
continue-on-error: true
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
for manifest in $(find . -name "Cargo.toml"); do
cargo fmt --manifest-path "$manifest" --check && \
echo "$manifest: formatting OK" || \
echo "$manifest: needs formatting"
done
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
- name: Clippy
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
status=0
for manifest in $(find . -name "Cargo.toml"); do
cargo clippy --manifest-path "$manifest" --all-targets --all-features -- -D warnings && \
echo "$manifest: Clippy passed" || \
{ echo "$manifest: Clippy failed"; status=1; }
done
exit $status
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
+1 -2
View File
@@ -1,4 +1,4 @@
**/__pycache__/
./__pycache__/
./result/
.pyre/
.cache/
@@ -12,4 +12,3 @@ pkg/
uv.lock
.qtcreator/
dist/
**/target/
-3
View File
@@ -1,3 +0,0 @@
.venv/
scripts/fzf.js
scripts/fuzzysort.js
-13
View File
@@ -1,13 +0,0 @@
{
"semi": true,
"singleQuote": false,
"jsxSingleQuote": false,
"tabWidth": 4,
"printWidth": 80,
"trailingComma": "es5",
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always",
"endOfLine": "lf",
"proseWrap": "preserve"
}
+1 -8
View File
@@ -31,13 +31,6 @@ if("shell" IN_LIST ENABLE_MODULES)
foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths)
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
endforeach()
# Disable watching for changes
file(READ shell.qml SHELL_QML)
string(REPLACE "settings.watchFiles: true" "settings.watchFiles: false" SHELL_QML "${SHELL_QML}")
file(WRITE "${CMAKE_BINARY_DIR}/qml/shell.qml" "${SHELL_QML}")
install(FILES "${CMAKE_BINARY_DIR}/qml/shell.qml" DESTINATION "${INSTALL_QSCONFDIR}")
# Greeter
install(FILES shell.qml DESTINATION "${INSTALL_QSCONFDIR}")
install(DIRECTORY Greeter/ DESTINATION "${INSTALL_GREETERCONFDIR}")
endif()
+2 -2
View File
@@ -2,7 +2,7 @@ import QtQuick
import qs.Config
NumberAnimation {
duration: Appearance.anim.durations.normal
easing.bezierCurve: Appearance.anim.curves.standard
duration: MaterialEasing.standardTime
easing.bezierCurve: MaterialEasing.standard
easing.type: Easing.BezierSpline
}
+2 -16
View File
@@ -8,34 +8,20 @@ Item {
id: root
property alias active: splitButton.active
property alias buttonAlias: splitButton
property bool enabled: true
property alias expanded: splitButton.expanded
property int expandedZ: 100
required property string label
property alias menuItems: splitButton.menuItems
property bool shouldBeActive: true
property alias type: splitButton.type
signal selected(item: MenuItem)
anchors.left: parent.left
anchors.right: parent.right
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
clip: false
implicitHeight: row.implicitHeight + Appearance.padding.smaller * 2
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
z: root.expanded ? expandedZ : -1
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
RowLayout {
id: row
-1
View File
@@ -15,7 +15,6 @@ Text {
color: DynamicColors.palette.m3onSurface
font.family: Appearance.font.family.sans
font.pointSize: Appearance.font.size.normal
linkColor: DynamicColors.palette.m3onPrimaryFixedVariant
renderType: Text.NativeRendering
textFormat: Text.PlainText
-33
View File
@@ -1,33 +0,0 @@
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;
}
}
}
+2 -1
View File
@@ -41,11 +41,12 @@ CustomRect {
color: type === IconButton.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour
implicitHeight: label.implicitHeight + padding * 2
implicitWidth: implicitHeight
radius: internalChecked ? 6 : (implicitHeight / 2 * Math.min(1, 1)) * Appearance.rounding.scale
radius: internalChecked ? 6 : implicitHeight / 2 * Math.min(1, 1)
Behavior on radius {
Anim {
id: radiusAnim
}
}
-4
View File
@@ -7,8 +7,4 @@ JsonObject {
property real alignX: 0.5
property real alignY: 0.5
property real zoom: 1.0
property real sourceClipX: 0
property real sourceClipY: 0
property real sourceClipW: 0
property real sourceClipH: 0
}
+12 -1
View File
@@ -8,6 +8,10 @@ JsonObject {
id: "workspaces",
enabled: true
},
{
id: "audio",
enabled: true
},
{
id: "media",
enabled: true
@@ -20,6 +24,10 @@ JsonObject {
id: "updates",
enabled: true
},
{
id: "dash",
enabled: true
},
{
id: "spacer",
enabled: true
@@ -40,6 +48,10 @@ JsonObject {
id: "tray",
enabled: true
},
{
id: "upower",
enabled: false
},
{
id: "network",
enabled: false
@@ -58,7 +70,6 @@ JsonObject {
property Popouts popouts: Popouts {
}
property int rounding: 8
property int smoothing: 32
component Popouts: JsonObject {
property bool activeWindow: true
-8
View File
@@ -1,13 +1,5 @@
import Quickshell.Io
JsonObject {
property Presets presets: Presets {
}
property string schemeType: "vibrant"
component Presets: JsonObject {
property string accent: ""
property string name: ""
property string variant: ""
}
}
+2 -44
View File
@@ -22,9 +22,7 @@ Singleton {
property alias notifs: adapter.notifs
property alias osd: adapter.osd
property alias overview: adapter.overview
property alias plugins: adapter.plugins
property bool recentlySaved: false
property alias screenshot: adapter.screenshot
property alias services: adapter.services
property alias sidebar: adapter.sidebar
property alias utilities: adapter.utilities
@@ -84,10 +82,6 @@ Singleton {
wallFadeDuration: background.wallFadeDuration,
enabled: background.enabled,
alignX: background.alignX,
sourceClipX: background.sourceClipX,
sourceClipY: background.sourceClipY,
sourceClipW: background.sourceClipW,
sourceClipH: background.sourceClipH,
alignY: background.alignY,
zoom: background.zoom
};
@@ -99,7 +93,6 @@ Singleton {
hideWhenNotif: barConfig.hideWhenNotif,
rounding: barConfig.rounding,
border: barConfig.border,
smoothing: barConfig.smoothing,
height: barConfig.height,
popouts: {
tray: barConfig.popouts.tray,
@@ -116,12 +109,7 @@ Singleton {
function serializeColors(): var {
return {
schemeType: colors.schemeType,
presets: {
name: colors.presets.name,
variant: colors.presets.variant,
accent: colors.presets.accent
}
schemeType: colors.schemeType
};
}
@@ -140,9 +128,7 @@ Singleton {
background: serializeBackground(),
launcher: serializeLauncher(),
colors: serializeColors(),
dock: serializeDock(),
screenshot: serializeScreenshot(),
plugins: serializePlugins()
dock: serializeDock()
};
}
@@ -194,7 +180,6 @@ Singleton {
logo: general.logo,
wallpaperPath: general.wallpaperPath,
desktopIcons: general.desktopIcons,
dateFormat: general.dateFormat,
color: {
mode: general.color.mode,
smart: general.color.smart,
@@ -248,8 +233,6 @@ Singleton {
return {
recolorLogo: lock.recolorLogo,
enableFprint: lock.enableFprint,
showNotifContent: lock.showNotifContent,
showNotifIcon: lock.showNotifIcon,
maxFprintTries: lock.maxFprintTries,
blurAmount: lock.blurAmount,
sizes: {
@@ -291,27 +274,6 @@ Singleton {
};
}
function serializePlugins(): var {
return {
enabled: plugins.enabled,
entries: plugins.entries
};
}
function serializeScreenshot(): var {
return {
enable_pp: screenshot.enable_pp,
mode: screenshot.mode,
corner_radius: screenshot.corner_radius,
drop_shadow: screenshot.drop_shadow,
rounded_corners: screenshot.rounded_corners,
shadow_blur_radius: screenshot.shadow_blur_radius,
shadow_color: screenshot.shadow_color,
shadow_offset_x: screenshot.shadow_offset_x,
shadow_offset_y: screenshot.shadow_offset_y
};
}
function serializeServices(): var {
return {
weatherLocation: services.weatherLocation,
@@ -467,10 +429,6 @@ Singleton {
}
property Overview overview: Overview {
}
property PluginConfig plugins: PluginConfig {
}
property Screenshot screenshot: Screenshot {
}
property Services services: Services {
}
property SidebarConfig sidebar: SidebarConfig {
+6 -38
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import QtQuick
import ZShell
import qs.Helpers
@@ -30,10 +29,9 @@ Singleton {
readonly property alias wallLuminance: analyser.luminance
function alterColor(c: color, a: real, layer: int): color {
const initLuminance = getLuminance(c);
const luminance = Math.max(initLuminance, 0.001);
const luminance = getLuminance(c);
const offset = (!light || layer == 1 ? 1 : -layer / 2) * (light ? 0.2 : 0.3) * (0.2 + 0.3 * (1 - transparency.base)) * (1 + wallLuminance * (light ? (layer == 1 ? 3 : 1) : 2.5));
const offset = (!light || layer == 1 ? 1 : -layer / 2) * (light ? 0.2 : 0.3) * (1 - transparency.base) * (1 + wallLuminance * (light ? (layer == 1 ? 3 : 1) : 2.5));
const scale = (luminance + offset) / luminance;
const r = Math.max(0, Math.min(1, c.r * scale));
const g = Math.max(0, Math.min(1, c.g * scale));
@@ -81,32 +79,10 @@ Singleton {
}
function reloadHyprRules(): void {
const blur = transparency.enabled ? 1 : 0;
const alpha = 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}`);
const barStr = "keyword layerrule %1 %2, match:namespace ZShell-Bar";
const authStr = "keyword layerrule %1 %2, match:namespace ZShell-Auth";
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)]);
}
function setMode(mode: string): void {
@@ -117,14 +93,6 @@ Singleton {
Component.onCompleted: debounceTimer.triggered()
Connections {
function onUsingLuaChanged(): void {
root.reloadHyprRules();
}
target: Hyprland
}
Connections {
function onConfigReloaded(): void {
root.reloadHyprRules();
-1
View File
@@ -6,7 +6,6 @@ JsonObject {
}
property Color color: Color {
}
property string dateFormat: "ddd d MMM - hh:mm:ss"
property bool desktopIcons: false
property Idle idle: Idle {
}
-2
View File
@@ -5,8 +5,6 @@ JsonObject {
property bool enableFprint: true
property int maxFprintTries: 3
property bool recolorLogo: false
property bool showNotifContent: false
property bool showNotifIcon: true
property Sizes sizes: Sizes {
}
-11
View File
@@ -1,11 +0,0 @@
import Quickshell.Io
JsonObject {
property bool enabled: false
property list<var> entries: [
{
id: "Plugin",
enabled: false
},
]
}
-13
View File
@@ -1,13 +0,0 @@
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
}
+175 -24
View File
@@ -3,33 +3,184 @@ import QtQuick
Canvas {
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 real penWidth: 4
property var points: []
property var pendingSegments: []
property bool strokeActive: false
property var strokes: []
function clear(): void {
var ctx = getContext('2d');
root.points = [];
ctx.reset();
root.requestPaint();
}
renderStrategy: Canvas.Cooperative
onPaint: {
if (points.length < 2)
function appendPoint(x, y) {
if (!strokeActive || strokes.length === 0)
return;
var ctx = root.getContext('2d');
ctx.save();
ctx.lineWidth = root.penWidth;
ctx.strokeStyle = root.penColor;
ctx.lineCap = "round";
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
for (var i = 1; i < points.length; i++)
ctx.lineTo(points[i].x, points[i].y);
ctx.stroke();
points = points.slice(points.length - 2);
ctx.restore();
const dx = x - lastPoint.x;
const dy = y - lastPoint.y;
if ((dx * dx + dy * dy) < (minPointDistance * minPointDistance))
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.lineJoin = "round";
ctx.lineWidth = penWidth;
ctx.strokeStyle = penColor;
ctx.fillStyle = penColor;
if (fullRepaintPending) {
fullRepaintPending = false;
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()
}
+5 -7
View File
@@ -30,10 +30,8 @@ CustomMouseArea {
const x = event.x;
const y = event.y;
if (root.visibilities.isDrawing && (event.buttons & Qt.LeftButton)) {
root.drawing.points.push(Qt.point(x, y));
root.drawing.requestPaint();
}
if (event.buttons & Qt.LeftButton)
root.drawing.appendPoint(x, y);
if (root.inLeftPanel(root.popout, x, y)) {
root.z = -2;
@@ -46,8 +44,7 @@ CustomMouseArea {
if (root.visibilities.isDrawing && (event.buttons & Qt.LeftButton)) {
root.panels.drawing.expanded = false;
root.drawing.points.push(Qt.point(x, y));
root.drawing.requestPaint();
root.drawing.beginStroke(x, y);
return;
}
@@ -55,6 +52,7 @@ CustomMouseArea {
root.drawing.clear();
}
onReleased: {
root.drawing.points = [];
if (root.visibilities.isDrawing)
root.drawing.endStroke();
}
}
-15
View File
@@ -12,37 +12,22 @@ Scope {
required property ShellScreen screen
ExclusionZone {
id: top
anchors.top: true
exclusiveZone: root.bar.exclusiveZone
}
ExclusionZone {
id: left
anchors.left: true
}
ExclusionZone {
id: right
anchors.right: true
}
ExclusionZone {
id: bottom
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 {
exclusiveZone: Config.barConfig.border
implicitHeight: 1
+1 -1
View File
@@ -78,7 +78,7 @@ CustomMouseArea {
const dragY = y - dragStart.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;
}
-11
View File
@@ -34,7 +34,6 @@ Item {
readonly property alias resourcesWrapper: resourcesWrapper
required property ShellScreen screen
readonly property alias settings: settings
readonly property alias settingsWrapper: settingsWrapper
readonly property alias sidebar: sidebar
readonly property alias toasts: toasts
readonly property alias utilities: utilities
@@ -177,15 +176,6 @@ Item {
visibilities: root.visibilities
}
Item {
id: settingsWrapper
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
clip: true
implicitHeight: settings.implicitHeight * (1 - settings.offsetScale)
implicitWidth: settings.implicitWidth
Settings.Wrapper {
id: settings
@@ -196,7 +186,6 @@ Item {
screen: root.screen
visibilities: root.visibilities
}
}
Dock.Wrapper {
id: dock
+18 -40
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import ZShell.Blobs
@@ -128,14 +127,6 @@ Variants {
Component.onCompleted: Visibilities.load(scope.modelData, this)
}
IpcHandler {
function toggleLauncher(fix: string): void {
visibilities.launcher = !visibilities.launcher;
}
target: "visibilities"
}
Binding {
property: "bar"
target: visibilities
@@ -158,7 +149,6 @@ Variants {
id: blobGroup
color: DynamicColors.palette.m3surface
smoothing: Config.barConfig.smoothing
Behavior on color {
CAnim {
@@ -180,34 +170,28 @@ Variants {
PanelBg {
id: dashBg
property real extraHeight: 0.2
deformAmount: 0.06
implicitHeight: panels.dashboard.height * (1 + extraHeight)
deformAmount: 0.08 * Config.appearance.deform.scale
implicitHeight: panels.dashboard.height
implicitWidth: panels.dashboard.width
panel: panels.dashboardWrapper
panel: panels.dashboard
radius: Appearance.rounding.normal
x: panels.dashboardWrapper.x + panels.dashboard.x + Config.barConfig.border
y: panels.dashboardWrapper.y + panels.dashboard.y + bar.implicitHeight - panels.dashboard.height * extraHeight
y: panels.dashboardWrapper.y + panels.dashboard.y + bar.implicitHeight
}
PanelBg {
id: launcherBg
property real extraHeight: 0.2
deformAmount: 0.06
implicitHeight: panels.launcher.height * (1 + extraHeight)
deformAmount: 0.08 * Config.appearance.deform.scale
panel: panels.launcher
radius: Appearance.rounding.smallest + 5
y: panels.launcher.y + bar.implicitHeight
}
PanelBg {
id: sidebarBg
bottomLeftRadius: 0
deformAmount: 0.04
deformAmount: 0.08 * Config.appearance.deform.scale
exclude: panels.sidebar.offsetScale > 0.08 ? [] : [utilsBg]
implicitHeight: panel.height * (1 / rawDeformMatrix.m22) + 2
panel: panels.sidebar
@@ -216,10 +200,10 @@ Variants {
PanelBg {
id: osdBg
deformAmount: 0.1
deformAmount: 0.1 * Config.appearance.deform.scale
implicitHeight: panels.osd.height
implicitWidth: panels.osd.width
panel: panels.osdWrapper
panel: panels.osd
radius: 20
x: panels.osdWrapper.x + panels.osd.x + Config.barConfig.border
y: panels.osdWrapper.y + panels.osd.y + bar.implicitHeight
@@ -234,7 +218,7 @@ Variants {
PanelBg {
id: utilsBg
deformAmount: panels.sidebar.visible ? (0.1) : (0.1)
deformAmount: panels.sidebar.visible ? (0.1 * Config.appearance.deform.scale) : (0.1 * Config.appearance.deform.scale)
exclude: panels.sidebar.offsetScale > 0.08 ? [] : [sidebarBg]
panel: panels.utilities
topLeftRadius: 0
@@ -245,11 +229,11 @@ Variants {
property real extraHeight: panels.popouts.isDetached ? 0 : 0.2
deformAmount: panels.popouts.isDetached ? 0.05 : panels.popouts.hasCurrent ? 0.15 : 0.1
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
implicitHeight: panels.popouts.height * (1 + extraHeight)
implicitWidth: panels.popouts.width
panel: panels.popoutsWrapper
radius: (panels.popouts.currentName.startsWith("audio") || panels.popouts.currentName.startsWith("updates")) ? Appearance.rounding.normal : 20 * Appearance.rounding.scale
panel: panels.popouts
radius: (panels.popouts.currentName.startsWith("audio") || panels.popouts.currentName.startsWith("updates")) ? Appearance.rounding.normal : Appearance.rounding.smallest
x: panels.popoutsWrapper.x + panels.popouts.x + Config.barConfig.border
y: panels.popoutsWrapper.y + panels.popouts.y + bar.implicitHeight - panels.popouts.height * extraHeight
@@ -262,10 +246,10 @@ Variants {
PanelBg {
id: resourcesBg
deformAmount: 0.05
deformAmount: 0.08 * Config.appearance.deform.scale
implicitHeight: panels.resources.height
implicitWidth: panels.resources.width
panel: panels.resourcesWrapper
panel: panels.resources
radius: Appearance.rounding.normal
x: panels.resourcesWrapper.x + panels.resources.x + Config.barConfig.border
y: panels.resourcesWrapper.y + panels.resources.y + bar.implicitHeight
@@ -274,23 +258,17 @@ Variants {
PanelBg {
id: settingsBg
property real extraHeight: 0.2
deformAmount: 0.03
implicitHeight: panels.settings.height * (1 + extraHeight)
implicitWidth: panels.settings.width
deformAmount: 0.08 * Config.appearance.deform.scale
panel: panels.settings
radius: Appearance.rounding.large
topLeftRadius: 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 {
id: dockBg
deformAmount: 0.08
deformAmount: 0.08 * Config.appearance.deform.scale
panel: panels.dock
radius: Appearance.rounding.normal
}
@@ -298,7 +276,7 @@ Variants {
PanelBg {
id: drawingBg
deformAmount: 0.08
deformAmount: 0.08 * Config.appearance.deform.scale
panel: panels.drawing
radius: Appearance.rounding.normal
}
@@ -393,7 +371,7 @@ Variants {
property real deformAmount: 0.15
required property Item panel
deformScale: (deformAmount * Config.appearance.deform.scale) / 10000
deformScale: deformAmount / 10000
group: blobGroup
implicitHeight: panel.height
implicitWidth: panel.width
-18
View File
@@ -1,18 +0,0 @@
pragma Singleton
import Quickshell
import ZShell.Models
Singleton {
id: root
property alias plugins: plugins.entries
FileSystemModel {
id: plugins
nameFilters: ["*.qml"]
path: Quickshell.env("HOME") + "/.config/zshell"
recursive: false
}
}
-17
View File
@@ -1,17 +0,0 @@
import Quickshell
import QtQuick
import ZShell.Models
import qs.Config
Repeater {
model: FetchPlugins.plugins
LazyLoader {
required property FileSystemEntry modelData
activeAsync: Config.plugins.entries.some(p => {
return p.id === modelData.baseName && p.enabled;
})
source: modelData.path
}
}
+20 -20
View File
@@ -16,14 +16,27 @@ Scope {
property bool launching: false
property string promptMessage: ""
readonly property var selectedSession: sessionIndex >= 0 ? sessions[sessionIndex] : null
readonly property var selectedUser: Users.selectedUser
property int sessionIndex: sessions.length > 0 ? 0 : -1
property var sessions: []
readonly property string userFace: selectedUser ? selectedUser.face : ""
readonly property string username: Users.selectedUsername
// User handling - now uses the Users singleton
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
@@ -45,11 +58,11 @@ Scope {
event.accepted = true;
return;
} else if (event.key === Qt.Key_Escape) {
buffer = "";
} else if (" abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) {
// No illegal characters (you are insane if you use unicode in your password)
}
if (event.text && !/[\r\n]/.test(event.text)) {
buffer += event.text;
event.accepted = true;
}
}
@@ -68,19 +81,6 @@ Scope {
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 {
errorMessage = "";
+1
View File
@@ -346,6 +346,7 @@ Singleton {
stdout: StdioCollector {
onStreamFinished: {
console.log("this is running");
if (root.gpuType === "GENERIC") {
const percs = text.trim().split("\n");
const sum = percs.reduce((acc, d) => acc + parseInt(d, 10), 0);
+44 -20
View File
@@ -7,30 +7,23 @@ import QtQuick
Singleton {
id: root
readonly property string defaultUserFile: "/etc/zshell-greeter/default-user"
property int selectedIndex: 0
readonly property var selectedUser: selectedIndex >= 0 && selectedIndex < users.length ? users[selectedIndex] : null
readonly property string selectedUsername: selectedUser ? selectedUser.username : ""
// The list of users that can log in graphically
// Each user object has: username, uid, home, shell, gecos (full name), face (avatar path)
property var users: []
function saveDefaultUser(): void {
if (selectedUser) {
defaultUserStorage.setText(selectedUser.username);
}
}
// The currently selected user index
property int selectedIndex: 0
function selectNext(): void {
if (users.length === 0)
return;
selectedIndex = (selectedIndex + 1) % users.length;
}
// The currently selected user object (or null if none)
readonly property var selectedUser: selectedIndex >= 0 && selectedIndex < users.length ? users[selectedIndex] : null
function selectPrevious(): void {
if (users.length === 0)
return;
selectedIndex = (selectedIndex - 1 + users.length) % users.length;
}
// Convenience property for the selected username
readonly property string selectedUsername: selectedUser ? selectedUser.username : ""
// 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 {
for (let i = 0; i < users.length; i++) {
if (users[i].username === username) {
@@ -41,6 +34,28 @@ Singleton {
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 {
id: userLister
@@ -52,10 +67,13 @@ Singleton {
try {
root.users = JSON.parse(text);
// If we have users and no selection yet, try to select the default user
if (root.users.length > 0) {
// Try to load the default user
if (defaultUserStorage.loaded) {
const defaultUsername = defaultUserStorage.text().trim();
if (defaultUsername && !root.selectUser(defaultUsername)) {
// Default user not found, select first user
root.selectedIndex = 0;
}
} else {
@@ -69,14 +87,15 @@ Singleton {
}
}
// FileView for persisting the default user
FileView {
id: defaultUserStorage
path: root.defaultUserFile
preload: true
onLoadFailed: {}
onLoaded: {
// If users are already loaded, try to select the default user
if (root.users.length > 0) {
const defaultUsername = text().trim();
if (defaultUsername) {
@@ -84,5 +103,10 @@ 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");
}
}
}
-63
View File
@@ -1,63 +0,0 @@
// FetchPresets.qml
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property var parsedPresets: ({})
readonly property var presets: parsedPresets
property bool ready: false
function accents(presetName, variantName) {
const variant = parsedPresets[presetName]?.variants?.[variantName];
return variant?.accents ?? [];
}
function defaultAccent(presetName, variantName) {
const variant = parsedPresets[presetName]?.variants?.[variantName];
return variant?.default_accent ?? "";
}
function modes(presetName, variantName) {
const variant = parsedPresets[presetName]?.variants?.[variantName];
return variant?.modes ?? [];
}
function presetNames() {
return Object.keys(parsedPresets);
}
function variantNames(presetName) {
const preset = parsedPresets[presetName];
if (!preset || !preset.variants)
return [];
return Object.keys(preset.variants);
}
Process {
command: ["zshell-cli", "scheme", "list-presets", "--json"]
running: true
stdout: StdioCollector {
onStreamFinished: {
try {
const parsed = JSON.parse(text);
root.parsedPresets = parsed.presets ?? {};
root.ready = true;
} catch (e) {
console.error("Failed to parse presets JSON:", e);
}
}
}
}
}
-72
View File
@@ -1,72 +0,0 @@
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 -1
View File
@@ -12,7 +12,7 @@ Singleton {
readonly property int darkEnd: Config.general.color.scheduleDarkEnd
readonly property int darkStart: Config.general.color.scheduleDarkStart
readonly property bool enabled: Config.general.color.scheduleDark && Config.general.color.schemeGeneration
readonly property bool enabled: Config.general.color.scheduleDark
function applyDarkMode() {
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", "dark"]);
+11
View File
@@ -0,0 +1,11 @@
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
}
+1 -2
View File
@@ -66,8 +66,7 @@ MouseArea {
function save(): void {
const tmpfile = Qt.resolvedUrl(`/tmp/zshell-picker-${Quickshell.processId}-${Date.now()}.png`);
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]));
ZShellIo.saveItem(screencopy, tmpfile, Qt.rect(Math.ceil(rsx), Math.ceil(rsy), Math.floor(sw), Math.floor(sh)), path => Quickshell.execDetached(["swappy", "-f", path]));
closeAnim.start();
}
+41 -82
View File
@@ -1,82 +1,41 @@
pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
Singleton {
id: root
readonly property alias elapsed: props.elapsed
property bool needsPause
property bool needsStart
property bool needsStop
readonly property alias paused: props.paused
readonly property alias running: props.running
property list<string> startArgs
function start(extraArgs = []): void {
needsStart = true;
startArgs = extraArgs;
checkProc.running = true;
}
function stop(): void {
needsStop = true;
checkProc.running = true;
}
function togglePause(): void {
needsPause = true;
checkProc.running = true;
}
PersistentProperties {
id: props
property real elapsed: 0
property bool paused: false
property bool running: false
reloadableId: "recorder"
}
Process {
id: checkProc
command: ["pidof", "gpu-screen-recorder"]
running: true
onExited: code => {
props.running = code === 0;
if (code === 0) {
if (root.needsStop) {
Quickshell.execDetached(["zshell-cli", "record", "record"]);
props.running = false;
props.paused = false;
} else if (root.needsPause) {
Quickshell.execDetached(["zshell-cli", "record", "record", "-p"]);
props.paused = !props.paused;
}
} else if (root.needsStart) {
Quickshell.execDetached(["zshell-cli", "record", "record", ...root.startArgs]);
props.running = true;
props.paused = false;
props.elapsed = 0;
}
root.needsStart = false;
root.needsStop = false;
root.needsPause = false;
}
}
Connections {
function onSecondsChanged(): void {
props.elapsed++;
}
target: Time // qmllint disable incompatible-type
}
}
// pragma Singleton
//
// import Quickshell
// import QtQuick
//
// Singleton {
// id: root
//
// function start(extraArgs = []): void {
// needsStart = true;
// startArgs = extraArgs;
// checkProc.running = true;
// }
//
// PersistentProperties {
// id: props
//
// property real elapsed: 0
// property bool paused: false
// property bool running: false
//
// reloadableId: "recorder"
// }
//
// Process {
// id: checkProc
//
// command: ["pidof", "gpu-screen-recorder"]
// running: true
//
// onExited: code => {
// props.running = code === 0;
//
// if (code === 0) {
// if (root.needsStop) {
// Quickshell.execDetached(["zshell-cli"]);
// }
// }
// }
// }
// }
+1 -1
View File
@@ -1,7 +1,7 @@
import Quickshell
import "../scripts/fzf.js" as Fzf
import "../scripts/fuzzysort.js" as Fuzzy
import QtQuick
import Quickshell
Singleton {
property var extraOpts: ({})
+2 -7
View File
@@ -1,23 +1,18 @@
pragma Singleton
import Quickshell
import QtQuick
import qs.Config
Singleton {
id: root
readonly property string amPmStr: timeComponents[2] ?? ""
readonly property date date: clock.date
readonly property string dateStr: format(Config.general.dateFormat)
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")
readonly property string timeStr: format("hh:mm")
function format(fmt: string): string {
return Qt.formatDateTime(clock.date, fmt);
-14
View File
@@ -6,21 +6,7 @@ import Quickshell.Services.UPower
Singleton {
id: root
readonly property real batteryPercent: UPower.displayDevice.percentage
readonly property list<UPowerDevice> devices: UPower.devices.values
readonly property UPowerDevice displayDevice: UPower.displayDevice
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 "))
// }
// }
}
-79
View File
@@ -11,13 +11,10 @@ Singleton {
id: root
property int availableUpdates: 0
property string cmd: ""
property bool commandReady
property bool loaded
property double now: Date.now()
property var updates: ({})
property bool updating
property string updatingPackage: ""
function formatUpdateTime(timestamp) {
const diffMs = root.now - timestamp;
@@ -37,22 +34,6 @@ Singleton {
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: {
if (!root.loaded)
return;
@@ -111,28 +92,6 @@ 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 {
id: updatesProc
@@ -156,44 +115,6 @@ 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 {
id: saveTimer
-51
View File
@@ -1,9 +1,7 @@
pragma Singleton
pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Io
import QtQuick
import ZShell.Models
import qs.Config
import qs.Modules
@@ -14,17 +12,10 @@ Searcher {
id: root
property string actualCurrent: WallpaperPath.currentWallpaperPath
property alias crops: adapter.monitorCrops
readonly property string current: showPreview ? previewPath : actualCurrent
property alias monitorCrops: monitorCrops
property string previewPath
property bool recentlyChanged
property bool showPreview: false
function getCrop(screen: string): var {
return root.crops[screen];
}
function preview(path: string): void {
previewPath = path;
if (Config.general.color.schemeGeneration)
@@ -32,35 +23,9 @@ Searcher {
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 {
actualCurrent = 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}`]);
if (Config.general.color.schemeGeneration)
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.general.color.mode}`]);
@@ -87,22 +52,6 @@ Searcher {
target: "wallpaper"
}
FileView {
id: monitorCrops
path: `${Paths.state}/wallpaper-crops.json`
watchChanges: true
onAdapterUpdated: writeAdapter()
onFileChanged: reload()
JsonAdapter {
id: adapter
property var monitorCrops: ({})
}
}
FileSystemModel {
id: wallpapers
+1 -1
View File
@@ -3,7 +3,7 @@ import QtQuick
import QtQuick.Layouts
import qs.Config
import qs.Modules
import qs.Helpers
import qs.Helpers as Helpers
import qs.Components
CustomRect {
+31
View File
@@ -0,0 +1,31 @@
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"
}
}
+74 -22
View File
@@ -12,29 +12,90 @@ Item {
required property Canvas drawing
property bool expanded: true
property real offsetScale: shouldBeActive ? 0 : 1
required property ShellScreen screen
readonly property bool shouldBeActive: visibilities.isDrawing
required property var visibilities
anchors.leftMargin: (-implicitWidth - 5) * offsetScale
implicitHeight: content.implicitHeight
implicitWidth: root.expanded ? content.implicitWidth : icon.implicitWidth
opacity: 1 - offsetScale
visible: offsetScale < 1
implicitWidth: 0
visible: width > 0
Behavior on implicitWidth {
states: [
State {
name: "hidden"
when: !root.shouldBeActive
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: [
Transition {
from: "*"
to: "*"
ParallelAnimation {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
easing.bezierCurve: MaterialEasing.expressiveEffects
property: "implicitWidth"
target: root
}
}
Behavior on offsetScale {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
duration: Appearance.anim.durations.small
property: "opacity"
target: icon
}
Anim {
duration: Appearance.anim.durations.small
property: "opacity"
target: content
}
}
}
]
onVisibleChanged: {
if (!visible)
@@ -48,12 +109,8 @@ Item {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
height: content.contentItem.height
opacity: root.expanded ? 0 : 1
opacity: 1
Behavior on opacity {
Anim {
}
}
sourceComponent: MaterialIcon {
font.pointSize: Appearance.font.size.larger
text: "arrow_forward_ios"
@@ -65,12 +122,7 @@ Item {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
opacity: root.expanded ? 1 : 0
Behavior on opacity {
Anim {
}
}
sourceComponent: Content {
drawing: root.drawing
visibilities: root.visibilities
+1
View File
@@ -13,6 +13,7 @@ Searcher {
function launch(entry: DesktopEntry): void {
appDb.incrementFrequency(entry.id);
console.log(root.command);
if (entry.runInTerminal)
Quickshell.execDetached({
+9 -14
View File
@@ -8,25 +8,21 @@ import qs.Helpers
Scope {
id: root
readonly property bool enabled: !Players.list.some(p => p.isPlaying)
required property Lock lock
readonly property bool enabled: !Players.list.some( p => p.isPlaying )
function handleIdleAction(action: var): void {
if (!action)
function handleIdleAction( action: var ): void {
if ( !action )
return;
if (action === "lock")
if ( action === "lock" )
lock.lock.locked = true;
else if (action === "unlock")
else if ( action === "unlock" )
lock.lock.locked = false;
else if (action === "dpms on")
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 if ( typeof action === "string" )
Hypr.dispatch( action );
else
Quickshell.execDetached(action);
Quickshell.execDetached( action );
}
Variants {
@@ -37,8 +33,7 @@ Scope {
enabled: root.enabled && modelData.timeout > 0 ? true : false
timeout: modelData.timeout
onIsIdleChanged: root.handleIdleAction(isIdle ? modelData.idleAction : modelData.activeAction)
onIsIdleChanged: root.handleIdleAction( isIdle ? modelData.idleAction : modelData.activeAction )
}
}
}
-3
View File
@@ -58,7 +58,6 @@ CustomRect {
fillMode: Image.PreserveAspectCrop
height: Config.notifs.sizes.image
source: Qt.resolvedUrl(root.image)
visible: Config.lock.showNotifIcon
width: Config.notifs.sizes.image
}
}
@@ -285,8 +284,6 @@ CustomRect {
Layout.fillWidth: true
color: root.urgency === "critical" ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface
text: {
if (!Config.lock.showNotifContent)
return "Unlock to view";
const summary = modelData.summary.replace(/\n/g, " ");
const body = modelData.body.replace(/\n/g, " ");
const color = root.urgency === "critical" ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3outline;
-2
View File
@@ -30,8 +30,6 @@ Scope {
} else {
buffer = buffer.slice(0, -1);
}
} else if (event.key === Qt.Key_Escape) {
buffer = "";
} else if (" abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) {
// No illegal characters (you are insane if you use unicode in your password)
buffer += event.text;
+9 -3
View File
@@ -10,6 +10,7 @@ Item {
readonly property int padding: 6
required property Item panels
required property Item sidebarPanel
required property PersistentProperties visibilities
anchors.bottom: parent.bottom
@@ -43,7 +44,7 @@ Item {
return Math.min((QsWindow.window?.screen?.height ?? 0) - 1 * 2, height + padding * 2);
}
implicitWidth: Config.notifs.sizes.width + padding * 2
implicitWidth: Math.max(sidebarPanel.width * (1 - sidebarPanel.offsetScale), Config.notifs.sizes.width + padding * 2)
Behavior on implicitHeight {
Anim {
@@ -72,8 +73,9 @@ Item {
required property NotifServer.Notif modelData
readonly property alias nonAnimHeight: notif.nonAnimHeight
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: notif.implicitHeight + (idx === 0 ? 0 : 8)
implicitWidth: notif.implicitWidth
ListView.onRemove: removeAnim.start()
onIndexChanged: {
@@ -124,16 +126,20 @@ Item {
}
ClippingRectangle {
// implicitWidth: notif.implicitWidth
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: wrapper.idx === 0 ? 0 : 8
color: "transparent"
implicitHeight: notif.implicitHeight
implicitWidth: notif.implicitWidth
radius: Appearance.rounding.smallest / 2
Notification {
id: notif
anchors.left: parent.left
anchors.right: parent.right
modelData: wrapper.modelData
}
}
+1 -1
View File
@@ -20,9 +20,9 @@ CustomRect {
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
// implicitWidth: Config.notifs.sizes.width
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3secondaryContainer : DynamicColors.tPalette.m3surfaceContainer
implicitHeight: inner.implicitHeight
implicitWidth: Config.notifs.sizes.width
radius: 6
x: Config.notifs.sizes.width
-3
View File
@@ -136,10 +136,7 @@ CustomRect {
wrapMode: Text.WordWrap
onLinkActivated: link => {
if (Config.launcher.uwsm)
Quickshell.execDetached(["app2unit", "-O", "--", link]);
else
Quickshell.execDetached(["xdg-open", link]);
root.visibilities.sidebar = false;
}
}
@@ -78,10 +78,6 @@ LazyListView {
}
}
onDoubleClicked: event => {
if (event.button === Qt.LeftButton)
notifInner.toggleExpand(!notifInner.expanded);
}
onPositionChanged: event => {
if (pressed) {
const diffY = event.y - startY;
@@ -79,10 +79,6 @@ LazyListView {
Component.onCompleted: modelData?.lock(this)
Component.onDestruction: modelData?.unlock(this)
onDoubleClicked: event => {
if (event.button === Qt.LeftButton)
root.requestToggleExpand(!root.expanded);
}
onPositionChanged: event => {
if (pressed && !root.expanded) {
const diffY = event.y - startY;
@@ -1,290 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
CustomRect {
id: root
required property var props
required property PersistentProperties visibilities
Layout.fillWidth: true
color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
radius: Appearance.rounding.smallest
ColumnLayout {
id: layout
anchors.fill: parent
anchors.margins: Appearance.padding.large
spacing: Appearance.spacing.normal
RowLayout {
spacing: Appearance.spacing.normal
z: 1
CustomRect {
color: Recorder.running ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3secondaryContainer
implicitHeight: {
const h = icon.implicitHeight + Appearance.padding.smaller * 2;
return h - (h % 2);
}
implicitWidth: implicitHeight
radius: Appearance.rounding.full
MaterialIcon {
id: icon
anchors.centerIn: parent
anchors.horizontalCenterOffset: -0.5
anchors.verticalCenterOffset: 1.5
color: Recorder.running ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSecondaryContainer
font.pointSize: Appearance.font.size.large
text: "screen_record"
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
CustomText {
Layout.fillWidth: true
elide: Text.ElideRight
font.pointSize: Appearance.font.size.normal
text: qsTr("Screen Recorder")
}
CustomText {
Layout.fillWidth: true
color: DynamicColors.palette.m3onSurfaceVariant
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
text: Recorder.paused ? qsTr("Recording paused") : Recorder.running ? qsTr("Recording running") : qsTr("Recording off")
}
}
CustomSplitButton {
active: menuItems.find(m => root.props.recordingMode === m.icon + m.text) ?? menuItems[0]
disabled: Recorder.running
menuItems: [
MenuItem {
activeText: qsTr("Fullscreen")
icon: "fullscreen"
text: qsTr("Record fullscreen")
onClicked: Recorder.start()
},
MenuItem {
activeText: qsTr("Region")
icon: "screenshot_region"
text: qsTr("Record region")
onClicked: Recorder.start(["-r"])
},
MenuItem {
activeText: qsTr("Fullscreen")
icon: "select_to_speak"
text: qsTr("Record fullscreen with sound")
onClicked: Recorder.start(["-s"])
},
MenuItem {
activeText: qsTr("Region")
icon: "volume_up"
text: qsTr("Record region with sound")
onClicked: Recorder.start(["-s", "-r"])
}
]
menu.onItemSelected: item => root.props.recordingMode = item.icon + item.text
}
}
Loader {
id: listOrControls
property bool running: Recorder.running
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
asynchronous: true
sourceComponent: running ? recordingControls : recordingList
Behavior on Layout.preferredHeight {
id: locHeightAnim
enabled: false
Anim {
}
}
Behavior on running {
SequentialAnimation {
ParallelAnimation {
Anim {
duration: Appearance.anim.durations.small
easing: Appearance.anim.curves.standardAccel
property: "scale"
target: listOrControls
to: 0.7
}
Anim {
duration: Appearance.anim.durations.small
easing: Appearance.anim.curves.standardAccel
property: "opacity"
target: listOrControls
to: 0
}
}
PropertyAction {
property: "enabled"
target: locHeightAnim
value: true
}
PropertyAction {
}
PropertyAction {
property: "enabled"
target: locHeightAnim
value: false
}
ParallelAnimation {
Anim {
duration: Appearance.anim.durations.small
easing: Appearance.anim.curves.standardDecel
property: "scale"
target: listOrControls
to: 1
}
Anim {
duration: Appearance.anim.durations.small
easing: Appearance.anim.curves.standardDecel
property: "opacity"
target: listOrControls
to: 1
}
}
}
}
}
}
Component {
id: recordingList
RecordingList {
props: root.props
visibilities: root.visibilities
}
}
Component {
id: recordingControls
RowLayout {
spacing: Appearance.spacing.normal
CustomRect {
color: Recorder.paused ? DynamicColors.palette.m3tertiary : DynamicColors.palette.m3error
implicitHeight: recText.implicitHeight + Appearance.padding.smaller * 2
implicitWidth: recText.implicitWidth + Appearance.padding.normal * 2
radius: Appearance.rounding.full
Behavior on implicitWidth {
Anim {
}
}
SequentialAnimation on opacity {
alwaysRunToEnd: true
loops: Animation.Infinite
running: !Recorder.paused
Anim {
duration: Appearance.anim.durations.large
easing: Appearance.anim.curves.emphasizedAccel
from: 1
to: 0
}
Anim {
duration: Appearance.anim.durations.extraLarge
easing: Appearance.anim.curves.emphasizedDecel
from: 0
to: 1
}
}
CustomText {
id: recText
anchors.centerIn: parent
animate: true
color: Recorder.paused ? DynamicColors.palette.m3onTertiary : DynamicColors.palette.m3onError
font.family: Appearance.font.family.mono
text: Recorder.paused ? "PAUSED" : "REC"
}
}
CustomText {
font.pointSize: Appearance.font.size.normal
text: {
const elapsed = Recorder.elapsed;
const hours = Math.floor(elapsed / 3600);
const mins = Math.floor((elapsed % 3600) / 60);
const secs = Math.floor(elapsed % 60).toString().padStart(2, "0");
let time;
if (hours > 0)
time = `${hours}:${mins.toString().padStart(2, "0")}:${secs}`;
else
time = `${mins}:${secs}`;
return qsTr("Recording for %1").arg(time);
}
}
Item {
Layout.fillWidth: true
}
IconButton {
checked: Recorder.paused
font.pointSize: Appearance.font.size.large
icon: Recorder.paused ? "play_arrow" : "pause"
label.animate: true
toggle: true
type: IconButton.Tonal
onClicked: {
Recorder.togglePause();
internalChecked = Recorder.paused;
}
}
IconButton {
font.pointSize: Appearance.font.size.large
icon: "stop"
inactiveColour: DynamicColors.palette.m3error
inactiveOnColour: DynamicColors.palette.m3onError
onClicked: Recorder.stop()
}
}
}
}
@@ -1,226 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import ZShell.Models
import qs.Components
import qs.Helpers
import qs.Paths
import qs.Config
ColumnLayout {
id: root
required property var props
required property PersistentProperties visibilities
spacing: 0
WrapperMouseArea {
Layout.fillWidth: true
cursorShape: Qt.PointingHandCursor
onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded
RowLayout {
spacing: Appearance.spacing.smaller
MaterialIcon {
Layout.alignment: Qt.AlignVCenter
font.pointSize: Appearance.font.size.large
text: "list"
}
CustomText {
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
font.pointSize: Appearance.font.size.normal
text: qsTr("Recordings")
}
IconButton {
icon: root.props.recordingListExpanded ? "unfold_less" : "unfold_more"
label.animate: true
type: IconButton.Text
onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded
}
}
}
CustomListView {
id: list
Layout.fillWidth: true
Layout.rightMargin: -Appearance.spacing.small
clip: true
implicitHeight: (Appearance.font.size.larger + Appearance.padding.small) * (root.props.recordingListExpanded ? 10 : 3)
CustomScrollBar.vertical: CustomScrollBar {
flickable: list
}
add: Transition {
Anim {
from: 0
property: "opacity"
to: 1
}
Anim {
from: 0.5
property: "scale"
to: 1
}
}
delegate: RowLayout {
id: recording
property string baseName
required property FileSystemEntry modelData
anchors.left: list.contentItem.left
anchors.right: list.contentItem.right
anchors.rightMargin: Appearance.spacing.small
spacing: Appearance.spacing.small / 2
Component.onCompleted: baseName = modelData.baseName
CustomText {
Layout.fillWidth: true
Layout.rightMargin: Appearance.spacing.small / 2
color: DynamicColors.palette.m3onSurfaceVariant
elide: Text.ElideRight
text: {
const time = recording.baseName;
const matches = time.match(/^recording_(\d{4})(\d{2})(\d{2})_(\d{2})-(\d{2})-(\d{2})/);
if (!matches)
return time;
const date = new Date(...matches.slice(1));
date.setMonth(date.getMonth() - 1);
return qsTr("Recording at %1").arg(Qt.formatDateTime(date, Qt.locale()));
}
}
IconButton {
icon: "play_arrow"
type: IconButton.Text
onClicked: {
root.visibilities.sidebar = false;
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]);
}
}
IconButton {
icon: "folder"
type: IconButton.Text
onClicked: {
root.visibilities.sidebar = false;
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]);
}
}
}
displaced: Transition {
Anim {
properties: "opacity,scale"
to: 1
}
Anim {
property: "y"
}
}
Behavior on implicitHeight {
Anim {
}
}
model: FileSystemModel {
nameFilters: ["recording_*.mp4"]
path: Paths.recsdir
sortReverse: true
}
remove: Transition {
Anim {
property: "opacity"
to: 0
}
Anim {
property: "scale"
to: 0.5
}
}
Loader {
active: opacity > 0
anchors.centerIn: parent
asynchronous: true
opacity: list.count === 0 ? 1 : 0
Behavior on opacity {
Anim {
}
}
sourceComponent: ColumnLayout {
spacing: Appearance.spacing.small
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: root.props.recordingListExpanded ? implicitHeight : 0
color: DynamicColors.palette.m3outline
font.pointSize: Appearance.font.size.extraLarge
opacity: root.props.recordingListExpanded ? 1 : 0
scale: root.props.recordingListExpanded ? 1 : 0
text: "scan_delete"
Behavior on Layout.preferredHeight {
Anim {
}
}
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
}
RowLayout {
spacing: Appearance.spacing.smaller
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: !root.props.recordingListExpanded ? implicitWidth : 0
color: DynamicColors.palette.m3outline
opacity: !root.props.recordingListExpanded ? 1 : 0
scale: !root.props.recordingListExpanded ? 1 : 0
text: "scan_delete"
Behavior on Layout.preferredWidth {
Anim {
}
}
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
}
CustomText {
color: DynamicColors.palette.m3outline
text: qsTr("No recordings found")
}
}
}
}
}
}
@@ -5,7 +5,6 @@ import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Modules
import qs.Helpers
import qs.Daemons
CustomRect {
@@ -33,7 +32,7 @@ CustomRect {
Toggle {
checked: Network.wifiEnabled
icon: Network.wifiEnabled ? "wifi" : "wifi_off"
visible: QSNetwork.Networking.devices.values.some(n => n.type === QSNetwork.DeviceType.Wifi)
visible: QSNetwork.Networking.devices.values.length > 0
onClicked: Network.toggleWifi()
}
@@ -80,13 +79,6 @@ CustomRect {
adapter.enabled = !adapter.enabled;
}
}
Toggle {
checked: GameMode.enabled
icon: GameMode.enabled ? "videogame_asset" : "videogame_asset_off"
onClicked: GameMode.enabled = !GameMode.enabled
}
}
}
@@ -1,14 +1,13 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Modules.Notifications.Sidebar.Utils.Cards
import qs.Config
import QtQuick
import QtQuick.Layouts
Item {
id: root
required property Item popouts
required property PersistentProperties props
required property var props
required property var visibilities
implicitHeight: layout.implicitHeight
@@ -23,12 +22,6 @@ Item {
IdleInhibit {
}
Record {
props: root.props
visibilities: root.visibilities
z: 1
}
Toggles {
popouts: root.popouts
visibilities: root.visibilities
+1
View File
@@ -17,6 +17,7 @@ Item {
id: content
panels: root.panels
sidebarPanel: root.sidebarPanel
visibilities: root.visibilities
}
}
+3 -5
View File
@@ -100,15 +100,13 @@ Item {
icon: `brightness_${(Math.round(value * 6) + 1)}`
value: root.brightness
onPressedChanged: {
if (!pressed) {
onMoved: {
if (Config.osd.allMonBrightness) {
root.monitor?.setBrightness(value);
} else {
for (const mon of Brightness.monitors) {
mon.setBrightness(value);
}
} else {
root.monitor?.setBrightness(value);
}
}
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ CustomRect {
color: visibilities.resources ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
implicitWidth: rowLayout.implicitWidth + Appearance.padding.normal * 2
radius: Appearance.rounding.full
radius: height / 2
StateLayer {
onClicked: root.visibilities.resources = !root.visibilities.resources
-24
View File
@@ -104,24 +104,6 @@ Item {
key: "launcher"
name: "Launcher"
}
ListElement {
icon: "screenshot_region"
key: "screenshot"
name: "Screenshot"
}
ListElement {
icon: "cached"
key: "updates"
name: "Updates"
}
ListElement {
icon: "extension"
key: "plugins"
name: "Extensions"
}
}
CustomClippingRect {
@@ -189,15 +171,9 @@ Item {
Layout.fillHeight: true
Layout.preferredWidth: icon.contentWidth
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
text: categoryItem.icon
verticalAlignment: Text.AlignVCenter
Behavior on fill {
Anim {
}
}
}
CustomText {
@@ -1,4 +1,3 @@
import QtQuick
import qs.Modules.Settings.Controls
import qs.Config
@@ -81,7 +80,6 @@ SettingsPage {
name: "Sans family"
object: Config.appearance.font.family
setting: "sans"
stringList: Qt.fontFamilies()
}
Separator {
@@ -91,7 +89,6 @@ SettingsPage {
name: "Monospace family"
object: Config.appearance.font.family
setting: "mono"
stringList: Qt.fontFamilies()
}
}
+8 -8
View File
@@ -1,4 +1,3 @@
import Quickshell
import QtQuick.Layouts
import qs.Modules.Settings.Controls
import qs.Config
@@ -6,8 +5,6 @@ import qs.Config
SettingsPage {
id: root
required property ShellScreen screen
SettingsSection {
sectionId: "Wallpaper"
@@ -32,17 +29,20 @@ SettingsPage {
step: 50
}
Separator {
}
WallpaperCropper {
}
// Separator {
// }
//
// WallpaperCropper {
// Layout.fillWidth: true
// Layout.preferredHeight: 300
// }
}
SettingsSection {
sectionId: "Wallpapers"
WallpaperGrid {
Layout.fillWidth: true
}
}
}
+6 -16
View File
@@ -19,8 +19,8 @@ SettingsPage {
}
SettingSpinBox {
min: 1
name: "Height"
min: 1
object: Config.barConfig
setting: "height"
}
@@ -29,8 +29,8 @@ SettingsPage {
}
SettingSpinBox {
min: 0
name: "Rounding"
min: 0
object: Config.barConfig
setting: "rounding"
}
@@ -39,21 +39,11 @@ SettingsPage {
}
SettingSpinBox {
min: 0
name: "Border"
min: 0
object: Config.barConfig
setting: "border"
}
Separator {
}
SettingSpinBox {
min: 0
name: "Smoothing"
object: Config.barConfig
setting: "smoothing"
}
}
SettingsSection {
@@ -155,8 +145,8 @@ SettingsPage {
}
SettingSpinBox {
min: 1
name: "Dock height"
min: 1
object: Config.dock
setting: "height"
}
@@ -183,8 +173,8 @@ SettingsPage {
}
SettingStringList {
addLabel: qsTr("Add pinned app")
name: "Pinned apps"
addLabel: qsTr("Add pinned app")
object: Config.dock
setting: "pinnedApps"
}
@@ -193,8 +183,8 @@ SettingsPage {
}
SettingStringList {
addLabel: qsTr("Add ignored regex")
name: "Ignored app regexes"
addLabel: qsTr("Add ignored regex")
object: Config.dock
setting: "ignoredAppRegexes"
}
+111 -111
View File
@@ -19,8 +19,8 @@ SettingsPage {
}
SettingSpinBox {
min: 0
name: "Media update interval"
min: 0
object: Config.dashboard
setting: "mediaUpdateInterval"
step: 50
@@ -30,8 +30,8 @@ SettingsPage {
}
SettingSpinBox {
min: 0
name: "Resource update interval"
min: 0
object: Config.dashboard
setting: "resourceUpdateInterval"
step: 50
@@ -41,8 +41,8 @@ SettingsPage {
}
SettingSpinBox {
min: 0
name: "Drag threshold"
min: 0
object: Config.dashboard
setting: "dragThreshold"
}
@@ -107,112 +107,112 @@ SettingsPage {
}
}
// SettingsSection {
// sectionId: "Layout Sizes"
//
// SettingsHeader {
// name: "Layout Sizes"
// }
//
// SettingReadOnly {
// name: "Tab indicator height"
// value: String(Config.dashboard.sizes.tabIndicatorHeight)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Tab indicator spacing"
// value: String(Config.dashboard.sizes.tabIndicatorSpacing)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Info width"
// value: String(Config.dashboard.sizes.infoWidth)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Info icon size"
// value: String(Config.dashboard.sizes.infoIconSize)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Date time width"
// value: String(Config.dashboard.sizes.dateTimeWidth)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Media width"
// value: String(Config.dashboard.sizes.mediaWidth)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Media progress sweep"
// value: String(Config.dashboard.sizes.mediaProgressSweep)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Media progress thickness"
// value: String(Config.dashboard.sizes.mediaProgressThickness)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Resource progress thickness"
// value: String(Config.dashboard.sizes.resourceProgessThickness)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Weather width"
// value: String(Config.dashboard.sizes.weatherWidth)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Media cover art size"
// value: String(Config.dashboard.sizes.mediaCoverArtSize)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Media visualiser size"
// value: String(Config.dashboard.sizes.mediaVisualiserSize)
// }
//
// Separator {
// }
//
// SettingReadOnly {
// name: "Resource size"
// value: String(Config.dashboard.sizes.resourceSize)
// }
// }
SettingsSection {
sectionId: "Layout Sizes"
SettingsHeader {
name: "Layout Sizes"
}
SettingReadOnly {
name: "Tab indicator height"
value: String(Config.dashboard.sizes.tabIndicatorHeight)
}
Separator {
}
SettingReadOnly {
name: "Tab indicator spacing"
value: String(Config.dashboard.sizes.tabIndicatorSpacing)
}
Separator {
}
SettingReadOnly {
name: "Info width"
value: String(Config.dashboard.sizes.infoWidth)
}
Separator {
}
SettingReadOnly {
name: "Info icon size"
value: String(Config.dashboard.sizes.infoIconSize)
}
Separator {
}
SettingReadOnly {
name: "Date time width"
value: String(Config.dashboard.sizes.dateTimeWidth)
}
Separator {
}
SettingReadOnly {
name: "Media width"
value: String(Config.dashboard.sizes.mediaWidth)
}
Separator {
}
SettingReadOnly {
name: "Media progress sweep"
value: String(Config.dashboard.sizes.mediaProgressSweep)
}
Separator {
}
SettingReadOnly {
name: "Media progress thickness"
value: String(Config.dashboard.sizes.mediaProgressThickness)
}
Separator {
}
SettingReadOnly {
name: "Resource progress thickness"
value: String(Config.dashboard.sizes.resourceProgessThickness)
}
Separator {
}
SettingReadOnly {
name: "Weather width"
value: String(Config.dashboard.sizes.weatherWidth)
}
Separator {
}
SettingReadOnly {
name: "Media cover art size"
value: String(Config.dashboard.sizes.mediaCoverArtSize)
}
Separator {
}
SettingReadOnly {
name: "Media visualiser size"
value: String(Config.dashboard.sizes.mediaVisualiserSize)
}
Separator {
}
SettingReadOnly {
name: "Resource size"
value: String(Config.dashboard.sizes.resourceSize)
}
}
}
-61
View File
@@ -1,6 +1,4 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Modules.Settings.Controls
import qs.Config
import qs.Components
@@ -49,15 +47,6 @@ SettingsPage {
object: Config.general
setting: "desktopIcons"
}
Separator {
}
SettingInput {
name: "Date format"
object: Config.general
setting: "dateFormat"
}
}
SettingsSection {
@@ -69,7 +58,6 @@ SettingsPage {
CustomSplitButtonRow {
active: Config.general.color.mode === "light" ? menuItems[0] : menuItems[1]
buttonAlias.disabled: !Config.general.color.schemeGeneration
label: qsTr("Scheme mode")
menuItems: [
@@ -103,7 +91,6 @@ SettingsPage {
id: schemeType
active: root.schemeTypeItem(menuItems, Config.colors.schemeType)
buttonAlias.disabled: !Config.general.color.schemeGeneration
label: qsTr("Scheme type")
z: 2
@@ -173,69 +160,21 @@ SettingsPage {
}
Separator {
shouldBeActive: Config.general.color.schemeGeneration ? 0 : 1
}
SchemesListView {
name: "Color scheme presets"
object: Config.colors.presets
setting: "name"
shouldBeActive: Config.general.color.schemeGeneration ? 0 : 1
stringList: FetchPresets.presetNames()
}
Separator {
shouldBeActive: Config.colors.presets.name !== "" && !Config.general.color.schemeGeneration
}
SchemesListView {
name: "Preset variant"
object: Config.colors.presets
setting: "variant"
shouldBeActive: Config.colors.presets.name !== "" && !Config.general.color.schemeGeneration
stringList: FetchPresets.variantNames(Config.colors.presets.name)
onOptionSet: item => {
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--preset", `${Config.colors.presets.name.toLowerCase()}:${item}`]);
}
}
Separator {
shouldBeActive: Config.colors.presets.variant !== "" && FetchPresets.accents(Config.colors.presets.name, Config.colors.presets.variant).length > 0 && !Config.general.color.schemeGeneration
}
SchemesListView {
name: "Preset accent"
object: Config.colors.presets
setting: "accent"
shouldBeActive: Config.colors.presets.variant !== "" && FetchPresets.accents(Config.colors.presets.name, Config.colors.presets.variant).length > 0 && !Config.general.color.schemeGeneration
stringList: FetchPresets.accents(Config.colors.presets.name, Config.colors.presets.variant)
onOptionSet: item => {
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--preset", `${Config.colors.presets.name.toLowerCase()}:${Config.colors.presets.variant}`, "--accent", `${item}`]);
}
}
Separator {
shouldBeActive: Config.general.color.schemeGeneration ? 1 : 0
}
SettingSwitch {
name: "Smart color scheme"
object: Config.general.color
setting: "smart"
shouldBeActive: Config.general.color.schemeGeneration ? 1 : 0
}
Separator {
shouldBeActive: Config.general.color.schemeGeneration ? 1 : 0
}
SettingSpinner {
name: "Schedule dark mode"
object: Config.general.color
settings: ["scheduleDarkStart", "scheduleDarkEnd", "scheduleDark"]
shouldBeActive: Config.general.color.schemeGeneration ? 1 : 0
}
Separator {
+5 -35
View File
@@ -31,8 +31,8 @@ SettingsPage {
}
SettingSpinBox {
min: 1
name: "Max fingerprint tries"
min: 1
object: Config.lock
setting: "maxFprintTries"
step: 1
@@ -41,27 +41,9 @@ SettingsPage {
Separator {
}
SettingSwitch {
name: "Show notification details"
object: Config.lock
setting: "showNotifContent"
}
Separator {
}
SettingSwitch {
name: "Show notification icon"
object: Config.lock
setting: "showNotifIcon"
}
Separator {
}
SettingSpinBox {
min: 0
name: "Blur amount"
min: 0
object: Config.lock
setting: "blurAmount"
step: 1
@@ -71,9 +53,9 @@ SettingsPage {
}
SettingSpinBox {
name: "Height multiplier"
max: 2
min: 0.1
name: "Height multiplier"
object: Config.lock.sizes
setting: "heightMult"
step: 0.05
@@ -83,9 +65,9 @@ SettingsPage {
}
SettingSpinBox {
name: "Aspect ratio"
max: 4
min: 0.5
name: "Aspect ratio"
object: Config.lock.sizes
setting: "ratio"
step: 0.05
@@ -95,26 +77,14 @@ SettingsPage {
}
SettingSpinBox {
min: 100
name: "Center width"
min: 100
object: Config.lock.sizes
setting: "centerWidth"
step: 10
}
}
SettingsSection {
sectionId: "Greeter"
SettingsHeader {
name: "Greeter"
}
SettingsIconButton {
name: "Install wallpaper and color scheme to greeter"
}
}
SettingsSection {
sectionId: "Idle"
@@ -9,8 +9,6 @@ import qs.Modules.Settings.Controls
ColumnLayout {
id: root
property bool shouldBeActive: true
function addTimeoutEntry() {
let list = [...Config.general.idle.timeouts];
@@ -24,13 +22,6 @@ ColumnLayout {
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) {
const list = [...Config.general.idle.timeouts];
let entry = list[i];
@@ -42,26 +33,8 @@ ColumnLayout {
Config.save();
}
anchors.left: parent.left
anchors.right: parent.right
height: shouldBeActive ? implicitHeight : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Settings {
name: "Idle Monitors"
@@ -72,15 +45,10 @@ ColumnLayout {
SettingList {
Layout.fillWidth: true
anchors.left: undefined
anchors.right: undefined
onAddActiveActionRequested: {
root.updateTimeoutEntry(index, "activeAction", "");
}
onDeleteRequested: function (index) {
root.deleteTimeoutEntry(index);
}
onFieldEdited: function (key, value) {
root.updateTimeoutEntry(index, key, value);
}
-18
View File
@@ -1,18 +0,0 @@
import qs.Modules.Settings.Controls
import qs.Config
SettingsPage {
SettingsSection {
sectionId: "Plugins"
SettingsHeader {
name: "Plugins"
}
SettingBarEntryList {
name: "Enable or disable plugins"
object: Config.plugins
setting: "entries"
}
}
}
-130
View File
@@ -1,130 +0,0 @@
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"
}
}
}
@@ -1,197 +0,0 @@
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
}))
}
}
}
}
+97 -97
View File
@@ -19,8 +19,8 @@ SettingsPage {
}
SettingSpinBox {
min: 1
name: "Max toasts"
min: 1
object: Config.utilities
setting: "maxToasts"
}
@@ -29,8 +29,8 @@ SettingsPage {
}
SettingSpinBox {
min: 1
name: "Panel width"
min: 1
object: Config.utilities.sizes
setting: "width"
}
@@ -39,8 +39,8 @@ SettingsPage {
}
SettingSpinBox {
min: 1
name: "Toast width"
min: 1
object: Config.utilities.sizes
setting: "toastWidth"
}
@@ -77,100 +77,100 @@ SettingsPage {
setting: "gameModeChanged"
}
// Separator {
// }
//
// SettingSwitch {
// name: "Do not disturb changed"
// object: Config.utilities.toasts
// setting: "dndChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Audio output changed"
// object: Config.utilities.toasts
// setting: "audioOutputChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Audio input changed"
// object: Config.utilities.toasts
// setting: "audioInputChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Caps lock changed"
// object: Config.utilities.toasts
// setting: "capsLockChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Num lock changed"
// object: Config.utilities.toasts
// setting: "numLockChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Keyboard layout changed"
// object: Config.utilities.toasts
// setting: "kbLayoutChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "VPN changed"
// object: Config.utilities.toasts
// setting: "vpnChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Now playing"
// object: Config.utilities.toasts
// setting: "nowPlaying"
// }
Separator {
}
// SettingsSection {
// sectionId: "VPN"
//
// SettingsHeader {
// name: "VPN"
// }
//
// SettingSwitch {
// name: "Enable VPN integration"
// object: Config.utilities.vpn
// setting: "enabled"
// }
//
// Separator {
// }
//
// SettingStringList {
// name: "Provider"
// addLabel: qsTr("Add VPN provider")
// object: Config.utilities.vpn
// setting: "provider"
// }
// }
SettingSwitch {
name: "Do not disturb changed"
object: Config.utilities.toasts
setting: "dndChanged"
}
Separator {
}
SettingSwitch {
name: "Audio output changed"
object: Config.utilities.toasts
setting: "audioOutputChanged"
}
Separator {
}
SettingSwitch {
name: "Audio input changed"
object: Config.utilities.toasts
setting: "audioInputChanged"
}
Separator {
}
SettingSwitch {
name: "Caps lock changed"
object: Config.utilities.toasts
setting: "capsLockChanged"
}
Separator {
}
SettingSwitch {
name: "Num lock changed"
object: Config.utilities.toasts
setting: "numLockChanged"
}
Separator {
}
SettingSwitch {
name: "Keyboard layout changed"
object: Config.utilities.toasts
setting: "kbLayoutChanged"
}
Separator {
}
SettingSwitch {
name: "VPN changed"
object: Config.utilities.toasts
setting: "vpnChanged"
}
Separator {
}
SettingSwitch {
name: "Now playing"
object: Config.utilities.toasts
setting: "nowPlaying"
}
}
SettingsSection {
sectionId: "VPN"
SettingsHeader {
name: "VPN"
}
SettingSwitch {
name: "Enable VPN integration"
object: Config.utilities.vpn
setting: "enabled"
}
Separator {
}
SettingStringList {
name: "Provider"
addLabel: qsTr("Add VPN provider")
object: Config.utilities.vpn
setting: "provider"
}
}
}
+2 -31
View File
@@ -1,5 +1,3 @@
pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Widgets
import QtQuick
@@ -22,6 +20,7 @@ Item {
required property PersistentProperties visibilities
function scrollToSetting(section: string, settingName: string) {
// Wait for the StackView transition to complete, then scroll
root.pendingSection = section;
root.pendingSetting = settingName;
scrollTimer.restart();
@@ -75,12 +74,6 @@ Item {
stack.push(osd);
else if (currentCategory === "launcher")
stack.push(launcher);
else if (currentCategory === "screenshot")
stack.push(screenshot);
else if (currentCategory === "updates")
stack.push(updates);
else if (currentCategory === "plugins")
stack.push(plugins);
}
target: root
@@ -136,7 +129,7 @@ Item {
anchors.right: parent.right
anchors.top: searchBar.bottom
anchors.topMargin: Appearance.spacing.smaller
color: DynamicColors.tPalette.m3surfaceContainerLowest
color: DynamicColors.tPalette.m3surfaceContainer
radius: Appearance.rounding.normal
StackView {
@@ -160,7 +153,6 @@ Item {
id: background
Cat.Background {
screen: root.screen
}
}
@@ -233,25 +225,4 @@ Item {
Cat.Launcher {
}
}
Component {
id: screenshot
Cat.Screenshot {
}
}
Component {
id: updates
Cat.SystemUpdates {
}
}
Component {
id: plugins
Cat.Plugins {
}
}
}
@@ -1,161 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Config
import qs.Components
Item {
id: root
required property string name
required property var object
property alias row: row
required property string setting
property bool shouldBeActive: true
required property list<var> stringList
signal optionSet(option: string)
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? row.height : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
RowLayout {
id: row
anchors.left: parent.left
anchors.margins: Appearance.padding.small
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
CustomText {
id: text
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.name
}
CustomClippingRect {
Layout.preferredHeight: 42 * 6 + Appearance.padding.normal * 2 + Appearance.spacing.small * 5
Layout.preferredWidth: 500
color: DynamicColors.tPalette.m3surfaceContainer
radius: (21 + Appearance.padding.normal) * Appearance.rounding.scale
CustomRect {
id: searchBox
anchors.left: parent.left
anchors.margins: Appearance.padding.normal
anchors.right: parent.right
anchors.top: parent.top
color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: 42
radius: Appearance.rounding.full
MaterialIcon {
id: searchIcon
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.large
anchors.top: parent.top
font.pointSize: Appearance.font.size.large
text: "search"
verticalAlignment: Text.AlignVCenter
}
CustomTextField {
id: textSearch
anchors.left: searchIcon.right
anchors.leftMargin: Appearance.spacing.small
anchors.right: parent.right
anchors.rightMargin: Appearance.spacing.normal
anchors.verticalCenter: parent.verticalCenter
placeholderText: "Search..."
}
}
CustomClippingRect {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: Appearance.padding.normal
anchors.right: parent.right
anchors.top: searchBox.bottom
bottomLeftRadius: 21
bottomRightRadius: 21
CustomListView {
anchors.fill: parent
clip: true
spacing: Appearance.spacing.small
delegate: CustomRect {
id: delegate
required property string modelData
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: 42
radius: Appearance.rounding.smallest
CustomText {
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
text: modelData
verticalAlignment: Text.AlignVCenter
}
MaterialIcon {
anchors.fill: parent
anchors.rightMargin: Appearance.padding.normal
color: DynamicColors.palette.m3primary
font.pointSize: Appearance.font.size.large
horizontalAlignment: Text.AlignRight
text: "check_circle"
verticalAlignment: Text.AlignVCenter
visible: root.object[root.setting] === delegate.modelData
}
StateLayer {
onClicked: {
root.object[root.setting] = delegate.modelData;
root.optionSet(delegate.modelData);
Config.save();
}
}
}
model: ScriptModel {
values: {
const values = root.stringList;
const search = textSearch.text;
var regex = new RegExp(search, "i");
return values.filter(n => regex.test(n));
}
}
}
}
}
}
}
+2 -21
View File
@@ -6,26 +6,7 @@ import qs.Config
CustomRect {
id: root
property bool shouldBeActive: true
anchors.left: parent.left
anchors.right: parent.right
Layout.fillWidth: true
Layout.preferredHeight: 1
color: DynamicColors.tPalette.m3outlineVariant
implicitHeight: shouldBeActive ? 1 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
}
@@ -13,7 +13,6 @@ ColumnLayout {
required property string name
required property var object
required property string setting
property bool shouldBeActive: true
function addAction() {
const list = [...root.object[root.setting]];
@@ -45,26 +44,8 @@ ColumnLayout {
Config.save();
}
anchors.left: parent.left
anchors.right: parent.right
height: shouldBeActive ? implicitHeight : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Rectangle {
anchors.fill: parent
@@ -127,9 +108,6 @@ ColumnLayout {
}
Separator {
Layout.fillWidth: true
anchors.left: undefined
anchors.right: undefined
}
RowLayout {
@@ -210,8 +188,6 @@ ColumnLayout {
StringListEditor {
Layout.fillWidth: true
addLabel: qsTr("Add command argument")
anchors.left: undefined
anchors.right: undefined
values: [...(modelData.command ?? [])]
onListEdited: function (values) {
@@ -220,9 +196,6 @@ ColumnLayout {
}
Separator {
Layout.fillWidth: true
anchors.left: undefined
anchors.right: undefined
}
RowLayout {
@@ -241,9 +214,6 @@ ColumnLayout {
}
Separator {
Layout.fillWidth: true
anchors.left: undefined
anchors.right: undefined
}
RowLayout {
+13 -44
View File
@@ -6,14 +6,13 @@ import qs.Components
import qs.Config
import qs.Helpers
CustomRect {
ColumnLayout {
id: root
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property var object
required property string setting
property bool shouldBeActive: true
function addAlias() {
const list = [...root.object[root.setting]];
@@ -41,25 +40,8 @@ CustomRect {
Config.save();
}
anchors.left: parent.left
anchors.right: parent.right
height: shouldBeActive ? layout.implicitHeight : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
Rectangle {
anchors.fill: parent
@@ -76,14 +58,6 @@ CustomRect {
}
}
ColumnLayout {
id: layout
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.smaller
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
@@ -128,17 +102,15 @@ CustomRect {
}
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: 33
Layout.preferredWidth: Math.max(Math.min(fromTextField.contentWidth + Appearance.padding.large * 2, 550), 50)
color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.full
CustomTextField {
id: fromTextField
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, 550)
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
text: modelData.from ?? ""
onEditingFinished: root.updateAlias(index, "from", text)
@@ -163,17 +135,15 @@ CustomRect {
}
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: 33
Layout.preferredWidth: Math.max(Math.min(toTextField.contentWidth + Appearance.padding.large * 2, 550), 50)
color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.full
color: DynamicColors.tPalette.m3surface
radius: Appearance.rounding.small
CustomTextField {
id: toTextField
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, 550)
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
text: modelData.to ?? ""
onEditingFinished: root.updateAlias(index, "to", text)
@@ -199,5 +169,4 @@ CustomRect {
text: qsTr("Add alias")
}
}
}
}
+346 -47
View File
@@ -25,15 +25,75 @@ Item {
required property var object
property var pendingCommitEntries: []
required property string setting
property bool shouldBeActive: true
property int uidCounter: 0
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() {
if (!root.dragActive && !root.dropAnimating)
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) {
switch (id) {
case "workspaces":
@@ -93,7 +153,7 @@ Item {
case "spacer":
return qsTr("Spacer");
case "activeWindow":
return qsTr("Title");
return qsTr("Active window");
case "tray":
return qsTr("Tray");
case "upower":
@@ -103,14 +163,34 @@ Item {
case "clock":
return qsTr("Clock");
case "notifBell":
return qsTr("Notifs");
case "hyprsunset":
return qsTr("Night light");
return qsTr("Notification bell");
default:
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() {
const entries = root.object[root.setting] ?? [];
const next = [];
@@ -145,31 +225,15 @@ Item {
list[index] = entry;
root.object[root.setting] = list;
Config.save();
root.ensureVisualEntries();
}
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? layout.implicitHeight : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
implicitHeight: layout.implicitHeight
Component.onCompleted: root.rebuildVisualEntries()
CustomRect {
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
@@ -184,12 +248,39 @@ Item {
}
}
RowLayout {
ParallelAnimation {
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
anchors.fill: parent
spacing: Appearance.spacing.smaller
// spacing: Appearance.spacing.smaller
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.name
}
DelegateModel {
id: visualModel
@@ -202,40 +293,248 @@ Item {
}
}
Repeater {
delegate: entryDelegate
ListView {
id: listView
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
boundsBehavior: Flickable.StopAtBounds
clip: false
implicitHeight: contentHeight
implicitWidth: width
interactive: !(root.dragActive || root.dropAnimating)
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 {
id: entryDelegate
IconButton {
required property int index
DropArea {
id: slot
readonly property var entryData: modelData.entry
required property var modelData
readonly property string uid: modelData.uid
Layout.fillWidth: true
Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? 18 : internalChecked ? 7 : 0)
checked: modelData.entry.enabled ?? true
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))
function previewReorder(drag) {
const source = drag.source;
if (!source || !source.uid || source.uid === slot.uid)
return;
Behavior on Layout.preferredWidth {
const from = source.visualIndex;
const hovered = slot.DelegateModel.itemsIndex;
if (from < 0 || hovered < 0)
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 {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
}
}
onClicked: root.updateEntry(index, internalChecked)
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)
}
}
}
}
}
}
@@ -11,7 +11,6 @@ Item {
required property string name
required property var object
required property list<string> settings
property bool shouldBeActive: true
function commitChoice(choice: int, setting: string): void {
root.object[setting] = choice;
@@ -33,25 +32,8 @@ Item {
return Qt.formatTime(d, "h AP");
}
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
+2 -20
View File
@@ -11,7 +11,6 @@ Item {
required property string name
required property var object
required property string setting
property bool shouldBeActive: true
function formattedValue(): string {
const value = root.object[root.setting];
@@ -22,25 +21,8 @@ Item {
return String(value);
}
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
+10 -57
View File
@@ -8,31 +8,12 @@ Item {
required property int index
required property var modelData
property bool shouldBeActive: true
signal addActiveActionRequested
signal deleteRequested(int index)
signal fieldEdited(string key, var value)
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
CustomRect {
anchors.left: parent.left
@@ -84,64 +65,42 @@ Item {
HoverHandler {
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 {
anchors.left: parent.left
anchors.leftMargin: nameHover.hovered ? editButton.width + Appearance.spacing.smaller * 2 : 0
anchors.right: deleteButton.left
anchors.right: editButton.left
anchors.rightMargin: Appearance.spacing.small
anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight // enable if CustomText supports it
font.pointSize: Appearance.font.size.larger
text: root.modelData.name
visible: !nameCell.editing
Behavior on anchors.leftMargin {
Anim {
}
}
}
HoverIconButton {
id: deleteButton
IconButton {
id: editButton
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
font.pointSize: Appearance.font.size.large
icon: "delete"
shouldBeVisible: nameHover.hovered && !nameCell.editing
icon: "edit"
visible: nameHover.hovered && !nameCell.editing
onClicked: root.deleteRequested(root.index)
onClicked: nameCell.beginEdit()
}
CustomRect {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.fill: parent
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
visible: nameCell.editing
CustomTextField {
id: nameEditor
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, nameCell.width - Appearance.padding.normal)
anchors.fill: parent
text: nameCell.draftName
Keys.onEscapePressed: {
@@ -194,9 +153,6 @@ Item {
}
Separator {
Layout.fillWidth: true
anchors.left: undefined
anchors.right: undefined
}
RowLayout {
@@ -228,9 +184,6 @@ Item {
}
Separator {
Layout.fillWidth: true
anchors.left: undefined
anchors.right: undefined
}
Item {
+5 -28
View File
@@ -11,32 +11,10 @@ Item {
required property string name
required property var object
property alias row: row
required property string setting
property bool shouldBeActive: true
required property list<var> stringList
signal optionSet
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? row.height : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
Layout.preferredHeight: row.height
RowLayout {
id: row
@@ -60,7 +38,7 @@ Item {
Layout.preferredHeight: 42 * 6 + Appearance.padding.normal * 2 + Appearance.spacing.small * 5
Layout.preferredWidth: 500
color: DynamicColors.tPalette.m3surfaceContainer
radius: (21 + Appearance.padding.normal) * Appearance.rounding.scale
radius: 21 + Appearance.padding.normal
CustomRect {
id: searchBox
@@ -142,18 +120,17 @@ Item {
StateLayer {
onClicked: {
root.object[root.setting] = fontDelegate.modelData;
root.optionSet();
Config.save();
}
}
}
model: ScriptModel {
values: {
const values = root.stringList;
const fonts = Qt.fontFamilies();
const search = fontSearch.text;
var regex = new RegExp(search, "i");
return values.filter(n => regex.test(n));
return fonts.filter(n => regex.test(n));
}
}
}
+2 -20
View File
@@ -9,28 +9,10 @@ Item {
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
property bool shouldBeActive: true
required property string value
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
+2 -20
View File
@@ -13,28 +13,10 @@ Item {
required property string name
required property var object
required property string setting
property bool shouldBeActive: true
property real step: 1
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
+2 -20
View File
@@ -11,7 +11,6 @@ Item {
required property string name
required property var object
required property list<string> settings
property bool shouldBeActive: true
function commitChoice(choice: int, setting: string): void {
root.object[setting] = choice;
@@ -33,25 +32,8 @@ Item {
return Qt.formatTime(d, "h AP");
}
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
@@ -12,27 +12,9 @@ Item {
required property string name
required property var object
required property string setting
property bool shouldBeActive: true
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? layout.implicitHeight : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
Layout.preferredHeight: layout.implicitHeight
Rectangle {
anchors.fill: parent
@@ -64,9 +46,6 @@ Item {
StringListEditor {
Layout.fillWidth: true
addLabel: root.addLabel
anchors.left: undefined
anchors.right: undefined
anchors.verticalCenter: undefined
values: [...(root.object[root.setting] ?? [])]
onListEdited: function (values) {
+2 -20
View File
@@ -11,27 +11,9 @@ Item {
required property string name
required property var object
required property string setting
property bool shouldBeActive: true
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
+2 -6
View File
@@ -7,13 +7,9 @@ CustomRect {
id: root
required property string name
property bool shouldBeActive: true
implicitHeight: 60
implicitWidth: 200
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Layout.preferredHeight: 60
Layout.preferredWidth: 200
CustomText {
anchors.fill: parent
@@ -1,83 +0,0 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Paths
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
property alias button: iButton
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
property bool shouldBeActive: true
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
RowLayout {
id: row
anchors.left: parent.left
anchors.margins: Appearance.padding.small
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
CustomText {
id: text
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.name
}
IconButton {
id: iButton
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
icon: "download"
onClicked: {
const lockBg = `${Paths.state}/lockscreen_bg.png`;
const scheme = `${Paths.state}/scheme.json`;
const face = `${Paths.home}/.face`;
const destination = "/etc/zshell-greeter/images";
Quickshell.execDetached(["pkexec", "sh", "-c", `mkdir -p ${destination}; cp ${lockBg} ${destination}; cp ${scheme} /etc/zshell-greeter; cp ${face} ${destination}`]);
}
}
}
}
+1 -7
View File
@@ -60,18 +60,12 @@ CustomClippingRect {
}
}
Column {
ColumnLayout {
id: clayout
anchors.left: parent.left
anchors.right: parent.right
spacing: Appearance.spacing.small
// move: Transition {
// Anim {
// properties: "y"
// }
// }
}
}
}
+4 -25
View File
@@ -10,39 +10,18 @@ CustomRect {
property real contentPadding: Appearance.padding.large
property string sectionId: ""
anchors.left: parent.left
anchors.right: parent.right
Layout.fillWidth: true
Layout.preferredHeight: layout.implicitHeight + contentPadding * 2
color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: layout.height + contentPadding * 2
radius: Appearance.rounding.normal - Appearance.padding.smaller
Behavior on implicitHeight {
Anim {
}
}
Behavior on y {
Anim {
}
}
Column {
ColumnLayout {
id: layout
anchors.left: parent.left
anchors.margins: root.contentPadding
anchors.right: parent.right
anchors.top: parent.top
// anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.normal
Behavior on height {
Anim {
}
}
move: Transition {
Anim {
properties: "y"
}
}
}
}
@@ -12,29 +12,12 @@ CustomRect {
property alias expanded: menu.expanded
property alias label: label
property alias menu: menu
property bool shouldBeActive: true
property alias text: label.text
color: enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
opacity: shouldBeActive ? 1 : 0
radius: Appearance.rounding.full
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
z: expanded ? 100 : 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
CustomText {
id: label
+1 -20
View File
@@ -9,7 +9,6 @@ ColumnLayout {
id: root
property string addLabel: qsTr("Add entry")
property bool shouldBeActive: true
property var values: []
signal listEdited(var values)
@@ -32,26 +31,8 @@ ColumnLayout {
root.listEdited(list);
}
anchors.left: parent.left
anchors.right: parent.right
height: shouldBeActive ? implicitHeight : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Repeater {
model: [...root.values]
+71 -248
View File
@@ -1,279 +1,102 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import ZShell.Internal
import qs.Config
import qs.Components
import qs.Helpers
Item {
id: wrapper
property bool changesMade: false
property bool shouldBeActive: true
signal requestCrop
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: shouldBeActive ? 400 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
IconButton {
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
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
onClicked: {
wrapper.requestCrop();
wrapper.changesMade = false;
}
}
RowLayout {
ColumnLayout {
id: root
anchors.fill: parent
spacing: Appearance.spacing.normal
spacing: 15
width: Math.min(parent ? parent.width : 600, 600)
Repeater {
model: ScriptModel {
values: [...Quickshell.screens].sort((a, b) => {
return a.x - b.x;
})
}
Item {
id: delegate
required property ShellScreen modelData
function applyCrop(): void {
const croprect = cropRect.mapToItem(scaledImg, 0, 0, cropRect.width, cropRect.height);
const upscaledRect = Qt.rect((croprect.x - cropRect.imageX) / scaledImg.paintedWidth, (croprect.y - cropRect.imageY) / scaledImg.paintedHeight, croprect.width / scaledImg.paintedWidth, croprect.height / scaledImg.paintedHeight);
Wallpapers.setCrop(delegate.modelData.name, upscaledRect, croprect, cropRect.zoom);
}
function zoomClipRect(zoom: real): void {
let oldCenterX = cropRect.x + cropRect.width * 0.5;
let oldCenterY = cropRect.y + cropRect.height * 0.5;
cropRect.zoom = zoom;
cropRect.x = oldCenterX - cropRect.width * 0.5;
cropRect.y = oldCenterY - cropRect.height * 0.5;
cropRect.clampToBounds();
}
Rectangle {
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)
clip: true
color: DynamicColors.palette.m3surfaceContainer
radius: Config.appearance.rounding.scale * 10
Connections {
function onRequestCrop(): void {
delegate.applyCrop();
}
Image {
id: img
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;
}
}
}
CachingImage {
id: scaledImg
property var displayData
property real monitorScale: 1.0
anchors.bottom: sliderLayout.top
anchors.bottomMargin: Appearance.spacing.normal
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.fill: parent
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 {
Rectangle {
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();
}
}
property real cropHeight: (imageAspect > screenAspect ? paintedHeight : paintedWidth / screenAspect) / Config.background.zoom
property real cropWidth: (imageAspect > screenAspect ? paintedHeight * screenAspect : paintedWidth) / Config.background.zoom
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
border.width: 2
height: baseHeight / zoom
opacity: 1
width: baseWidth / zoom
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
Behavior on opacity {
Anim {
DragHandler {
target: null
onActiveTranslationChanged: {
if (active) {
let newX = cropRect.x - cropRect.paintedX + translation.x;
let newY = cropRect.y - cropRect.paintedY + translation.y;
let rangeX = cropRect.paintedWidth - cropRect.width;
let rangeY = cropRect.paintedHeight - cropRect.height;
if (rangeX > 0) {
let valX = newX / rangeX;
Config.background.alignX = Math.max(0.0, Math.min(1.0, valX));
Config.save();
}
if (rangeY > 0) {
let valY = newY / rangeY;
Config.background.alignY = Math.max(0.0, Math.min(1.0, valY));
Config.save();
}
}
}
}
Component.onCompleted: clampToBounds()
onHeightChanged: clampToBounds()
onWidthChanged: clampToBounds()
PinchHandler {
maximumScale: 5.0
minimumScale: 1.0
target: null
onActiveScaleChanged: {
if (active) {
let newZoom = Config.background.zoom * (1 / (1 + (activeScale - 1) * 0.1));
Config.background.zoom = Math.max(1.0, Math.min(newZoom, 5.0));
}
}
}
}
}
}
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
}
}
+35 -47
View File
@@ -12,30 +12,37 @@ GridView {
readonly property int columnsCount: Math.max(1, Math.floor(width / minCellWidth))
readonly property int minCellWidth: 200 + Appearance.spacing.normal
property bool shouldBeActive: true
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredHeight: contentHeight
cellHeight: 140 + Appearance.spacing.normal
cellWidth: width / columnsCount
clip: true
implicitHeight: shouldBeActive ? contentHeight : 0
interactive: false
model: Wallpapers.list
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
delegate: Item {
required property int index
readonly property bool isCurrent: modelData && modelData.path === Wallpapers.actualCurrent
readonly property real itemMargin: Appearance.spacing.normal
readonly property real itemRadius: Appearance.rounding.small
readonly property real itemMargin: Appearance.spacing.normal / 2
readonly property real itemRadius: Appearance.rounding.normal
required property var modelData
height: root.cellHeight
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 {
id: image
@@ -46,6 +53,8 @@ GridView {
anchors.topMargin: itemMargin
antialiasing: true
color: DynamicColors.tPalette.m3surfaceContainer
layer.enabled: true
layer.smooth: true
radius: itemRadius
CachingImage {
@@ -91,13 +100,29 @@ GridView {
}
}
Timer {
id: fallbackTimer
property bool triggered: false
interval: 800
running: cachingImage.status === Image.Loading || cachingImage.status === Image.Null
onTriggered: triggered = true
}
}
Rectangle {
anchors.bottomMargin: itemMargin
anchors.fill: parent
anchors.leftMargin: itemMargin
anchors.rightMargin: itemMargin
anchors.topMargin: itemMargin
antialiasing: true
border.color: DynamicColors.palette.m3primary
border.width: isCurrent ? 2 : 0
color: "transparent"
radius: itemRadius + 2
radius: itemRadius - border.width
smooth: true
Behavior on border.width {
@@ -117,42 +142,5 @@ GridView {
visible: isCurrent
}
}
Timer {
id: fallbackTimer
property bool triggered: false
interval: 800
running: cachingImage.status === Image.Loading || cachingImage.status === Image.Null
onTriggered: triggered = true
}
}
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
}
}
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
}
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -6,7 +6,7 @@ import QtQuick.Controls
import qs.Components
import qs.Config
import "../../scripts/fuzzysort.js" as Fuzzy
import "../../scripts/SettingsIndex.mjs" as SettingsIndex
import "./SettingsIndex.mjs" as SettingsIndex
Item {
id: root
@@ -53,10 +53,11 @@ Item {
Shortcut {
sequence: "/"
onActivated: searchField.forceActiveFocus()
}
Component.onCompleted: console.log(root.height)
ListModel {
id: resultsModel
}
+30 -9
View File
@@ -7,24 +7,45 @@ import qs.Helpers
Item {
id: root
property real offsetScale: shouldBeActive ? 0 : 1
required property var panels
required property ShellScreen screen
readonly property bool shouldBeActive: visibilities.settings
required property PersistentProperties visibilities
anchors.topMargin: (-implicitHeight - 5) * offsetScale
implicitHeight: content.implicitHeight
implicitHeight: 0
implicitWidth: content.implicitWidth
opacity: 1 - offsetScale
visible: offsetScale < 1
visible: height > 0
states: State {
name: "visible"
when: root.visibilities.settings
PropertyChanges {
root.implicitHeight: content.implicitHeight
}
}
transitions: [
Transition {
from: ""
to: "visible"
Behavior on offsetScale {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
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 {
anchors.fill: parent

Some files were not shown because too many files have changed in this diff Show More