47 Commits

Author SHA1 Message Date
AramJonghu d799e61c79 clang-tidy fixes incoming 2026-06-05 18:02:27 +02:00
zach 9cefdf509c cmake build hotfix 2026-06-05 12:31:37 +02:00
zach 27924aca37 disable incompatible-type for qmllint in clock 2026-06-04 23:22:28 +02:00
zach b4716d25c0 nodiscard 2026-06-04 22:57:45 +02:00
zach d8f047dbc9 nodiscard 2026-06-04 22:38:17 +02:00
zach 91b50b312d open launcher with gesture from bottom border 2026-06-04 19:01:02 +02:00
zach 3e933a8b78 remove logging 2026-06-04 18:56:42 +02:00
zach e127928126 Merge pull request 'Rewrite the manager responsible for handling automatic hyprsunset temperature activation as a qml plugin' (#117) from hyprsunset-manager-rewrite into main
Reviewed-on: #117
2026-06-04 15:05:45 +02:00
zach 94f2cf076c fix applying end() on init
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 12s
Python / lint-format (pull_request) Successful in 23s
Python / test (pull_request) Successful in 49s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m3s
2026-06-04 15:05:18 +02:00
zach 9168b6e893 Merge branch 'main' into hyprsunset-manager-rewrite
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 12s
Python / lint-format (pull_request) Successful in 24s
Python / test (pull_request) Successful in 42s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m3s
2026-06-04 14:56:53 +02:00
zach a477fb2e22 fix namespaces and logging names 2026-06-04 14:56:20 +02:00
zach 6586cc2788 do not use apply() in initializer
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 12s
Python / lint-format (pull_request) Successful in 17s
Python / test (pull_request) Successful in 48s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m4s
2026-06-03 23:21:07 +02:00
zach 0be98a64ac Merge branch 'main' into hyprsunset-manager-rewrite
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 15s
Python / lint-format (pull_request) Successful in 23s
Python / test (pull_request) Successful in 54s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m4s
2026-06-03 18:02:27 +02:00
zach b6e7ee7a54 Merge pull request 'lid behavior watcher to lock session' (#115) from lid-switch-behavior into main
Reviewed-on: #115
2026-06-03 18:02:21 +02:00
AramJonghu 59789ab8d3 unused imports in shell.qml
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 11s
Python / lint-format (pull_request) Successful in 21s
Python / test (pull_request) Successful in 51s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m4s
2026-06-03 18:01:10 +02:00
AramJonghu a128c0fa40 removal reduntant config option and settings, unused lines in Lock.qml
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 11s
Python / lint-format (pull_request) Successful in 21s
Python / test (pull_request) Successful in 52s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m4s
2026-06-03 17:59:03 +02:00
AramJonghu 6f856e2162 fix typo
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 11s
Python / lint-format (pull_request) Successful in 18s
Python / test (pull_request) Successful in 44s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m5s
2026-06-03 17:47:12 +02:00
AramJonghu a19701222b forgotton import and removal LidService
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 11s
Python / lint-format (pull_request) Successful in 26s
Python / test (pull_request) Successful in 41s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m4s
2026-06-03 17:43:58 +02:00
AramJonghu 0d8f558f66 Took caelestia lid logic (prepare to sleep) instead
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 12s
Python / lint-format (pull_request) Successful in 19s
Python / test (pull_request) Successful in 45s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m3s
2026-06-03 17:41:29 +02:00
AramJonghu ed28d8b56a Took caelestia lid logic (prepare to sleep) instead 2026-06-03 17:41:17 +02:00
AramJonghu deef85d10c troubleshooting dbus
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 15s
Python / lint-format (pull_request) Successful in 19s
Python / test (pull_request) Successful in 49s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m5s
2026-06-03 17:02:46 +02:00
AramJonghu f9ab1e2a10 inability to connect to DBus.Properties resolved
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 13s
Python / lint-format (pull_request) Successful in 20s
Python / test (pull_request) Successful in 51s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m3s
2026-06-03 16:51:15 +02:00
AramJonghu 7dbce0bf8c qmlls lied to me - import ZShell returned
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 11s
Python / lint-format (pull_request) Successful in 23s
Python / test (pull_request) Successful in 45s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m4s
2026-06-03 16:29:11 +02:00
AramJonghu 2920c57163 removes direct extern access, receives signal properly now, removed declaration unused method
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 14s
Python / lint-format (pull_request) Successful in 21s
Python / test (pull_request) Successful in 44s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m6s
2026-06-03 16:27:31 +02:00
AramJonghu 0584cd618e missing changes
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 31s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m3s
2026-06-03 02:30:13 +02:00
AramJonghu 896e5e520d Added clang-format/tidy for additional rules. Adjusted inbranch cpp files.
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 15s
Python / lint-format (pull_request) Successful in 37s
Python / test (pull_request) Successful in 59s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m20s
2026-06-03 02:05:18 +02:00
AramJonghu 45f36ce71c added lock. in shell.qml, wrong scope
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 12s
Python / lint-format (pull_request) Successful in 20s
Python / test (pull_request) Successful in 47s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m5s
2026-06-03 01:14:37 +02:00
AramJonghu 3bcdbbabbb build fix
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 16s
Python / lint-format (pull_request) Successful in 23s
Python / test (pull_request) Successful in 48s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m9s
2026-06-03 01:02:50 +02:00
AramJonghu 016dcc008f Cpp changes, minor refactor plus separate signal logic, typo.
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 12s
Python / lint-format (pull_request) Successful in 26s
Python / test (pull_request) Successful in 1m3s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m9s
- typo in searchindex
- Cpp plugin changed to use enum lidstate
- minor refactor
- Using signals instead of direct property access.
- Using states instead
- checking lidclosed instead of preparetosleep
2026-06-03 00:54:44 +02:00
zach d246ba1800 rewrite the manager responsible for handling automatic hyprsunset temperature activation as a qml plugin
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 13s
Python / lint-format (pull_request) Successful in 19s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m2s
2026-06-02 16:09:48 +02:00
AramJonghu c91b53fbaa QTQuick
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 12s
Python / lint-format (pull_request) Successful in 24s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m7s
2026-06-02 00:03:30 +02:00
AramJonghu ad2ee99d9c format using qmlformat
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 12s
Python / lint-format (pull_request) Successful in 20s
Python / test (pull_request) Successful in 51s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m5s
2026-06-01 23:59:07 +02:00
AramJonghu 7da2c7827a refactor: using more oop
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 14s
Python / lint-format (pull_request) Successful in 20s
Python / test (pull_request) Successful in 52s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m6s
2026-06-01 23:53:26 +02:00
AramJonghu db9c98b322 set default enabled for laptops, disabled for non battery devices
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 15s
Python / lint-format (pull_request) Successful in 22s
Python / test (pull_request) Successful in 46s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m5s
2026-06-01 21:03:59 +02:00
AramJonghu 1c1c6275df move lid watch toggle into lock settings 2026-06-01 20:45:04 +02:00
AramJonghu 83cf008a19 setting option to disable lidwatcher, also in settingswindow 2026-06-01 20:28:55 +02:00
AramJonghu c514e98687 nonexistant locked should be resolved 2026-06-01 20:12:17 +02:00
AramJonghu 0d097524c3 shell.qml could not load Connections, now fixed 2026-06-01 20:07:09 +02:00
AramJonghu 7de8cc3104 lidwatcher plugin initial setup 2026-06-01 20:02:37 +02:00
AramJonghu 82aa7c415f initial commit 2026-06-01 19:50:40 +02:00
zach 807b2525b7 Merge pull request 'initial refactor of Interactions.qml to add better support for touch screen gestures' (#114) from feat/improved-gestures into main
Reviewed-on: #114
Reviewed-by: AramJonghu <2+aramjonghu@noreply.git.zach-dev.cc>
Reviewed-by: Inorishio <inorishio@gmail.com>
2026-06-01 19:18:53 +02:00
zach 9e3cad6dbd Merge branch 'main' into feat/improved-gestures
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 13s
Python / lint-format (pull_request) Successful in 25s
Python / test (pull_request) Successful in 51s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m3s
2026-06-01 19:01:12 +02:00
zach 9436acd626 change charging color 2026-06-01 17:12:28 +02:00
AramJonghu 17e600e78e Merge branch 'main' into feat/improved-gestures
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 12s
Python / lint-format (pull_request) Successful in 18s
Python / test (pull_request) Successful in 47s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m6s
2026-06-01 15:05:04 +02:00
zach 7eba84c8be Better battery indicator and dedicated Battery singleton in helpers 2026-06-01 15:04:48 +02:00
zach 0820c8e023 Merge branch 'main' into feat/improved-gestures
Python / lint-format (pull_request) Successful in 22s
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 27s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m2s
2026-06-01 12:13:33 +02:00
zach ebedf4b6fe increase slider visibility and remove debug logging 2026-06-01 12:12:00 +02:00
49 changed files with 1098 additions and 591 deletions
+58
View File
@@ -0,0 +1,58 @@
---
BasedOnStyle: LLVM
AccessModifierOffset: 0
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignOperands: Align
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Never
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
FixNamespaceComments: true
IndentCaseLabels: false
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 100
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
ReflowComments: false
SortIncludes: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: c++20
TabWidth: 4
UseTab: Always
+30
View File
@@ -0,0 +1,30 @@
---
Checks: >
-*,
bugprone-*,
clang-analyzer-*,
modernize-*,
-modernize-use-trailing-return-type,
performance-*,
readability-braces-around-statements,
readability-else-after-return,
readability-identifier-naming,
readability-redundant-*,
readability-simplify-*,
CheckOptions:
readability-identifier-naming.ClassCase: CamelCase
readability-identifier-naming.EnumCase: CamelCase
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
HeaderFilterRegex: ""
FormatStyle: file
...
+1
View File
@@ -25,6 +25,7 @@ add_compile_options(
if("plugin" IN_LIST ENABLE_MODULES) if("plugin" IN_LIST ENABLE_MODULES)
add_subdirectory(Plugins) add_subdirectory(Plugins)
endif() endif()
if("shell" IN_LIST ENABLE_MODULES) if("shell" IN_LIST ENABLE_MODULES)
+11 -7
View File
@@ -10,31 +10,35 @@ Slider {
background: Item { background: Item {
CustomRect { CustomRect {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.bottomMargin: root.implicitHeight / 6
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: root.implicitHeight / 6
bottomRightRadius: root.implicitHeight / 6 bottomRightRadius: root.implicitHeight / 6
color: root.color color: root.color
implicitWidth: root.handle.x - root.implicitHeight / 2 implicitWidth: root.handle.x - root.implicitHeight / 6
radius: Appearance.rounding.full radius: root.implicitHeight / 6
topRightRadius: root.implicitHeight / 6 topRightRadius: root.implicitHeight / 6
} }
CustomRect { CustomRect {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.bottomMargin: root.implicitHeight / 6
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: root.implicitHeight / 6
bottomLeftRadius: root.implicitHeight / 6 bottomLeftRadius: root.implicitHeight / 6
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainerHighest
implicitWidth: parent.width - root.handle.x - root.handle.implicitWidth - root.implicitHeight / 2 implicitWidth: parent.width - root.handle.x - root.handle.implicitWidth - root.implicitHeight / 6
radius: Appearance.rounding.full radius: root.implicitHeight / 6
topLeftRadius: root.implicitHeight / 6 topLeftRadius: root.implicitHeight / 6
} }
} }
handle: CustomRect { handle: CustomRect {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: root.color color: root.color
implicitHeight: 15 implicitHeight: root.implicitHeight
implicitWidth: 5 implicitWidth: root.implicitHeight / 4.5
radius: Appearance.rounding.full radius: Appearance.rounding.full
x: root.visualPosition * root.availableWidth - implicitWidth / 2 x: root.visualPosition * root.availableWidth - implicitWidth / 2
+4
View File
@@ -115,6 +115,10 @@ Singleton {
Config.save(); Config.save();
} }
function swapRG(c: color): color {
return Qt.rgba(c.g, c.r, c.b, c.a);
}
Component.onCompleted: debounceTimer.triggered() Component.onCompleted: debounceTimer.triggered()
Connections { Connections {
@@ -4,17 +4,16 @@ import QtQuick
import ZShell import ZShell
import qs.Config import qs.Config
import qs.Components.Toast import qs.Components.Toast
import qs.Helpers
Scope { Scope {
id: root id: root
readonly property real currentPerc: UPower.displayDevice.percentage
readonly property list<var> popupThresholds: [...Config.general.battery.popupThresholds].sort((a, b) => b.perc - a.perc) readonly property list<var> popupThresholds: [...Config.general.battery.popupThresholds].sort((a, b) => b.perc - a.perc)
function nearestThresholdAbove(p: real): var { function nearestThresholdAbove(p: real): var {
const thresholds = [...root.popupThresholds]; const thresholds = [...root.popupThresholds];
for (const perc of thresholds) { for (const perc of thresholds) {
console.log(perc.message);
if (p < perc.perc) if (p < perc.perc)
return perc; return perc;
} }
@@ -24,13 +23,13 @@ Scope {
Connections { Connections {
function onOnBatteryChanged(): void { function onOnBatteryChanged(): void {
if (!UPower.displayDevice.ready) if (!Battery.ready)
return; return;
if (UPower.onBattery) { if (Battery.onBattery) {
if (Config.utilities.toasts.chargingChanged) if (Config.utilities.toasts.chargingChanged)
Toaster.toast(qsTr("Charger unplugged"), qsTr("Battery is discharging"), "power_off"); Toaster.toast(qsTr("Charger unplugged"), qsTr("Battery is discharging"), "power_off");
const p = root.currentPerc * 100; const p = Battery.currentPerc * 100;
const perc = root.nearestThresholdAbove(p); const perc = root.nearestThresholdAbove(p);
if (perc) if (perc)
Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning); Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning);
@@ -40,15 +39,15 @@ Scope {
} }
} }
target: UPower target: Battery
} }
Connections { Connections {
function onPercentageChanged(): void { function onCurrentPercChanged(): void {
if (!UPower.onBattery) if (!Battery.onBattery)
return; return;
const p = root.currentPerc * 100; const p = Battery.currentPerc * 100;
for (const perc of root.popupThresholds) { for (const perc of root.popupThresholds) {
if (p == perc.perc) { if (p == perc.perc) {
Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery perc is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning); Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery perc is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning);
@@ -57,15 +56,15 @@ Scope {
} }
function onReadyChanged(): void { function onReadyChanged(): void {
if (!UPower.displayDevice.ready) if (!Battery.ready)
return; return;
const p = root.currentPerc * 100; const p = Battery.currentPerc * 100;
const perc = root.nearestThresholdAbove(p); const perc = root.nearestThresholdAbove(p);
if (perc) if (perc)
Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning); Toaster.toast(perc.title ?? qsTr("Battery warning"), perc.message ?? qsTr("Battery is low"), perc.icon ?? "battery_android_alert", perc.critical ? Toast.Error : Toast.Warning);
} }
target: UPower.displayDevice target: Battery
} }
} }
+6 -3
View File
@@ -69,14 +69,17 @@ Item {
root.singleGestureTriggered = false; root.singleGestureTriggered = false;
} }
onCentroidChanged: { onCentroidChanged: {
if (root.singleGestureTriggered)
return;
const x = centroid.position.x; const x = centroid.position.x;
const y = centroid.position.y; const y = centroid.position.y;
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 && dragY < -200)
root.visibilities.launcher = true;
if (root.singleGestureTriggered)
return;
if (centroid.pressPosition.y < root.bar.implicitHeight) { if (centroid.pressPosition.y < root.bar.implicitHeight) {
if (dragY > 20) { if (dragY > 20) {
root.visibilities.settings = true; root.visibilities.settings = true;
+32
View File
@@ -0,0 +1,32 @@
pragma Singleton
import Quickshell
import Quickshell.Services.UPower
import qs.Config
Singleton {
id: root
readonly property var colors: {
if (deviceState === UPowerDeviceState.Charging || deviceState === UPowerDeviceState.FullyCharged)
return {
fg: DynamicColors.swapRG(DynamicColors.palette.m3error),
bg: DynamicColors.swapRG(DynamicColors.palette.m3onError)
};
else if (currentPerc <= 0.2)
return {
fg: DynamicColors.palette.m3error,
bg: DynamicColors.palette.m3onError
};
else
return {
fg: DynamicColors.palette.m3onSurface,
bg: DynamicColors.palette.m3surface
};
}
readonly property real currentPerc: UPower.displayDevice.percentage
readonly property var deviceState: UPower.displayDevice.state
readonly property bool isLaptop: UPower.displayDevice.isLaptopBattery
readonly property bool onBattery: UPower.onBattery
readonly property bool ready: UPower.displayDevice.ready
}
+11 -59
View File
@@ -2,12 +2,13 @@ pragma Singleton
import Quickshell import Quickshell
import QtQuick import QtQuick
import ZShell.Services
import qs.Config import qs.Config
Singleton { Singleton {
id: root id: root
property bool enabled readonly property bool enabled: service.enabled
readonly property int end: Config.general.color.scheduleHyprsunsetEnd readonly property int end: Config.general.color.scheduleHyprsunsetEnd
property bool manualToggle: false property bool manualToggle: false
readonly property int start: Config.general.color.scheduleHyprsunsetStart readonly property int start: Config.general.color.scheduleHyprsunsetStart
@@ -17,69 +18,20 @@ Singleton {
if (!Config.general.color.scheduleHyprsunset) if (!Config.general.color.scheduleHyprsunset)
return; return;
var now = new Date(); service.apply();
if (now.getHours() >= root.start || now.getHours() < root.end) {
root.startNightLight(root.temp);
} else {
root.stopNightLight();
}
}
function startNightLight(temp: int): void {
Quickshell.execDetached(["hyprctl", "hyprsunset", "temperature", `${temp}`]);
root.enabled = true;
}
function stopNightLight(): void {
Quickshell.execDetached(["hyprctl", "hyprsunset", "identity"]);
root.enabled = false;
} }
function toggleNightLight(): void { function toggleNightLight(): void {
if (enabled) service.manualToggle = true;
stopNightLight(); service.toggle();
else
startNightLight(temp);
} }
onManualToggleChanged: { HyprsunsetManager {
if (root.manualToggle) id: service
manualTimer.start();
}
Timer { activeAuto: Config.general.color.scheduleHyprsunset
id: manualTimer endTime: root.end
startTime: root.start
interval: 60000 * 60 temp: root.temp
repeat: false
running: false
onTriggered: {
root.manualToggle = false;
}
}
Timer {
interval: 5000
repeat: true
running: true
triggeredOnStart: true
onTriggered: {
if (!Config.general.color.scheduleHyprsunset)
return;
if (root.manualToggle)
return;
var now = new Date();
if (now.getHours() >= root.start || now.getHours() < root.end) {
if (!root.enabled)
root.startNightLight(root.temp);
} else {
if (root.enabled)
root.stopNightLight();
}
}
} }
} }
-26
View File
@@ -1,26 +0,0 @@
pragma Singleton
import Quickshell
import Quickshell.Services.UPower
Singleton {
id: root
readonly property real batteryPercent: UPower.displayDevice.percentage
readonly property list<UPowerDevice> devices: UPower.devices.values
readonly property UPowerDevice displayDevice: UPower.displayDevice
readonly property bool onBattery: UPower.onBattery
// property bool toastShown
//
// Connections {
// target: UPower
//
// function onPercentageChanged(): {
// if (root.batteryPercent >= 0.2 && toastShown)
// return;
//
// root.toastShown = true;
// Toaster.toast(qsTr("Battery "))
// }
// }
}
+1 -1
View File
@@ -23,7 +23,7 @@ CustomRect {
anchors.centerIn: parent anchors.centerIn: parent
color: root.visibilities.dashboard ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface color: root.visibilities.dashboard ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
font: Appearance.font.family.mono font: Appearance.font.family.mono // qmllint disable incompatible-type
text: Time.dateStr text: Time.dateStr
Behavior on color { Behavior on color {
+5
View File
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import ZShell.Internal
import qs.Config import qs.Config
import qs.Helpers import qs.Helpers
@@ -29,6 +30,10 @@ Scope {
Quickshell.execDetached(action); Quickshell.execDetached(action);
} }
LidWatcher {
onAboutToSleep: root.lock.lock.locked = true
}
Variants { Variants {
model: Config.general.idle.timeouts model: Config.general.idle.timeouts
@@ -1,5 +1,6 @@
import qs.Modules.Settings.Categories.Lockscreen import qs.Modules.Settings.Categories.Lockscreen
import qs.Modules.Settings.Controls import qs.Modules.Settings.Controls
import qs.Helpers
import qs.Config import qs.Config
SettingsPage { SettingsPage {
@@ -80,7 +80,8 @@ Item {
required property ShellScreen modelData required property ShellScreen modelData
function applyCrop(): void { function applyCrop(): void {
if (!cropRectLoader.item) return; if (!cropRectLoader.item)
return;
const cropRect = cropRectLoader.item; const cropRect = cropRectLoader.item;
// We need to calculate the exact percentage coordinates that map perfectly // We need to calculate the exact percentage coordinates that map perfectly
@@ -97,7 +98,8 @@ Item {
} }
function zoomClipRect(zoom: real): void { function zoomClipRect(zoom: real): void {
if (!cropRectLoader.item) return; if (!cropRectLoader.item)
return;
const cropRect = cropRectLoader.item; const cropRect = cropRectLoader.item;
let oldCenterX = cropRect.x + cropRect.width * 0.5; let oldCenterX = cropRect.x + cropRect.width * 0.5;
@@ -139,8 +141,9 @@ Item {
id: zoomSlider id: zoomSlider
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 10 Layout.preferredHeight: 30
from: 1.0 from: 1.0
implicitHeight: 30
to: 5.0 to: 5.0
value: cropRectLoader.item ? cropRectLoader.item.zoom : 1.0 value: cropRectLoader.item ? cropRectLoader.item.zoom : 1.0
@@ -198,6 +201,7 @@ Item {
Loader { Loader {
id: cropRectLoader id: cropRectLoader
active: scaledImg.paintedWidth > 0 && scaledImg.status == Image.Ready active: scaledImg.paintedWidth > 0 && scaledImg.status == Image.Ready
sourceComponent: Component { sourceComponent: Component {
@@ -272,7 +276,8 @@ Item {
id: mouse id: mouse
function updateCrop(mouseX, mouseY) { function updateCrop(mouseX, mouseY) {
if (!cropRectLoader.item) return; if (!cropRectLoader.item)
return;
const cropRect = cropRectLoader.item; const cropRect = cropRectLoader.item;
let nx = mouseX - cropRect.width * 0.5; let nx = mouseX - cropRect.width * 0.5;
+67 -47
View File
@@ -52,25 +52,25 @@ Item {
CustomRect { CustomRect {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 Layout.preferredHeight: 50 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding radius: root.rounding
RowLayout { Item {
id: outputVolume id: sinkIcon
anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.margins: Appearance.spacing.smaller anchors.leftMargin: Appearance.padding.normal
anchors.right: parent.right anchors.top: parent.top
anchors.verticalCenter: parent.verticalCenter implicitWidth: childrenRect.width
spacing: 15
CustomRect { CustomRect {
Layout.alignment: Qt.AlignVCenter anchors.centerIn: parent
Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 40
implicitWidth: 40
radius: Appearance.rounding.full radius: Appearance.rounding.full
MaterialIcon { MaterialIcon {
@@ -92,11 +92,20 @@ Item {
} }
} }
} }
}
ColumnLayout { ColumnLayout {
Layout.fillWidth: true anchors.bottom: parent.bottom
anchors.bottomMargin: Appearance.padding.smallest
anchors.left: sinkIcon.right
anchors.leftMargin: Appearance.spacing.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.large
anchors.top: parent.top
anchors.topMargin: Appearance.padding.smaller
RowLayout { RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
CustomText { CustomText {
@@ -114,14 +123,14 @@ Item {
CustomMouseArea { CustomMouseArea {
Layout.bottomMargin: 5 Layout.bottomMargin: 5
Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 10
CustomSlider { CustomSlider {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 10 implicitHeight: parent.height
value: Audio.volume value: Audio.volume
Behavior on value { Behavior on value {
@@ -134,11 +143,10 @@ Item {
} }
} }
} }
}
CustomClippingRect { CustomClippingRect {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 Layout.preferredHeight: 50 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding radius: root.rounding
@@ -165,20 +173,20 @@ Item {
} }
} }
RowLayout { Item {
id: inputVolume id: sourceIcon
anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.margins: Appearance.spacing.smaller anchors.leftMargin: Appearance.padding.normal
anchors.right: parent.right anchors.top: parent.top
anchors.verticalCenter: parent.verticalCenter implicitWidth: childrenRect.width
spacing: 15
CustomRect { CustomRect {
Layout.alignment: Qt.AlignVCenter anchors.centerIn: parent
Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 40
implicitWidth: 40
radius: Appearance.rounding.full radius: Appearance.rounding.full
MaterialIcon { MaterialIcon {
@@ -200,9 +208,17 @@ Item {
} }
} }
} }
}
ColumnLayout { ColumnLayout {
Layout.fillWidth: true anchors.bottom: parent.bottom
anchors.bottomMargin: Appearance.padding.smallest
anchors.left: sourceIcon.right
anchors.leftMargin: Appearance.spacing.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.large
anchors.top: parent.top
anchors.topMargin: Appearance.padding.smaller
RowLayout { RowLayout {
Layout.fillHeight: true Layout.fillHeight: true
@@ -223,14 +239,14 @@ Item {
CustomMouseArea { CustomMouseArea {
Layout.bottomMargin: 5 Layout.bottomMargin: 5
Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: 10
CustomSlider { CustomSlider {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 10 implicitHeight: parent.height
value: Audio.sourceVolume value: Audio.sourceVolume
Behavior on value { Behavior on value {
@@ -243,7 +259,6 @@ Item {
} }
} }
} }
}
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
@@ -265,7 +280,7 @@ Item {
required property var modelData required property var modelData
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 Layout.preferredHeight: 50 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding radius: root.rounding
@@ -292,18 +307,20 @@ Item {
} }
} }
RowLayout { Item {
id: layoutVolume id: appBoxIcon
anchors.fill: parent anchors.bottom: parent.bottom
anchors.margins: Appearance.spacing.smaller anchors.left: parent.left
spacing: 15 anchors.leftMargin: Appearance.padding.normal
anchors.top: parent.top
implicitWidth: childrenRect.width
CustomRect { CustomRect {
Layout.alignment: Qt.AlignVCenter anchors.centerIn: parent
Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 40
implicitWidth: 40
radius: Appearance.rounding.full radius: Appearance.rounding.full
MaterialIcon { MaterialIcon {
@@ -325,10 +342,7 @@ Item {
} }
} }
} }
}
ColumnLayout {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillHeight: true
TextMetrics { TextMetrics {
id: metrics id: metrics
@@ -338,13 +352,22 @@ Item {
text: Audio.getStreamName(appBox.modelData) text: Audio.getStreamName(appBox.modelData)
} }
ColumnLayout {
anchors.bottom: parent.bottom
anchors.bottomMargin: Appearance.padding.smallest
anchors.left: appBoxIcon.right
anchors.leftMargin: Appearance.spacing.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.large
anchors.top: parent.top
anchors.topMargin: Appearance.padding.smaller
RowLayout { RowLayout {
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
elide: Text.ElideRight elide: Text.ElideRight
text: metrics.elidedText text: metrics.elidedText
@@ -352,23 +375,21 @@ Item {
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.fillHeight: true
font.bold: true font.bold: true
text: qsTr("%1").arg(appBox.modelData.audio.muted ? qsTr("Muted") : `${Math.round(appBox.modelData.audio.volume * 100)}%`) text: qsTr("%1").arg(appBox.modelData.audio.muted ? qsTr("Muted") : `${Math.round(appBox.modelData.audio.volume * 100)}%`)
} }
} }
CustomMouseArea { CustomMouseArea {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft Layout.bottomMargin: 5
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: 10
CustomSlider { CustomSlider {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 10 implicitHeight: parent.height
value: appBox.modelData.audio.volume value: appBox.modelData.audio.volume
onMoved: { onMoved: {
@@ -381,4 +402,3 @@ Item {
} }
} }
} }
}
+100 -13
View File
@@ -3,33 +3,120 @@ import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.Components import qs.Components
import qs.Config import qs.Config
import qs.Helpers as Helpers import qs.Helpers
RowLayout { Item {
id: root id: root
implicitHeight: Battery.isLaptop ? batteryIconLoader.item.implicitHeight : upowerIconLoader.item.implicitHeight
implicitWidth: Battery.isLaptop ? batteryIconLoader.item.implicitWidth : upowerIconLoader.item.implicitWidth
Loader {
id: batteryIconLoader
active: Battery.isLaptop
anchors.centerIn: parent
sourceComponent: Row {
id: batteryIcon
property real batHeight: 16
property real batWidth: 30
property real nubHeight: 6
property real nubWidth: 2
property real radius: Appearance.rounding.smallest / 2
spacing: 1
CustomRect {
id: track
anchors.verticalCenter: parent.verticalCenter
color: Battery.colors.bg
height: batteryIcon.batHeight
radius: batteryIcon.radius
width: batteryIcon.batWidth
CustomText {
color: Battery.colors.fg
font.pointSize: Appearance.font.size.larger / 1.5
font.weight: 800
height: track.height
horizontalAlignment: Text.AlignHCenter
text: Math.round(Battery.currentPerc * 100)
verticalAlignment: Text.AlignVCenter
width: track.width
}
Item {
clip: true
width: parent.width * Battery.currentPerc
anchors {
bottom: parent.bottom
left: parent.left
top: parent.top
}
CustomRect {
id: fill
color: Battery.colors.fg
height: track.height
radius: track.radius
width: track.width
CustomText {
id: batteryLabel
clip: true
color: Battery.colors.bg
font.pointSize: 7.5
font.weight: 800
height: track.height
horizontalAlignment: Text.AlignHCenter
text: Math.round(Battery.currentPerc * 100)
verticalAlignment: Text.AlignVCenter
width: track.width
}
}
}
}
CustomRect {
id: nub
anchors.verticalCenter: parent.verticalCenter
bottomRightRadius: 20
color: Battery.currentPerc < 0.99 ? track.color : fill.color
height: batteryIcon.nubHeight
topRightRadius: 20
width: batteryIcon.nubWidth
}
}
}
Loader {
id: upowerIconLoader
active: !Battery.isLaptop
anchors.centerIn: parent
sourceComponent: RowLayout {
id: upowerIcon
MaterialIcon { MaterialIcon {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
animate: true animate: true
color: !Helpers.UPower.onBattery || UPower.displayDevice.percentage > 0.2 ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3error
fill: 1 fill: 1
text: { text: {
if (!Helpers.UPower.displayDevice.isLaptopBattery) {
if (PowerProfiles.profile === PowerProfile.PowerSaver) if (PowerProfiles.profile === PowerProfile.PowerSaver)
return "nest_eco_leaf"; return "nest_eco_leaf";
if (PowerProfiles.profile === PowerProfile.Performance) if (PowerProfiles.profile === PowerProfile.Performance)
return "bolt"; return "bolt";
return "power_settings_new"; return "power_settings_new";
} }
}
const perc = Helpers.UPower.displayDevice.percentage;
const charging = [UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(Helpers.UPower.displayDevice.state);
if (perc === 1)
return charging ? "battery_charging_full" : "battery_full";
let level = Math.floor(perc * 7);
if (charging && (level === 4 || level === 1))
level--;
return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`;
} }
} }
} }
+4 -4
View File
@@ -18,13 +18,13 @@ public:
explicit BlobGroup(QObject* parent = nullptr); explicit BlobGroup(QObject* parent = nullptr);
~BlobGroup() override; ~BlobGroup() override;
qreal smoothing() const { [[nodiscard]] qreal smoothing() const {
return m_smoothing; return m_smoothing;
} }
void setSmoothing(qreal s); void setSmoothing(qreal s);
QColor color() const { [[nodiscard]] QColor color() const {
return m_color; return m_color;
} }
@@ -36,11 +36,11 @@ void removeShape(BlobShape* shape);
void setInvertedRect(BlobInvertedRect* rect); void setInvertedRect(BlobInvertedRect* rect);
void clearInvertedRect(BlobInvertedRect* rect); void clearInvertedRect(BlobInvertedRect* rect);
const QList<BlobShape*>& shapes() const { [[nodiscard]] const QList<BlobShape*>& shapes() const {
return m_shapes; return m_shapes;
} }
BlobInvertedRect* invertedRect() const { [[nodiscard]] BlobInvertedRect* invertedRect() const {
return m_invertedRect; return m_invertedRect;
} }
+5 -5
View File
@@ -16,25 +16,25 @@ public:
explicit BlobInvertedRect(QQuickItem* parent = nullptr); explicit BlobInvertedRect(QQuickItem* parent = nullptr);
~BlobInvertedRect() override; ~BlobInvertedRect() override;
qreal borderLeft() const { [[nodiscard]] qreal borderLeft() const {
return m_borderLeft; return m_borderLeft;
} }
void setBorderLeft(qreal v); void setBorderLeft(qreal v);
qreal borderRight() const { [[nodiscard]] qreal borderRight() const {
return m_borderRight; return m_borderRight;
} }
void setBorderRight(qreal v); void setBorderRight(qreal v);
qreal borderTop() const { [[nodiscard]] qreal borderTop() const {
return m_borderTop; return m_borderTop;
} }
void setBorderTop(qreal v); void setBorderTop(qreal v);
qreal borderBottom() const { [[nodiscard]] qreal borderBottom() const {
return m_borderBottom; return m_borderBottom;
} }
@@ -47,7 +47,7 @@ void borderTopChanged();
void borderBottomChanged(); void borderBottomChanged();
protected: protected:
bool isInvertedRect() const override { [[nodiscard]] bool isInvertedRect() const override {
return true; return true;
} }
+2 -2
View File
@@ -21,8 +21,8 @@ struct BlobRectData {
class BlobMaterial : public QSGMaterial { class BlobMaterial : public QSGMaterial {
public: public:
QSGMaterialType* type() const override; [[nodiscard]] QSGMaterialType* type() const override;
QSGMaterialShader* createShader(QSGRendererInterface::RenderMode) const override; [[nodiscard]] QSGMaterialShader* createShader(QSGRendererInterface::RenderMode) const override;
int compare(const QSGMaterial* other) const override; int compare(const QSGMaterial* other) const override;
float m_paddedX = 0; float m_paddedX = 0;
+7 -7
View File
@@ -24,7 +24,7 @@ public:
explicit BlobRect(QQuickItem* parent = nullptr); explicit BlobRect(QQuickItem* parent = nullptr);
~BlobRect() override; ~BlobRect() override;
qreal stiffness() const { [[nodiscard]] qreal stiffness() const {
return m_stiffness; return m_stiffness;
} }
@@ -35,7 +35,7 @@ void setStiffness(qreal s) {
} }
} }
qreal damping() const { [[nodiscard]] qreal damping() const {
return m_damping; return m_damping;
} }
@@ -46,7 +46,7 @@ void setDamping(qreal d) {
} }
} }
qreal deformScale() const { [[nodiscard]] qreal deformScale() const {
return m_deformScale; return m_deformScale;
} }
@@ -62,25 +62,25 @@ QQmlListProperty<BlobRect> exclude();
bool isExcluded(const BlobShape* other) const override; bool isExcluded(const BlobShape* other) const override;
void cornerRadii(float out[4]) const override; void cornerRadii(float out[4]) const override;
qreal topLeftRadius() const { [[nodiscard]] qreal topLeftRadius() const {
return m_topLeftRadius; return m_topLeftRadius;
} }
void setTopLeftRadius(qreal r); void setTopLeftRadius(qreal r);
qreal topRightRadius() const { [[nodiscard]] qreal topRightRadius() const {
return m_topRightRadius; return m_topRightRadius;
} }
void setTopRightRadius(qreal r); void setTopRightRadius(qreal r);
qreal bottomLeftRadius() const { [[nodiscard]] qreal bottomLeftRadius() const {
return m_bottomLeftRadius; return m_bottomLeftRadius;
} }
void setBottomLeftRadius(qreal r); void setBottomLeftRadius(qreal r);
qreal bottomRightRadius() const { [[nodiscard]] qreal bottomRightRadius() const {
return m_bottomRightRadius; return m_bottomRightRadius;
} }
+6 -7
View File
@@ -21,23 +21,23 @@ public:
explicit BlobShape(QQuickItem* parent = nullptr); explicit BlobShape(QQuickItem* parent = nullptr);
~BlobShape() override = default; ~BlobShape() override = default;
BlobGroup* group() const { [[nodiscard]] BlobGroup* group() const {
return m_group; return m_group;
} }
void setGroup(BlobGroup* g); void setGroup(BlobGroup* g);
qreal radius() const { [[nodiscard]] qreal radius() const {
return m_radius; return m_radius;
} }
void setRadius(qreal r); void setRadius(qreal r);
QMatrix4x4 deformMatrix() const { [[nodiscard]] QMatrix4x4 deformMatrix() const {
return m_centeredDeformMatrix; return m_centeredDeformMatrix;
} }
QMatrix4x4 rawDeformMatrix() const { [[nodiscard]] QMatrix4x4 rawDeformMatrix() const {
return m_deformMatrix; return m_deformMatrix;
} }
@@ -53,7 +53,7 @@ void geometryChange(const QRectF& newGeometry, const QRectF& oldGeometry) overri
void updatePolish() override; void updatePolish() override;
QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) override; QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) override;
virtual bool isInvertedRect() const { [[nodiscard]] virtual bool isInvertedRect() const {
return false; return false;
} }
@@ -72,10 +72,9 @@ void updateCenteredDeformMatrix();
BlobGroup* m_group = nullptr; BlobGroup* m_group = nullptr;
qreal m_radius = 0; qreal m_radius = 0;
QMatrix4x4 m_deformMatrix; // identity by default QMatrix4x4 m_deformMatrix;
QMatrix4x4 m_centeredDeformMatrix; QMatrix4x4 m_centeredDeformMatrix;
// Cached data from updatePolish
float m_cachedPaddedX = 0; float m_cachedPaddedX = 0;
float m_cachedPaddedY = 0; float m_cachedPaddedY = 0;
float m_cachedPaddedW = 0; float m_cachedPaddedW = 0;
+1
View File
@@ -50,6 +50,7 @@ qml_module(ZShell
Qt::Quick Qt::Quick
Qt::Concurrent Qt::Concurrent
Qt::Sql Qt::Sql
Qt::DBus
PkgConfig::Qalculate PkgConfig::Qalculate
) )
+1
View File
@@ -9,6 +9,7 @@ qml_module(ZShell-internal
sparklineitem.hpp sparklineitem.cpp sparklineitem.hpp sparklineitem.cpp
arcgauge.hpp arcgauge.cpp arcgauge.hpp arcgauge.cpp
wallpaperimage.hpp wallpaperimage.cpp wallpaperimage.hpp wallpaperimage.cpp
lidwatcher.hpp lidwatcher.cpp
LIBRARIES LIBRARIES
Qt::Gui Qt::Gui
Qt::Quick Qt::Quick
+1 -1
View File
@@ -58,4 +58,4 @@ qreal m_sweepAngle = 1.5 * M_PI;
qreal m_lineWidth = 10.0; qreal m_lineWidth = 10.0;
}; };
} // namespace ZShell::internal } // namespace ZShell::Internal
@@ -19,7 +19,8 @@ class CachingImageManager : public QObject {
public: public:
explicit CachingImageManager(QObject* parent = nullptr) explicit CachingImageManager(QObject* parent = nullptr)
: QObject(parent) : QObject(parent)
, m_item(nullptr) {} , m_item(nullptr) {
}
[[nodiscard]] QQuickItem* item() const; [[nodiscard]] QQuickItem* item() const;
void setItem(QQuickItem* item); void setItem(QQuickItem* item);
+2 -2
View File
@@ -2,7 +2,7 @@
#include <algorithm> #include <algorithm>
namespace caelestia::internal { namespace ZShell::internal {
CircularBuffer::CircularBuffer(QObject* parent) CircularBuffer::CircularBuffer(QObject* parent)
: QObject(parent) { : QObject(parent) {
@@ -92,4 +92,4 @@ qreal CircularBuffer::at(int index) const {
return m_data[actualIndex]; return m_data[actualIndex];
} }
} // namespace caelestia::internal } // namespace ZShell::internal
+2 -2
View File
@@ -4,7 +4,7 @@
#include <qqmlintegration.h> #include <qqmlintegration.h>
#include <qvector.h> #include <qvector.h>
namespace caelestia::internal { namespace ZShell::internal {
class CircularBuffer : public QObject { class CircularBuffer : public QObject {
Q_OBJECT Q_OBJECT
@@ -41,4 +41,4 @@ int m_count = 0;
int m_capacity = 0; int m_capacity = 0;
}; };
} // namespace caelestia::internal } // namespace ZShell::internal
@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <cstdint>
#include <qeasingcurve.h> #include <qeasingcurve.h>
#include <qobject.h> #include <qobject.h>
#include <qqmlintegration.h> #include <qqmlintegration.h>
+86
View File
@@ -0,0 +1,86 @@
#include "lidwatcher.hpp"
#include <QtDBus/qdbusconnection.h>
#include <QtDBus/qdbuserror.h>
#include <QtDBus/qdbusinterface.h>
#include <QtDBus/qdbusreply.h>
#include <qloggingcategory.h>
Q_LOGGING_CATEGORY(lcLidWatcher, "ZShell.internal.logindmanager", QtInfoMsg)
namespace ZShell::internal {
LidWatcher::LidWatcher(QObject* parent) : QObject(parent) {
auto bus = QDBusConnection::systemBus();
if (!bus.isConnected()) {
qCWarning(lcLidWatcher)
<< "Failed to connect to system bus:" << bus.lastError().message();
return;
}
bool ok = bus.connect("org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"PrepareForSleep",
this,
SLOT(handlePrepareForSleep(bool)));
if (!ok) {
qCWarning(lcLidWatcher)
<< "Failed to connect to PrepareForSleep signal:"
<< bus.lastError().message();
}
QDBusInterface login1("org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
bus);
const QDBusReply<QDBusObjectPath> reply = login1.call("GetSession", "auto");
if (!reply.isValid()) {
qCWarning(lcLidWatcher) << "Failed to get session path";
return;
}
const auto sessionPath = reply.value().path();
ok = bus.connect("org.freedesktop.login1",
sessionPath,
"org.freedesktop.login1.Session",
"Lock",
this,
SLOT(handleLockRequested()));
if (!ok) {
qCWarning(lcLidWatcher)
<< "Failed to connect to Lock signal:" << bus.lastError().message();
}
ok = bus.connect("org.freedesktop.login1",
sessionPath,
"org.freedesktop.login1.Session",
"Unlock",
this,
SLOT(handleUnlockRequested()));
if (!ok) {
qCWarning(lcLidWatcher) << "Failed to connect to Unlock signal:"
<< bus.lastError().message();
}
}
void LidWatcher::handlePrepareForSleep(bool sleep) {
if (sleep) {
emit aboutToSleep();
} else {
emit resumed();
}
}
void LidWatcher::handleLockRequested() {
emit lockRequested();
}
void LidWatcher::handleUnlockRequested() {
emit unlockRequested();
}
} // namespace ZShell::internal
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <qobject.h>
#include <qqmlintegration.h>
namespace ZShell::internal {
class LidWatcher : public QObject {
Q_OBJECT
QML_ELEMENT
public:
explicit LidWatcher(QObject* parent = nullptr);
signals:
void aboutToSleep();
void resumed();
void lockRequested();
void unlockRequested();
private slots:
void handlePrepareForSleep(bool sleep);
void handleLockRequested();
void handleUnlockRequested();
};
} // namespace ZShell::internal
+2 -2
View File
@@ -4,7 +4,7 @@
#include <qpainterpath.h> #include <qpainterpath.h>
#include <qpen.h> #include <qpen.h>
namespace caelestia::internal { namespace ZShell::internal {
SparklineItem::SparklineItem(QQuickItem* parent) SparklineItem::SparklineItem(QQuickItem* parent)
: QQuickPaintedItem(parent) { : QQuickPaintedItem(parent) {
@@ -212,4 +212,4 @@ void SparklineItem::setLineWidth(qreal width) {
update(); update();
} }
} // namespace caelestia::internal } // namespace ZShell::internal
+2 -2
View File
@@ -7,7 +7,7 @@
#include "circularbuffer.hpp" #include "circularbuffer.hpp"
namespace caelestia::internal { namespace ZShell::internal {
class SparklineItem : public QQuickPaintedItem { class SparklineItem : public QQuickPaintedItem {
Q_OBJECT Q_OBJECT
@@ -87,4 +87,4 @@ int m_historyLength = 30;
qreal m_lineWidth = 2.0; qreal m_lineWidth = 2.0;
}; };
} // namespace caelestia::internal } // namespace ZShell::internal
+4 -3
View File
@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <cstdint>
#include <qabstractitemmodel.h> #include <qabstractitemmodel.h>
#include <qdir.h> #include <qdir.h>
#include <qfilesystemwatcher.h> #include <qfilesystemwatcher.h>
@@ -85,9 +86,9 @@ public:
explicit FileSystemModel(QObject* parent = nullptr); explicit FileSystemModel(QObject* parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex()) const override; [[nodiscard]] int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; [[nodiscard]] QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override; [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
[[nodiscard]] QString path() const; [[nodiscard]] QString path() const;
void setPath(const QString& path); void setPath(const QString& path);
+1
View File
@@ -9,6 +9,7 @@ qml_module(ZShell-services
cavaprovider.hpp cavaprovider.cpp cavaprovider.hpp cavaprovider.cpp
desktopmodel.hpp desktopmodel.cpp desktopmodel.hpp desktopmodel.cpp
desktopstatemanager.hpp desktopstatemanager.cpp desktopstatemanager.hpp desktopstatemanager.cpp
hyprsunsetmanager.hpp hyprsunsetmanager.cpp
LIBRARIES LIBRARIES
Qt6::Core Qt6::Core
Qt6::Qml Qt6::Qml
+1 -1
View File
@@ -59,7 +59,7 @@ quint32 readChunk(double* out, quint32 count = 0);
private: private:
explicit AudioCollector(QObject* parent = nullptr); explicit AudioCollector(QObject* parent = nullptr);
~AudioCollector(); ~AudioCollector() override;
std::jthread m_thread; std::jthread m_thread;
std::vector<float> m_buffer1; std::vector<float> m_buffer1;
+2 -3
View File
@@ -11,11 +11,10 @@ Q_OBJECT
public: public:
explicit AudioProcessor(QObject* parent = nullptr); explicit AudioProcessor(QObject* parent = nullptr);
~AudioProcessor(); ~AudioProcessor() override;
void init(); void init();
public slots:
void start(); void start();
void stop(); void stop();
@@ -31,7 +30,7 @@ Q_OBJECT
public: public:
explicit AudioProvider(QObject* parent = nullptr); explicit AudioProvider(QObject* parent = nullptr);
~AudioProvider(); ~AudioProvider() override;
protected: protected:
AudioProcessor* m_processor; AudioProcessor* m_processor;
+1 -1
View File
@@ -11,7 +11,7 @@ Q_OBJECT
public: public:
explicit BeatProcessor(QObject* parent = nullptr); explicit BeatProcessor(QObject* parent = nullptr);
~BeatProcessor(); ~BeatProcessor() override;
signals: signals:
void beat(smpl_t bpm); void beat(smpl_t bpm);
+1 -1
View File
@@ -11,7 +11,7 @@ Q_OBJECT
public: public:
explicit CavaProcessor(QObject* parent = nullptr); explicit CavaProcessor(QObject* parent = nullptr);
~CavaProcessor(); ~CavaProcessor() override;
void setBars(int bars); void setBars(int bars);
+5 -4
View File
@@ -4,6 +4,7 @@
#include <QList> #include <QList>
#include <QString> #include <QString>
#include <QQmlEngine> #include <QQmlEngine>
#include <cstdint>
namespace ZShell::services { namespace ZShell::services {
@@ -30,9 +31,9 @@ enum DesktopRoles {
explicit DesktopModel(QObject *parent = nullptr); explicit DesktopModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override; [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE void loadDirectory(const QString &path); Q_INVOKABLE void loadDirectory(const QString &path);
Q_INVOKABLE void moveIcon(int index, int newX, int newY); Q_INVOKABLE void moveIcon(int index, int newX, int newY);
@@ -43,4 +44,4 @@ QList<DesktopItem> m_items;
void saveCurrentLayout(); void saveCurrentLayout();
}; };
} // namespace ZShell::services } // namespace ZShell::Services
@@ -18,7 +18,7 @@ Q_INVOKABLE void saveLayout(const QVariantMap& layout);
Q_INVOKABLE QVariantMap getLayout(); Q_INVOKABLE QVariantMap getLayout();
private: private:
QString getConfigFilePath() const; [[nodiscard]] QString getConfigFilePath() const;
}; };
} // namespace ZShell::services } // namespace ZShell::services
@@ -0,0 +1,147 @@
#include "hyprsunsetmanager.hpp"
#include <qlogging.h>
#include <qobject.h>
#include <qprocess.h>
#include <qtimer.h>
namespace ZShell::services {
HyprsunsetManager::HyprsunsetManager(QObject* parent) : QObject(parent) {
connect(&m_timer, &QTimer::timeout, this, &HyprsunsetManager::apply);
connect(&m_manualTimer, &QTimer::timeout, this, [this] {
m_manualToggle = false;
emit manualToggleChanged();
apply();
});
connect(&m_startCooldown, &QTimer::timeout, this, [this] {
m_startAllowed = true;
apply();
});
m_startCooldown.start(2000);
m_manualTimer.setSingleShot(true);
m_timer.start(60000);
m_process.setStandardInputFile(QProcess::nullDevice());
m_process.setStandardOutputFile(QProcess::nullDevice());
}
int HyprsunsetManager::startTime() const {
return m_startTime;
}
int HyprsunsetManager::endTime() const {
return m_endTime;
}
bool HyprsunsetManager::manualToggle() const {
return m_manualToggle;
}
bool HyprsunsetManager::enabled() const {
return m_enabled;
}
bool HyprsunsetManager::activeAuto() const {
return m_activeAuto;
}
int HyprsunsetManager::temp() const {
return m_temp;
}
void HyprsunsetManager::setActiveAuto(bool activeAuto) {
if (activeAuto == m_activeAuto)
return;
m_activeAuto = activeAuto;
emit activeAutoChanged();
}
void HyprsunsetManager::setManualToggle(bool toggle) {
if (toggle == m_manualToggle)
return;
m_manualToggle = toggle;
emit manualToggleChanged();
m_manualTimer.start(60 * 60 * 1000);
}
void HyprsunsetManager::setEndTime(const int& time) {
if (time == m_endTime)
return;
m_endTime = time;
emit endTimeChanged();
apply();
}
void HyprsunsetManager::setStartTime(const int& time) {
if (time == m_startTime)
return;
m_startTime = time;
emit startTimeChanged();
apply();
}
void HyprsunsetManager::setTemp(const int& temp) {
if (temp == m_temp)
return;
m_temp = temp;
emit tempChanged();
apply();
}
void HyprsunsetManager::toggle() {
if (m_enabled) {
end();
} else {
start();
}
}
void HyprsunsetManager::start() {
if (m_enabled && m_initialized)
return;
m_initialized = true;
m_enabled = true;
emit enabledChanged();
m_process.setProgram("hyprctl");
m_process.setArguments({"hyprsunset", "temperature", QString::number(m_temp)});
m_process.startDetached();
}
void HyprsunsetManager::end() {
if (!m_enabled && m_initialized)
return;
m_initialized = true;
m_enabled = false;
emit enabledChanged();
m_process.setProgram("hyprctl");
m_process.setArguments({"hyprsunset", "identity"});
m_process.startDetached();
}
void HyprsunsetManager::apply() {
if (m_manualToggle || !m_activeAuto || !m_startAllowed)
return;
const auto current = QTime::currentTime().hour();
if (current >= m_startTime || current < m_endTime) {
start();
} else {
end();
}
}
};
@@ -0,0 +1,66 @@
#pragma once
#include <QObject>
#include <QTime>
#include <QProcess>
#include <QTimer>
#include <qqmlintegration.h>
#include <qtmetamacros.h>
namespace ZShell::services {
class HyprsunsetManager : public QObject {
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged)
Q_PROPERTY(int startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
Q_PROPERTY(int endTime READ endTime WRITE setEndTime NOTIFY endTimeChanged)
Q_PROPERTY(int temp READ temp WRITE setTemp NOTIFY tempChanged)
Q_PROPERTY(bool activeAuto READ activeAuto WRITE setActiveAuto NOTIFY activeAutoChanged)
Q_PROPERTY(bool manualToggle READ manualToggle WRITE setManualToggle NOTIFY manualToggleChanged)
public:
explicit HyprsunsetManager(QObject* parent = nullptr);
[[nodiscard]] int startTime() const;
[[nodiscard]] int endTime() const;
[[nodiscard]] bool enabled() const;
[[nodiscard]] int temp() const;
[[nodiscard]] bool activeAuto() const;
[[nodiscard]] bool manualToggle() const;
Q_INVOKABLE void toggle();
Q_INVOKABLE void apply();
void setStartTime(const int& time);
void setEndTime(const int& time);
void setTemp(const int& temp);
void setActiveAuto(bool activeAuto);
void setManualToggle(bool toggle);
signals:
void enabledChanged();
void startTimeChanged();
void activeAutoChanged();
void endTimeChanged();
void tempChanged();
void manualToggleChanged();
private:
int m_startTime;
int m_endTime;
bool m_enabled = false;
bool m_manualToggle = false;
bool m_activeAuto;
bool m_startAllowed = false;
bool m_initialized = false;
QTimer m_startCooldown;
int m_temp;
QProcess m_process;
QTimer m_timer;
QTimer m_manualTimer;
void start();
void end();
};
};
+1 -1
View File
@@ -13,7 +13,7 @@ QML_SINGLETON
public: public:
explicit Qalculator(QObject* parent = nullptr); explicit Qalculator(QObject* parent = nullptr);
Q_INVOKABLE QString eval(const QString& expr, bool printExpr = true) const; Q_INVOKABLE [[nodiscard]] QString eval(const QString& expr, bool printExpr = true) const;
}; };
} // namespace ZShell } // namespace ZShell
+2 -1
View File
@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <cstdint>
#include <qobject.h> #include <qobject.h>
#include <qqmlintegration.h> #include <qqmlintegration.h>
#include <qqmllist.h> #include <qqmllist.h>
@@ -20,7 +21,7 @@ Q_PROPERTY(int timeout READ timeout CONSTANT)
Q_PROPERTY(Type type READ type CONSTANT) Q_PROPERTY(Type type READ type CONSTANT)
public: public:
enum class Type { enum class Type: std::uint8_t {
Info = 0, Info = 0,
Success, Success,
Warning, Warning,
+3 -3
View File
@@ -29,9 +29,9 @@ Q_INVOKABLE void cacheImage(const QUrl& source, const QString& cacheDir, QJSValu
Q_INVOKABLE void cacheImage(const QUrl& source, const QString& cacheDir, QJSValue onSaved, QJSValue onFailed); Q_INVOKABLE void cacheImage(const QUrl& source, const QString& cacheDir, QJSValue onSaved, QJSValue onFailed);
// clang-format on // clang-format on
Q_INVOKABLE bool copyFile(const QUrl& source, const QUrl& target, bool overwrite = true) const; Q_INVOKABLE [[nodiscard]] bool copyFile(const QUrl& source, const QUrl& target, bool overwrite = true) const;
Q_INVOKABLE bool deleteFile(const QUrl& path) const; Q_INVOKABLE [[nodiscard]] bool deleteFile(const QUrl& path) const;
Q_INVOKABLE QString toLocalFile(const QUrl& url) const; Q_INVOKABLE [[nodiscard]] QString toLocalFile(const QUrl& url) const;
private: private:
bool loadSourceImage(const QUrl& source, QImage& image) const; bool loadSourceImage(const QUrl& source, QImage& image) const;
+1 -1
View File
@@ -48,7 +48,7 @@ ShellRoot {
LazyLoader { LazyLoader {
activeAsync: root.laptop activeAsync: root.laptop
component: Battery { component: BatteryService {
} }
} }
} }