Compare commits
20
Commits
v0.1.0
...
3f7bbc01aa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f7bbc01aa | ||
|
|
bc9d8af0fe | ||
|
|
01d521b42d | ||
|
|
7d65578a5f | ||
|
|
77ec1c87f8 | ||
|
|
f883b3d7fe | ||
|
|
e685500698 | ||
|
|
04481ae7e1 | ||
|
|
82a660229b | ||
|
|
ce6e314fde | ||
|
|
0b92cbb3b4 | ||
|
|
6a15be7b15 | ||
|
|
01c63ebead | ||
|
|
ecfa1115cd | ||
|
|
d08b2b7ac6 | ||
|
|
4df31d7564 | ||
|
|
5c6882d2a8 | ||
|
|
6a80961b2b | ||
|
|
2366901b24 | ||
|
|
ea4d5376f6 |
+10
-19
@@ -2,29 +2,20 @@
|
|||||||
Checks: >
|
Checks: >
|
||||||
-*,
|
-*,
|
||||||
bugprone-*,
|
bugprone-*,
|
||||||
|
-bugprone-easily-swappable-parameters,
|
||||||
|
-bugprone-narrowing-conversions,
|
||||||
|
-bugprone-implicit-widening-of-multiplication-result,
|
||||||
clang-analyzer-*,
|
clang-analyzer-*,
|
||||||
modernize-*,
|
cppcoreguidelines-init-variables,
|
||||||
-modernize-use-trailing-return-type,
|
misc-no-recursion,
|
||||||
performance-*,
|
concurrency-mt-unsafe,
|
||||||
readability-braces-around-statements,
|
|
||||||
readability-else-after-return,
|
readability-else-after-return,
|
||||||
readability-identifier-naming,
|
readability-make-member-function-const,
|
||||||
readability-redundant-*,
|
readability-redundant-*,
|
||||||
readability-simplify-*,
|
readability-simplify-*,
|
||||||
CheckOptions:
|
modernize-use-override,
|
||||||
readability-identifier-naming.ClassCase: CamelCase
|
modernize-use-nullptr,
|
||||||
readability-identifier-naming.EnumCase: CamelCase
|
modernize-deprecated-headers,
|
||||||
readability-identifier-naming.FunctionCase: camelBack
|
|
||||||
readability-identifier-naming.MemberCase: camelBack
|
|
||||||
readability-identifier-naming.MemberPrefix: m_
|
|
||||||
readability-identifier-naming.MethodCase: camelBack
|
|
||||||
readability-identifier-naming.NamespaceCase: CamelCase
|
|
||||||
readability-identifier-naming.ParameterCase: camelBack
|
|
||||||
readability-identifier-naming.PrivateMemberPrefix: m_
|
|
||||||
readability-identifier-naming.StaticConstantCase: UPPER_CASE
|
|
||||||
readability-identifier-naming.StaticConstantPrefix: k
|
|
||||||
readability-identifier-naming.VariableCase: camelBack
|
|
||||||
WarningsAsErrors: "*"
|
|
||||||
HeaderFilterRegex: ".*"
|
HeaderFilterRegex: ".*"
|
||||||
FormatStyle: file
|
FormatStyle: file
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
name: Rebuild CI Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 6 * * 1'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: alpine
|
||||||
|
env:
|
||||||
|
IMAGE: git.aramjonghu.nl/aramjonghu/zshell-ci:latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build image
|
||||||
|
run: docker build -t "$IMAGE" -f ci/Dockerfile .
|
||||||
|
|
||||||
|
- name: Push image
|
||||||
|
run: docker push "$IMAGE"
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: C++
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: alpine
|
||||||
|
container:
|
||||||
|
image: git.aramjonghu.nl/aramjonghu/zshell-ci:latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: cmake -B build -G Ninja -DENABLE_MODULES=plugin -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: ninja -C build
|
||||||
|
|
||||||
|
- name: clang-tidy
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
set -o pipefail
|
||||||
|
run-clang-tidy -p build -j $(nproc) -header-filter="Plugins/.*" 2>&1 | \
|
||||||
|
grep -v 'Suppressed\|non-user\|non-system\|unknown argument.*mno-direct'
|
||||||
+37
-8
@@ -1,6 +1,35 @@
|
|||||||
cmake_minimum_required(VERSION 3.19)
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
project(ZShell)
|
if(NOT DEFINED VERSION)
|
||||||
|
execute_process(
|
||||||
|
COMMAND git describe --tags --abbrev=0
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE GIT_LAST_TAG
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
)
|
||||||
|
|
||||||
|
if (GIT_LAST_TAG)
|
||||||
|
string(REGEX REPLACE "^v" "" GIT_LAST_TAG "${GIT_LAST_TAG}")
|
||||||
|
|
||||||
|
string(REPLACE "." ";" VERSION_LIST "${GIT_LAST_TAG}")
|
||||||
|
list(GET VERSION_LIST 0 VERSION_MAJOR)
|
||||||
|
list(GET VERSION_LIST 1 VERSION_MINOR)
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND git rev-list v${VERSION_MAJOR}.${VERSION_MINOR}.0..HEAD --count
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE VERSION_PATCH
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||||
|
|
||||||
|
project(ZShell VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
|
||||||
|
message(STATUS "ZShell version: ${VERSION}")
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
@@ -15,11 +44,11 @@ set(INSTALL_QSCONFDIR "etc/xdg/quickshell/zshell" CACHE STRING "Quickshell confi
|
|||||||
set(INSTALL_GREETERCONFDIR "etc/xdg/quickshell/zshell-greeter" CACHE STRING "Quickshell greeter install dir")
|
set(INSTALL_GREETERCONFDIR "etc/xdg/quickshell/zshell-greeter" CACHE STRING "Quickshell greeter install dir")
|
||||||
|
|
||||||
add_compile_options(
|
add_compile_options(
|
||||||
-Wall -Wextra -Wpedantic -Wshadow -Wconversion
|
-Wall -Wextra -Wpedantic -Wshadow -Wconversion
|
||||||
-Wold-style-cast -Wnull-dereference -Wdouble-promotion
|
-Wold-style-cast -Wnull-dereference -Wdouble-promotion
|
||||||
-Wformat=2 -Wfloat-equal -Woverloaded-virtual
|
-Wformat=2 -Wfloat-equal -Woverloaded-virtual
|
||||||
-Wsign-conversion -Wredundant-decls -Wswitch
|
-Wsign-conversion -Wredundant-decls -Wswitch
|
||||||
-Wunreachable-code
|
-Wunreachable-code
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -30,8 +59,8 @@ endif()
|
|||||||
|
|
||||||
if("shell" IN_LIST ENABLE_MODULES)
|
if("shell" IN_LIST ENABLE_MODULES)
|
||||||
foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths)
|
foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths)
|
||||||
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
|
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# Disable watching for changes
|
# Disable watching for changes
|
||||||
file(READ shell.qml SHELL_QML)
|
file(READ shell.qml SHELL_QML)
|
||||||
|
|||||||
@@ -4,12 +4,30 @@ import qs.Helpers
|
|||||||
Flickable {
|
Flickable {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property bool doneFakeFlick
|
||||||
|
|
||||||
interactive: !Visibilities.getForActive().isDrawing
|
interactive: !Visibilities.getForActive().isDrawing
|
||||||
maximumFlickVelocity: 3000
|
maximumFlickVelocity: 3000
|
||||||
|
|
||||||
rebound: Transition {
|
rebound: Transition {
|
||||||
|
onRunningChanged: {
|
||||||
|
if (!running && !root.doneFakeFlick) {
|
||||||
|
root.doneFakeFlick = true;
|
||||||
|
root.flick(1, 1);
|
||||||
|
root.flick(-1, -1);
|
||||||
|
Qt.callLater(() => root.cancelFlick());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Anim {
|
Anim {
|
||||||
properties: "x,y"
|
properties: "x,y"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 10
|
||||||
|
running: root.doneFakeFlick
|
||||||
|
|
||||||
|
onTriggered: root.doneFakeFlick = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,9 +87,15 @@ RowLayout {
|
|||||||
id: upButton
|
id: upButton
|
||||||
|
|
||||||
color: root.enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 1)
|
color: root.enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 1)
|
||||||
implicitHeight: upIcon.implicitHeight + Appearance.padding.small * 2
|
implicitHeight: upIcon.implicitHeight + Appearance.padding.extraSmall * 2
|
||||||
implicitWidth: implicitHeight
|
implicitWidth: implicitHeight
|
||||||
radius: Appearance.rounding.full
|
radius: upState.pressed ? Appearance.rounding.small : Appearance.rounding.normal
|
||||||
|
|
||||||
|
Behavior on radius {
|
||||||
|
Anim {
|
||||||
|
type: Anim.FastEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
id: upState
|
id: upState
|
||||||
@@ -120,9 +126,15 @@ RowLayout {
|
|||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
color: root.enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 1)
|
color: root.enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 1)
|
||||||
implicitHeight: downIcon.implicitHeight + Appearance.padding.small * 2
|
implicitHeight: downIcon.implicitHeight + Appearance.padding.extraSmall * 2
|
||||||
implicitWidth: implicitHeight
|
implicitWidth: implicitHeight
|
||||||
radius: Appearance.rounding.full
|
radius: downState.pressed ? Appearance.rounding.small : Appearance.rounding.normal
|
||||||
|
|
||||||
|
Behavior on radius {
|
||||||
|
Anim {
|
||||||
|
type: Anim.FastEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
id: downState
|
id: downState
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int fadeInAnim: Anim.DefaultEffects
|
||||||
|
property int fadeInLargeAnim: Anim.StandardLarge
|
||||||
|
property int fadeOutAnim: Anim.FastEffects
|
||||||
|
property bool fadingOut
|
||||||
|
property bool hadPrevious
|
||||||
|
property bool preventInit
|
||||||
|
|
||||||
|
function maybeStartInAnim(): void {
|
||||||
|
if (!preventInit && !opacityInAnim.running && status === Image.Ready) {
|
||||||
|
opacityInAnim.type = hadPrevious ? fadeInAnim : fadeInLargeAnim;
|
||||||
|
opacityInAnim.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
opacity: 0
|
||||||
|
retainWhileLoading: true
|
||||||
|
sourceSize: {
|
||||||
|
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
|
||||||
|
return Qt.size(width * dpr, height * dpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim on opacity {
|
||||||
|
id: opacityInAnim
|
||||||
|
|
||||||
|
running: false
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
Behavior on source {
|
||||||
|
SequentialAnimation {
|
||||||
|
ScriptAction {
|
||||||
|
script: opacityInAnim.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
property: "fadingOut"
|
||||||
|
target: root
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
target: root
|
||||||
|
to: 0
|
||||||
|
type: root.fadeOutAnim
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
property: "fadingOut"
|
||||||
|
target: root
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
property: "hadPrevious"
|
||||||
|
target: root
|
||||||
|
value: root.source
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptAction {
|
||||||
|
script: root.maybeStartInAnim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPreventInitChanged: maybeStartInAnim()
|
||||||
|
onStatusChanged: maybeStartInAnim()
|
||||||
|
}
|
||||||
@@ -63,6 +63,7 @@ ButtonBase {
|
|||||||
id: label
|
id: label
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.topMargin: -1
|
||||||
color: root.onColor
|
color: root.onColor
|
||||||
font: root.font
|
font: root.font
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,309 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
enum Variant {
|
||||||
|
Outlined,
|
||||||
|
Filled
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property color accent: !root.enabled ? DynamicColors.palette.m3onSurface : (isError ? DynamicColors.palette.m3error : (focused ? DynamicColors.palette.m3primary : DynamicColors.palette.m3outline))
|
||||||
|
readonly property real disabledOpacity: 0.38
|
||||||
|
readonly property string effectiveTrailingIcon: root.trailingIcon.length > 0 ? root.trailingIcon : (root.password ? (field.echoMode === TextInput.Password ? "visibility" : "visibility_off") : (root.isError ? "error" : ""))
|
||||||
|
property string errorText: ""
|
||||||
|
readonly property alias field: field
|
||||||
|
readonly property bool floating: focused || hasContent || prefixText.length > 0
|
||||||
|
readonly property bool focused: field.activeFocus
|
||||||
|
readonly property bool hasContent: field.text.length > 0
|
||||||
|
readonly property color iconColor: !root.enabled ? DynamicColors.palette.m3onSurface : (isError ? DynamicColors.palette.m3error : (focused ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant))
|
||||||
|
property int inputMethodHints: Qt.ImhNone
|
||||||
|
property bool isError: false
|
||||||
|
property string label: ""
|
||||||
|
readonly property color labelColor: !root.enabled ? DynamicColors.palette.m3onSurface : (isError ? DynamicColors.palette.m3error : (focused ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant))
|
||||||
|
property string leadingIcon: ""
|
||||||
|
property int maxLength: 0
|
||||||
|
property color notchColor: DynamicColors.palette.m3surface
|
||||||
|
readonly property bool outlined: variant === M3TextField.Variant.Outlined
|
||||||
|
property bool password: false
|
||||||
|
property string placeholder: ""
|
||||||
|
property string prefixText: ""
|
||||||
|
property string suffixText: ""
|
||||||
|
readonly property color supportColor: !root.enabled ? DynamicColors.palette.m3onSurface : (isError ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurfaceVariant)
|
||||||
|
property string supportingText: ""
|
||||||
|
property alias text: field.text
|
||||||
|
property string trailingIcon: ""
|
||||||
|
readonly property bool trailingInteractive: root.password && root.trailingIcon.length === 0
|
||||||
|
property var validator: null
|
||||||
|
property int variant: M3TextField.Variant.Outlined
|
||||||
|
|
||||||
|
signal accepted
|
||||||
|
|
||||||
|
function forceFieldFocus(): void {
|
||||||
|
field.forceActiveFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitHeight: 56 + (supportRow.visible ? supportRow.implicitHeight + Appearance.spacing.extraSmall : 0)
|
||||||
|
implicitWidth: 240
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: filledBg
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
color: root.enabled ? (root.focused ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 1) : DynamicColors.palette.m3surfaceContainerHigh) : DynamicColors.palette.m3onSurface
|
||||||
|
implicitHeight: 56
|
||||||
|
opacity: root.enabled ? 1 : 0.04 // M3 filled disabled container @ 4%
|
||||||
|
|
||||||
|
topLeftRadius: Appearance.rounding.small
|
||||||
|
topRightRadius: Appearance.rounding.small
|
||||||
|
visible: !root.outlined
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: root.isError ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurface
|
||||||
|
enabled: root.enabled
|
||||||
|
topLeftRadius: Appearance.rounding.small
|
||||||
|
topRightRadius: Appearance.rounding.small
|
||||||
|
|
||||||
|
onClicked: field.forceActiveFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
color: root.accent
|
||||||
|
implicitHeight: root.focused || root.isError ? 2 : 1
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
Anim {
|
||||||
|
type: Anim.StandardSmall
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: outline
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
border.color: root.accent
|
||||||
|
border.width: root.focused || root.isError ? 2 : 1
|
||||||
|
color: "transparent"
|
||||||
|
implicitHeight: 56
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
visible: root.outlined
|
||||||
|
|
||||||
|
Behavior on border.color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on border.width {
|
||||||
|
Anim {
|
||||||
|
type: Anim.StandardSmall
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: outline.border.width
|
||||||
|
color: root.isError ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurface
|
||||||
|
enabled: root.enabled
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
onClicked: field.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: root.notchColor
|
||||||
|
height: outline.border.width
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
visible: root.outlined && root.floating && root.label.length > 0
|
||||||
|
width: labelText.width + Appearance.spacing.extraSmall
|
||||||
|
x: labelText.x - Appearance.spacing.extraSmall / 2
|
||||||
|
y: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: labelText
|
||||||
|
|
||||||
|
color: root.labelColor
|
||||||
|
font.pointSize: root.floating ? Appearance.font.size.small : Appearance.font.size.medium
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
text: root.label
|
||||||
|
visible: root.label.length > 0
|
||||||
|
x: root.floating ? (Appearance.padding.larger + Appearance.spacing.extraSmall / 2) : (leading.visible ? leading.x + leading.width + Appearance.spacing.small : Appearance.padding.larger)
|
||||||
|
y: root.floating ? (root.outlined ? -height / 2 : Appearance.padding.extraSmall) : (56 - height) / 2
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on x {
|
||||||
|
Anim {
|
||||||
|
type: Anim.StandardSmall
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
type: Anim.StandardSmall
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: leading
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Appearance.padding.larger
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: (56 - height) / 2
|
||||||
|
color: root.iconColor
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
text: root.leadingIcon
|
||||||
|
visible: root.leadingIcon.length > 0
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: trailing
|
||||||
|
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Appearance.padding.larger
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: (56 - height) / 2
|
||||||
|
color: root.isError ? DynamicColors.palette.m3error : (root.enabled ? DynamicColors.palette.m3onSurfaceVariant : DynamicColors.palette.m3onSurface)
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
text: root.effectiveTrailingIcon
|
||||||
|
visible: root.effectiveTrailingIcon.length > 0
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -Appearance.padding.small
|
||||||
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
enabled: root.trailingInteractive && root.enabled
|
||||||
|
|
||||||
|
onClicked: field.echoMode = field.echoMode === TextInput.Password ? TextInput.Normal : TextInput.Password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: prefix
|
||||||
|
|
||||||
|
anchors.left: leading.visible ? leading.right : parent.left
|
||||||
|
anchors.leftMargin: leading.visible ? Appearance.spacing.small : Appearance.padding.larger
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: root.floating && !root.outlined ? Appearance.font.size.small + Appearance.padding.extraSmall : 0
|
||||||
|
color: root.enabled ? DynamicColors.palette.m3onSurfaceVariant : DynamicColors.palette.m3onSurface
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
height: 56
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
text: root.prefixText
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
visible: root.prefixText.length > 0 && root.floating
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: suffix
|
||||||
|
|
||||||
|
anchors.right: trailing.visible ? trailing.left : parent.right
|
||||||
|
anchors.rightMargin: trailing.visible ? Appearance.spacing.small : Appearance.padding.larger
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: root.floating && !root.outlined ? Appearance.font.size.small + Appearance.padding.extraSmall : 0
|
||||||
|
color: root.enabled ? DynamicColors.palette.m3onSurfaceVariant : DynamicColors.palette.m3onSurface
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
height: 56
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
text: root.suffixText
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
visible: root.suffixText.length > 0 && root.floating
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: field
|
||||||
|
|
||||||
|
anchors.left: prefix.visible ? prefix.right : (leading.visible ? leading.right : parent.left)
|
||||||
|
anchors.leftMargin: prefix.visible ? Appearance.spacing.extraSmall : (leading.visible ? Appearance.spacing.small : Appearance.padding.larger)
|
||||||
|
anchors.right: suffix.visible ? suffix.left : (trailing.visible ? trailing.left : parent.right)
|
||||||
|
anchors.rightMargin: suffix.visible ? Appearance.spacing.extraSmall : (trailing.visible ? Appearance.spacing.small : Appearance.padding.larger)
|
||||||
|
anchors.top: parent.top
|
||||||
|
color: DynamicColors.palette.m3onSurface
|
||||||
|
echoMode: root.password ? TextInput.Password : TextInput.Normal
|
||||||
|
enabled: root.enabled
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
height: 56
|
||||||
|
inputMethodHints: root.inputMethodHints
|
||||||
|
maximumLength: root.maxLength > 0 ? root.maxLength : 32767
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
placeholderText: root.focused ? root.placeholder : ""
|
||||||
|
topPadding: root.floating && !root.outlined ? Appearance.font.size.small + Appearance.padding.extraSmall : 0
|
||||||
|
validator: root.validator
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
||||||
|
onAccepted: root.accepted()
|
||||||
|
onTextEdited: if (root.isError)
|
||||||
|
root.isError = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: supportRow
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 56 + Appearance.spacing.extraSmall
|
||||||
|
implicitHeight: Math.max(supportText.implicitHeight, counter.implicitHeight)
|
||||||
|
visible: (root.isError && root.errorText.length > 0) || root.supportingText.length > 0 || root.maxLength > 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: supportText
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Appearance.padding.larger
|
||||||
|
anchors.right: counter.visible ? counter.left : parent.right
|
||||||
|
anchors.rightMargin: Appearance.spacing.small
|
||||||
|
color: root.supportColor
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
text: root.isError && root.errorText.length > 0 ? root.errorText : root.supportingText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: counter
|
||||||
|
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Appearance.padding.larger
|
||||||
|
color: root.supportColor
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
opacity: root.enabled ? 1 : root.disabledOpacity
|
||||||
|
text: `${root.text.length}/${root.maxLength}`
|
||||||
|
visible: root.maxLength > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ MouseArea {
|
|||||||
return (Math.sqrt(Math.max(d1, d2, d3, d4)) + (shapeMorph ? 24 : 0)) * 1.3;
|
return (Math.sqrt(Math.max(d1, d2, d3, d4)) + (shapeMorph ? 24 : 0)) * 1.3;
|
||||||
}
|
}
|
||||||
property real endRadiusAtPress
|
property real endRadiusAtPress
|
||||||
|
property bool manualHoverOverride
|
||||||
property bool manualPressOverride
|
property bool manualPressOverride
|
||||||
property real pressX: width / 2
|
property real pressX: width / 2
|
||||||
property real pressY: height / 2
|
property real pressY: height / 2
|
||||||
@@ -27,7 +28,7 @@ MouseArea {
|
|||||||
readonly property alias rect: base
|
readonly property alias rect: base
|
||||||
property bool shapeMorph
|
property bool shapeMorph
|
||||||
property bool showHoverBackground: true
|
property bool showHoverBackground: true
|
||||||
property real stateOpacity: containsMouse ? 0.08 : 0
|
property real stateOpacity: containsMouse || manualHoverOverride ? 0.08 : 0
|
||||||
property alias topLeftRadius: base.topLeftRadius
|
property alias topLeftRadius: base.topLeftRadius
|
||||||
property alias topRightRadius: base.topRightRadius
|
property alias topRightRadius: base.topRightRadius
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.Effects
|
||||||
|
|
||||||
|
CustomFlickable {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property real bottomFadeOpacity: fadeShouldBeActive(false) ? 0 : 1
|
||||||
|
property real fadeAmount: 0.1
|
||||||
|
property real topFadeOpacity: fadeShouldBeActive(true) ? 0 : 1
|
||||||
|
|
||||||
|
function fadeShouldBeActive(isStart: bool): bool {
|
||||||
|
// When content is smaller than flickable size, hide fade when rebound starts
|
||||||
|
if (contentHeight + topMargin + bottomMargin < height && rebound.running && ((isStart ? verticalOvershoot > 0 : verticalOvershoot < 0)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isStart)
|
||||||
|
return visibleArea.yPosition > 0;
|
||||||
|
return visibleArea.yPosition + visibleArea.heightRatio < 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
layer.enabled: true
|
||||||
|
|
||||||
|
Behavior on bottomFadeOpacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layer.effect: Mask {
|
||||||
|
maskSource: mask
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: mask
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
layer.enabled: true
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
gradient: Gradient {
|
||||||
|
orientation: Gradient.Vertical
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(0, 0, 0, root.topFadeOpacity)
|
||||||
|
position: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(0, 0, 0, 1)
|
||||||
|
position: root.fadeAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(0, 0, 0, 1)
|
||||||
|
position: 1 - root.fadeAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(0, 0, 0, root.bottomFadeOpacity)
|
||||||
|
position: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on topFadeOpacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.Effects
|
||||||
|
|
||||||
|
CustomListView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property real bottomFadeOpacity: fadeShouldBeActive(false) ? 0 : 1
|
||||||
|
property real fadeAmount: 0.1
|
||||||
|
property real topFadeOpacity: fadeShouldBeActive(true) ? 0 : 1
|
||||||
|
|
||||||
|
function fadeShouldBeActive(isStart: bool): bool {
|
||||||
|
// When content is smaller than flickable size, hide fade when rebound starts
|
||||||
|
if (contentHeight + topMargin + bottomMargin < height && rebound.running && ((isStart ? verticalOvershoot > 0 : verticalOvershoot < 0)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isStart)
|
||||||
|
return visibleArea.yPosition > 0;
|
||||||
|
return visibleArea.yPosition + visibleArea.heightRatio < 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
layer.enabled: true
|
||||||
|
orientation: ListView.Vertical
|
||||||
|
|
||||||
|
Behavior on bottomFadeOpacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layer.effect: Mask {
|
||||||
|
maskSource: mask
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: mask
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
layer.enabled: true
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
gradient: Gradient {
|
||||||
|
orientation: Gradient.Vertical
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(0, 0, 0, root.topFadeOpacity)
|
||||||
|
position: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(0, 0, 0, 1)
|
||||||
|
position: root.fadeAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(0, 0, 0, 1)
|
||||||
|
position: 1 - root.fadeAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(0, 0, 0, root.bottomFadeOpacity)
|
||||||
|
position: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on topFadeOpacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,6 +72,12 @@ JsonObject {
|
|||||||
property bool upower: true
|
property bool upower: true
|
||||||
}
|
}
|
||||||
component Tray: JsonObject {
|
component Tray: JsonObject {
|
||||||
|
property bool showAudio: true
|
||||||
|
property bool showBluetooth: false
|
||||||
|
property bool showMicrophone: true
|
||||||
|
property bool showNetwork: false
|
||||||
|
property bool showPower: true
|
||||||
|
property bool showWifi: false
|
||||||
property int trayIconSize: 24
|
property int trayIconSize: 24
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-359
@@ -12,7 +12,7 @@ Singleton {
|
|||||||
|
|
||||||
property alias appearance: adapter.appearance
|
property alias appearance: adapter.appearance
|
||||||
property alias background: adapter.background
|
property alias background: adapter.background
|
||||||
property alias barConfig: adapter.barConfig
|
property alias bar: adapter.bar
|
||||||
property alias clipboard: adapter.clipboard
|
property alias clipboard: adapter.clipboard
|
||||||
property alias colors: adapter.colors
|
property alias colors: adapter.colors
|
||||||
property alias dashboard: adapter.dashboard
|
property alias dashboard: adapter.dashboard
|
||||||
@@ -20,6 +20,7 @@ Singleton {
|
|||||||
property alias general: adapter.general
|
property alias general: adapter.general
|
||||||
property alias launcher: adapter.launcher
|
property alias launcher: adapter.launcher
|
||||||
property alias lock: adapter.lock
|
property alias lock: adapter.lock
|
||||||
|
property bool migratingLegacyBar: false
|
||||||
property alias notifs: adapter.notifs
|
property alias notifs: adapter.notifs
|
||||||
property alias osd: adapter.osd
|
property alias osd: adapter.osd
|
||||||
property alias overview: adapter.overview
|
property alias overview: adapter.overview
|
||||||
@@ -29,6 +30,41 @@ Singleton {
|
|||||||
property alias sidebar: adapter.sidebar
|
property alias sidebar: adapter.sidebar
|
||||||
property alias utilities: adapter.utilities
|
property alias utilities: adapter.utilities
|
||||||
|
|
||||||
|
function applyLegacyBarConfig(legacy): void {
|
||||||
|
const tray = legacy.tray ?? {};
|
||||||
|
const popouts = legacy.popouts ?? {};
|
||||||
|
|
||||||
|
bar.autoHide = pick(legacy.autoHide, bar.autoHide);
|
||||||
|
bar.hideWhenNotif = pick(legacy.hideWhenNotif, bar.hideWhenNotif);
|
||||||
|
bar.rounding = pick(legacy.rounding, bar.rounding);
|
||||||
|
bar.border = pick(legacy.border, bar.border);
|
||||||
|
bar.smoothing = pick(legacy.smoothing, bar.smoothing);
|
||||||
|
bar.height = pick(legacy.height, bar.height);
|
||||||
|
bar.tray.trayIconSize = pick(tray.trayIconSize, bar.tray.trayIconSize);
|
||||||
|
bar.popouts.tray = pick(popouts.tray, bar.popouts.tray);
|
||||||
|
bar.popouts.audio = pick(popouts.audio, bar.popouts.audio);
|
||||||
|
bar.popouts.activeWindow = pick(popouts.activeWindow, bar.popouts.activeWindow);
|
||||||
|
bar.popouts.resources = pick(popouts.resources, bar.popouts.resources);
|
||||||
|
bar.popouts.clock = pick(popouts.clock, bar.popouts.clock);
|
||||||
|
bar.popouts.network = pick(popouts.network, bar.popouts.network);
|
||||||
|
bar.popouts.upower = pick(popouts.upower, bar.popouts.upower);
|
||||||
|
bar.entries = pick(legacy.entries, bar.entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateLegacyBarConfig(raw): bool {
|
||||||
|
if (raw.bar !== undefined || raw.barConfig === undefined)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
migratingLegacyBar = true;
|
||||||
|
applyLegacyBarConfig(raw.barConfig);
|
||||||
|
migratingLegacyBar = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pick(value, fallback) {
|
||||||
|
return value === undefined ? fallback : value;
|
||||||
|
}
|
||||||
|
|
||||||
function save(): void {
|
function save(): void {
|
||||||
saveTimer.restart();
|
saveTimer.restart();
|
||||||
recentlySaved = true;
|
recentlySaved = true;
|
||||||
@@ -39,348 +75,6 @@ Singleton {
|
|||||||
saveTimer.restart();
|
saveTimer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
function serializeAppearance(): var {
|
|
||||||
return {
|
|
||||||
rounding: {
|
|
||||||
scale: appearance.rounding.scale
|
|
||||||
},
|
|
||||||
spacing: {
|
|
||||||
scale: appearance.spacing.scale
|
|
||||||
},
|
|
||||||
padding: {
|
|
||||||
scale: appearance.padding.scale
|
|
||||||
},
|
|
||||||
deform: {
|
|
||||||
scale: appearance.deform.scale
|
|
||||||
},
|
|
||||||
font: {
|
|
||||||
family: {
|
|
||||||
sans: appearance.font.family.sans,
|
|
||||||
mono: appearance.font.family.mono,
|
|
||||||
material: appearance.font.family.material,
|
|
||||||
clock: appearance.font.family.clock
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
scale: appearance.font.size.scale
|
|
||||||
}
|
|
||||||
},
|
|
||||||
anim: {
|
|
||||||
mediaGifSpeedAdjustment: appearance.anim.mediaGifSpeedAdjustment,
|
|
||||||
sessionGifSpeed: appearance.anim.sessionGifSpeed,
|
|
||||||
durations: {
|
|
||||||
scale: appearance.anim.durations.scale
|
|
||||||
}
|
|
||||||
},
|
|
||||||
transparency: {
|
|
||||||
enabled: appearance.transparency.enabled,
|
|
||||||
base: appearance.transparency.base,
|
|
||||||
layers: appearance.transparency.layers
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeBackground(): var {
|
|
||||||
return {
|
|
||||||
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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeBar(): var {
|
|
||||||
return {
|
|
||||||
autoHide: barConfig.autoHide,
|
|
||||||
hideWhenNotif: barConfig.hideWhenNotif,
|
|
||||||
rounding: barConfig.rounding,
|
|
||||||
border: barConfig.border,
|
|
||||||
smoothing: barConfig.smoothing,
|
|
||||||
height: barConfig.height,
|
|
||||||
tray: {
|
|
||||||
trayIconSize: barConfig.tray.trayIconSize
|
|
||||||
},
|
|
||||||
popouts: {
|
|
||||||
tray: barConfig.popouts.tray,
|
|
||||||
audio: barConfig.popouts.audio,
|
|
||||||
activeWindow: barConfig.popouts.activeWindow,
|
|
||||||
resources: barConfig.popouts.resources,
|
|
||||||
clock: barConfig.popouts.clock,
|
|
||||||
network: barConfig.popouts.network,
|
|
||||||
upower: barConfig.popouts.upower
|
|
||||||
},
|
|
||||||
entries: barConfig.entries
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeClipboard(): var {
|
|
||||||
return {
|
|
||||||
enabled: clipboard.enabled,
|
|
||||||
maxEntriesShown: clipboard.maxEntriesShown,
|
|
||||||
sizes: {
|
|
||||||
width: clipboard.sizes.width,
|
|
||||||
previewWidth: clipboard.sizes.previewWidth,
|
|
||||||
minPreviewWidth: clipboard.sizes.minPreviewWidth,
|
|
||||||
itemHeight: clipboard.sizes.itemHeight
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeColors(): var {
|
|
||||||
return {
|
|
||||||
schemeType: colors.schemeType,
|
|
||||||
presets: {
|
|
||||||
name: colors.presets.name,
|
|
||||||
variant: colors.presets.variant,
|
|
||||||
accent: colors.presets.accent
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeConfig(): var {
|
|
||||||
return {
|
|
||||||
barConfig: serializeBar(),
|
|
||||||
lock: serializeLock(),
|
|
||||||
general: serializeGeneral(),
|
|
||||||
services: serializeServices(),
|
|
||||||
notifs: serializeNotifs(),
|
|
||||||
sidebar: serializeSidebar(),
|
|
||||||
utilities: serializeUtilities(),
|
|
||||||
dashboard: serializeDashboard(),
|
|
||||||
appearance: serializeAppearance(),
|
|
||||||
osd: serializeOsd(),
|
|
||||||
background: serializeBackground(),
|
|
||||||
launcher: serializeLauncher(),
|
|
||||||
colors: serializeColors(),
|
|
||||||
dock: serializeDock(),
|
|
||||||
screenshot: serializeScreenshot(),
|
|
||||||
clipboard: serializeClipboard()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeDashboard(): var {
|
|
||||||
return {
|
|
||||||
enabled: dashboard.enabled,
|
|
||||||
mediaUpdateInterval: dashboard.mediaUpdateInterval,
|
|
||||||
resourceUpdateInterval: dashboard.resourceUpdateInterval,
|
|
||||||
dragThreshold: dashboard.dragThreshold,
|
|
||||||
performance: {
|
|
||||||
showBattery: dashboard.performance.showBattery,
|
|
||||||
showGpu: dashboard.performance.showGpu,
|
|
||||||
showCpu: dashboard.performance.showCpu,
|
|
||||||
showMemory: dashboard.performance.showMemory,
|
|
||||||
showStorage: dashboard.performance.showStorage,
|
|
||||||
showNetwork: dashboard.performance.showNetwork
|
|
||||||
},
|
|
||||||
sizes: {
|
|
||||||
tabIndicatorHeight: dashboard.sizes.tabIndicatorHeight,
|
|
||||||
tabIndicatorSpacing: dashboard.sizes.tabIndicatorSpacing,
|
|
||||||
infoWidth: dashboard.sizes.infoWidth,
|
|
||||||
infoIconSize: dashboard.sizes.infoIconSize,
|
|
||||||
dateTimeWidth: dashboard.sizes.dateTimeWidth,
|
|
||||||
mediaWidth: dashboard.sizes.mediaWidth,
|
|
||||||
mediaProgressSweep: dashboard.sizes.mediaProgressSweep,
|
|
||||||
mediaProgressThickness: dashboard.sizes.mediaProgressThickness,
|
|
||||||
resourceProgessThickness: dashboard.sizes.resourceProgessThickness,
|
|
||||||
weatherWidth: dashboard.sizes.weatherWidth,
|
|
||||||
mediaCoverArtSize: dashboard.sizes.mediaCoverArtSize,
|
|
||||||
mediaVisualizerSize: dashboard.sizes.mediaVisualizerSize,
|
|
||||||
resourceSize: dashboard.sizes.resourceSize
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeDock(): var {
|
|
||||||
return {
|
|
||||||
enable: dock.enable,
|
|
||||||
height: dock.height,
|
|
||||||
hoverToReveal: dock.hoverToReveal,
|
|
||||||
pinnedApps: dock.pinnedApps,
|
|
||||||
pinnedOnStartup: dock.pinnedOnStartup,
|
|
||||||
ignoredAppRegexes: dock.ignoredAppRegexes
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeGeneral(): var {
|
|
||||||
return {
|
|
||||||
logo: general.logo,
|
|
||||||
wallpaperPath: general.wallpaperPath,
|
|
||||||
showOverFullscreen: general.showOverFullscreen,
|
|
||||||
desktopIcons: general.desktopIcons,
|
|
||||||
dateFormat: general.dateFormat,
|
|
||||||
color: {
|
|
||||||
mode: general.color.mode,
|
|
||||||
smart: general.color.smart,
|
|
||||||
scheduleDark: general.color.scheduleDark,
|
|
||||||
scheduleHyprsunset: general.color.scheduleHyprsunset,
|
|
||||||
scheduleHyprsunsetStart: general.color.scheduleHyprsunsetStart,
|
|
||||||
hyprsunsetTemp: general.color.hyprsunsetTemp,
|
|
||||||
scheduleHyprsunsetEnd: general.color.scheduleHyprsunsetEnd,
|
|
||||||
schemeGeneration: general.color.schemeGeneration,
|
|
||||||
scheduleDarkStart: general.color.scheduleDarkStart,
|
|
||||||
scheduleDarkEnd: general.color.scheduleDarkEnd,
|
|
||||||
neovimColors: general.color.neovimColors
|
|
||||||
},
|
|
||||||
apps: {
|
|
||||||
terminal: general.apps.terminal,
|
|
||||||
audio: general.apps.audio,
|
|
||||||
playback: general.apps.playback,
|
|
||||||
explorer: general.apps.explorer
|
|
||||||
},
|
|
||||||
idle: {
|
|
||||||
timeouts: general.idle.timeouts
|
|
||||||
},
|
|
||||||
battery: {
|
|
||||||
popupThresholds: general.battery.popupThresholds,
|
|
||||||
critPerc: general.battery.critPerc
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeLauncher(): var {
|
|
||||||
return {
|
|
||||||
maxAppsShown: launcher.maxAppsShown,
|
|
||||||
maxWallpapers: launcher.maxWallpapers,
|
|
||||||
uwsm: launcher.uwsm,
|
|
||||||
actionPrefix: launcher.actionPrefix,
|
|
||||||
specialPrefix: launcher.specialPrefix,
|
|
||||||
useFuzzy: {
|
|
||||||
apps: launcher.useFuzzy.apps,
|
|
||||||
actions: launcher.useFuzzy.actions,
|
|
||||||
schemes: launcher.useFuzzy.schemes,
|
|
||||||
variants: launcher.useFuzzy.variants,
|
|
||||||
wallpapers: launcher.useFuzzy.wallpapers
|
|
||||||
},
|
|
||||||
sizes: {
|
|
||||||
itemWidth: launcher.sizes.itemWidth,
|
|
||||||
itemHeight: launcher.sizes.itemHeight,
|
|
||||||
wallpaperWidth: launcher.sizes.wallpaperWidth,
|
|
||||||
wallpaperHeight: launcher.sizes.wallpaperHeight
|
|
||||||
},
|
|
||||||
actions: launcher.actions
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeLock(): var {
|
|
||||||
return {
|
|
||||||
recolorLogo: lock.recolorLogo,
|
|
||||||
enableFprint: lock.enableFprint,
|
|
||||||
showNotifContent: lock.showNotifContent,
|
|
||||||
showNotifIcon: lock.showNotifIcon,
|
|
||||||
maxFprintTries: lock.maxFprintTries,
|
|
||||||
blurAmount: lock.blurAmount,
|
|
||||||
sizes: {
|
|
||||||
heightMult: lock.sizes.heightMult,
|
|
||||||
ratio: lock.sizes.ratio,
|
|
||||||
centerWidth: lock.sizes.centerWidth
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeNotifs(): var {
|
|
||||||
return {
|
|
||||||
expire: notifs.expire,
|
|
||||||
defaultExpireTimeout: notifs.defaultExpireTimeout,
|
|
||||||
appNotifCooldown: notifs.appNotifCooldown,
|
|
||||||
clearThreshold: notifs.clearThreshold,
|
|
||||||
expandThreshold: notifs.expandThreshold,
|
|
||||||
actionOnClick: notifs.actionOnClick,
|
|
||||||
groupPreviewNum: notifs.groupPreviewNum,
|
|
||||||
sizes: {
|
|
||||||
width: notifs.sizes.width,
|
|
||||||
image: notifs.sizes.image,
|
|
||||||
badge: notifs.sizes.badge
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeOsd(): var {
|
|
||||||
return {
|
|
||||||
enabled: osd.enabled,
|
|
||||||
hideDelay: osd.hideDelay,
|
|
||||||
enableBrightness: osd.enableBrightness,
|
|
||||||
enableMicrophone: osd.enableMicrophone,
|
|
||||||
allMonBrightness: osd.allMonBrightness,
|
|
||||||
sizes: {
|
|
||||||
sliderWidth: osd.sizes.sliderWidth,
|
|
||||||
sliderHeight: osd.sizes.sliderHeight
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeScreenshot(): var {
|
|
||||||
return {
|
|
||||||
enable_pp: screenshot.enable_pp,
|
|
||||||
mode: screenshot.mode,
|
|
||||||
radius: screenshot.radius,
|
|
||||||
shadow: screenshot.shadow,
|
|
||||||
rounding: screenshot.rounding,
|
|
||||||
shadow_blur: screenshot.shadow_blur,
|
|
||||||
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,
|
|
||||||
updates: services.updates,
|
|
||||||
useFahrenheit: services.useFahrenheit,
|
|
||||||
minBrightness: services.minBrightness,
|
|
||||||
ddcutilService: services.ddcutilService,
|
|
||||||
useTwelveHourClock: services.useTwelveHourClock,
|
|
||||||
gpuType: services.gpuType,
|
|
||||||
audioIncrement: services.audioIncrement,
|
|
||||||
brightnessIncrement: services.brightnessIncrement,
|
|
||||||
maxVolume: services.maxVolume,
|
|
||||||
defaultPlayer: services.defaultPlayer,
|
|
||||||
playerAliases: services.playerAliases,
|
|
||||||
visualizerBars: services.visualizerBars
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeSidebar(): var {
|
|
||||||
return {
|
|
||||||
enabled: sidebar.enabled,
|
|
||||||
sizes: {
|
|
||||||
width: sidebar.sizes.width
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeUtilities(): var {
|
|
||||||
return {
|
|
||||||
enabled: utilities.enabled,
|
|
||||||
maxToasts: utilities.maxToasts,
|
|
||||||
sizes: {
|
|
||||||
width: utilities.sizes.width,
|
|
||||||
toastWidth: utilities.sizes.toastWidth
|
|
||||||
},
|
|
||||||
toasts: {
|
|
||||||
configLoaded: utilities.toasts.configLoaded,
|
|
||||||
chargingChanged: utilities.toasts.chargingChanged,
|
|
||||||
gameModeChanged: utilities.toasts.gameModeChanged,
|
|
||||||
dndChanged: utilities.toasts.dndChanged,
|
|
||||||
audioOutputChanged: utilities.toasts.audioOutputChanged,
|
|
||||||
audioInputChanged: utilities.toasts.audioInputChanged,
|
|
||||||
capsLockChanged: utilities.toasts.capsLockChanged,
|
|
||||||
numLockChanged: utilities.toasts.numLockChanged,
|
|
||||||
kbLayoutChanged: utilities.toasts.kbLayoutChanged,
|
|
||||||
vpnChanged: utilities.toasts.vpnChanged,
|
|
||||||
nowPlaying: utilities.toasts.nowPlaying
|
|
||||||
},
|
|
||||||
vpn: {
|
|
||||||
enabled: utilities.vpn.enabled,
|
|
||||||
provider: utilities.vpn.provider
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ElapsedTimer {
|
ElapsedTimer {
|
||||||
id: timer
|
id: timer
|
||||||
}
|
}
|
||||||
@@ -392,20 +86,7 @@ Singleton {
|
|||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
timer.restart();
|
timer.restart();
|
||||||
try {
|
fileView.writeAdapter();
|
||||||
let config = {};
|
|
||||||
try {
|
|
||||||
config = JSON.parse(fileView.text());
|
|
||||||
} catch (e) {
|
|
||||||
config = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
config = root.serializeConfig();
|
|
||||||
|
|
||||||
fileView.setText(JSON.stringify(config, null, 4));
|
|
||||||
} catch (e) {
|
|
||||||
Toaster.toast(qsTr("Failed to serialize config"), e.message, "settings_alert", Toast.Error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,6 +106,10 @@ Singleton {
|
|||||||
path: `${Paths.config}/config.json`
|
path: `${Paths.config}/config.json`
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
|
|
||||||
|
onAdapterUpdated: {
|
||||||
|
if (!root.migratingLegacyBar)
|
||||||
|
root.save();
|
||||||
|
}
|
||||||
onFileChanged: {
|
onFileChanged: {
|
||||||
if (!root.recentlySaved) {
|
if (!root.recentlySaved) {
|
||||||
timer.restart();
|
timer.restart();
|
||||||
@@ -441,7 +126,11 @@ Singleton {
|
|||||||
ModeScheduler.checkStartup();
|
ModeScheduler.checkStartup();
|
||||||
Hyprsunset.checkStartup();
|
Hyprsunset.checkStartup();
|
||||||
try {
|
try {
|
||||||
JSON.parse(text());
|
const raw = JSON.parse(text());
|
||||||
|
const migrated = root.migrateLegacyBarConfig(raw);
|
||||||
|
if (migrated)
|
||||||
|
root.save();
|
||||||
|
|
||||||
const elapsed = timer.elapsedMs();
|
const elapsed = timer.elapsedMs();
|
||||||
|
|
||||||
if (adapter.utilities.toasts.configLoaded && !root.recentlySaved) {
|
if (adapter.utilities.toasts.configLoaded && !root.recentlySaved) {
|
||||||
@@ -462,7 +151,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
property BackgroundConfig background: BackgroundConfig {
|
property BackgroundConfig background: BackgroundConfig {
|
||||||
}
|
}
|
||||||
property BarConfig barConfig: BarConfig {
|
property BarConfig bar: BarConfig {
|
||||||
}
|
}
|
||||||
property ClipboardConfig clipboard: ClipboardConfig {
|
property ClipboardConfig clipboard: ClipboardConfig {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
|
||||||
JsonObject {
|
JsonObject {
|
||||||
property int dragThreshold: 50
|
|
||||||
property bool enabled: true
|
property bool enabled: true
|
||||||
property int mediaUpdateInterval: 500
|
property int mediaUpdateInterval: 500
|
||||||
property Performance performance: Performance {
|
property Performance performance: Performance {
|
||||||
@@ -11,6 +10,7 @@ JsonObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
component Performance: JsonObject {
|
component Performance: JsonObject {
|
||||||
|
property bool enabled: true
|
||||||
property bool showBattery: true
|
property bool showBattery: true
|
||||||
property bool showCpu: true
|
property bool showCpu: true
|
||||||
property bool showGpu: true
|
property bool showGpu: true
|
||||||
|
|||||||
@@ -84,6 +84,11 @@ JsonObject {
|
|||||||
dangerous: false
|
dangerous: false
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
property int dragThreshold: 50
|
||||||
|
property bool enableDangerousActions: false
|
||||||
|
property bool enabled: true
|
||||||
|
property list<string> favoriteApps: []
|
||||||
|
property list<string> hiddenApps: []
|
||||||
property int maxAppsShown: 10
|
property int maxAppsShown: 10
|
||||||
property int maxWallpapers: 7
|
property int maxWallpapers: 7
|
||||||
property Sizes sizes: Sizes {
|
property Sizes sizes: Sizes {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ JsonObject {
|
|||||||
property bool expire: true
|
property bool expire: true
|
||||||
property int groupPreviewNum: 3
|
property int groupPreviewNum: 3
|
||||||
property bool openExpanded: false
|
property bool openExpanded: false
|
||||||
|
property bool showInFullscreen: true
|
||||||
property Sizes sizes: Sizes {
|
property Sizes sizes: Sizes {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
|
||||||
JsonObject {
|
JsonObject {
|
||||||
|
property int dragThreshold: 30
|
||||||
property bool enabled: true
|
property bool enabled: true
|
||||||
property Sizes sizes: Sizes {
|
property Sizes sizes: Sizes {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ Singleton {
|
|||||||
property alias server: server
|
property alias server: server
|
||||||
|
|
||||||
function shouldThrottle(appName: string): bool {
|
function shouldThrottle(appName: string): bool {
|
||||||
if (props.dnd)
|
if (props.dnd || [...Visibilities.screens.values()].some(v => v.sidebar))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const key = (appName || "unknown").trim().toLowerCase();
|
const key = (appName || "unknown").trim().toLowerCase();
|
||||||
@@ -49,11 +49,6 @@ Singleton {
|
|||||||
if (loaded) {
|
if (loaded) {
|
||||||
saveTimer.restart();
|
saveTimer.restart();
|
||||||
}
|
}
|
||||||
if (root.list.length > 0) {
|
|
||||||
HasNotifications.hasNotifications = true;
|
|
||||||
} else {
|
|
||||||
HasNotifications.hasNotifications = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
component ExclusionZone: CustomWindow {
|
component ExclusionZone: CustomWindow {
|
||||||
exclusiveZone: Config.barConfig.border
|
exclusiveZone: Config.bar.border
|
||||||
implicitHeight: 1
|
implicitHeight: 1
|
||||||
implicitWidth: 1
|
implicitWidth: 1
|
||||||
name: "Bar-Exclusion"
|
name: "Bar-Exclusion"
|
||||||
|
|||||||
+12
-10
@@ -21,15 +21,15 @@ Item {
|
|||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
function inBottomPanel(panel: Item, x: real, y: real): bool {
|
function inBottomPanel(panel: Item, x: real, y: real): bool {
|
||||||
return y > root.height - panel.height - Config.barConfig.border && withinPanelWidth(panel, x, y);
|
return y > root.height - panel.height - Config.bar.border && withinPanelWidth(panel, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
function inLeftPanel(panel: Item, x: real, y: real): bool {
|
function inLeftPanel(panel: Item, x: real, y: real): bool {
|
||||||
return x < panel.x + panel.width + Config.barConfig.border && withinPanelHeight(panel, x, y);
|
return x < panel.x + panel.width + Config.bar.border && withinPanelHeight(panel, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
function inRightPanel(panel: Item, x: real, y: real): bool {
|
function inRightPanel(panel: Item, x: real, y: real): bool {
|
||||||
return x > panel.x - Config.barConfig.border && withinPanelHeight(panel, x, y);
|
return x > panel.x - Config.bar.border && withinPanelHeight(panel, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
function inTopPanel(panel: Item, x: real, y: real): bool {
|
function inTopPanel(panel: Item, x: real, y: real): bool {
|
||||||
@@ -75,7 +75,7 @@ Item {
|
|||||||
const dragX = x - centroid.pressPosition.x;
|
const dragX = x - centroid.pressPosition.x;
|
||||||
const dragY = y - centroid.pressPosition.y;
|
const dragY = y - centroid.pressPosition.y;
|
||||||
|
|
||||||
if (centroid.pressPosition.y >= root.screen.height - Config.barConfig.border && centroid.pressPosition.x > root.screen.width / 5 && dragY < -200)
|
if (centroid.pressPosition.y >= root.screen.height - Config.bar.border && centroid.pressPosition.x > root.screen.width / 5 && dragY < -Config.launcher.dragThreshold)
|
||||||
root.visibilities.launcher = true;
|
root.visibilities.launcher = true;
|
||||||
|
|
||||||
if (root.singleGestureTriggered)
|
if (root.singleGestureTriggered)
|
||||||
@@ -91,7 +91,7 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (centroid.pressPosition.y > root.screen.height - Config.barConfig.border && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50)
|
if (centroid.pressPosition.y > root.screen.height - Config.bar.border && centroid.pressPosition.x < root.screen.width / 5 && dragY < -50)
|
||||||
root.visibilities.clipboard = true;
|
root.visibilities.clipboard = true;
|
||||||
|
|
||||||
if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.bar.implicitHeight && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher)
|
if (!Config.dock.hoverToReveal && centroid.pressPosition.y > root.screen.height - root.bar.implicitHeight && centroid.pressPosition.x > root.screen.width / 5 && !root.visibilities.launcher)
|
||||||
@@ -100,17 +100,17 @@ Item {
|
|||||||
root.singleGestureTriggered = true;
|
root.singleGestureTriggered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (centroid.pressPosition.x > root.screen.width - Config.barConfig.border && centroid.pressPosition.y < (root.screen.height / 2) && dragX < -20) {
|
if (centroid.pressPosition.x > root.screen.width - Config.bar.border && centroid.pressPosition.y < (root.screen.height / 2) && dragX < -Config.sidebar.dragThreshold) {
|
||||||
root.visibilities.sidebar = true;
|
root.visibilities.sidebar = true;
|
||||||
root.singleGestureTriggered = true;
|
root.singleGestureTriggered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (centroid.pressPosition.x >= root.screen.width - Config.barConfig.border && centroid.pressPosition.y > (root.screen.height / 2) && dragX < -20) {
|
if (centroid.pressPosition.x >= root.screen.width - Config.bar.border && centroid.pressPosition.y > (root.screen.height / 2) && dragX < -20) {
|
||||||
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r+1', on_current_monitor = true })`);
|
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r+1', on_current_monitor = true })`);
|
||||||
root.singleGestureTriggered = true;
|
root.singleGestureTriggered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (centroid.pressPosition.x <= Config.barConfig.border && dragX > 20) {
|
if (centroid.pressPosition.x <= Config.bar.border && dragX > 20) {
|
||||||
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r-1', on_current_monitor = true })`);
|
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r-1', on_current_monitor = true })`);
|
||||||
root.singleGestureTriggered = true;
|
root.singleGestureTriggered = true;
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ Item {
|
|||||||
root.popouts.hasCurrent = false;
|
root.popouts.hasCurrent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.barConfig.autoHide)
|
if (Config.bar.autoHide)
|
||||||
root.bar.isHovered = false;
|
root.bar.isHovered = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ Item {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!root.visibilities.bar && Config.barConfig.autoHide && y < root.bar.implicitHeight)
|
if (!root.visibilities.bar && Config.bar.autoHide && y < root.bar.implicitHeight)
|
||||||
root.bar.isHovered = true;
|
root.bar.isHovered = true;
|
||||||
|
|
||||||
if (root.panels.sidebar.width === 0) {
|
if (root.panels.sidebar.width === 0) {
|
||||||
@@ -298,6 +298,8 @@ Item {
|
|||||||
root.visibilities.sidebar = false;
|
root.visibilities.sidebar = false;
|
||||||
root.panels.popouts.hasCurrent = false;
|
root.panels.popouts.hasCurrent = false;
|
||||||
root.visibilities.launcher = false;
|
root.visibilities.launcher = false;
|
||||||
|
} else {
|
||||||
|
Config.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -10,7 +10,7 @@ import qs.Modules.Osd as Osd
|
|||||||
import qs.Components.Toast as Toasts
|
import qs.Components.Toast as Toasts
|
||||||
import qs.Modules.Launcher as Launcher
|
import qs.Modules.Launcher as Launcher
|
||||||
import qs.Modules.Resources as Resources
|
import qs.Modules.Resources as Resources
|
||||||
import qs.Modules.Settings as Settings
|
import qs.Modules.SettingsNew as Settings
|
||||||
import qs.Modules.Drawing as Drawing
|
import qs.Modules.Drawing as Drawing
|
||||||
import qs.Modules.Dock as Dock
|
import qs.Modules.Dock as Dock
|
||||||
import qs.Modules.Clipboard as Clipboard
|
import qs.Modules.Clipboard as Clipboard
|
||||||
@@ -184,11 +184,11 @@ Item {
|
|||||||
Item {
|
Item {
|
||||||
id: settingsWrapper
|
id: settingsWrapper
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
clip: true
|
clip: true
|
||||||
implicitHeight: settings.implicitHeight * (1 - settings.offsetScale)
|
implicitHeight: settings.implicitHeight
|
||||||
implicitWidth: settings.implicitWidth
|
implicitWidth: settings.implicitWidth
|
||||||
|
x: (root.width - settings.implicitWidth) / 2
|
||||||
|
y: (settings.implicitHeight + (root.height - root.bar.implicitHeight - settings.implicitHeight) / 2) * (1 - settings.offsetScale) - settings.implicitHeight - 5
|
||||||
|
|
||||||
Settings.Wrapper {
|
Settings.Wrapper {
|
||||||
id: settings
|
id: settings
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import qs.Modules.Bar as Bar
|
||||||
|
|
||||||
|
Region {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Bar.BarLoader bar
|
||||||
|
readonly property real borderThickness: win.borderThickness
|
||||||
|
readonly property alias menuPopoutRegion: menuPopoutRegion
|
||||||
|
required property Panels panels
|
||||||
|
required property var win
|
||||||
|
|
||||||
|
height: win.height - bar.implicitHeight - win.borderThickness - win.dragMaskPadding * 2
|
||||||
|
intersection: Intersection.Xor
|
||||||
|
width: win.width - win.borderThickness * 2 - win.dragMaskPadding * 2
|
||||||
|
x: win.borderThickness + win.dragMaskPadding
|
||||||
|
y: bar.implicitHeight + win.dragMaskPadding
|
||||||
|
|
||||||
|
R {
|
||||||
|
panel: root.panels.dashboardWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
R {
|
||||||
|
panel: root.panels.launcher
|
||||||
|
}
|
||||||
|
|
||||||
|
R {
|
||||||
|
id: sidebarRegion
|
||||||
|
|
||||||
|
panel: root.panels.sidebar
|
||||||
|
width: panel.width * (1 - root.panels.sidebar.offsetScale) + root.borderThickness
|
||||||
|
x: root.win.width - width
|
||||||
|
}
|
||||||
|
|
||||||
|
R {
|
||||||
|
panel: root.panels.osdWrapper
|
||||||
|
width: panel.width * (1 - root.panels.osd.offsetScale) + root.borderThickness
|
||||||
|
x: root.win.width - width
|
||||||
|
}
|
||||||
|
|
||||||
|
R {
|
||||||
|
panel: root.panels.notifications
|
||||||
|
}
|
||||||
|
|
||||||
|
R {
|
||||||
|
height: panel.height * (1 - root.panels.utilities.offsetScale) + root.borderThickness
|
||||||
|
panel: root.panels.utilities
|
||||||
|
y: root.win.height - height
|
||||||
|
}
|
||||||
|
|
||||||
|
R {
|
||||||
|
panel: root.panels.popoutsWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
R {
|
||||||
|
panel: root.panels.resourcesWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
R {
|
||||||
|
panel: root.panels.settingsWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
R {
|
||||||
|
panel: root.panels.dock
|
||||||
|
}
|
||||||
|
|
||||||
|
R {
|
||||||
|
panel: root.panels.clipboard
|
||||||
|
}
|
||||||
|
|
||||||
|
Region {
|
||||||
|
id: menuPopoutRegion
|
||||||
|
|
||||||
|
intersection: Intersection.Subtract
|
||||||
|
}
|
||||||
|
|
||||||
|
component R: Region {
|
||||||
|
required property Item panel
|
||||||
|
|
||||||
|
height: panel.height
|
||||||
|
intersection: Intersection.Subtract
|
||||||
|
width: panel.width
|
||||||
|
x: panel.x + root.borderThickness
|
||||||
|
y: panel.y + root.bar.implicitHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
-45
@@ -18,9 +18,9 @@ CustomWindow {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property alias bar: bar
|
readonly property alias bar: bar
|
||||||
readonly property real borderLayoutThickness: hasFullscreen ? 0 : Config.barConfig.border
|
readonly property real borderLayoutThickness: hasFullscreen ? 0 : Config.bar.border
|
||||||
readonly property real borderRounding: Config.barConfig.rounding * (1 - fsTransitionProg)
|
readonly property real borderRounding: Config.bar.rounding * (1 - fsTransitionProg)
|
||||||
readonly property real borderThickness: Config.barConfig.border * (1 - fsTransitionProg)
|
readonly property real borderThickness: Config.bar.border * (1 - fsTransitionProg)
|
||||||
readonly property int dragMaskPadding: {
|
readonly property int dragMaskPadding: {
|
||||||
if (focusGrab.active)
|
if (focusGrab.active)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -44,7 +44,7 @@ CustomWindow {
|
|||||||
readonly property bool hasFullscreenOnNormalWs: monitor?.activeWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1) ?? false
|
readonly property bool hasFullscreenOnNormalWs: monitor?.activeWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1) ?? false
|
||||||
readonly property bool hasSpecialWorkspace: (monitor?.lastIpcObject.specialWorkspace?.name.length ?? 0) > 0
|
readonly property bool hasSpecialWorkspace: (monitor?.lastIpcObject.specialWorkspace?.name.length ?? 0) > 0
|
||||||
readonly property alias interactionWrapper: interactions
|
readonly property alias interactionWrapper: interactions
|
||||||
readonly property alias menuRegion: menuPopoutRegion
|
readonly property alias menuRegion: regions.menuPopoutRegion
|
||||||
readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen)
|
readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen)
|
||||||
property var root: Quickshell.shellDir
|
property var root: Quickshell.shellDir
|
||||||
readonly property real sdfBorderOffset: 2 * fsTransitionProg
|
readonly property real sdfBorderOffset: 2 * fsTransitionProg
|
||||||
@@ -56,7 +56,7 @@ CustomWindow {
|
|||||||
WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top
|
WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
contentItem.focus: true
|
contentItem.focus: true
|
||||||
mask: visibilities.isDrawing ? null : (hasFullscreen ? emptyRegion : region)
|
mask: visibilities.isDrawing ? null : (hasFullscreen ? emptyRegion : regions)
|
||||||
name: "Bar"
|
name: "Bar"
|
||||||
|
|
||||||
Behavior on fsTransitionProg {
|
Behavior on fsTransitionProg {
|
||||||
@@ -69,7 +69,7 @@ CustomWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentItem.Keys.onEscapePressed: {
|
contentItem.Keys.onEscapePressed: {
|
||||||
if (Config.barConfig.autoHide)
|
if (Config.bar.autoHide)
|
||||||
visibilities.bar = false;
|
visibilities.bar = false;
|
||||||
visibilities.launcher = false;
|
visibilities.launcher = false;
|
||||||
visibilities.sidebar = false;
|
visibilities.sidebar = false;
|
||||||
@@ -93,12 +93,6 @@ CustomWindow {
|
|||||||
panels.popouts.hasCurrent = false;
|
panels.popouts.hasCurrent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Region {
|
|
||||||
id: menuPopoutRegion
|
|
||||||
|
|
||||||
intersection: Intersection.Subtract
|
|
||||||
}
|
|
||||||
|
|
||||||
Region {
|
Region {
|
||||||
id: emptyRegion
|
id: emptyRegion
|
||||||
|
|
||||||
@@ -106,17 +100,21 @@ CustomWindow {
|
|||||||
width: panels.notifications.width
|
width: panels.notifications.width
|
||||||
x: panels.notifications.x + root.borderThickness
|
x: panels.notifications.x + root.borderThickness
|
||||||
y: panels.notifications.y + bar.implicitHeight
|
y: panels.notifications.y + bar.implicitHeight
|
||||||
|
|
||||||
|
Region {
|
||||||
|
height: panels.osd.height
|
||||||
|
width: panels.osdWrapper.width * (1 - panels.osd.offsetScale) + root.borderThickness
|
||||||
|
x: root.width - width
|
||||||
|
y: panels.osdWrapper.y + bar.implicitHeight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Region {
|
Regions {
|
||||||
id: region
|
id: regions
|
||||||
|
|
||||||
height: root.height - bar.implicitHeight - root.borderThickness - root.dragMaskPadding * 2
|
bar: bar
|
||||||
intersection: Intersection.Xor
|
panels: panels
|
||||||
regions: [...popoutRegions.instances, menuPopoutRegion]
|
win: root
|
||||||
width: root.width - root.borderThickness * 2 - root.dragMaskPadding * 2
|
|
||||||
x: root.borderThickness + root.dragMaskPadding
|
|
||||||
y: bar.implicitHeight + root.dragMaskPadding
|
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
@@ -126,22 +124,6 @@ CustomWindow {
|
|||||||
top: true
|
top: true
|
||||||
}
|
}
|
||||||
|
|
||||||
Variants {
|
|
||||||
id: popoutRegions
|
|
||||||
|
|
||||||
model: panels.children
|
|
||||||
|
|
||||||
Region {
|
|
||||||
required property Item modelData
|
|
||||||
|
|
||||||
height: modelData.height
|
|
||||||
intersection: Intersection.Subtract
|
|
||||||
width: modelData.width
|
|
||||||
x: modelData.x + root.borderThickness
|
|
||||||
y: modelData.y + bar.implicitHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
HyprlandFocusGrab {
|
||||||
id: focusGrab
|
id: focusGrab
|
||||||
|
|
||||||
@@ -190,8 +172,8 @@ CustomWindow {
|
|||||||
Binding {
|
Binding {
|
||||||
property: "bar"
|
property: "bar"
|
||||||
target: visibilities
|
target: visibilities
|
||||||
value: visibilities.sidebar || visibilities.dashboard || visibilities.osd || (!Config.barConfig.hideWhenNotif && visibilities.notif) || visibilities.resources || visibilities.settings || bar.isHovered
|
value: visibilities.sidebar || visibilities.dashboard || visibilities.osd || (!Config.bar.hideWhenNotif && visibilities.notif) || visibilities.resources || visibilities.settings || bar.isHovered
|
||||||
when: Config.barConfig.autoHide
|
when: Config.bar.autoHide
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -211,7 +193,7 @@ CustomWindow {
|
|||||||
id: blobGroup
|
id: blobGroup
|
||||||
|
|
||||||
color: root.surfaceColor
|
color: root.surfaceColor
|
||||||
smoothing: Config.barConfig.smoothing
|
smoothing: Config.bar.smoothing
|
||||||
}
|
}
|
||||||
|
|
||||||
BlobInvertedRect {
|
BlobInvertedRect {
|
||||||
@@ -323,15 +305,13 @@ CustomWindow {
|
|||||||
PanelBg {
|
PanelBg {
|
||||||
id: settingsBg
|
id: settingsBg
|
||||||
|
|
||||||
property real extraHeight: 0.2
|
property real extraHeight: 0
|
||||||
|
|
||||||
deformAmount: 0.03
|
deformAmount: 0.03
|
||||||
implicitHeight: panels.settings.height * (1 + extraHeight)
|
implicitHeight: panels.settings.height * (1 + extraHeight)
|
||||||
implicitWidth: panels.settings.width
|
implicitWidth: panels.settings.width
|
||||||
panel: panels.settings
|
panel: panels.settingsWrapper
|
||||||
radius: Appearance.rounding.large
|
radius: Appearance.rounding.large + Appearance.padding.normal
|
||||||
topLeftRadius: Appearance.rounding.large + Appearance.padding.smaller
|
|
||||||
topRightRadius: Appearance.rounding.large + Appearance.padding.smaller
|
|
||||||
x: panels.settingsWrapper.x + panels.settings.x + root.borderThickness
|
x: panels.settingsWrapper.x + panels.settings.x + root.borderThickness
|
||||||
y: panels.settingsWrapper.y + panels.settings.y + bar.implicitHeight - panels.settings.height * extraHeight
|
y: panels.settingsWrapper.y + panels.settings.y + bar.implicitHeight - panels.settings.height * extraHeight
|
||||||
}
|
}
|
||||||
@@ -441,7 +421,7 @@ CustomWindow {
|
|||||||
resources.transform: Matrix4x4 {
|
resources.transform: Matrix4x4 {
|
||||||
matrix: resourcesBg.deformMatrix
|
matrix: resourcesBg.deformMatrix
|
||||||
}
|
}
|
||||||
settings.transform: Matrix4x4 {
|
settingsWrapper.transform: Matrix4x4 {
|
||||||
matrix: settingsBg.deformMatrix
|
matrix: settingsBg.deformMatrix
|
||||||
}
|
}
|
||||||
sidebar.transform: Matrix4x4 {
|
sidebar.transform: Matrix4x4 {
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
maskEnabled: true
|
||||||
|
maskSpreadAtMin: 1
|
||||||
|
maskThresholdMin: 0.5
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property alias hasNotifications: adapter.hasNotifications
|
|
||||||
|
|
||||||
JsonObject {
|
|
||||||
id: adapter
|
|
||||||
|
|
||||||
property bool hasNotifications: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
property var _regexCache: ({})
|
||||||
|
|
||||||
|
function testRegexList(filterList: list<string>, target: string): bool {
|
||||||
|
const regexChecker = /^\^.*\$$/;
|
||||||
|
for (const filter of filterList) {
|
||||||
|
if (regexChecker.test(filter)) {
|
||||||
|
let re = _regexCache[filter];
|
||||||
|
if (!re) {
|
||||||
|
re = new RegExp(filter);
|
||||||
|
_regexCache[filter] = re;
|
||||||
|
}
|
||||||
|
if (re.test(target))
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (filter === target)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,13 @@ Searcher {
|
|||||||
property bool recentlyChanged
|
property bool recentlyChanged
|
||||||
property bool showPreview: false
|
property bool showPreview: false
|
||||||
|
|
||||||
|
function getCategoryFor(w: FileSystemEntry): string {
|
||||||
|
let category = w.parentDir.slice(Paths.wallsdir.length + 1);
|
||||||
|
if (category.includes("/"))
|
||||||
|
category = category.slice(0, category.indexOf("/"));
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
function getCrop(screen: string): var {
|
function getCrop(screen: string): var {
|
||||||
return root.crops[screen];
|
return root.crops[screen];
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -57,15 +57,15 @@ RowLayout {
|
|||||||
const item = ch.item;
|
const item = ch.item;
|
||||||
const itemWidth = item.implicitWidth;
|
const itemWidth = item.implicitWidth;
|
||||||
|
|
||||||
if (id === "audio" && Config.barConfig.popouts.audio) {
|
if (id === "audio" && Config.bar.popouts.audio) {
|
||||||
popouts.currentName = "audio";
|
popouts.currentName = "audio";
|
||||||
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
||||||
popouts.hasCurrent = true;
|
popouts.hasCurrent = true;
|
||||||
} else if (id === "network" && Config.barConfig.popouts.network) {
|
} else if (id === "network" && Config.bar.popouts.network) {
|
||||||
popouts.currentName = "network";
|
popouts.currentName = "network";
|
||||||
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
||||||
popouts.hasCurrent = true;
|
popouts.hasCurrent = true;
|
||||||
} else if (id === "upower" && Config.barConfig.popouts.upower) {
|
} else if (id === "upower" && Config.bar.popouts.upower) {
|
||||||
popouts.currentName = "upower";
|
popouts.currentName = "upower";
|
||||||
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
||||||
popouts.hasCurrent = true;
|
popouts.hasCurrent = true;
|
||||||
@@ -81,8 +81,8 @@ RowLayout {
|
|||||||
Repeater {
|
Repeater {
|
||||||
id: repeater
|
id: repeater
|
||||||
|
|
||||||
// model: Config.barConfig.entries.filted(n => n.index > 50).sort(n => n.index)
|
// model: Config.bar.entries.filted(n => n.index > 50).sort(n => n.index)
|
||||||
model: Config.barConfig.entries
|
model: Config.bar.entries
|
||||||
|
|
||||||
DelegateChooser {
|
DelegateChooser {
|
||||||
role: "id"
|
role: "id"
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ import qs.Modules.Network
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property int contentHeight: Config.barConfig.height + padding * 2
|
readonly property int contentHeight: Config.bar.height + padding * 2
|
||||||
readonly property int exclusiveZone: Config.barConfig.autoHide ? Config.barConfig.border : contentHeight
|
readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentHeight
|
||||||
required property bool fullscreen
|
required property bool fullscreen
|
||||||
property bool isHovered
|
property bool isHovered
|
||||||
readonly property int padding: Math.max(Appearance.padding.smaller, Config.barConfig.border)
|
readonly property int padding: Math.max(Appearance.padding.smaller, Config.bar.border)
|
||||||
required property Wrapper popouts
|
required property Wrapper popouts
|
||||||
required property ClipWrapper popoutsWrapper
|
required property ClipWrapper popoutsWrapper
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
readonly property bool shouldBeVisible: !fullscreen && (!Config.barConfig.autoHide || visibilities.bar || isHovered)
|
readonly property bool shouldBeVisible: !fullscreen && (!Config.bar.autoHide || visibilities.bar || isHovered)
|
||||||
readonly property int vPadding: 6
|
readonly property int vPadding: 6
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
@@ -31,8 +31,8 @@ Item {
|
|||||||
content.item?.checkPopout(x);
|
content.item?.checkPopout(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
implicitHeight: fullscreen ? 0 : Config.barConfig.border
|
implicitHeight: fullscreen ? 0 : Config.bar.border
|
||||||
visible: height > Config.barConfig.border
|
visible: height > Config.bar.border
|
||||||
|
|
||||||
states: State {
|
states: State {
|
||||||
name: "visible"
|
name: "visible"
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ Item {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Config.barConfig.border + 1
|
anchors.margins: Config.bar.border + 1
|
||||||
anchors.topMargin: root.bar.implicitHeight + 1
|
anchors.topMargin: root.bar.implicitHeight + 1
|
||||||
radius: Config.barConfig.border > 0 ? Config.barConfig.rounding : 0
|
radius: Config.bar.border > 0 ? Config.bar.rounding : 0
|
||||||
topLeftRadius: Config.barConfig.rounding
|
topLeftRadius: Config.bar.rounding
|
||||||
topRightRadius: Config.barConfig.rounding
|
topRightRadius: Config.bar.rounding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ CustomRect {
|
|||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
color: visibilities.dashboard ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
|
color: visibilities.dashboard ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
implicitHeight: Config.bar.height + Appearance.padding.smallest * 2
|
||||||
implicitWidth: timeText.contentWidth + Appearance.padding.normal * 2
|
implicitWidth: timeText.contentWidth + Appearance.padding.normal * 2
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ CustomRect {
|
|||||||
property bool tempEnabled: Hyprsunset.enabled
|
property bool tempEnabled: Hyprsunset.enabled
|
||||||
|
|
||||||
color: root.tempEnabled ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
|
color: root.tempEnabled ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
implicitHeight: Config.bar.height + Appearance.padding.smallest * 2
|
||||||
implicitWidth: implicitHeight
|
implicitWidth: implicitHeight
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
|||||||
@@ -65,5 +65,20 @@ Item {
|
|||||||
width: root.width - icon.width - Appearance.rounding.normal * 2
|
width: root.width - icon.width - Appearance.rounding.normal * 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: favoriteIcon
|
||||||
|
|
||||||
|
active: root.modelData && Strings.testRegexList(Config.launcher.favoriteApps, root.modelData.id)
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: MaterialIcon {
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
fill: 1
|
||||||
|
text: "favorite"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Searcher {
|
|||||||
Variants {
|
Variants {
|
||||||
id: variants
|
id: variants
|
||||||
|
|
||||||
model: Config.launcher.actions.filter(a => (a.enabled ?? true))
|
model: Config.launcher.actions.filter(a => (a.enabled ?? true) && (Config.launcher.enableDangerousActions || !(a.dangerous ?? false)))
|
||||||
|
|
||||||
Action {
|
Action {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,8 @@ Searcher {
|
|||||||
AppDb {
|
AppDb {
|
||||||
id: appDb
|
id: appDb
|
||||||
|
|
||||||
entries: DesktopEntries.applications.values
|
entries: DesktopEntries.applications.values.filter(a => !Strings.testRegexList(Config.launcher.hiddenApps, a.id))
|
||||||
|
favoriteApps: Config.launcher.favoriteApps
|
||||||
path: `${Paths.state}/apps.sqlite`
|
path: `${Paths.state}/apps.sqlite`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ PathView {
|
|||||||
let outerMargins = 0;
|
let outerMargins = 0;
|
||||||
if ((visibilities.utilities || visibilities.sidebar) && panels.utilities.implicitWidth > outerMargins)
|
if ((visibilities.utilities || visibilities.sidebar) && panels.utilities.implicitWidth > outerMargins)
|
||||||
outerMargins = panels.utilities.implicitWidth;
|
outerMargins = panels.utilities.implicitWidth;
|
||||||
const maxWidth = screen.width - Config.barConfig.rounding * 4 - (barMargins + outerMargins) * 2;
|
const maxWidth = screen.width - Config.bar.rounding * 4 - (barMargins + outerMargins) * 2;
|
||||||
|
|
||||||
if (maxWidth <= 0)
|
if (maxWidth <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ CustomRect {
|
|||||||
readonly property int textWidth: Math.min(metrics.width, 200)
|
readonly property int textWidth: Math.min(metrics.width, 200)
|
||||||
|
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
implicitHeight: Config.bar.height + Appearance.padding.smallest * 2
|
||||||
implicitWidth: layout.implicitWidth + Appearance.padding.normal * 2
|
implicitWidth: layout.implicitWidth + Appearance.padding.normal * 2
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Hyprland
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Helpers
|
import qs.Daemons
|
||||||
import qs.Components
|
import qs.Components
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
@@ -12,7 +11,7 @@ CustomRect {
|
|||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
color: visibilities.sidebar ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
|
color: visibilities.sidebar ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
implicitHeight: Config.bar.height + Appearance.padding.smallest * 2
|
||||||
implicitWidth: implicitHeight
|
implicitWidth: implicitHeight
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ CustomRect {
|
|||||||
fill: root.visibilities.sidebar ? 1 : 0
|
fill: root.visibilities.sidebar ? 1 : 0
|
||||||
font.family: "Material Symbols Rounded"
|
font.family: "Material Symbols Rounded"
|
||||||
font.pointSize: Appearance.font.size.larger
|
font.pointSize: Appearance.font.size.larger
|
||||||
text: HasNotifications.hasNotifications ? "\uf4fe" : "\ue7f4"
|
text: NotifServer.list.length ? "\uf4fe" : "\ue7f4"
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
CAnim {
|
CAnim {
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import qs.Components
|
|
||||||
import qs.Config
|
|
||||||
import qs.Daemons
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Daemons
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -72,7 +73,15 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
model: ScriptModel {
|
model: ScriptModel {
|
||||||
values: NotifServer.popups.filter(n => !n.closed)
|
values: {
|
||||||
|
const popups = NotifServer.popups.filter(n => !n.closed);
|
||||||
|
|
||||||
|
if (!Config.notifs.showInFullscreen) {
|
||||||
|
if (Hypr.monitorFor(root.panels.screen).activeWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1) ?? false)
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return popups;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
move: Transition {
|
move: Transition {
|
||||||
Anim {
|
Anim {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ ShapePath {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property bool flatten: wrapper.height < rounding * 2
|
readonly property bool flatten: wrapper.height < rounding * 2
|
||||||
readonly property real rounding: Config.barConfig.rounding
|
readonly property real rounding: Config.bar.rounding
|
||||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||||
required property var sidebar
|
required property var sidebar
|
||||||
required property Wrapper wrapper
|
required property Wrapper wrapper
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ CustomRect {
|
|||||||
CustomSplitButton {
|
CustomSplitButton {
|
||||||
active: menuItems.find(m => root.props.recordingMode === m.icon + m.text) ?? menuItems[0]
|
active: menuItems.find(m => root.props.recordingMode === m.icon + m.text) ?? menuItems[0]
|
||||||
enabled: !Recorder.running
|
enabled: !Recorder.running
|
||||||
|
menuOnTop: true
|
||||||
|
|
||||||
menuItems: [
|
menuItems: [
|
||||||
MenuItem {
|
MenuItem {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ CustomRect {
|
|||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
color: visibilities.resources ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
|
color: visibilities.resources ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
implicitHeight: Config.bar.height + Appearance.padding.smallest * 2
|
||||||
implicitWidth: rowLayout.implicitWidth + Appearance.padding.larger * 2
|
implicitWidth: rowLayout.implicitWidth + Appearance.padding.larger * 2
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ SettingsPage {
|
|||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Auto hide"
|
name: "Auto hide"
|
||||||
object: Config.barConfig
|
object: Config.bar
|
||||||
setting: "autoHide"
|
setting: "autoHide"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ SettingsPage {
|
|||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 1
|
min: 1
|
||||||
name: "Height"
|
name: "Height"
|
||||||
object: Config.barConfig
|
object: Config.bar
|
||||||
setting: "height"
|
setting: "height"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ SettingsPage {
|
|||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 0
|
min: 0
|
||||||
name: "Rounding"
|
name: "Rounding"
|
||||||
object: Config.barConfig
|
object: Config.bar
|
||||||
setting: "rounding"
|
setting: "rounding"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ SettingsPage {
|
|||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 0
|
min: 0
|
||||||
name: "Border"
|
name: "Border"
|
||||||
object: Config.barConfig
|
object: Config.bar
|
||||||
setting: "border"
|
setting: "border"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ SettingsPage {
|
|||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 0
|
min: 0
|
||||||
name: "Smoothing"
|
name: "Smoothing"
|
||||||
object: Config.barConfig
|
object: Config.bar
|
||||||
setting: "smoothing"
|
setting: "smoothing"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ SettingsPage {
|
|||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 16
|
min: 16
|
||||||
name: "Tray icon size"
|
name: "Tray icon size"
|
||||||
object: Config.barConfig.tray
|
object: Config.bar.tray
|
||||||
setting: "trayIconSize"
|
setting: "trayIconSize"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ SettingsPage {
|
|||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Tray"
|
name: "Tray"
|
||||||
object: Config.barConfig.popouts
|
object: Config.bar.popouts
|
||||||
setting: "tray"
|
setting: "tray"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ SettingsPage {
|
|||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Audio"
|
name: "Audio"
|
||||||
object: Config.barConfig.popouts
|
object: Config.bar.popouts
|
||||||
setting: "audio"
|
setting: "audio"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ SettingsPage {
|
|||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Active window"
|
name: "Active window"
|
||||||
object: Config.barConfig.popouts
|
object: Config.bar.popouts
|
||||||
setting: "activeWindow"
|
setting: "activeWindow"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ SettingsPage {
|
|||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Resources"
|
name: "Resources"
|
||||||
object: Config.barConfig.popouts
|
object: Config.bar.popouts
|
||||||
setting: "resources"
|
setting: "resources"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ SettingsPage {
|
|||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Clock"
|
name: "Clock"
|
||||||
object: Config.barConfig.popouts
|
object: Config.bar.popouts
|
||||||
setting: "clock"
|
setting: "clock"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ SettingsPage {
|
|||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Network"
|
name: "Network"
|
||||||
object: Config.barConfig.popouts
|
object: Config.bar.popouts
|
||||||
setting: "network"
|
setting: "network"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ SettingsPage {
|
|||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Power"
|
name: "Power"
|
||||||
object: Config.barConfig.popouts
|
object: Config.bar.popouts
|
||||||
setting: "upower"
|
setting: "upower"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ SettingsPage {
|
|||||||
|
|
||||||
SettingBarEntryList {
|
SettingBarEntryList {
|
||||||
name: "Bar entries"
|
name: "Bar entries"
|
||||||
object: Config.barConfig
|
object: Config.bar
|
||||||
setting: "entries"
|
setting: "entries"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
ItemList {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int currentId: -1
|
||||||
|
property string iconName: "speaker"
|
||||||
|
property var nodes: []
|
||||||
|
|
||||||
|
signal selected(node: PwNode)
|
||||||
|
|
||||||
|
last: true
|
||||||
|
showList: true
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
id: device
|
||||||
|
|
||||||
|
readonly property bool active: device.modelData?.id === root.currentId
|
||||||
|
required property int index
|
||||||
|
required property PwNode modelData
|
||||||
|
|
||||||
|
anchors.left: root.list.contentItem.left
|
||||||
|
anchors.right: root.list.contentItem.right
|
||||||
|
implicitHeight: deviceLayout.implicitHeight + deviceLayout.anchors.margins * 2
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
bottomLeftRadius: device.index === root?.list.count - 1 ? Appearance.rounding.large : radius
|
||||||
|
bottomRightRadius: device.index === root?.list.count - 1 ? Appearance.rounding.large : radius
|
||||||
|
radius: Appearance.rounding.extraSmall
|
||||||
|
|
||||||
|
onClicked: root.selected(device.modelData)
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: deviceLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.largeIncreased
|
||||||
|
anchors.margins: Appearance.padding.large
|
||||||
|
anchors.rightMargin: Appearance.padding.largeIncreased
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
color: device.active ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondaryContainer
|
||||||
|
implicitHeight: devIcon.implicitHeight + Appearance.padding.normal * 2
|
||||||
|
implicitWidth: implicitHeight
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: devIcon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: device.active ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondaryContainer
|
||||||
|
fill: device.active ? 1 : 0
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: root.iconName
|
||||||
|
|
||||||
|
Behavior on fill {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.smaller
|
||||||
|
text: device.modelData?.description || device.modelData?.name || qsTr("Unknown")
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
opacity: device.active ? 1 : 0
|
||||||
|
text: "check"
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model: ScriptModel {
|
||||||
|
values: [...root.nodes].sort((a, b) => (a.description || a.name || "").localeCompare(b.description || b.name || ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
import QtQuick
|
||||||
|
import ZShell.Blobs
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property real animDriver
|
||||||
|
property alias color: blobGroup.color
|
||||||
|
default required property Item content
|
||||||
|
property bool hoverOverride
|
||||||
|
readonly property alias hovered: btn.containsMouse
|
||||||
|
property alias icon: icon.text
|
||||||
|
property bool open
|
||||||
|
property int padding
|
||||||
|
property bool pressOverride
|
||||||
|
property int topMovement: Appearance.padding.large
|
||||||
|
|
||||||
|
implicitHeight: btn.implicitHeight * 0.9
|
||||||
|
implicitWidth: btn.implicitWidth * 0.9
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
property: "opacity"
|
||||||
|
target: root.content
|
||||||
|
value: root.animDriver
|
||||||
|
}
|
||||||
|
|
||||||
|
BlobGroup {
|
||||||
|
id: blobGroup
|
||||||
|
|
||||||
|
color: DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
cornerFill: false
|
||||||
|
smoothing: Appearance.rounding.medium
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BlobRect {
|
||||||
|
id: btnRect
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: (!(btn.pressed || root.pressOverride) && (btn.containsMouse || root.hoverOverride) ? -Appearance.padding.extraSmall : 0) + (root.open ? -Appearance.padding.extraSmall : 0)
|
||||||
|
group: blobGroup
|
||||||
|
radius: root.open ? Appearance.rounding.large : Appearance.rounding.medium
|
||||||
|
|
||||||
|
Behavior on anchors.margins {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on radius {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BlobRect {
|
||||||
|
id: rect
|
||||||
|
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
deformScale: 0.00001
|
||||||
|
group: blobGroup
|
||||||
|
implicitHeight: parent.height
|
||||||
|
implicitWidth: parent.width
|
||||||
|
radius: Appearance.rounding.small + Appearance.padding.small
|
||||||
|
|
||||||
|
states: State {
|
||||||
|
name: "open"
|
||||||
|
when: root.open
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
rect.anchors.rightMargin: root.width - Appearance.spacing.small
|
||||||
|
rect.anchors.topMargin: -root.topMovement
|
||||||
|
rect.implicitHeight: root.content.implicitHeight + root.padding * 2
|
||||||
|
rect.implicitWidth: root.content.implicitWidth + root.padding * 2
|
||||||
|
root.animDriver: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transitions: Transition {
|
||||||
|
Anim {
|
||||||
|
properties: "rightMargin,implicitWidth"
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.expressiveFastEffects
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.expressiveFastEffects
|
||||||
|
properties: "topMargin,implicitHeight"
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
property: "animDriver"
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea { // MouseArea to catch inputs
|
||||||
|
anchors.fill: parent
|
||||||
|
children: [root.content]
|
||||||
|
clip: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: btn
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
implicitHeight: icon.implicitHeight + Appearance.padding.extraSmall * 2
|
||||||
|
implicitWidth: implicitHeight
|
||||||
|
|
||||||
|
onClicked: root.open = !root.open
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
text: "view_apps"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
property bool first
|
||||||
|
property bool last
|
||||||
|
|
||||||
|
bottomLeftRadius: last ? Appearance.rounding.large : Appearance.rounding.extraSmall
|
||||||
|
bottomRightRadius: last ? Appearance.rounding.large : Appearance.rounding.extraSmall
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
topLeftRadius: first ? Appearance.rounding.large : Appearance.rounding.extraSmall
|
||||||
|
topRightRadius: first ? Appearance.rounding.large : Appearance.rounding.extraSmall
|
||||||
|
}
|
||||||
@@ -0,0 +1,659 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property string endTime: {
|
||||||
|
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
||||||
|
d.setMinutes(object[settings[2]]);
|
||||||
|
return Qt.formatTime(d, "hh:mm AP");
|
||||||
|
}
|
||||||
|
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
|
||||||
|
required property string name
|
||||||
|
required property var object
|
||||||
|
required property list<string> settings
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
readonly property string startTime: {
|
||||||
|
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
||||||
|
d.setMinutes(object[settings[1]]);
|
||||||
|
return Qt.formatTime(d, "hh:mm AP");
|
||||||
|
}
|
||||||
|
|
||||||
|
function commitChoice(choice: int, setting: string): void {
|
||||||
|
root.object[setting] = choice;
|
||||||
|
Config.save();
|
||||||
|
Hyprsunset.checkStartup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertHour(timeValue: int): int {
|
||||||
|
return Math.floor(timeValue / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertMinute(timeValue: int): int {
|
||||||
|
return timeValue % 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertToMinutes(hour: int, minute: int): int {
|
||||||
|
return hour * 60 + minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
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
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: text
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
text: root.name
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
Layout.preferredWidth: Math.min(contentWidth, optionLayout.x - Appearance.spacing.normal)
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.normal
|
||||||
|
text: qsTr("Hyprsunset will turn on at %1, and turn off at %2.").arg(root.startTime).arg(root.endTime)
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: optionLayout
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
CustomText {
|
||||||
|
Layout.preferredWidth: spacer.x + spacer.width
|
||||||
|
text: qsTr("Start")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.preferredWidth: endMinuteRect.width + endHourRect.width
|
||||||
|
text: qsTr("End")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignHCenter
|
||||||
|
text: qsTr("Enabled: ")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomSwitch {
|
||||||
|
id: enabledSwitch
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignHCenter
|
||||||
|
checked: root.object[root.settings[0]]
|
||||||
|
|
||||||
|
onToggled: {
|
||||||
|
root.object[root.settings[0]] = checked;
|
||||||
|
Config.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: startHourRect
|
||||||
|
|
||||||
|
Layout.preferredHeight: 72
|
||||||
|
Layout.preferredWidth: 96
|
||||||
|
color: startHourField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
implicitHeight: 72
|
||||||
|
implicitWidth: 96
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
border.color: startHourField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
border.width: startHourField.focus ? 2 : 0
|
||||||
|
radius: parent.radius - border.width
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: startHourField
|
||||||
|
|
||||||
|
function setConfigText(setting: string): string {
|
||||||
|
var val = root.convertHour(root.object[setting]);
|
||||||
|
if (val === 0) {
|
||||||
|
return "00";
|
||||||
|
}
|
||||||
|
return String(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
clip: true
|
||||||
|
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
|
||||||
|
cursorHeight: height - Appearance.padding.normal * 2
|
||||||
|
font.family: "Roboto"
|
||||||
|
font.letterSpacing: -0.25
|
||||||
|
font.pixelSize: 56
|
||||||
|
font.weight: 400
|
||||||
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
text: setConfigText(root.settings[1])
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Backspace) {
|
||||||
|
event.accepted = true;
|
||||||
|
if (startHourField.text.length >= 2) {
|
||||||
|
startHourField.text = "0" + startHourField.text[0];
|
||||||
|
} else if (startHourField.text.length === 1) {
|
||||||
|
startHourField.text = "0";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
event.accepted = true;
|
||||||
|
startHourField.text = setConfigText(root.settings[1]);
|
||||||
|
startHourField.focus = false;
|
||||||
|
} else if (event.key === Qt.Key_Return) {
|
||||||
|
startHourField.focus = false;
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Tab) {
|
||||||
|
startMinuteField.focus = true;
|
||||||
|
} else if (event.key === Qt.Key_Backtab) {
|
||||||
|
endMinuteField.focus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
|
||||||
|
event.accepted = true;
|
||||||
|
var digit = event.text;
|
||||||
|
var textLen = startHourField.text.length;
|
||||||
|
|
||||||
|
if (textLen >= 2 && startHourField.text[0] !== '0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = 0;
|
||||||
|
if (textLen === 0) {
|
||||||
|
val = parseInt(digit);
|
||||||
|
} else if (textLen === 1) {
|
||||||
|
val = parseInt(startHourField.text + digit);
|
||||||
|
} else {
|
||||||
|
val = parseInt(startHourField.text[1] + digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
|
||||||
|
if (textLen >= 2 && val < 10) {
|
||||||
|
startHourField.text = "0" + val;
|
||||||
|
} else {
|
||||||
|
startHourField.text = val.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
onCursorPositionChanged: cursorPosition = 2
|
||||||
|
onEditingFinished: {
|
||||||
|
root.commitChoice(root.convertToMinutes(parseInt(startHourField.text), parseInt(startMinuteField.text)), root.settings[1]);
|
||||||
|
}
|
||||||
|
onTextEdited: {
|
||||||
|
if (startHourField.text === "")
|
||||||
|
return;
|
||||||
|
var val = parseInt(startHourField.text);
|
||||||
|
if (isNaN(val))
|
||||||
|
return;
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
var newText = val.toString();
|
||||||
|
if (newText !== startHourField.text)
|
||||||
|
startHourField.text = newText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: startSeparator
|
||||||
|
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
text: ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: startMinuteRect
|
||||||
|
|
||||||
|
Layout.preferredHeight: 72
|
||||||
|
Layout.preferredWidth: 96
|
||||||
|
color: startMinuteField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
implicitHeight: 72
|
||||||
|
implicitWidth: 96
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
border.color: startMinuteField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
border.width: startMinuteField.focus ? 2 : 0
|
||||||
|
radius: parent.radius - border.width
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: startMinuteField
|
||||||
|
|
||||||
|
function setConfigText(setting: string): string {
|
||||||
|
var val = root.convertMinute(root.object[setting]);
|
||||||
|
if (val === 0) {
|
||||||
|
return "00";
|
||||||
|
}
|
||||||
|
return String(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
clip: true
|
||||||
|
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
|
||||||
|
cursorHeight: height - Appearance.padding.normal * 2
|
||||||
|
font.family: "Roboto"
|
||||||
|
font.letterSpacing: -0.25
|
||||||
|
font.pixelSize: 56
|
||||||
|
font.weight: 400
|
||||||
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
text: setConfigText(root.settings[1])
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Backspace) {
|
||||||
|
event.accepted = true;
|
||||||
|
if (startMinuteField.text.length >= 2) {
|
||||||
|
startMinuteField.text = "0" + startMinuteField.text[0];
|
||||||
|
} else if (startMinuteField.text.length === 1) {
|
||||||
|
startMinuteField.text = "0";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
event.accepted = true;
|
||||||
|
startMinuteField.text = setConfigText(root.settings[1]);
|
||||||
|
startMinuteField.focus = false;
|
||||||
|
} else if (event.key === Qt.Key_Return) {
|
||||||
|
startMinuteField.focus = false;
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Tab) {
|
||||||
|
endHourField.focus = true;
|
||||||
|
} else if (event.key === Qt.Key_Backtab) {
|
||||||
|
startHourField.focus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
|
||||||
|
event.accepted = true;
|
||||||
|
var digit = event.text;
|
||||||
|
var textLen = startMinuteField.text.length;
|
||||||
|
|
||||||
|
if (textLen >= 2 && startMinuteField.text[0] !== '0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = 0;
|
||||||
|
if (textLen === 0) {
|
||||||
|
val = parseInt(digit);
|
||||||
|
} else if (textLen === 1) {
|
||||||
|
val = parseInt(startMinuteField.text + digit);
|
||||||
|
} else {
|
||||||
|
val = parseInt(startMinuteField.text[1] + digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = Math.max(0, Math.min(59, val));
|
||||||
|
|
||||||
|
if (textLen >= 2 && val < 10) {
|
||||||
|
startMinuteField.text = "0" + val;
|
||||||
|
} else {
|
||||||
|
startMinuteField.text = val.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
onCursorPositionChanged: cursorPosition = 2
|
||||||
|
onEditingFinished: {
|
||||||
|
root.commitChoice(root.convertToMinutes(parseInt(startHourField.text), parseInt(startMinuteField.text)), root.settings[1]);
|
||||||
|
}
|
||||||
|
onTextEdited: {
|
||||||
|
if (startMinuteField.text === "")
|
||||||
|
return;
|
||||||
|
var val = parseInt(startMinuteField.text);
|
||||||
|
if (isNaN(val))
|
||||||
|
return;
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
var newText = val.toString();
|
||||||
|
if (newText !== startMinuteField.text)
|
||||||
|
startMinuteField.text = newText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: spacer
|
||||||
|
|
||||||
|
Layout.preferredWidth: Appearance.spacing.large
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: endHourRect
|
||||||
|
|
||||||
|
Layout.preferredHeight: 72
|
||||||
|
Layout.preferredWidth: 96
|
||||||
|
color: endHourField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
implicitHeight: 72
|
||||||
|
implicitWidth: 96
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
border.color: endHourField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
border.width: endHourField.focus ? 2 : 0
|
||||||
|
radius: parent.radius - border.width
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: endHourField
|
||||||
|
|
||||||
|
function setConfigText(setting: string): string {
|
||||||
|
var val = root.convertHour(root.object[setting]);
|
||||||
|
if (val === 0) {
|
||||||
|
return "00";
|
||||||
|
}
|
||||||
|
return String(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
clip: true
|
||||||
|
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
|
||||||
|
cursorHeight: height - Appearance.padding.normal * 2
|
||||||
|
font.family: "Roboto"
|
||||||
|
font.letterSpacing: -0.25
|
||||||
|
font.pixelSize: 56
|
||||||
|
font.weight: 400
|
||||||
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
text: setConfigText(root.settings[2])
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Backspace) {
|
||||||
|
event.accepted = true;
|
||||||
|
if (endHourField.text.length >= 2) {
|
||||||
|
endHourField.text = "0" + endHourField.text[0];
|
||||||
|
} else if (endHourField.text.length === 1) {
|
||||||
|
endHourField.text = "0";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
event.accepted = true;
|
||||||
|
endHourField.text = setConfigText(root.settings[2]);
|
||||||
|
endHourField.focus = false;
|
||||||
|
} else if (event.key === Qt.Key_Return) {
|
||||||
|
endHourField.focus = false;
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Tab) {
|
||||||
|
endMinuteField.focus = true;
|
||||||
|
} else if (event.key === Qt.Key_Backtab) {
|
||||||
|
startMinuteField.focus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
|
||||||
|
event.accepted = true;
|
||||||
|
var digit = event.text;
|
||||||
|
var textLen = endHourField.text.length;
|
||||||
|
|
||||||
|
if (textLen >= 2 && endHourField.text[0] !== '0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = 0;
|
||||||
|
if (textLen === 0) {
|
||||||
|
val = parseInt(digit);
|
||||||
|
} else if (textLen === 1) {
|
||||||
|
val = parseInt(endHourField.text + digit);
|
||||||
|
} else {
|
||||||
|
val = parseInt(endHourField.text[1] + digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
|
||||||
|
if (textLen >= 2 && val < 10) {
|
||||||
|
endHourField.text = "0" + val;
|
||||||
|
} else {
|
||||||
|
endHourField.text = val.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
onCursorPositionChanged: cursorPosition = 2
|
||||||
|
onEditingFinished: {
|
||||||
|
root.commitChoice(root.convertToMinutes(parseInt(endHourField.text), parseInt(endMinuteField.text)), root.settings[2]);
|
||||||
|
}
|
||||||
|
onTextEdited: {
|
||||||
|
if (endHourField.text === "")
|
||||||
|
return;
|
||||||
|
var val = parseInt(endHourField.text);
|
||||||
|
if (isNaN(val))
|
||||||
|
return;
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
var newText = val.toString();
|
||||||
|
if (newText !== endHourField.text)
|
||||||
|
endHourField.text = newText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: endSeparator
|
||||||
|
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
text: ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: endMinuteRect
|
||||||
|
|
||||||
|
Layout.preferredHeight: 72
|
||||||
|
Layout.preferredWidth: 96
|
||||||
|
color: endMinuteField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
implicitHeight: 72
|
||||||
|
implicitWidth: 96
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
border.color: endMinuteField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
border.width: endMinuteField.focus ? 2 : 0
|
||||||
|
radius: parent.radius - border.width
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: endMinuteField
|
||||||
|
|
||||||
|
function setConfigText(setting: string): string {
|
||||||
|
var val = root.convertMinute(root.object[setting]);
|
||||||
|
if (val === 0) {
|
||||||
|
return "00";
|
||||||
|
}
|
||||||
|
return String(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
clip: true
|
||||||
|
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
|
||||||
|
cursorHeight: height - Appearance.padding.normal * 2
|
||||||
|
font.family: "Roboto"
|
||||||
|
font.letterSpacing: -0.25
|
||||||
|
font.pixelSize: 56
|
||||||
|
font.weight: 400
|
||||||
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
text: setConfigText(root.settings[2])
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Backspace) {
|
||||||
|
event.accepted = true;
|
||||||
|
if (endMinuteField.text.length >= 2) {
|
||||||
|
endMinuteField.text = "0" + endMinuteField.text[0];
|
||||||
|
} else if (endMinuteField.text.length === 1) {
|
||||||
|
endMinuteField.text = "0";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
event.accepted = true;
|
||||||
|
endMinuteField.text = setConfigText(root.settings[2]);
|
||||||
|
endMinuteField.focus = false;
|
||||||
|
} else if (event.key === Qt.Key_Return) {
|
||||||
|
endMinuteField.focus = false;
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Tab) {
|
||||||
|
startHourField.focus = true;
|
||||||
|
} else if (event.key === Qt.Key_Backtab) {
|
||||||
|
endHourField.focus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
|
||||||
|
event.accepted = true;
|
||||||
|
var digit = event.text;
|
||||||
|
var textLen = endMinuteField.text.length;
|
||||||
|
|
||||||
|
if (textLen >= 2 && endMinuteField.text[0] !== '0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = 0;
|
||||||
|
if (textLen === 0) {
|
||||||
|
val = parseInt(digit);
|
||||||
|
} else if (textLen === 1) {
|
||||||
|
val = parseInt(endMinuteField.text + digit);
|
||||||
|
} else {
|
||||||
|
val = parseInt(endMinuteField.text[1] + digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = Math.max(0, Math.min(59, val));
|
||||||
|
|
||||||
|
if (textLen >= 2 && val < 10) {
|
||||||
|
endMinuteField.text = "0" + val;
|
||||||
|
} else {
|
||||||
|
endMinuteField.text = val.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
onCursorPositionChanged: cursorPosition = 2
|
||||||
|
onEditingFinished: {
|
||||||
|
root.commitChoice(root.convertToMinutes(parseInt(endHourField.text), parseInt(endMinuteField.text)), root.settings[2]);
|
||||||
|
}
|
||||||
|
onTextEdited: {
|
||||||
|
if (endMinuteField.text === "")
|
||||||
|
return;
|
||||||
|
var val = parseInt(endMinuteField.text);
|
||||||
|
if (isNaN(val))
|
||||||
|
return;
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
var newText = val.toString();
|
||||||
|
if (newText !== endMinuteField.text)
|
||||||
|
endMinuteField.text = newText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: startHour
|
||||||
|
|
||||||
|
Layout.preferredWidth: startSeparator.x + startSeparator.width
|
||||||
|
text: qsTr("Hour")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: startMinute
|
||||||
|
|
||||||
|
Layout.preferredWidth: spacer.x + spacer.width - x
|
||||||
|
text: qsTr("Minute")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.preferredWidth: endSeparator.x + endSeparator.width - x
|
||||||
|
text: qsTr("Hour")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
text: qsTr("Minute")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
ConnectedRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias delegate: list.delegate
|
||||||
|
property int extraHeight
|
||||||
|
readonly property alias list: list
|
||||||
|
property alias model: list.model
|
||||||
|
property string placeholderIcon
|
||||||
|
property string placeholderText
|
||||||
|
property bool showList
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
clip: true
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: (showList && list.count > 0 ? list.contentHeight : placeholder.implicitHeight + Appearance.padding.extraLarge * 2) + extraHeight
|
||||||
|
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: placeholder
|
||||||
|
|
||||||
|
active: opacity > 0
|
||||||
|
anchors.centerIn: parent
|
||||||
|
opacity: root.showList && list.count > 0 ? 0 : 1
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sourceComponent: ColumnLayout {
|
||||||
|
spacing: Appearance.spacing.extraSmall
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
animate: true
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: root.placeholderIcon
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
animate: true
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: root.placeholderText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: list
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
interactive: false
|
||||||
|
opacity: root.showList ? 1 : 0
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
add: Transition {
|
||||||
|
Anim {
|
||||||
|
from: 0
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displaced: Transition {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
property: "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
move: Transition {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
property: "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remove: Transition {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
ConnectedRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias icon: icon.text
|
||||||
|
property alias status: status.text
|
||||||
|
property alias text: label.text
|
||||||
|
|
||||||
|
signal clicked
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: navLayout.implicitHeight + navLayout.anchors.margins * 2
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
onClicked: root.clicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: navLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.largeIncreased
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.rightMargin: Appearance.padding.largeIncreased
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: status
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
animate: true
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
visible: text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
text: "chevron_right"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.SettingsNew
|
||||||
|
|
||||||
|
ConnectedRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias checked: switchButton.checked
|
||||||
|
property int horizontalPadding: Appearance.padding.largeIncreased
|
||||||
|
required property Component popup
|
||||||
|
property alias subtext: subtext.text
|
||||||
|
property alias text: text.text
|
||||||
|
property int verticalPadding: Appearance.padding.normal
|
||||||
|
|
||||||
|
signal clicked(checked: bool)
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: layout.implicitHeight + verticalPadding * 2
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: layout
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: root.horizontalPadding
|
||||||
|
anchors.right: icon.left
|
||||||
|
anchors.rightMargin: Appearance.padding.normal
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: text
|
||||||
|
|
||||||
|
font.pointSize: Appearance.font.size.smaller
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: subtext
|
||||||
|
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
anchors.right: switchButton.left
|
||||||
|
anchors.rightMargin: Appearance.spacing.normal
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: "open_in_new"
|
||||||
|
}
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
onClicked: PopupManager.requestOpen(root.popup)
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomSwitch {
|
||||||
|
id: switchButton
|
||||||
|
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: root.horizontalPadding
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
onClicked: root.clicked(checked)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Modules.SettingsNew
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property int cappedWidth: Math.min(800, width)
|
||||||
|
default property Item contentChild
|
||||||
|
readonly property alias flickable: flickable
|
||||||
|
property bool isSubPage
|
||||||
|
required property SettingsState sState
|
||||||
|
required property string title
|
||||||
|
|
||||||
|
spacing: Appearance.spacing.large
|
||||||
|
|
||||||
|
MouseArea { // Prevent clicks from reaching flickable
|
||||||
|
Layout.bottomMargin: -flickable.topMargin // Extra height to block clicks on flickable top margin
|
||||||
|
|
||||||
|
implicitHeight: header.implicitHeight - Layout.bottomMargin
|
||||||
|
implicitWidth: header.implicitWidth
|
||||||
|
z: 1
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: header
|
||||||
|
|
||||||
|
spacing: Appearance.spacing.large
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
active: root.isSubPage
|
||||||
|
asynchronous: true
|
||||||
|
visible: active
|
||||||
|
|
||||||
|
sourceComponent: IconButton {
|
||||||
|
icon: "arrow_back"
|
||||||
|
inactiveColor: DynamicColors.tPalette.m3surfaceContainerHigh
|
||||||
|
inactiveOnColor: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
isRound: true
|
||||||
|
type: IconButton.Tonal
|
||||||
|
|
||||||
|
onClicked: root.sState.closeSubPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: root.title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalFadeFlickable {
|
||||||
|
id: flickable
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: -topMargin
|
||||||
|
bottomMargin: Appearance.padding.extraLarge
|
||||||
|
contentHeight: root.contentChild?.implicitHeight ?? 0
|
||||||
|
contentItem.children: [root.contentChild]
|
||||||
|
fadeAmount: 0.1
|
||||||
|
topMargin: Appearance.padding.large
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Drawers
|
||||||
|
|
||||||
|
ConnectedRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
default required property Item content
|
||||||
|
property alias icon: icon.text
|
||||||
|
property bool keepPopupAsChild
|
||||||
|
readonly property alias popup: popup
|
||||||
|
property alias status: status.text
|
||||||
|
property alias text: label.text
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: navLayout.implicitHeight + navLayout.anchors.margins * 2
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
id: stateLayer
|
||||||
|
|
||||||
|
manualHoverOverride: popup.hovered && !popup.open
|
||||||
|
|
||||||
|
onClicked: popup.open = true
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: navLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.largeIncreased
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.rightMargin: Appearance.padding.largeIncreased
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: status
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
animate: true
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
visible: text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: triggerArea
|
||||||
|
|
||||||
|
implicitHeight: popup.implicitHeight
|
||||||
|
implicitWidth: popup.implicitWidth
|
||||||
|
|
||||||
|
TransformWatcher {
|
||||||
|
id: tWatcher
|
||||||
|
|
||||||
|
a: area.parent
|
||||||
|
b: triggerArea
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: area
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: popup.open ? Qt.ArrowCursor : undefined
|
||||||
|
enabled: popup.open
|
||||||
|
hoverEnabled: true
|
||||||
|
parent: {
|
||||||
|
if (root.keepPopupAsChild)
|
||||||
|
return triggerArea;
|
||||||
|
|
||||||
|
const win = QsWindow.window;
|
||||||
|
const contentWin = win as Windows; // If inside the drawer content window, put it inside the interaction wrapper so hover works
|
||||||
|
return contentWin ? contentWin.interactionWrapper : (win as QsWindow).contentItem;
|
||||||
|
}
|
||||||
|
preventStealing: true
|
||||||
|
propagateComposedEvents: false
|
||||||
|
z: popup.animDriver > 0 ? 1 : 0
|
||||||
|
|
||||||
|
onClicked: popup.open = false
|
||||||
|
|
||||||
|
BlobPopup {
|
||||||
|
id: popup
|
||||||
|
|
||||||
|
color: open || hovered || stateLayer.containsMouse ? DynamicColors.palette.m3secondaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
content: root.content
|
||||||
|
hoverOverride: stateLayer.containsMouse
|
||||||
|
padding: Appearance.padding.small
|
||||||
|
pressOverride: stateLayer.pressed
|
||||||
|
x: {
|
||||||
|
tWatcher.transform;
|
||||||
|
return triggerArea.mapToItem(area.parent, 0, 0).x;
|
||||||
|
}
|
||||||
|
y: {
|
||||||
|
tWatcher.transform;
|
||||||
|
return triggerArea.mapToItem(area.parent, 0, 0).y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
property bool first
|
||||||
|
|
||||||
|
Layout.bottomMargin: Appearance.spacing.extraSmall
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: Appearance.padding.small
|
||||||
|
Layout.topMargin: first ? 0 : Appearance.spacing.large - ((parent as ColumnLayout).spacing ?? 0)
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
ConnectedRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias active: splitButton.active
|
||||||
|
property alias fallbackIcon: splitButton.fallbackIcon
|
||||||
|
property alias fallbackText: splitButton.fallbackText
|
||||||
|
property alias menuItems: splitButton.menuItems
|
||||||
|
property alias menuOnTop: splitButton.menuOnTop
|
||||||
|
property string subtext
|
||||||
|
property alias text: label.text
|
||||||
|
|
||||||
|
signal selected(item: MenuItem)
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
clip: false
|
||||||
|
implicitHeight: rowLayout.implicitHeight + rowLayout.anchors.margins * 2
|
||||||
|
z: splitButton.expanded ? 1 : 0
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: rowLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.largeIncreased
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.rightMargin: Appearance.padding.largeIncreased
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.smaller
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: root.subtext
|
||||||
|
visible: root.subtext
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomSplitButton {
|
||||||
|
id: splitButton
|
||||||
|
|
||||||
|
type: CustomSplitButton.Tonal
|
||||||
|
|
||||||
|
menu.onItemSelected: item => root.selected(item)
|
||||||
|
stateLayer.onClicked: splitButton.expanded = !splitButton.expanded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
ConnectedRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias icon: slider.insetIcon
|
||||||
|
property alias label: label.text
|
||||||
|
property real value
|
||||||
|
property alias valueLabel: valueLabel.text
|
||||||
|
|
||||||
|
signal moved(value: real)
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: rowLayout.implicitHeight + rowLayout.anchors.margins + rowLayout.anchors.topMargin
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: rowLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Appearance.padding.largeIncreased
|
||||||
|
anchors.topMargin: Appearance.padding.large
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: valueLabel
|
||||||
|
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomMouseArea {
|
||||||
|
function onWheel(event: WheelEvent): void {
|
||||||
|
const step = Config.services.audioIncrement;
|
||||||
|
if (event.angleDelta.y > 0)
|
||||||
|
root.moved(Math.min(1, root.value + step));
|
||||||
|
else if (event.angleDelta.y < 0)
|
||||||
|
root.moved(Math.max(0, root.value - step));
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: Appearance.padding.larger * 3
|
||||||
|
|
||||||
|
CustomSlider {
|
||||||
|
id: slider
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
enabled: root.enabled
|
||||||
|
implicitHeight: parent.implicitHeight
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
value: root.value
|
||||||
|
|
||||||
|
onInteraction: v => root.moved(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
ConnectedRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property real from: 0
|
||||||
|
property real stepSize: 1
|
||||||
|
property string subtext
|
||||||
|
property alias text: label.text
|
||||||
|
property real to: 99
|
||||||
|
property real value
|
||||||
|
|
||||||
|
signal moved(value: real)
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: rowLayout.implicitHeight + rowLayout.anchors.margins * 2
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: rowLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.largeIncreased
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.rightMargin: Appearance.padding.largeIncreased
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.smaller
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: root.subtext
|
||||||
|
visible: root.subtext
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomSpinBox {
|
||||||
|
max: root.to
|
||||||
|
min: root.from
|
||||||
|
step: root.stepSize
|
||||||
|
value: root.value
|
||||||
|
|
||||||
|
onValueModified: v => root.moved(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.SettingsNew
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
StackView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property int animMovement: Appearance.padding.extraLarge * 2
|
||||||
|
default property list<Component> pages
|
||||||
|
required property SettingsState sState
|
||||||
|
|
||||||
|
function openSubPage(idx: int, immediate: bool): void {
|
||||||
|
const page = pages[idx];
|
||||||
|
if (page) {
|
||||||
|
push(page, {
|
||||||
|
sState
|
||||||
|
}, immediate ? StackView.Immediate : StackView.PushTransition);
|
||||||
|
} else {
|
||||||
|
console.warn(logCat, "Attempted to open invalid sub-page index", idx);
|
||||||
|
sState.closeSubPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clip: busy
|
||||||
|
|
||||||
|
popEnter: Transition {
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
property: "opacity"
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PauseAnimation {
|
||||||
|
duration: Appearance.anim.durations.expressiveEffects
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
from: -root.animMovement
|
||||||
|
property: "x"
|
||||||
|
to: 0
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
popExit: Transition {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pushEnter: Transition {
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
property: "opacity"
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PauseAnimation {
|
||||||
|
duration: Appearance.anim.durations.expressiveEffects
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
from: root.animMovement
|
||||||
|
property: "x"
|
||||||
|
to: 0
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pushExit: Transition {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
openSubPage(0, true);
|
||||||
|
for (const page of sState.subPageIdxStack)
|
||||||
|
openSubPage(page, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoggingCategory {
|
||||||
|
id: logCat
|
||||||
|
|
||||||
|
defaultLogLevel: LoggingCategory.Info
|
||||||
|
name: "ZShell.settings"
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onSubPageClosed(): void {
|
||||||
|
if (root.depth < root.sState.subPageIdxStack.length) {
|
||||||
|
console.log(logCat, "Attempted to close page while depth < stack depth. Ignoring.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
root.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubPageOpened(idx: int): void {
|
||||||
|
root.openSubPage(idx, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
target: root.sState
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,585 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import ZShell.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var object
|
||||||
|
required property list<string> settings
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
|
signal applySettings(startTime: int, endTime: int)
|
||||||
|
signal close
|
||||||
|
|
||||||
|
function convertHour(timeValue: int): int {
|
||||||
|
return Math.floor(timeValue / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertMinute(timeValue: int): int {
|
||||||
|
return timeValue % 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertToMinutes(hour: int, minute: int): int {
|
||||||
|
return hour * 60 + minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
color: DynamicColors.palette.m3surfaceContainer
|
||||||
|
implicitHeight: column.implicitHeight + column.anchors.margins * 2 + buttonRow.implicitHeight + buttonRow.anchors.topMargin
|
||||||
|
implicitWidth: column.implicitWidth + column.anchors.margins * 2
|
||||||
|
radius: Appearance.rounding.large
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.largeIncreased
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
text: qsTr("Select time")
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
CustomRect {
|
||||||
|
id: startHourRect
|
||||||
|
|
||||||
|
Layout.preferredHeight: 72
|
||||||
|
Layout.preferredWidth: 96
|
||||||
|
color: startHourField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
implicitHeight: 72
|
||||||
|
implicitWidth: 96
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
border.color: startHourField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
border.width: startHourField.focus ? 2 : 0
|
||||||
|
radius: parent.radius - border.width
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: startHourField
|
||||||
|
|
||||||
|
function setConfigText(setting: string): string {
|
||||||
|
var val = root.convertHour(root.object[setting]);
|
||||||
|
if (val === 0) {
|
||||||
|
return "00";
|
||||||
|
}
|
||||||
|
return String(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
clip: true
|
||||||
|
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
|
||||||
|
cursorHeight: height - Appearance.padding.normal * 2
|
||||||
|
font.family: "Roboto"
|
||||||
|
font.letterSpacing: -0.25
|
||||||
|
font.pixelSize: 56
|
||||||
|
font.weight: 400
|
||||||
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
text: setConfigText(root.settings[1])
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Backspace) {
|
||||||
|
event.accepted = true;
|
||||||
|
if (startHourField.text.length >= 2) {
|
||||||
|
startHourField.text = "0" + startHourField.text[0];
|
||||||
|
} else if (startHourField.text.length === 1) {
|
||||||
|
startHourField.text = "0";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
event.accepted = true;
|
||||||
|
startHourField.text = setConfigText(root.settings[1]);
|
||||||
|
startHourField.focus = false;
|
||||||
|
} else if (event.key === Qt.Key_Return) {
|
||||||
|
startHourField.focus = false;
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Tab) {
|
||||||
|
startMinuteField.focus = true;
|
||||||
|
} else if (event.key === Qt.Key_Backtab) {
|
||||||
|
endMinuteField.focus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
|
||||||
|
event.accepted = true;
|
||||||
|
var digit = event.text;
|
||||||
|
var textLen = startHourField.text.length;
|
||||||
|
|
||||||
|
if (textLen >= 2 && startHourField.text[0] !== '0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = 0;
|
||||||
|
if (textLen === 0) {
|
||||||
|
val = parseInt(digit);
|
||||||
|
} else if (textLen === 1) {
|
||||||
|
val = parseInt(startHourField.text + digit);
|
||||||
|
} else {
|
||||||
|
val = parseInt(startHourField.text[1] + digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
|
||||||
|
if (textLen >= 2 && val < 10) {
|
||||||
|
startHourField.text = "0" + val;
|
||||||
|
} else {
|
||||||
|
startHourField.text = val.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
onCursorPositionChanged: cursorPosition = 2
|
||||||
|
onTextEdited: {
|
||||||
|
if (startHourField.text === "")
|
||||||
|
return;
|
||||||
|
var val = parseInt(startHourField.text);
|
||||||
|
if (isNaN(val))
|
||||||
|
return;
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
var newText = val.toString();
|
||||||
|
if (newText !== startHourField.text)
|
||||||
|
startHourField.text = newText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: startSeparator
|
||||||
|
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
text: ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: startMinuteRect
|
||||||
|
|
||||||
|
Layout.preferredHeight: 72
|
||||||
|
Layout.preferredWidth: 96
|
||||||
|
color: startMinuteField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
implicitHeight: 72
|
||||||
|
implicitWidth: 96
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
border.color: startMinuteField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
border.width: startMinuteField.focus ? 2 : 0
|
||||||
|
radius: parent.radius - border.width
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: startMinuteField
|
||||||
|
|
||||||
|
function setConfigText(setting: string): string {
|
||||||
|
var val = root.convertMinute(root.object[setting]);
|
||||||
|
if (val === 0) {
|
||||||
|
return "00";
|
||||||
|
}
|
||||||
|
return String(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
clip: true
|
||||||
|
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
|
||||||
|
cursorHeight: height - Appearance.padding.normal * 2
|
||||||
|
font.family: "Roboto"
|
||||||
|
font.letterSpacing: -0.25
|
||||||
|
font.pixelSize: 56
|
||||||
|
font.weight: 400
|
||||||
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
text: setConfigText(root.settings[1])
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Backspace) {
|
||||||
|
event.accepted = true;
|
||||||
|
if (startMinuteField.text.length >= 2) {
|
||||||
|
startMinuteField.text = "0" + startMinuteField.text[0];
|
||||||
|
} else if (startMinuteField.text.length === 1) {
|
||||||
|
startMinuteField.text = "0";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
event.accepted = true;
|
||||||
|
startMinuteField.text = setConfigText(root.settings[1]);
|
||||||
|
startMinuteField.focus = false;
|
||||||
|
} else if (event.key === Qt.Key_Return) {
|
||||||
|
startMinuteField.focus = false;
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Tab) {
|
||||||
|
endHourField.focus = true;
|
||||||
|
} else if (event.key === Qt.Key_Backtab) {
|
||||||
|
startHourField.focus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
|
||||||
|
event.accepted = true;
|
||||||
|
var digit = event.text;
|
||||||
|
var textLen = startMinuteField.text.length;
|
||||||
|
|
||||||
|
if (textLen >= 2 && startMinuteField.text[0] !== '0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = 0;
|
||||||
|
if (textLen === 0) {
|
||||||
|
val = parseInt(digit);
|
||||||
|
} else if (textLen === 1) {
|
||||||
|
val = parseInt(startMinuteField.text + digit);
|
||||||
|
} else {
|
||||||
|
val = parseInt(startMinuteField.text[1] + digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = Math.max(0, Math.min(59, val));
|
||||||
|
|
||||||
|
if (textLen >= 2 && val < 10) {
|
||||||
|
startMinuteField.text = "0" + val;
|
||||||
|
} else {
|
||||||
|
startMinuteField.text = val.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
onCursorPositionChanged: cursorPosition = 2
|
||||||
|
onTextEdited: {
|
||||||
|
if (startMinuteField.text === "")
|
||||||
|
return;
|
||||||
|
var val = parseInt(startMinuteField.text);
|
||||||
|
if (isNaN(val))
|
||||||
|
return;
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
var newText = val.toString();
|
||||||
|
if (newText !== startMinuteField.text)
|
||||||
|
startMinuteField.text = newText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: spacer
|
||||||
|
|
||||||
|
Layout.preferredWidth: Appearance.spacing.large
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: endHourRect
|
||||||
|
|
||||||
|
Layout.preferredHeight: 72
|
||||||
|
Layout.preferredWidth: 96
|
||||||
|
color: endHourField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
implicitHeight: 72
|
||||||
|
implicitWidth: 96
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
border.color: endHourField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
border.width: endHourField.focus ? 2 : 0
|
||||||
|
radius: parent.radius - border.width
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: endHourField
|
||||||
|
|
||||||
|
function setConfigText(setting: string): string {
|
||||||
|
var val = root.convertHour(root.object[setting]);
|
||||||
|
if (val === 0) {
|
||||||
|
return "00";
|
||||||
|
}
|
||||||
|
return String(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
clip: true
|
||||||
|
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
|
||||||
|
cursorHeight: height - Appearance.padding.normal * 2
|
||||||
|
font.family: "Roboto"
|
||||||
|
font.letterSpacing: -0.25
|
||||||
|
font.pixelSize: 56
|
||||||
|
font.weight: 400
|
||||||
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
text: setConfigText(root.settings[2])
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Backspace) {
|
||||||
|
event.accepted = true;
|
||||||
|
if (endHourField.text.length >= 2) {
|
||||||
|
endHourField.text = "0" + endHourField.text[0];
|
||||||
|
} else if (endHourField.text.length === 1) {
|
||||||
|
endHourField.text = "0";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
event.accepted = true;
|
||||||
|
endHourField.text = setConfigText(root.settings[2]);
|
||||||
|
endHourField.focus = false;
|
||||||
|
} else if (event.key === Qt.Key_Return) {
|
||||||
|
endHourField.focus = false;
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Tab) {
|
||||||
|
endMinuteField.focus = true;
|
||||||
|
} else if (event.key === Qt.Key_Backtab) {
|
||||||
|
startMinuteField.focus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
|
||||||
|
event.accepted = true;
|
||||||
|
var digit = event.text;
|
||||||
|
var textLen = endHourField.text.length;
|
||||||
|
|
||||||
|
if (textLen >= 2 && endHourField.text[0] !== '0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = 0;
|
||||||
|
if (textLen === 0) {
|
||||||
|
val = parseInt(digit);
|
||||||
|
} else if (textLen === 1) {
|
||||||
|
val = parseInt(endHourField.text + digit);
|
||||||
|
} else {
|
||||||
|
val = parseInt(endHourField.text[1] + digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
|
||||||
|
if (textLen >= 2 && val < 10) {
|
||||||
|
endHourField.text = "0" + val;
|
||||||
|
} else {
|
||||||
|
endHourField.text = val.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
onCursorPositionChanged: cursorPosition = 2
|
||||||
|
onTextEdited: {
|
||||||
|
if (endHourField.text === "")
|
||||||
|
return;
|
||||||
|
var val = parseInt(endHourField.text);
|
||||||
|
if (isNaN(val))
|
||||||
|
return;
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
var newText = val.toString();
|
||||||
|
if (newText !== endHourField.text)
|
||||||
|
endHourField.text = newText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: endSeparator
|
||||||
|
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
text: ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: endMinuteRect
|
||||||
|
|
||||||
|
Layout.preferredHeight: 72
|
||||||
|
Layout.preferredWidth: 96
|
||||||
|
color: endMinuteField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
implicitHeight: 72
|
||||||
|
implicitWidth: 96
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
border.color: endMinuteField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
|
||||||
|
border.width: endMinuteField.focus ? 2 : 0
|
||||||
|
radius: parent.radius - border.width
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: endMinuteField
|
||||||
|
|
||||||
|
function setConfigText(setting: string): string {
|
||||||
|
var val = root.convertMinute(root.object[setting]);
|
||||||
|
if (val === 0) {
|
||||||
|
return "00";
|
||||||
|
}
|
||||||
|
return String(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
clip: true
|
||||||
|
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
|
||||||
|
cursorHeight: height - Appearance.padding.normal * 2
|
||||||
|
font.family: "Roboto"
|
||||||
|
font.letterSpacing: -0.25
|
||||||
|
font.pixelSize: 56
|
||||||
|
font.weight: 400
|
||||||
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
text: setConfigText(root.settings[2])
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Backspace) {
|
||||||
|
event.accepted = true;
|
||||||
|
if (endMinuteField.text.length >= 2) {
|
||||||
|
endMinuteField.text = "0" + endMinuteField.text[0];
|
||||||
|
} else if (endMinuteField.text.length === 1) {
|
||||||
|
endMinuteField.text = "0";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
event.accepted = true;
|
||||||
|
endMinuteField.text = setConfigText(root.settings[2]);
|
||||||
|
endMinuteField.focus = false;
|
||||||
|
} else if (event.key === Qt.Key_Return) {
|
||||||
|
endMinuteField.focus = false;
|
||||||
|
return;
|
||||||
|
} else if (event.key === Qt.Key_Tab) {
|
||||||
|
startHourField.focus = true;
|
||||||
|
} else if (event.key === Qt.Key_Backtab) {
|
||||||
|
endHourField.focus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
|
||||||
|
event.accepted = true;
|
||||||
|
var digit = event.text;
|
||||||
|
var textLen = endMinuteField.text.length;
|
||||||
|
|
||||||
|
if (textLen >= 2 && endMinuteField.text[0] !== '0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = 0;
|
||||||
|
if (textLen === 0) {
|
||||||
|
val = parseInt(digit);
|
||||||
|
} else if (textLen === 1) {
|
||||||
|
val = parseInt(endMinuteField.text + digit);
|
||||||
|
} else {
|
||||||
|
val = parseInt(endMinuteField.text[1] + digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = Math.max(0, Math.min(59, val));
|
||||||
|
|
||||||
|
if (textLen >= 2 && val < 10) {
|
||||||
|
endMinuteField.text = "0" + val;
|
||||||
|
} else {
|
||||||
|
endMinuteField.text = val.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
onCursorPositionChanged: cursorPosition = 2
|
||||||
|
onTextEdited: {
|
||||||
|
if (endMinuteField.text === "")
|
||||||
|
return;
|
||||||
|
var val = parseInt(endMinuteField.text);
|
||||||
|
if (isNaN(val))
|
||||||
|
return;
|
||||||
|
val = Math.max(0, Math.min(23, val));
|
||||||
|
var newText = val.toString();
|
||||||
|
if (newText !== endMinuteField.text)
|
||||||
|
endMinuteField.text = newText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
CustomText {
|
||||||
|
Layout.preferredWidth: spacer.x + spacer.width
|
||||||
|
text: qsTr("Start")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.preferredWidth: endMinuteRect.width + endHourRect.width
|
||||||
|
text: qsTr("End")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: buttonRow
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.largeIncreased
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: column.bottom
|
||||||
|
anchors.topMargin: Appearance.spacing.normal
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: buttonSpacer
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonRow {
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
IconTextButton {
|
||||||
|
font.pointSize: Appearance.font.size.normal
|
||||||
|
icon: "close"
|
||||||
|
inactiveColor: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 2)
|
||||||
|
inactiveOnColor: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
isRound: true
|
||||||
|
isToggle: false
|
||||||
|
shapeMorph: true
|
||||||
|
shapeMorphExpansion: pressed ? 12 : 0
|
||||||
|
text: "Cancel"
|
||||||
|
|
||||||
|
onClicked: root.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
IconTextButton {
|
||||||
|
font.pointSize: Appearance.font.size.normal
|
||||||
|
icon: "check"
|
||||||
|
isRound: true
|
||||||
|
isToggle: false
|
||||||
|
shapeMorph: true
|
||||||
|
shapeMorphExpansion: pressed ? 12 : 0
|
||||||
|
text: "Apply"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
const start = root.convertToMinutes(parseInt(startHourField.text)) + parseInt(startMinuteField.text);
|
||||||
|
const end = root.convertToMinutes(parseInt(endHourField.text)) + parseInt(endMinuteField.text);
|
||||||
|
root.applySettings(start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
CustomSwitch {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property alias bg: bg
|
||||||
|
property alias first: bg.first
|
||||||
|
property alias last: bg.last
|
||||||
|
property string subtext
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
cLayer: 2
|
||||||
|
horizontalPadding: Appearance.padding.largeIncreased
|
||||||
|
implicitHeight: Math.max(implicitContentHeight, implicitIndicatorHeight) + verticalPadding * 2
|
||||||
|
implicitWidth: implicitContentWidth + implicitIndicatorWidth + horizontalPadding * 2
|
||||||
|
indicator.anchors.right: right
|
||||||
|
indicator.anchors.rightMargin: root.horizontalPadding
|
||||||
|
indicator.anchors.verticalCenter: verticalCenter
|
||||||
|
verticalPadding: Appearance.padding.normal
|
||||||
|
|
||||||
|
background: ConnectedRect {
|
||||||
|
id: bg
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
id: stateLayer
|
||||||
|
|
||||||
|
manualPressOverride: root.pressed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contentItem: Item {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: root.horizontalPadding
|
||||||
|
anchors.right: root.indicator.left
|
||||||
|
anchors.rightMargin: Appearance.spacing.normal
|
||||||
|
implicitHeight: column.implicitHeight
|
||||||
|
implicitWidth: column.implicitWidth
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: column
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font: {
|
||||||
|
const f = Qt.font(label.font);
|
||||||
|
f.pointSize = Appearance.font.size.smaller;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
text: root.text
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: subtext
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font: {
|
||||||
|
const f = Qt.font(subtext.font);
|
||||||
|
f.pointSize = Appearance.font.size.small;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
text: root.subtext
|
||||||
|
visible: root.subtext
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressed: stateLayer.press(stateLayer.mouseX, stateLayer.mouseY)
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias imgHeight: imgWrapper.implicitHeight
|
||||||
|
property alias radius: imgWrapper.radius
|
||||||
|
property alias source: img.source
|
||||||
|
|
||||||
|
signal clicked
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: layout.implicitHeight
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: layout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
id: imgWrapper
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: width
|
||||||
|
radius: Appearance.rounding.large
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: img
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
opacity: status === Image.Ready ? 1 : 0
|
||||||
|
retainWhileLoading: true
|
||||||
|
sourceSize: {
|
||||||
|
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
|
||||||
|
return Qt.size(width * dpr, height * dpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
anchors.bottomMargin: layout.implicitHeight - imgWrapper.implicitHeight
|
||||||
|
|
||||||
|
onClicked: root.clicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import ZShell.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: wrapper
|
||||||
|
|
||||||
|
property int buttonRowHeight: Appearance.padding.large * 3
|
||||||
|
property bool changesMade: false
|
||||||
|
readonly property var currentScreen: screens.length > selectedScreenIndex ? screens[selectedScreenIndex] : null
|
||||||
|
property var screens: []
|
||||||
|
property int selectedScreenIndex: 0
|
||||||
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
|
function applyCrop(): void {
|
||||||
|
if (!cropRectLoader.item || !currentScreen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const cropRect = cropRectLoader.item;
|
||||||
|
|
||||||
|
const cropXPercent = (cropRect.x - cropRect.imageX) / scaledImg.paintedWidth;
|
||||||
|
const cropYPercent = (cropRect.y - cropRect.imageY) / scaledImg.paintedHeight;
|
||||||
|
const cropWidthPercent = cropRect.width / scaledImg.paintedWidth;
|
||||||
|
const cropHeightPercent = cropRect.height / scaledImg.paintedHeight;
|
||||||
|
|
||||||
|
Wallpapers.setCrop(currentScreen.name, Qt.rect(cropXPercent, cropYPercent, cropWidthPercent, cropHeightPercent), cropRect.zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshScreens(): void {
|
||||||
|
screens = [...Quickshell.screens].sort((a, b) => a.x - b.x);
|
||||||
|
selectedScreenIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectScreen(index: int): void {
|
||||||
|
if (index < 0 || index >= screens.length || index === selectedScreenIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selectedScreenIndex = index;
|
||||||
|
|
||||||
|
if (cropRectLoader.item)
|
||||||
|
Qt.callLater(syncCropToScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncCropToScreen(): void {
|
||||||
|
if (cropRectLoader.item)
|
||||||
|
cropRectLoader.item.restoreFromData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoomClipRect(zoom: real): void {
|
||||||
|
if (!cropRectLoader.item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const cropRect = cropRectLoader.item;
|
||||||
|
|
||||||
|
const centerX = cropRect.x + cropRect.width * 0.5;
|
||||||
|
const centerY = cropRect.y + cropRect.height * 0.5;
|
||||||
|
|
||||||
|
cropRect.zoom = zoom;
|
||||||
|
|
||||||
|
cropRect.x = centerX - cropRect.width * 0.5;
|
||||||
|
cropRect.y = centerY - cropRect.height * 0.5;
|
||||||
|
|
||||||
|
cropRect.clampToBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
implicitHeight: shouldBeActive ? 430 : 0
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
refreshScreens();
|
||||||
|
Qt.callLater(syncCropToScreen);
|
||||||
|
}
|
||||||
|
onSelectedScreenIndexChanged: {
|
||||||
|
Qt.callLater(syncCropToScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.applyCrop();
|
||||||
|
wrapper.changesMade = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonRow {
|
||||||
|
id: screenSelector
|
||||||
|
|
||||||
|
anchors.bottom: scaledImg.top
|
||||||
|
anchors.bottomMargin: Appearance.spacing.normal
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Appearance.padding.extraLarge * 2
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Appearance.padding.extraLarge * 2
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: wrapper.screens
|
||||||
|
|
||||||
|
delegate: TextButton {
|
||||||
|
required property int index
|
||||||
|
readonly property bool isCurrent: wrapper.selectedScreenIndex === index
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
fillWidth: true
|
||||||
|
inactiveColor: isCurrent ? DynamicColors.palette.m3primary : Qt.alpha(DynamicColors.palette.m3surfaceContainer, 0.7)
|
||||||
|
inactiveOnColor: isCurrent ? DynamicColors.palette.m3onPrimary : Qt.alpha(DynamicColors.palette.m3onSurface, 0.7)
|
||||||
|
isRound: true
|
||||||
|
shapeMorph: true
|
||||||
|
text: modelData.name
|
||||||
|
|
||||||
|
onClicked: wrapper.selectScreen(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: sliderLayout
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
implicitHeight: 30
|
||||||
|
|
||||||
|
CustomSlider {
|
||||||
|
id: zoomSlider
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: Appearance.padding.normal
|
||||||
|
Layout.preferredHeight: Appearance.padding.larger * 3
|
||||||
|
Layout.rightMargin: Appearance.padding.normal
|
||||||
|
from: 1.0
|
||||||
|
implicitHeight: Appearance.padding.larger * 3
|
||||||
|
insetIcon: "crop"
|
||||||
|
to: 5.0
|
||||||
|
value: cropRectLoader.item ? cropRectLoader.item.zoom : 1.0
|
||||||
|
|
||||||
|
onInteraction: value => {
|
||||||
|
wrapper.zoomClipRect(1 + (value * 4));
|
||||||
|
wrapper.changesMade = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
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.topMargin: wrapper.buttonRowHeight + Appearance.spacing.normal
|
||||||
|
// anchors.top: screenSelector.bottom
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
retainWhileLoading: true
|
||||||
|
source: Wallpapers.current
|
||||||
|
sourceSize.height: parent.height
|
||||||
|
sourceSize.width: parent.width
|
||||||
|
|
||||||
|
onPaintedWidthChanged: {
|
||||||
|
if (paintedWidth > 0 && cropRectLoader.item) {
|
||||||
|
if (!wrapper.screens.length)
|
||||||
|
wrapper.refreshScreens();
|
||||||
|
|
||||||
|
wrapper.syncCropToScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSourceChanged: {
|
||||||
|
if (cropRectLoader.item) {
|
||||||
|
if (!wrapper.screens.length)
|
||||||
|
wrapper.refreshScreens();
|
||||||
|
|
||||||
|
wrapper.syncCropToScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onStatusChanged: {
|
||||||
|
if (scaledImg.status == Image.Ready && cropRectLoader.item) {
|
||||||
|
if (!wrapper.screens.length)
|
||||||
|
wrapper.refreshScreens();
|
||||||
|
|
||||||
|
wrapper.syncCropToScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: cropRectLoader
|
||||||
|
|
||||||
|
active: scaledImg.status === Image.Ready
|
||||||
|
|
||||||
|
sourceComponent: Component {
|
||||||
|
CustomRect {
|
||||||
|
id: cropRect
|
||||||
|
|
||||||
|
property real aspectRatio: wrapper.currentScreen ? wrapper.currentScreen.width / wrapper.currentScreen.height : 1
|
||||||
|
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: 1.0
|
||||||
|
|
||||||
|
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 = Wallpapers.getCrop(wrapper.currentScreen.name);
|
||||||
|
|
||||||
|
console.log(data.x, data.y);
|
||||||
|
|
||||||
|
if (data && (Math.abs(data.x) > 0.001 || Math.abs(data.y) > 0.001 || Math.abs(data.width - 1.0) > 0.001 || Math.abs(data.height - 1.0) > 0.001)) {
|
||||||
|
zoom = data.zoom > 0 ? data.zoom : 1.0;
|
||||||
|
x = imageX + (data.x * scaledImg.paintedWidth);
|
||||||
|
y = imageY + (data.y * scaledImg.paintedHeight);
|
||||||
|
|
||||||
|
clampToBounds();
|
||||||
|
} else {
|
||||||
|
zoom = 1.0;
|
||||||
|
centerInImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
border.color: DynamicColors.palette.m3primary
|
||||||
|
border.width: 2
|
||||||
|
height: baseHeight / zoom
|
||||||
|
opacity: 1
|
||||||
|
width: baseWidth / zoom
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
restoreFromData();
|
||||||
|
}
|
||||||
|
onHeightChanged: clampToBounds()
|
||||||
|
onWidthChanged: clampToBounds()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouse
|
||||||
|
|
||||||
|
function updateCrop(mouseX, mouseY) {
|
||||||
|
if (!cropRectLoader.item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const cropRect = cropRectLoader.item;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import ZShell.Blobs
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property color blobColor: DynamicColors.tPalette.m3surfaceContainerLow
|
||||||
|
readonly property real ratio: 16.0 / 9.0
|
||||||
|
readonly property SettingsState sState: SettingsState {
|
||||||
|
id: sState
|
||||||
|
|
||||||
|
onClose: root.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
signal close
|
||||||
|
|
||||||
|
implicitHeight: sState.screen.height * 0.7
|
||||||
|
implicitWidth: implicitHeight * ratio
|
||||||
|
radius: Appearance.rounding.large + Appearance.padding.normal
|
||||||
|
|
||||||
|
Behavior on blobColor {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BlobGroup {
|
||||||
|
id: blobGroup
|
||||||
|
|
||||||
|
color: root.blobColor
|
||||||
|
smoothing: Appearance.rounding.normal
|
||||||
|
}
|
||||||
|
|
||||||
|
BlobInvertedRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
borderBottom: Appearance.padding.normal
|
||||||
|
borderLeft: navPane.width + navPane.anchors.margins * 2
|
||||||
|
borderRight: Appearance.padding.normal
|
||||||
|
borderTop: Appearance.padding.normal
|
||||||
|
group: blobGroup
|
||||||
|
opacity: root.blobColor.a
|
||||||
|
radius: Appearance.rounding.large
|
||||||
|
}
|
||||||
|
|
||||||
|
NavPane {
|
||||||
|
id: navPane
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.large
|
||||||
|
anchors.top: parent.top
|
||||||
|
sState: root.sState
|
||||||
|
width: Math.min(600, Math.round(root.width / 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
Pages {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: navPane.right
|
||||||
|
anchors.leftMargin: navPane.anchors.margins + anchors.margins
|
||||||
|
anchors.margins: Appearance.padding.extraLarge
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
sState: root.sState
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupOverlay {
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Modules.SettingsNew.NavPane
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property SettingsState sState
|
||||||
|
|
||||||
|
spacing: Appearance.spacing.large
|
||||||
|
|
||||||
|
SearchBar {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
sState: root.sState
|
||||||
|
}
|
||||||
|
|
||||||
|
NavLocations {
|
||||||
|
Layout.bottomMargin: -bottomMargin
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: -topMargin
|
||||||
|
sState: root.sState
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew
|
||||||
|
|
||||||
|
VerticalFadeFlickable {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property SettingsState sState
|
||||||
|
|
||||||
|
bottomMargin: Appearance.padding.large
|
||||||
|
contentHeight: content.implicitHeight
|
||||||
|
fadeAmount: 0.1
|
||||||
|
topMargin: Appearance.padding.large
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: content
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
spacing: Appearance.spacing.extraSmall
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: list
|
||||||
|
|
||||||
|
model: PageRegistry.pages
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: item
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
readonly property bool isCategoryEnd: index === list.model.length - 1 || PageRegistry.pages[index + 1].category !== modelData.category
|
||||||
|
readonly property bool isCategoryStart: index === 0 || PageRegistry.pages[index - 1].category !== modelData.category
|
||||||
|
readonly property bool isCurrentPage: index === root.sState.currentPageIdx
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: index !== 0 && isCategoryStart ? Appearance.spacing.small : 0
|
||||||
|
bottomLeftRadius: stateLayer.pressed ? Appearance.rounding.medium : isCurrentPage ? Appearance.rounding.large : isCategoryEnd ? Appearance.rounding.normal : Appearance.rounding.extraSmall
|
||||||
|
bottomRightRadius: stateLayer.pressed ? Appearance.rounding.medium : isCurrentPage ? Appearance.rounding.large : isCategoryEnd ? Appearance.rounding.normal : Appearance.rounding.extraSmall
|
||||||
|
color: isCurrentPage ? DynamicColors.palette.m3secondaryContainer : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
|
||||||
|
implicitHeight: {
|
||||||
|
const h = layout.implicitHeight + layout.anchors.margins * 2;
|
||||||
|
return h % 2 === 0 ? h : h + 1;
|
||||||
|
}
|
||||||
|
topLeftRadius: stateLayer.pressed ? Appearance.rounding.medium : isCurrentPage ? Appearance.rounding.large : isCategoryStart ? Appearance.rounding.normal : Appearance.rounding.extraSmall
|
||||||
|
topRightRadius: stateLayer.pressed ? Appearance.rounding.medium : isCurrentPage ? Appearance.rounding.large : isCategoryStart ? Appearance.rounding.normal : Appearance.rounding.extraSmall
|
||||||
|
|
||||||
|
RadiusBehavior on bottomLeftRadius {
|
||||||
|
}
|
||||||
|
RadiusBehavior on bottomRightRadius {
|
||||||
|
}
|
||||||
|
RadiusBehavior on topLeftRadius {
|
||||||
|
}
|
||||||
|
RadiusBehavior on topRightRadius {
|
||||||
|
}
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
id: stateLayer
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
bottomLeftRadius: parent.bottomLeftRadius
|
||||||
|
bottomRightRadius: parent.bottomRightRadius
|
||||||
|
topLeftRadius: parent.topLeftRadius
|
||||||
|
topRightRadius: parent.topRightRadius
|
||||||
|
|
||||||
|
onClicked: root.sState.currentPageIdx = item.index
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: layout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Appearance.padding.large
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
Layout.bottomMargin: -1
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.topMargin: -1
|
||||||
|
color: item.isCurrentPage ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondaryContainer
|
||||||
|
implicitWidth: height
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: 1
|
||||||
|
color: item.isCurrentPage ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSecondaryContainer
|
||||||
|
fill: item.modelData.noFill ? 0 : 1
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
grade: 25
|
||||||
|
text: item.modelData.icon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
text: item.modelData.name
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
elide: Text.ElideRight
|
||||||
|
text: item.modelData.description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component RadiusBehavior: Behavior {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Modules.SettingsNew
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property SettingsState sState
|
||||||
|
|
||||||
|
border.color: DynamicColors.palette.m3outlineVariant
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainerLowest
|
||||||
|
implicitHeight: searchLayout.implicitHeight + Appearance.padding.normal * 2
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
Behavior on border.color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.IBeamCursor
|
||||||
|
|
||||||
|
onClicked: searchField.focus = true
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: searchLayout
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.large
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
text: "search"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: searchField
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
placeholderText: qsTr("Search settings")
|
||||||
|
placeholderTextColor: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
property: "searchOpen"
|
||||||
|
target: root.sState
|
||||||
|
value: searchField.text.length > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
icon: "close"
|
||||||
|
isRound: true
|
||||||
|
opacity: searchField.text.length > 0 ? 1 : 0
|
||||||
|
padding: Appearance.padding.extraSmall
|
||||||
|
type: IconButton.Text
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: searchField.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
import qs.Modules.SettingsNew.Pages
|
||||||
|
import qs.Modules.SettingsNew.Pages.Wallpaper
|
||||||
|
import qs.Modules.SettingsNew.Pages.Audio
|
||||||
|
import qs.Modules.SettingsNew.Pages.Apps
|
||||||
|
import qs.Modules.SettingsNew.Pages.Panels
|
||||||
|
import qs.Modules.SettingsNew.Pages.Panels.Bar
|
||||||
|
import qs.Modules.SettingsNew.Pages.Services
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property list<Component> pageComps: [
|
||||||
|
// Appearance
|
||||||
|
Component {
|
||||||
|
// Wallpaper & style
|
||||||
|
StackPage {
|
||||||
|
Component {
|
||||||
|
Wallpaper {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
WallpaperSelect {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Component {
|
||||||
|
// Screenshot
|
||||||
|
StackPage {
|
||||||
|
Component {
|
||||||
|
Screenshot {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Connectivity
|
||||||
|
Component {
|
||||||
|
PlaceholderComp {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Component {
|
||||||
|
PlaceholderComp {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Component {
|
||||||
|
// Audio
|
||||||
|
StackPage {
|
||||||
|
Component {
|
||||||
|
AudioPage {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
AppVolumes {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Shell
|
||||||
|
Component {
|
||||||
|
StackPage {
|
||||||
|
Component {
|
||||||
|
PanelsPage {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
BarPanel {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
DashboardPanel {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
ResourcesPanel {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
LauncherPanel {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
SidebarPanel {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bar sub pages
|
||||||
|
Component {
|
||||||
|
BarTray {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
BarStatusIcons {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
BarClock {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Apps
|
||||||
|
Component {
|
||||||
|
StackPage {
|
||||||
|
Component {
|
||||||
|
AppsPage {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
AllApps {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
AppInfo {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Services
|
||||||
|
Component {
|
||||||
|
StackPage {
|
||||||
|
Component {
|
||||||
|
ServicesPage {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
NotificationsPage {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
readonly property Component placeholderComp: Component {
|
||||||
|
PlaceholderComp {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component PlaceholderComp: Item {
|
||||||
|
property SettingsState sState // To avoid the warning from non-existent property
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Appearance.padding.extraSmall
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: DynamicColors.palette.m3outlineVariant
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
text: "handyman"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: DynamicColors.palette.m3outlineVariant
|
||||||
|
text: qsTr("Page under construction")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: DynamicColors.palette.m3outlineVariant
|
||||||
|
text: qsTr("This page will be available in a future update.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property list<var> pages: [
|
||||||
|
// Appearance
|
||||||
|
{
|
||||||
|
name: qsTr("Appearance"),
|
||||||
|
icon: "colors",
|
||||||
|
description: qsTr("Colors, animations, font, wallpaper"),
|
||||||
|
category: "appearance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: qsTr("Screenshot"),
|
||||||
|
icon: "screenshot_region",
|
||||||
|
description: qsTr("Set screenshot effects"),
|
||||||
|
category: "appearance"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Connectivity
|
||||||
|
{
|
||||||
|
name: qsTr("Network"),
|
||||||
|
icon: "wifi",
|
||||||
|
description: qsTr("Wi-Fi, ethernet"),
|
||||||
|
category: "connectivity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: qsTr("Connected devices"),
|
||||||
|
icon: "devices_other",
|
||||||
|
description: qsTr("Bluetooth, pairing"),
|
||||||
|
category: "connectivity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: qsTr("Audio"),
|
||||||
|
icon: "volume_up",
|
||||||
|
description: qsTr("App volumes, sound devices"),
|
||||||
|
category: "connectivity"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Shell
|
||||||
|
{
|
||||||
|
name: qsTr("Panels"),
|
||||||
|
icon: "dock_to_bottom",
|
||||||
|
description: qsTr("Bar, dashboard, launcher, sidebar"),
|
||||||
|
category: "shell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: qsTr("Apps"),
|
||||||
|
icon: "apps",
|
||||||
|
description: qsTr("Default apps, favorites, hidden apps"),
|
||||||
|
category: "shell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: qsTr("Services"),
|
||||||
|
icon: "build",
|
||||||
|
description: qsTr("Poll intervals, audio and brightness increments"),
|
||||||
|
category: "shell"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int animOff
|
||||||
|
property Item currentItem
|
||||||
|
property int lastPageIdx
|
||||||
|
required property SettingsState sState
|
||||||
|
|
||||||
|
function loadPage(idx: int): void {
|
||||||
|
if (currentItem)
|
||||||
|
currentItem.destroy();
|
||||||
|
|
||||||
|
const comp = PageCompRegistry.pageComps[idx] ?? PageCompRegistry.placeholderComp;
|
||||||
|
const incubator = comp.incubateObject(container, {
|
||||||
|
sState
|
||||||
|
});
|
||||||
|
|
||||||
|
const attach = () => {
|
||||||
|
incubator.object.anchors.fill = container;
|
||||||
|
currentItem = incubator.object;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (incubator.status === Component.Ready)
|
||||||
|
attach();
|
||||||
|
else
|
||||||
|
incubator.onStatusChanged = status => {
|
||||||
|
if (status === Component.Ready)
|
||||||
|
attach();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: container
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
layer.enabled: opacity < 1
|
||||||
|
objectName: "PageContainer"
|
||||||
|
|
||||||
|
Component.onCompleted: root.loadPage(root.sState.currentPageIdx)
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onCurrentPageIdxChanged(): void {
|
||||||
|
switchAnim.complete();
|
||||||
|
root.animOff = Appearance.padding.normal * (root.sState.currentPageIdx > root.lastPageIdx ? 1 : -1);
|
||||||
|
switchAnim.start();
|
||||||
|
root.lastPageIdx = root.sState.currentPageIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
target: root.sState
|
||||||
|
}
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: switchAnim
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
target: container
|
||||||
|
to: 0
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptAction {
|
||||||
|
script: root.loadPage(root.sState.currentPageIdx)
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
property: "topMargin"
|
||||||
|
target: container.anchors
|
||||||
|
value: root.animOff
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
property: "bottomMargin"
|
||||||
|
target: container.anchors
|
||||||
|
value: -root.animOff
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
from: 0
|
||||||
|
property: "opacity"
|
||||||
|
target: container
|
||||||
|
to: 1
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
properties: "topMargin,bottomMargin"
|
||||||
|
target: container.anchors
|
||||||
|
to: 0
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("All apps")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: list
|
||||||
|
|
||||||
|
model: [...DesktopEntries.applications.values].sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
|
||||||
|
ConnectedRect {
|
||||||
|
id: appItem
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
required property DesktopEntry modelData
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
first: index === 0
|
||||||
|
implicitHeight: appRow.implicitHeight + appRow.anchors.margins * 2
|
||||||
|
last: index === list.count - 1
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
onClicked: {
|
||||||
|
root.sState.selectedApp = appItem.modelData;
|
||||||
|
root.sState.openSubPage(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: appRow
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.largeIncreased
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.rightMargin: Appearance.padding.largeIncreased
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
asynchronous: true
|
||||||
|
implicitSize: Math.round(Appearance.font.size.large * 1.8)
|
||||||
|
source: Quickshell.iconPath(appItem.modelData.icon, "image-missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: appItem.modelData.name
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: (appItem.modelData.comment || appItem.modelData.genericName) ?? ""
|
||||||
|
visible: text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
fill: 1
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: "favorite"
|
||||||
|
visible: Strings.testRegexList(Config.launcher.favoriteApps, appItem.modelData.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
text: "chevron_right"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property DesktopEntry app: sState.selectedApp
|
||||||
|
readonly property bool favoriteByRegex: app && matchedByRegex(Config.launcher.favoriteApps, app.id)
|
||||||
|
readonly property bool hiddenByRegex: app && matchedByRegex(Config.launcher.hiddenApps, app.id)
|
||||||
|
|
||||||
|
function isRegexEntry(s: string): bool {
|
||||||
|
return /^\^.*\$$/.test(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchedByRegex(filterList: list<string>, id: string): bool {
|
||||||
|
return filterList.some(f => isRegexEntry(f) && new RegExp(f).test(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("App info")
|
||||||
|
|
||||||
|
onAppChanged: {
|
||||||
|
// Auto close when app lost
|
||||||
|
if (!app)
|
||||||
|
sState.closeSubPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
// Header
|
||||||
|
RowLayout {
|
||||||
|
Layout.bottomMargin: Appearance.spacing.large
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: Appearance.padding.small
|
||||||
|
spacing: Appearance.spacing.large
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
asynchronous: true
|
||||||
|
implicitSize: Math.round(Appearance.font.size.large * 3)
|
||||||
|
source: Quickshell.iconPath(root.app?.icon, "image-missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
text: root.app?.name ?? ""
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: (root.app?.comment || root.app?.genericName) ?? ""
|
||||||
|
visible: text
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Launcher
|
||||||
|
SectionHeader {
|
||||||
|
first: true
|
||||||
|
text: qsTr("Launcher")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: root.app && Strings.testRegexList(Config.launcher.favoriteApps, root.app.id)
|
||||||
|
enabled: !root.favoriteByRegex
|
||||||
|
first: true
|
||||||
|
subtext: root.favoriteByRegex ? qsTr("Matched by a regex in favoriteApps — edit the config file to change") : qsTr("Pin to the bottom of the launcher")
|
||||||
|
text: qsTr("Favorite")
|
||||||
|
|
||||||
|
onToggled: {
|
||||||
|
const apps = Config.launcher.favoriteApps;
|
||||||
|
Config.launcher.favoriteApps = checked ? [...apps, root.app.id] : apps.filter(a => a !== root.app.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: root.app && Strings.testRegexList(Config.launcher.hiddenApps, root.app.id)
|
||||||
|
enabled: !root.hiddenByRegex
|
||||||
|
last: true
|
||||||
|
subtext: root.hiddenByRegex ? qsTr("Matched by a regex in hiddenApps — edit the config file to change") : qsTr("Hide from the launcher")
|
||||||
|
text: qsTr("Hidden")
|
||||||
|
|
||||||
|
onToggled: {
|
||||||
|
const apps = Config.launcher.hiddenApps;
|
||||||
|
Config.launcher.hiddenApps = checked ? [...apps, root.app.id] : apps.filter(a => a !== root.app.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Details
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Details")
|
||||||
|
}
|
||||||
|
|
||||||
|
WrapInfoRow {
|
||||||
|
id: appId
|
||||||
|
|
||||||
|
first: true
|
||||||
|
label: qsTr("App ID")
|
||||||
|
labelComp.Layout.preferredWidth: Math.max(labelComp.implicitWidth, command.labelComp.implicitWidth)
|
||||||
|
value: root.app?.id ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
WrapInfoRow {
|
||||||
|
id: command
|
||||||
|
|
||||||
|
label: qsTr("Command")
|
||||||
|
labelComp.Layout.preferredWidth: Math.max(labelComp.implicitWidth, appId.labelComp.implicitWidth)
|
||||||
|
last: true
|
||||||
|
value: (root.app?.command ?? []).join(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component WrapInfoRow: ConnectedRect {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
property alias label: label.text
|
||||||
|
readonly property alias labelComp: label
|
||||||
|
property alias value: value.text
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: rowLayout.implicitHeight + rowLayout.anchors.margins * 2
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: rowLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.largeIncreased
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.rightMargin: Appearance.padding.largeIncreased
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: value
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.maximumWidth: implicitWidth + 1 // Whyyyyyyyyy
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import ZShell
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
title: qsTr("Apps")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
// Default applications
|
||||||
|
SectionHeader {
|
||||||
|
first: true
|
||||||
|
text: qsTr("Default applications")
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultRow {
|
||||||
|
first: true
|
||||||
|
icon: "terminal"
|
||||||
|
status: Config.general.apps.terminal.join(" ")
|
||||||
|
text: qsTr("Terminal")
|
||||||
|
|
||||||
|
onSelected: app => Config.general.apps.terminal = app.command
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultRow {
|
||||||
|
icon: "volume_up"
|
||||||
|
status: Config.general.apps.audio.join(" ")
|
||||||
|
text: qsTr("Audio")
|
||||||
|
|
||||||
|
onSelected: app => Config.general.apps.audio = app.command
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultRow {
|
||||||
|
icon: "play_circle"
|
||||||
|
status: Config.general.apps.playback.join(" ")
|
||||||
|
text: qsTr("Media playback")
|
||||||
|
|
||||||
|
onSelected: app => Config.general.apps.playback = app.command
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultRow {
|
||||||
|
icon: "folder"
|
||||||
|
last: true
|
||||||
|
status: Config.general.apps.explorer.join(" ")
|
||||||
|
text: qsTr("File manager")
|
||||||
|
|
||||||
|
onSelected: app => Config.general.apps.explorer = app.command
|
||||||
|
}
|
||||||
|
|
||||||
|
// Library
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Library")
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
first: true
|
||||||
|
icon: "apps"
|
||||||
|
last: true
|
||||||
|
status: qsTr("Browse installed apps, set favorites and hidden")
|
||||||
|
text: qsTr("All apps")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component DefaultRow: PopupRow {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
readonly property int popupHeight: root.flickable.height - y + root.flickable.contentY - Appearance.padding.large - Appearance.padding.extraLarge
|
||||||
|
|
||||||
|
signal selected(app: DesktopEntry)
|
||||||
|
|
||||||
|
keepPopupAsChild: {
|
||||||
|
if (root.sState.animatingContainer || root.opacity < 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
let p = root.parent;
|
||||||
|
while (p && p.objectName !== "PageContainer")
|
||||||
|
p = p.parent;
|
||||||
|
return p?.opacity < 1;
|
||||||
|
}
|
||||||
|
popup.topMovement: Appearance.padding.large
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
active: row.popup.animDriver > 0
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
sourceComponent: VerticalFadeListView {
|
||||||
|
id: list
|
||||||
|
|
||||||
|
fadeAmount: 0.05
|
||||||
|
implicitHeight: ZUtils.clamp(row.popupHeight, 200, 800)
|
||||||
|
implicitWidth: 300
|
||||||
|
model: {
|
||||||
|
const apps = [...DesktopEntries.applications.values];
|
||||||
|
const favorited = new Set(apps.filter(a => Strings.testRegexList(Config.launcher.favoriteApps, a.id)));
|
||||||
|
return apps.sort((a, b) => (favorited.has(b) - favorited.has(a)) || a.name.localeCompare(b.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: StateLayer {
|
||||||
|
id: appItem
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
required property DesktopEntry modelData
|
||||||
|
|
||||||
|
anchors.fill: undefined
|
||||||
|
anchors.left: list.contentItem.left
|
||||||
|
anchors.right: list.contentItem.right
|
||||||
|
implicitHeight: itemLayout.implicitHeight + itemLayout.anchors.margins * 2
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
row.popup.open = false;
|
||||||
|
row.selected(modelData);
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: itemLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
asynchronous: true
|
||||||
|
implicitSize: Math.round(Appearance.font.size.large * 1.8)
|
||||||
|
source: Quickshell.iconPath(appItem.modelData.icon, "image-missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: appItem.modelData.name
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: (appItem.modelData.comment || appItem.modelData.genericName) ?? ""
|
||||||
|
visible: text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
fill: 1
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: "favorite"
|
||||||
|
visible: Strings.testRegexList(Config.launcher.favoriteApps, appItem.modelData.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Daemons
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("App volumes")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.bottomMargin: Appearance.spacing.small
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: Appearance.padding.small
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: qsTr("Adjust the volume of individual apps currently playing audio.")
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemList {
|
||||||
|
id: streamList
|
||||||
|
|
||||||
|
color: list.count === 0 ? DynamicColors.tPalette.m3surfaceContainer : "transparent"
|
||||||
|
first: true
|
||||||
|
last: true
|
||||||
|
list.spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
placeholderIcon: "music_off"
|
||||||
|
placeholderText: qsTr("No apps playing audio")
|
||||||
|
showList: true
|
||||||
|
|
||||||
|
delegate: SliderRow {
|
||||||
|
id: stream
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
required property PwNode modelData
|
||||||
|
|
||||||
|
anchors.left: streamList.list.contentItem.left
|
||||||
|
anchors.right: streamList.list.contentItem.right
|
||||||
|
enabled: !stream.modelData?.audio?.muted
|
||||||
|
first: index === 0
|
||||||
|
icon: Icons.getVolumeIcon(stream.modelData?.audio?.volume ?? 0, stream.modelData?.audio?.muted ?? false)
|
||||||
|
label: Audio.getStreamName(stream.modelData)
|
||||||
|
last: index === streamList.list.count - 1
|
||||||
|
value: stream.modelData?.audio?.volume ?? 0
|
||||||
|
valueLabel: Math.round(value * 100) + "%"
|
||||||
|
|
||||||
|
onMoved: v => Audio.setStreamVolume(stream.modelData, v)
|
||||||
|
}
|
||||||
|
model: ScriptModel {
|
||||||
|
values: [...Audio.streams]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Daemons
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
title: qsTr("Audio")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
// Output
|
||||||
|
SliderRow {
|
||||||
|
enabled: !Audio.muted
|
||||||
|
first: true
|
||||||
|
icon: Icons.getVolumeIcon(Audio.volume, Audio.muted)
|
||||||
|
label: qsTr("Output")
|
||||||
|
value: Audio.volume
|
||||||
|
valueLabel: Math.round(value * 100) + "%"
|
||||||
|
|
||||||
|
onMoved: v => Audio.setVolume(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Audio.muted
|
||||||
|
text: qsTr("Muted")
|
||||||
|
|
||||||
|
onToggled: Audio.setStreamMuted(Audio.sink, checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioDeviceList {
|
||||||
|
currentId: Audio.sink?.id ?? -1
|
||||||
|
iconName: "speaker"
|
||||||
|
nodes: Audio.sinks
|
||||||
|
placeholderIcon: "speaker"
|
||||||
|
placeholderText: qsTr("No output devices")
|
||||||
|
|
||||||
|
onSelected: node => Audio.setAudioSink(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input
|
||||||
|
SliderRow {
|
||||||
|
Layout.topMargin: Appearance.spacing.large - parent.spacing
|
||||||
|
enabled: !Audio.sourceMuted
|
||||||
|
first: true
|
||||||
|
icon: Icons.getMicVolumeIcon(Audio.sourceVolume, Audio.sourceMuted)
|
||||||
|
label: qsTr("Input")
|
||||||
|
value: Audio.sourceVolume
|
||||||
|
valueLabel: Math.round(value * 100) + "%"
|
||||||
|
|
||||||
|
onMoved: v => Audio.setSourceVolume(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Audio.sourceMuted
|
||||||
|
text: qsTr("Muted")
|
||||||
|
|
||||||
|
onToggled: Audio.setStreamMuted(Audio.source, checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioDeviceList {
|
||||||
|
currentId: Audio.source?.id ?? -1
|
||||||
|
iconName: "mic"
|
||||||
|
nodes: Audio.sources
|
||||||
|
placeholderIcon: "mic_off"
|
||||||
|
placeholderText: qsTr("No input devices")
|
||||||
|
|
||||||
|
onSelected: node => Audio.setAudioSource(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per-app volumes
|
||||||
|
ConnectedRect {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: Appearance.spacing.large - parent.spacing
|
||||||
|
first: true
|
||||||
|
implicitHeight: appLayout.implicitHeight + appLayout.anchors.margins * 2
|
||||||
|
last: true
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
onClicked: root.sState.openSubPage(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: appLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.largeIncreased
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
anchors.rightMargin: Appearance.padding.largeIncreased
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
text: "tune"
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: qsTr("App volumes")
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
animate: true
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
text: Audio.streams.length === 0 ? qsTr("No apps playing audio") : Audio.streams.length === 1 ? qsTr("1 app playing audio") : qsTr("%1 apps playing audio").arg(Audio.streams.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.medium
|
||||||
|
text: "chevron_right"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property list<MenuItem> clockFormats: [
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Long format")
|
||||||
|
value: "dddd d MMM - hh:mm"
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Short format")
|
||||||
|
value: "ddd d MMM - hh:mm"
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Time only")
|
||||||
|
value: "hh:mm"
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Long format seconds")
|
||||||
|
value: "dddd d MMM - hh:mm:ss"
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Short format seconds")
|
||||||
|
value: "ddd d MMM - hh:mm:ss"
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Time only seconds")
|
||||||
|
value: "hh:mm:ss"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("Clock")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
SelectRow {
|
||||||
|
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
active: root.clockFormats.find(item => item.value === Config.general.dateFormat)
|
||||||
|
first: true
|
||||||
|
last: true
|
||||||
|
menuItems: root.clockFormats
|
||||||
|
subtext: qsTr("Change how time is displayed in the widget")
|
||||||
|
text: qsTr("Time format")
|
||||||
|
|
||||||
|
onSelected: item => {
|
||||||
|
Config.general.dateFormat = item.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("System icons")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
// Visible icons
|
||||||
|
SectionHeader {
|
||||||
|
first: true
|
||||||
|
text: qsTr("Visible icons")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.bar.tray.showAudio
|
||||||
|
first: true
|
||||||
|
text: qsTr("Speakers")
|
||||||
|
|
||||||
|
onToggled: Config.bar.tray.showAudio = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.bar.tray.showMicrophone
|
||||||
|
text: qsTr("Microphone")
|
||||||
|
|
||||||
|
onToggled: Config.bar.tray.showMicrophone = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
//////// FOR LATER:
|
||||||
|
// ToggleRow {
|
||||||
|
// checked: Config.bar.tray.showNetwork
|
||||||
|
// text: qsTr("Network")
|
||||||
|
//
|
||||||
|
// onToggled: Config.bar.tray.showNetwork = checked
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ToggleRow {
|
||||||
|
// checked: Config.bar.tray.showWifi
|
||||||
|
// text: qsTr("Wi-Fi")
|
||||||
|
//
|
||||||
|
// onToggled: Config.bar.tray.showWifi = checked
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ToggleRow {
|
||||||
|
// checked: Config.bar.tray.showBluetooth
|
||||||
|
// text: qsTr("Bluetooth")
|
||||||
|
//
|
||||||
|
// onToggled: Config.bar.tray.showBluetooth = checked
|
||||||
|
// }
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.bar.tray.showPower
|
||||||
|
last: true
|
||||||
|
text: qsTr("Battery")
|
||||||
|
|
||||||
|
onToggled: Config.bar.tray.showPower = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
// Behaviour
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Behavior")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.bar.popouts.audio
|
||||||
|
first: true
|
||||||
|
subtext: qsTr("Show a details popout when hovering the audio icons")
|
||||||
|
text: qsTr("Audio popout on hover")
|
||||||
|
|
||||||
|
onToggled: Config.bar.popouts.audio = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.bar.popouts.upower
|
||||||
|
last: true
|
||||||
|
subtext: qsTr("Show a details popout when hovering the power icon")
|
||||||
|
text: qsTr("Power popout on hover")
|
||||||
|
|
||||||
|
onToggled: Config.bar.popouts.upower = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("Tray")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
first: true
|
||||||
|
from: 12
|
||||||
|
last: true
|
||||||
|
stepSize: 1
|
||||||
|
text: qsTr("Icon size")
|
||||||
|
to: 24
|
||||||
|
value: Config.bar.tray.trayIconSize
|
||||||
|
|
||||||
|
onMoved: value => Config.bar.tray.trayIconSize = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("Taskbar")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
// Behavior
|
||||||
|
SectionHeader {
|
||||||
|
first: true
|
||||||
|
text: qsTr("Behavior")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.bar.autoHide
|
||||||
|
first: true
|
||||||
|
last: true
|
||||||
|
subtext: qsTr("Hide the bar, reveal on hover")
|
||||||
|
text: qsTr("Auto hide")
|
||||||
|
|
||||||
|
onToggled: Config.bar.autoHide = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
// Components
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Components")
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
first: true
|
||||||
|
icon: "widgets"
|
||||||
|
status: qsTr("System tray icons")
|
||||||
|
text: qsTr("Tray")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(6)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
icon: "signal_cellular_alt"
|
||||||
|
status: qsTr("Visible indicators")
|
||||||
|
text: qsTr("Status icons")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(7)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
icon: "schedule"
|
||||||
|
last: true
|
||||||
|
status: qsTr("Date, icon, background")
|
||||||
|
text: qsTr("Clock")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("Dashboard")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
// General
|
||||||
|
SectionHeader {
|
||||||
|
first: true
|
||||||
|
text: qsTr("General")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.dashboard.enabled
|
||||||
|
first: true
|
||||||
|
last: true
|
||||||
|
text: qsTr("Enabled")
|
||||||
|
|
||||||
|
onToggled: Config.dashboard.enabled = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("Launcher")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
// General
|
||||||
|
SectionHeader {
|
||||||
|
first: true
|
||||||
|
text: qsTr("General")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.launcher.enabled
|
||||||
|
first: true
|
||||||
|
last: true
|
||||||
|
text: qsTr("Enabled")
|
||||||
|
|
||||||
|
onToggled: Config.launcher.enabled = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Display")
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
first: true
|
||||||
|
from: 1
|
||||||
|
stepSize: 1
|
||||||
|
text: qsTr("Max items shown")
|
||||||
|
to: 20
|
||||||
|
value: Config.launcher.maxAppsShown
|
||||||
|
|
||||||
|
onMoved: v => Config.launcher.maxShown = v
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
from: 1
|
||||||
|
stepSize: 1
|
||||||
|
text: qsTr("Max wallpapers")
|
||||||
|
to: 30
|
||||||
|
value: Config.launcher.maxWallpapers
|
||||||
|
|
||||||
|
onMoved: v => Config.launcher.maxWallpapers = v
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
from: 0
|
||||||
|
last: true
|
||||||
|
stepSize: 5
|
||||||
|
subtext: qsTr("Pixels dragged before the launcher opens")
|
||||||
|
text: qsTr("Drag threshold")
|
||||||
|
to: 200
|
||||||
|
value: Config.launcher.dragThreshold
|
||||||
|
|
||||||
|
onMoved: v => Config.launcher.dragThreshold = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Behavior
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Behavior")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.launcher.enableDangerousActions
|
||||||
|
first: true
|
||||||
|
last: true
|
||||||
|
subtext: qsTr("Allow actions that shut down or log out")
|
||||||
|
text: qsTr("Enable dangerous actions")
|
||||||
|
|
||||||
|
onToggled: Config.launcher.enableDangerousActions = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fuzzy search
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Fuzzy search")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.launcher.useFuzzy.apps
|
||||||
|
first: true
|
||||||
|
text: qsTr("Apps")
|
||||||
|
|
||||||
|
onToggled: Config.launcher.useFuzzy.apps = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.launcher.useFuzzy.actions
|
||||||
|
text: qsTr("Actions")
|
||||||
|
|
||||||
|
onToggled: Config.launcher.useFuzzy.actions = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.launcher.useFuzzy.schemes
|
||||||
|
text: qsTr("Schemes")
|
||||||
|
|
||||||
|
onToggled: Config.launcher.useFuzzy.schemes = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.launcher.useFuzzy.variants
|
||||||
|
text: qsTr("Variants")
|
||||||
|
|
||||||
|
onToggled: Config.launcher.useFuzzy.variants = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.launcher.useFuzzy.wallpapers
|
||||||
|
last: true
|
||||||
|
text: qsTr("Wallpapers")
|
||||||
|
|
||||||
|
onToggled: Config.launcher.useFuzzy.wallpapers = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("Resources")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
// General
|
||||||
|
SectionHeader {
|
||||||
|
first: true
|
||||||
|
text: qsTr("General")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.dashboard.performance.enabled
|
||||||
|
first: true
|
||||||
|
last: true
|
||||||
|
text: qsTr("Enabled")
|
||||||
|
|
||||||
|
onToggled: Config.dashboard.performance.enabled = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performance widgets
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Performance widgets")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.dashboard.performance.showBattery
|
||||||
|
first: true
|
||||||
|
text: qsTr("Battery")
|
||||||
|
|
||||||
|
onToggled: Config.dashboard.performance.showBattery = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.dashboard.performance.showGpu
|
||||||
|
text: qsTr("GPU")
|
||||||
|
|
||||||
|
onToggled: Config.dashboard.performance.showGpu = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.dashboard.performance.showCpu
|
||||||
|
text: qsTr("CPU")
|
||||||
|
|
||||||
|
onToggled: Config.dashboard.performance.showCpu = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.dashboard.performance.showMemory
|
||||||
|
text: qsTr("Memory")
|
||||||
|
|
||||||
|
onToggled: Config.dashboard.performance.showMemory = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.dashboard.performance.showStorage
|
||||||
|
text: qsTr("Storage")
|
||||||
|
|
||||||
|
onToggled: Config.dashboard.performance.showStorage = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.dashboard.performance.showNetwork
|
||||||
|
last: true
|
||||||
|
text: qsTr("Network")
|
||||||
|
|
||||||
|
onToggled: Config.dashboard.performance.showNetwork = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("Sidebar")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
SectionHeader {
|
||||||
|
first: true
|
||||||
|
text: qsTr("General")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.sidebar.enabled
|
||||||
|
first: true
|
||||||
|
text: qsTr("Enabled")
|
||||||
|
|
||||||
|
onToggled: Config.sidebar.enabled = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
from: 0
|
||||||
|
last: true
|
||||||
|
stepSize: 5
|
||||||
|
subtext: qsTr("Pixels dragged before the sidebar opens")
|
||||||
|
text: qsTr("Drag threshold")
|
||||||
|
to: 200
|
||||||
|
value: Config.sidebar.dragThreshold
|
||||||
|
|
||||||
|
onMoved: v => Config.sidebar.dragThreshold = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
title: qsTr("Panels")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
first: true
|
||||||
|
icon: "dock_to_bottom"
|
||||||
|
status: !Config.bar.autoHide ? qsTr("Always visible") : qsTr("Reveal on hover")
|
||||||
|
text: qsTr("Bar")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
icon: "dashboard"
|
||||||
|
status: Config.dashboard.enabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||||
|
text: qsTr("Dashboard")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
icon: "insert_chart"
|
||||||
|
status: Config.dashboard.performance.enabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||||
|
text: qsTr("Resources")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
icon: "apps"
|
||||||
|
status: Config.launcher.enabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||||
|
text: qsTr("Launcher")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
icon: "dock_to_right"
|
||||||
|
last: true
|
||||||
|
status: Config.sidebar.enabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||||
|
text: qsTr("Sidebar")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import ZShell.Components
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
title: qsTr("Screenshot effects")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.large
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.screenshot.enable_pp
|
||||||
|
first: true
|
||||||
|
text: qsTr("Enable effects")
|
||||||
|
|
||||||
|
onToggled: Config.screenshot.enable_pp = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectRow {
|
||||||
|
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
active: Config.screenshot.mode === "manual" ? menuItems[0] : menuItems[1]
|
||||||
|
enabled: Config.screenshot.enable_pp
|
||||||
|
last: true
|
||||||
|
subtext: qsTr("Automatic or manual effect values")
|
||||||
|
text: 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.screenshot.rounding
|
||||||
|
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual"
|
||||||
|
first: true
|
||||||
|
text: qsTr("Enable rounded corners")
|
||||||
|
|
||||||
|
onToggled: Config.screenshot.rounding = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual" && Config.screenshot.rounding
|
||||||
|
from: 0
|
||||||
|
last: true
|
||||||
|
stepSize: 1
|
||||||
|
text: qsTr("Corner radius")
|
||||||
|
to: 50
|
||||||
|
value: Config.screenshot.radius
|
||||||
|
|
||||||
|
onMoved: value => {
|
||||||
|
const newVal = Math.floor(value);
|
||||||
|
Config.screenshot.radius = newVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.screenshot.shadow
|
||||||
|
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual"
|
||||||
|
first: true
|
||||||
|
text: qsTr("Enable shadow")
|
||||||
|
|
||||||
|
onToggled: Config.screenshot.shadow = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual" && Config.screenshot.shadow
|
||||||
|
from: 0
|
||||||
|
stepSize: 1
|
||||||
|
text: qsTr("Shadow blur amount")
|
||||||
|
to: 100
|
||||||
|
value: Config.screenshot.shadow_blur
|
||||||
|
|
||||||
|
onMoved: value => {
|
||||||
|
const newVal = Math.floor(value);
|
||||||
|
Config.screenshot.shadow_blur = newVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual" && Config.screenshot.shadow
|
||||||
|
from: -100
|
||||||
|
stepSize: 10
|
||||||
|
text: qsTr("Shadow horizontal offset")
|
||||||
|
to: 100
|
||||||
|
value: Config.screenshot.shadow_offset_x
|
||||||
|
|
||||||
|
onMoved: value => {
|
||||||
|
const newVal = Math.floor(value);
|
||||||
|
Config.screenshot.shadow_offset_x = newVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual" && Config.screenshot.shadow
|
||||||
|
from: -100
|
||||||
|
last: true
|
||||||
|
stepSize: 10
|
||||||
|
text: qsTr("Shadow vertical offset")
|
||||||
|
to: 100
|
||||||
|
value: Config.screenshot.shadow_offset_y
|
||||||
|
|
||||||
|
onMoved: value => {
|
||||||
|
const newVal = Math.floor(value);
|
||||||
|
Config.screenshot.shadow_offset_y = newVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("Notifications")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
// Notifications
|
||||||
|
SectionHeader {
|
||||||
|
first: true
|
||||||
|
text: qsTr("Notifications")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.notifs.showInFullscreen
|
||||||
|
first: true
|
||||||
|
subtext: qsTr("Whether notifications appear over fullscreen apps")
|
||||||
|
text: qsTr("Show in fullscreen")
|
||||||
|
|
||||||
|
onToggled: Config.notifs.showInFullscreen = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.notifs.expire
|
||||||
|
subtext: qsTr("Dismiss notifications after their timeout")
|
||||||
|
text: qsTr("Expire automatically")
|
||||||
|
|
||||||
|
onToggled: Config.notifs.expire = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.notifs.openExpanded
|
||||||
|
subtext: qsTr("Show notifications expanded by default")
|
||||||
|
text: qsTr("Open expanded")
|
||||||
|
|
||||||
|
onToggled: Config.notifs.openExpanded = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
from: 1000
|
||||||
|
stepSize: 500
|
||||||
|
subtext: qsTr("Time before a notification dismisses (ms)")
|
||||||
|
text: qsTr("Default timeout")
|
||||||
|
to: 60000
|
||||||
|
value: Config.notifs.defaultExpireTimeout
|
||||||
|
|
||||||
|
onMoved: v => Config.notifs.defaultExpireTimeout = Math.round(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
from: 1
|
||||||
|
last: true
|
||||||
|
stepSize: 1
|
||||||
|
subtext: qsTr("Notifications shown per group before collapsing")
|
||||||
|
text: qsTr("Group preview count")
|
||||||
|
to: 10
|
||||||
|
value: Config.notifs.groupPreviewNum
|
||||||
|
|
||||||
|
onMoved: v => Config.notifs.groupPreviewNum = Math.round(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toasts
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Toasts")
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
first: true
|
||||||
|
from: 1
|
||||||
|
stepSize: 1
|
||||||
|
subtext: qsTr("Maximum number of toasts shown at once")
|
||||||
|
text: qsTr("Visible toasts")
|
||||||
|
to: 10
|
||||||
|
value: Config.utilities.maxToasts
|
||||||
|
|
||||||
|
onMoved: v => Config.utilities.maxToasts = Math.round(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.utilities.toasts.chargingChanged
|
||||||
|
text: qsTr("Charging changes")
|
||||||
|
|
||||||
|
onToggled: Config.utilities.toasts.chargingChanged = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.utilities.toasts.gameModeChanged
|
||||||
|
text: qsTr("Game mode changes")
|
||||||
|
|
||||||
|
onToggled: Config.utilities.toasts.gameModeChanged = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToggleRow {
|
||||||
|
// checked: Config.utilities.toasts.dndChanged
|
||||||
|
// text: qsTr("Do not disturb changes")
|
||||||
|
//
|
||||||
|
// onToggled: Config.utilities.toasts.dndChanged = checked
|
||||||
|
// }
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.utilities.toasts.audioOutputChanged
|
||||||
|
text: qsTr("Audio output changes")
|
||||||
|
|
||||||
|
onToggled: Config.utilities.toasts.audioOutputChanged = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.utilities.toasts.audioInputChanged
|
||||||
|
last: true
|
||||||
|
text: qsTr("Audio input changes")
|
||||||
|
|
||||||
|
onToggled: Config.utilities.toasts.audioInputChanged = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToggleRow {
|
||||||
|
// checked: Config.utilities.toasts.capsLockChanged
|
||||||
|
// text: qsTr("Caps lock changes")
|
||||||
|
//
|
||||||
|
// onToggled: Config.utilities.toasts.capsLockChanged = checked
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ToggleRow {
|
||||||
|
// checked: Config.utilities.toasts.numLockChanged
|
||||||
|
// text: qsTr("Num lock changes")
|
||||||
|
//
|
||||||
|
// onToggled: Config.utilities.toasts.numLockChanged = checked
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ToggleRow {
|
||||||
|
// checked: Config.utilities.toasts.kbLayoutChanged
|
||||||
|
// text: qsTr("Keyboard layout changes")
|
||||||
|
//
|
||||||
|
// onToggled: Config.utilities.toasts.kbLayoutChanged = checked
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ToggleRow {
|
||||||
|
// checked: Config.utilities.toasts.vpnChanged
|
||||||
|
// text: qsTr("VPN changes")
|
||||||
|
//
|
||||||
|
// onToggled: Config.utilities.toasts.vpnChanged = checked
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ToggleRow {
|
||||||
|
// checked: Config.utilities.toasts.nowPlaying
|
||||||
|
// last: true
|
||||||
|
// text: qsTr("Now playing")
|
||||||
|
//
|
||||||
|
// onToggled: Config.utilities.toasts.nowPlaying = checked
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import ZShell.Services
|
||||||
|
import qs.Components
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// GPU options + the config string each maps to (see Gpu::parseType)
|
||||||
|
readonly property list<MenuItem> gpuItems: [
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Auto")
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
text: "NVIDIA"
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Generic")
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("None")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
readonly property list<string> gpuValues: ["", "NVIDIA", "GENERIC", "None"]
|
||||||
|
|
||||||
|
function gpuKeyToIndex(key: string): int {
|
||||||
|
const u = (key ?? "").trim().toUpperCase();
|
||||||
|
if (u === "")
|
||||||
|
return 0; // Auto
|
||||||
|
if (u === "NVIDIA")
|
||||||
|
return 1;
|
||||||
|
if (u === "GENERIC")
|
||||||
|
return 2;
|
||||||
|
return 3; // None
|
||||||
|
}
|
||||||
|
|
||||||
|
title: qsTr("Services")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
// Detected running players, used as default-player options
|
||||||
|
Variants {
|
||||||
|
id: playerVariants
|
||||||
|
|
||||||
|
model: [...new Set(Players.list.map(p => Players.getIdentity(p)).filter(id => id))]
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
required property string modelData
|
||||||
|
|
||||||
|
activeIcon: "music_note"
|
||||||
|
icon: modelData === Config.services.defaultPlayer ? "check" : ""
|
||||||
|
text: modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notifications
|
||||||
|
SectionHeader {
|
||||||
|
first: true
|
||||||
|
text: qsTr("Notifications")
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
first: true
|
||||||
|
icon: "notifications"
|
||||||
|
last: true
|
||||||
|
status: qsTr("Notifications, toasts, timeouts")
|
||||||
|
text: qsTr("Notifications")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polling
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Polling")
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
first: true
|
||||||
|
from: 100
|
||||||
|
stepSize: 50
|
||||||
|
subtext: qsTr("How often the media position updates (ms)")
|
||||||
|
text: qsTr("Media refresh")
|
||||||
|
to: 2000
|
||||||
|
value: Config.dashboard.mediaUpdateInterval
|
||||||
|
|
||||||
|
onMoved: v => Config.dashboard.mediaUpdateInterval = v
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
from: 0.5
|
||||||
|
last: true
|
||||||
|
stepSize: 0.5
|
||||||
|
subtext: qsTr("CPU, memory and GPU update interval (seconds)")
|
||||||
|
text: qsTr("System stats refresh")
|
||||||
|
to: 10
|
||||||
|
value: Config.dashboard.resourceUpdateInterval / 1000
|
||||||
|
|
||||||
|
onMoved: v => Config.dashboard.resourceUpdateInterval = Math.round(v * 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Media & lyrics
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Media")
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectRow {
|
||||||
|
active: menuItems.find(i => i.text === Config.services.defaultPlayer) ?? null
|
||||||
|
fallbackIcon: "music_note"
|
||||||
|
fallbackText: Config.services.defaultPlayer || qsTr("Auto")
|
||||||
|
first: true
|
||||||
|
last: true
|
||||||
|
menuItems: playerVariants.instances
|
||||||
|
subtext: qsTr("Preferred media player when several are open")
|
||||||
|
text: qsTr("Default player")
|
||||||
|
|
||||||
|
onSelected: item => Config.services.defaultPlayer = item.text
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input increments
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Input increments")
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
first: true
|
||||||
|
from: 1
|
||||||
|
stepSize: 1
|
||||||
|
subtext: qsTr("Amount the volume changes per input (%)")
|
||||||
|
text: qsTr("Volume step")
|
||||||
|
to: 50
|
||||||
|
value: Math.round(Config.services.audioIncrement * 100)
|
||||||
|
|
||||||
|
onMoved: v => Config.services.audioIncrement = v / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
from: 1
|
||||||
|
stepSize: 1
|
||||||
|
subtext: qsTr("Amount the brightness changes per input (%)")
|
||||||
|
text: qsTr("Brightness step")
|
||||||
|
to: 50
|
||||||
|
value: Math.round(Config.services.brightnessIncrement * 100)
|
||||||
|
|
||||||
|
onMoved: v => Config.services.brightnessIncrement = v / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
from: 1
|
||||||
|
stepSize: 1
|
||||||
|
subtext: qsTr("Lowest allowed brightness (%)")
|
||||||
|
text: qsTr("Brightness minimum")
|
||||||
|
to: 20
|
||||||
|
value: Math.round(Config.services.minBrightness * 100)
|
||||||
|
|
||||||
|
onMoved: v => Config.services.minBrightness = v / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
from: 50
|
||||||
|
last: true
|
||||||
|
stepSize: 5
|
||||||
|
subtext: qsTr("Upper limit for output volume (%)")
|
||||||
|
text: qsTr("Max volume")
|
||||||
|
to: 200
|
||||||
|
value: Math.round(Config.services.maxVolume * 100)
|
||||||
|
|
||||||
|
onMoved: v => Config.services.maxVolume = v / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service tuning
|
||||||
|
SectionHeader {
|
||||||
|
text: qsTr("Service tuning")
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
first: true
|
||||||
|
from: 10
|
||||||
|
stepSize: 2
|
||||||
|
subtext: qsTr("Resolution of the audio visualizer")
|
||||||
|
text: qsTr("Visualizer resolution")
|
||||||
|
to: 120
|
||||||
|
value: Config.services.visualizerBars
|
||||||
|
|
||||||
|
onMoved: v => Config.services.visualiserBars = v
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.general.color.smart
|
||||||
|
subtext: qsTr("Derive theme mode from the wallpaper")
|
||||||
|
text: qsTr("Smart color scheme")
|
||||||
|
|
||||||
|
onToggled: Config.general.color.smart = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectRow {
|
||||||
|
active: root.gpuItems[root.gpuKeyToIndex(Config.services.gpuType)]
|
||||||
|
last: true
|
||||||
|
menuItems: root.gpuItems
|
||||||
|
menuOnTop: true
|
||||||
|
subtext: Gpu.name ? qsTr("Monitoring: %1").arg(Gpu.name) : qsTr("Override for GPU type")
|
||||||
|
text: qsTr("GPU")
|
||||||
|
|
||||||
|
onSelected: item => Config.services.gpuType = root.gpuValues[root.gpuItems.indexOf(item)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import ZShell.Components
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
title: qsTr("Wallpaper & style")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.large
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: wallWrapper
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
implicitHeight: cropper.height
|
||||||
|
implicitWidth: root.cappedWidth
|
||||||
|
|
||||||
|
WallpaperCropper {
|
||||||
|
id: cropper
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconTextButton {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
enabled: Config.background.enabled
|
||||||
|
horizontalPadding: Appearance.padding.extraLarge
|
||||||
|
icon: "wallpaper"
|
||||||
|
isRound: true
|
||||||
|
shapeMorph: true
|
||||||
|
text: qsTr("Wallpapers")
|
||||||
|
type: IconTextButton.Tonal
|
||||||
|
verticalPadding: Appearance.padding.normal
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(1) // Wallpaper page
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.background.enabled
|
||||||
|
first: true
|
||||||
|
text: qsTr("Display wallpaper")
|
||||||
|
|
||||||
|
onToggled: Config.background.enabled = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
checked: DynamicColors.transparency.enabled
|
||||||
|
subtext: qsTr("Base %1, layers %2").arg(DynamicColors.transparency.base).arg(DynamicColors.transparency.layers)
|
||||||
|
text: qsTr("Transparency")
|
||||||
|
|
||||||
|
onToggled: Config.appearance.transparency.enabled = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
checked: !DynamicColors.light
|
||||||
|
last: true
|
||||||
|
text: qsTr("Dark theme")
|
||||||
|
|
||||||
|
onToggled: DynamicColors.setMode(checked ? "dark" : "light")
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayRow {
|
||||||
|
id: darkMode
|
||||||
|
|
||||||
|
readonly property string endTime: {
|
||||||
|
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
||||||
|
d.setMinutes(Config.general.color.scheduleDarkEnd);
|
||||||
|
return Qt.formatTime(d, "hh:mm AP");
|
||||||
|
}
|
||||||
|
readonly property string startTime: {
|
||||||
|
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
||||||
|
d.setMinutes(Config.general.color.scheduleDarkStart);
|
||||||
|
return Qt.formatTime(d, "hh:mm AP");
|
||||||
|
}
|
||||||
|
|
||||||
|
checked: Config.general.color.scheduleDark
|
||||||
|
first: true
|
||||||
|
subtext: qsTr("Dark mode will turn on at %1, and turn off at %2.").arg(startTime).arg(endTime)
|
||||||
|
text: qsTr("Schedule dark mode")
|
||||||
|
|
||||||
|
popup: Component {
|
||||||
|
TimeInput {
|
||||||
|
object: Config.general.color
|
||||||
|
settings: ["scheduleDark", "scheduleDarkStart", "scheduleDarkEnd"]
|
||||||
|
|
||||||
|
onApplySettings: (start, end) => {
|
||||||
|
Config.general.color.scheduleDarkStart = start;
|
||||||
|
Config.general.color.scheduleDarkEnd = end;
|
||||||
|
Config.save();
|
||||||
|
ModeScheduler.checkStartup();
|
||||||
|
PopupManager.requestClose();
|
||||||
|
}
|
||||||
|
onClose: PopupManager.requestClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: value => {
|
||||||
|
Config.general.color.scheduleDark = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayRow {
|
||||||
|
id: hyprsunset
|
||||||
|
|
||||||
|
readonly property string endTime: {
|
||||||
|
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
||||||
|
d.setMinutes(Config.general.color.scheduleHyprsunsetEnd);
|
||||||
|
return Qt.formatTime(d, "hh:mm AP");
|
||||||
|
}
|
||||||
|
readonly property string startTime: {
|
||||||
|
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
||||||
|
d.setMinutes(Config.general.color.scheduleHyprsunsetStart);
|
||||||
|
return Qt.formatTime(d, "hh:mm AP");
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
checked: Config.general.color.scheduleHyprsunset
|
||||||
|
last: true
|
||||||
|
subtext: qsTr("Hyprsunset will turn on at %1, and turn off at %2.").arg(startTime).arg(endTime)
|
||||||
|
text: qsTr("Schedule hyprsunset")
|
||||||
|
|
||||||
|
popup: Component {
|
||||||
|
TimeInput {
|
||||||
|
object: Config.general.color
|
||||||
|
settings: ["scheduleHyprsunset", "scheduleHyprsunsetStart", "scheduleHyprsunsetEnd"]
|
||||||
|
|
||||||
|
onApplySettings: (start, end) => {
|
||||||
|
Config.general.color.scheduleHyprsunsetStart = start;
|
||||||
|
Config.general.color.scheduleHyprsunsetEnd = end;
|
||||||
|
Config.save();
|
||||||
|
Hyprsunset.checkStartup();
|
||||||
|
PopupManager.requestClose();
|
||||||
|
}
|
||||||
|
onClose: PopupManager.requestClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: value => {
|
||||||
|
Config.general.color.scheduleHyprsunset = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import ZShell.Models
|
||||||
|
import qs.Paths
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SettingsNew.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: qsTr("Wallpapers")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.topMargin: Appearance.spacing.large
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: qsTr("Wallpapers")
|
||||||
|
}
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
columnSpacing: Appearance.spacing.extraSmall
|
||||||
|
columns: 4
|
||||||
|
rowSpacing: Appearance.spacing.extraSmall
|
||||||
|
visible: localWalls.count > 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: localWalls
|
||||||
|
|
||||||
|
model: {
|
||||||
|
const walls = Wallpapers.list;
|
||||||
|
var baseDir = Paths.wallsdir;
|
||||||
|
const categories = {};
|
||||||
|
const list = [];
|
||||||
|
for (const w of walls) {
|
||||||
|
var parentDir = w.parentDir;
|
||||||
|
if (!parentDir.endsWith("/"))
|
||||||
|
parentDir = parentDir + "/";
|
||||||
|
|
||||||
|
if (!baseDir.endsWith("/"))
|
||||||
|
baseDir = baseDir + "/";
|
||||||
|
|
||||||
|
if (parentDir !== baseDir) {
|
||||||
|
const category = Wallpapers.getCategoryFor(w);
|
||||||
|
if (category && (!(category in categories) || categories[category].name.localeCompare(w.name) > 0))
|
||||||
|
categories[category] = w;
|
||||||
|
} else {
|
||||||
|
list.push(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.push(...Object.values(categories));
|
||||||
|
list.sort((a, b) => ((a.parentDir === baseDir) - (b.parentDir === baseDir)) || a.name.localeCompare(b.name));
|
||||||
|
while (list.length < 4)
|
||||||
|
list.push(null);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
WallItem {
|
||||||
|
required property FileSystemEntry modelData
|
||||||
|
|
||||||
|
enabled: modelData
|
||||||
|
|
||||||
|
// Empty placeholders for sizing
|
||||||
|
opacity: modelData ? 1 : 0
|
||||||
|
source: String(modelData?.path ?? "")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
Wallpapers.setWallpaper(modelData.path);
|
||||||
|
root.sState.closeSubPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
active: localWalls.count === 0
|
||||||
|
asynchronous: true
|
||||||
|
visible: active
|
||||||
|
|
||||||
|
sourceComponent: CustomRect {
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: noWallsLayout.implicitHeight + Appearance.padding.extraLarge * 3
|
||||||
|
radius: Appearance.rounding.large
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: noWallsLayout
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Appearance.spacing.extraSmall
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
text: "hide_image"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: DynamicColors.palette.m3outline
|
||||||
|
text: qsTr("No local wallpapers found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool closed: true
|
||||||
|
property Component currentPopup: null
|
||||||
|
|
||||||
|
function requestClose(): void {
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestOpen(component: Component): void {
|
||||||
|
currentPopup = component;
|
||||||
|
closed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property bool closing: PopupManager.closed
|
||||||
|
readonly property var currentPopup: PopupManager.currentPopup
|
||||||
|
property bool shouldBeVisible: loader.status === Loader.Ready
|
||||||
|
|
||||||
|
color: Qt.alpha(DynamicColors.palette.m3shadow, 0.3)
|
||||||
|
opacity: shouldBeVisible && !closing ? 1 : 0
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onVisibleChanged: if (!visible)
|
||||||
|
PopupManager.currentPopup = null
|
||||||
|
|
||||||
|
CustomMouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
preventStealing: true
|
||||||
|
propagateComposedEvents: false
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
const insideItemWidth = mouseX < loader.x + loader.item.width && mouseX > loader.x;
|
||||||
|
const insideItemHeight = mouseY < loader.y + loader.item.height && mouseY > loader.y;
|
||||||
|
if (insideItemHeight && insideItemWidth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PopupManager.requestClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: loader
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
sourceComponent: root.currentPopup
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Bluetooth
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool animatingContainer
|
||||||
|
property int currentPageIdx
|
||||||
|
property bool isWindow
|
||||||
|
property ShellScreen screen
|
||||||
|
property bool searchOpen
|
||||||
|
property DesktopEntry selectedApp
|
||||||
|
property BluetoothDevice selectedBtDevice
|
||||||
|
property string selectedWallpaperCategory
|
||||||
|
property list<int> subPageIdxStack
|
||||||
|
|
||||||
|
signal close
|
||||||
|
signal subPageClosed
|
||||||
|
signal subPageOpened(idx: int)
|
||||||
|
|
||||||
|
function closeSubPage(): void {
|
||||||
|
subPageClosed();
|
||||||
|
subPageIdxStack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSubPage(idx: int): void {
|
||||||
|
subPageIdxStack.push(idx);
|
||||||
|
subPageOpened(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentPageIdxChanged: subPageIdxStack.length = 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
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
|
||||||
|
|
||||||
|
implicitHeight: content.implicitHeight
|
||||||
|
implicitWidth: content.implicitWidth
|
||||||
|
opacity: 1 - offsetScale
|
||||||
|
visible: offsetScale < 1
|
||||||
|
|
||||||
|
Behavior on offsetScale {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: content
|
||||||
|
|
||||||
|
active: root.shouldBeActive || root.visible
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
sourceComponent: Content {
|
||||||
|
sState.animatingContainer: content.opacity < 1
|
||||||
|
sState.currentPageIdx: ["wallpaper"][0]
|
||||||
|
sState.screen: root.screen
|
||||||
|
|
||||||
|
onClose: console.log("shouldclose")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,19 +45,19 @@ Item {
|
|||||||
CustomRect {
|
CustomRect {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 3
|
anchors.margins: 3
|
||||||
color: Config.general.color.scheduleDark && root.current ? DynamicColors.palette.m3primary : "transparent"
|
color: icon.layer.enabled && root.current ? DynamicColors.palette.m3primary : "transparent"
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Config.general.color.scheduleDark && root.current ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
|
color: icon.layer.enabled && root.current ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
|
||||||
|
|
||||||
onClicked: mouse => {
|
onClicked: mouse => {
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
root.item.activate();
|
root.item.activate();
|
||||||
console.log(icon.source + "\n" + root.item.id);
|
console.log(icon.source + "\n" + root.item.id);
|
||||||
} else if (mouse.button === Qt.RightButton && Config.barConfig.popouts.tray) {
|
} else if (mouse.button === Qt.RightButton && Config.bar.popouts.tray) {
|
||||||
root.popouts.currentName = `traymenu${root.ind}`;
|
root.popouts.currentName = `traymenu${root.ind}`;
|
||||||
root.popouts.currentCenter = Qt.binding(() => root.mapToItem(root.loader, root.implicitWidth / 2, 0).x);
|
root.popouts.currentCenter = Qt.binding(() => root.mapToItem(root.loader, root.implicitWidth / 2, 0).x);
|
||||||
root.popouts.hasCurrent = true;
|
root.popouts.hasCurrent = true;
|
||||||
@@ -77,7 +77,7 @@ Item {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
color: root.current ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
|
color: root.current ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
|
||||||
implicitSize: Config.barConfig.tray.trayIconSize * root.dpr
|
implicitSize: Config.bar.tray.trayIconSize * root.dpr
|
||||||
layer.enabled: Config.general.color.smart || Config.general.color.scheduleDark
|
layer.enabled: Config.general.color.smart || Config.general.color.scheduleDark
|
||||||
scale: 1 / root.dpr
|
scale: 1 / root.dpr
|
||||||
source: root.resolveIcon(root.item.id, root.item.icon)
|
source: root.resolveIcon(root.item.id, root.item.icon)
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ RowLayout {
|
|||||||
let modRowPos = sysTrayMod.mapToItem(sysModRow, modPos.x, modPos.y);
|
let modRowPos = sysTrayMod.mapToItem(sysModRow, modPos.x, modPos.y);
|
||||||
let child = closestRowChild(sysModRow, modRowPos.x);
|
let child = closestRowChild(sysModRow, modRowPos.x);
|
||||||
if (child) {
|
if (child) {
|
||||||
if (child.objectName === "audioWidget" && Config.barConfig.popouts.audio)
|
if (child.objectName === "audioWidget" && Config.bar.popouts.audio)
|
||||||
return {
|
return {
|
||||||
id: "audio",
|
id: "audio",
|
||||||
item: child
|
item: child
|
||||||
};
|
};
|
||||||
if (child.objectName === "upowerWidget" && Config.barConfig.popouts.upower)
|
if (child.objectName === "upowerWidget" && Config.bar.popouts.upower)
|
||||||
return {
|
return {
|
||||||
id: "upower",
|
id: "upower",
|
||||||
item: child
|
item: child
|
||||||
@@ -75,7 +75,7 @@ RowLayout {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
height: Config.barConfig.height + Appearance.padding.smallest * 2
|
height: Config.bar.height + Appearance.padding.smallest * 2
|
||||||
spacing: Appearance.padding.small
|
spacing: Appearance.padding.small
|
||||||
width: sysTray.implicitWidth + sysTrayMod.implicitWidth + Appearance.padding.small
|
width: sysTray.implicitWidth + sysTrayMod.implicitWidth + Appearance.padding.small
|
||||||
|
|
||||||
@@ -123,22 +123,31 @@ RowLayout {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
bottomLeftRadius: Appearance.rounding.smallest / 2
|
bottomLeftRadius: Appearance.rounding.smallest / 2
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitWidth: sysModRow.width + Appearance.padding.smaller * 2
|
implicitWidth: sysModRow.implicitWidth + Appearance.padding.smaller + Appearance.padding.normal
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
topLeftRadius: Appearance.rounding.smallest / 2
|
topLeftRadius: Appearance.rounding.smallest / 2
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
id: sysModRow
|
id: sysModRow
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.fill: parent
|
||||||
spacing: Appearance.padding.small
|
anchors.leftMargin: Appearance.padding.smaller
|
||||||
|
anchors.rightMargin: Appearance.padding.normal
|
||||||
|
|
||||||
AudioWidget {
|
AudioWidget {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.rightMargin: hasContent ? Appearance.spacing.extraSmall / 2 : 0
|
||||||
objectName: "audioWidget"
|
objectName: "audioWidget"
|
||||||
|
|
||||||
|
Behavior on Layout.rightMargin {
|
||||||
|
Anim {
|
||||||
|
type: Anim.FastEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UPowerWidget {
|
UPowerWidget {
|
||||||
height: parent.height
|
Layout.fillHeight: true
|
||||||
objectName: "upowerWidget"
|
objectName: "upowerWidget"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,25 +11,68 @@ RowLayout {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property color barColor: DynamicColors.palette.m3primary
|
property color barColor: DynamicColors.palette.m3primary
|
||||||
|
readonly property bool hasContent: mic.visible || speaker.visible
|
||||||
property color textColor: DynamicColors.palette.m3onSurface
|
property color textColor: DynamicColors.palette.m3onSurface
|
||||||
|
|
||||||
|
width: hasContent ? implicitWidth : 0
|
||||||
|
|
||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
id: mic
|
id: mic
|
||||||
|
|
||||||
|
readonly property bool shouldBeVisible: Config.bar.tray.showMicrophone
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.maximumWidth: shouldBeVisible ? implicitWidth : 0
|
||||||
animate: true
|
animate: true
|
||||||
color: (Audio.sourceMuted ?? false) ? DynamicColors.palette.m3error : root.textColor
|
color: (Audio.sourceMuted ?? false) ? DynamicColors.palette.m3error : root.textColor
|
||||||
fill: 1
|
fill: 1
|
||||||
font.pointSize: Appearance.font.size.larger
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
opacity: shouldBeVisible ? 1 : 0
|
||||||
|
scale: shouldBeVisible ? 1 : 0
|
||||||
text: Audio.sourceMuted ? "mic_off" : "mic"
|
text: Audio.sourceMuted ? "mic_off" : "mic"
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on Layout.maximumWidth {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
|
id: speaker
|
||||||
|
|
||||||
|
readonly property bool shouldBeVisible: Config.bar.tray.showAudio
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.maximumWidth: shouldBeVisible ? implicitWidth : 0
|
||||||
animate: true
|
animate: true
|
||||||
color: Audio.muted ? DynamicColors.palette.m3error : root.textColor
|
color: Audio.muted ? DynamicColors.palette.m3error : root.textColor
|
||||||
fill: 1
|
fill: 1
|
||||||
font.pointSize: Appearance.font.size.larger
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
opacity: shouldBeVisible ? 1 : 0
|
||||||
|
scale: shouldBeVisible ? 1 : 0
|
||||||
text: Audio.muted ? "volume_off" : "volume_up"
|
text: Audio.muted ? "volume_off" : "volume_up"
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on Layout.maximumWidth {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,32 @@ import qs.Helpers
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
readonly property bool shouldBeActive: Config.bar.tray.showPower
|
||||||
|
|
||||||
|
Layout.preferredHeight: shouldBeActive ? implicitHeight : 0
|
||||||
|
Layout.preferredWidth: shouldBeActive ? implicitWidth : 0
|
||||||
implicitHeight: Battery.isLaptop ? batteryIconLoader.item.implicitHeight : upowerIconLoader.item.implicitHeight
|
implicitHeight: Battery.isLaptop ? batteryIconLoader.item.implicitHeight : upowerIconLoader.item.implicitHeight
|
||||||
implicitWidth: Battery.isLaptop ? batteryIconLoader.item.implicitWidth : upowerIconLoader.item.implicitWidth
|
implicitWidth: Battery.isLaptop ? batteryIconLoader.item.implicitWidth : upowerIconLoader.item.implicitWidth
|
||||||
|
opacity: shouldBeActive ? 1 : 0
|
||||||
|
scale: shouldBeActive ? 1 : 0
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on Layout.preferredHeight {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on Layout.preferredWidth {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: batteryIconLoader
|
id: batteryIconLoader
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ CustomRect {
|
|||||||
property color textColor: DynamicColors.palette.m3onSurface
|
property color textColor: DynamicColors.palette.m3onSurface
|
||||||
|
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
implicitHeight: Config.bar.height + Appearance.padding.smallest * 2
|
||||||
implicitWidth: contentRow.implicitWidth + Appearance.spacing.small * 2
|
implicitWidth: contentRow.implicitWidth + Appearance.spacing.small * 2
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ Item {
|
|||||||
readonly property int workspacesShown: workspaces.length
|
readonly property int workspacesShown: workspaces.length
|
||||||
|
|
||||||
height: implicitHeight
|
height: implicitHeight
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smaller * 2
|
implicitHeight: Config.bar.height + Appearance.padding.smaller * 2
|
||||||
implicitWidth: (root.workspaceButtonWidth * root.workspacesShown) + root.activeWorkspaceMargin * 2
|
implicitWidth: (root.workspaceButtonWidth * root.workspacesShown) + root.activeWorkspaceMargin * 2
|
||||||
|
|
||||||
Behavior on implicitWidth {
|
Behavior on implicitWidth {
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ Singleton {
|
|||||||
readonly property string recsdir: Quickshell.env("ZSHELL_RECORDINGS_DIR") || `${videos}/Recordings`
|
readonly property string recsdir: Quickshell.env("ZSHELL_RECORDINGS_DIR") || `${videos}/Recordings`
|
||||||
readonly property string state: `${Quickshell.env("XDG_STATE_HOME") || `${home}/.local/state`}/zshell`
|
readonly property string state: `${Quickshell.env("XDG_STATE_HOME") || `${home}/.local/state`}/zshell`
|
||||||
readonly property string videos: Quickshell.env("XDG_VIDEOS_DIR") || `${home}/Videos`
|
readonly property string videos: Quickshell.env("XDG_VIDEOS_DIR") || `${home}/Videos`
|
||||||
readonly property string wallsdir: Quickshell.env("ZSHELL_WALLPAPERS_DIR") || absolutePath(Config.wallpaperPath)
|
readonly property string wallsdir: Quickshell.env("ZSHELL_WALLPAPERS_DIR") || absolutePath(Config.general.wallpaperPath)
|
||||||
|
|
||||||
function absolutePath(path: string): string {
|
function absolutePath(path: string): string {
|
||||||
return toLocalFile(path.replace("~", home));
|
return toLocalFile(path.replace("~", home));
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ void BlobGroup::setColor(const QColor& c) {
|
|||||||
markDirty();
|
markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlobGroup::setCornerFill(bool e) {
|
||||||
|
if (m_cornerFill == e)
|
||||||
|
return;
|
||||||
|
m_cornerFill = e;
|
||||||
|
emit cornerFillChanged();
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
|
|
||||||
void BlobGroup::addShape(BlobShape* shape) {
|
void BlobGroup::addShape(BlobShape* shape) {
|
||||||
if (!shape || m_shapes.contains(shape))
|
if (!shape || m_shapes.contains(shape))
|
||||||
return;
|
return;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user