formatter

This commit is contained in:
Zacharias-Brohn
2026-02-24 23:20:11 +01:00
parent 40cd984b6d
commit d56a0260fb
202 changed files with 15037 additions and 15352 deletions
+1 -1
View File
@@ -3,6 +3,6 @@ import qs.Config
NumberAnimation { NumberAnimation {
duration: MaterialEasing.standardTime duration: MaterialEasing.standardTime
easing.type: Easing.BezierSpline
easing.bezierCurve: MaterialEasing.standard easing.bezierCurve: MaterialEasing.standard
easing.type: Easing.BezierSpline
} }
+1 -1
View File
@@ -3,6 +3,6 @@ import qs.Config
ColorAnimation { ColorAnimation {
duration: MaterialEasing.standardTime duration: MaterialEasing.standardTime
easing.type: Easing.BezierSpline
easing.bezierCurve: MaterialEasing.standard easing.bezierCurve: MaterialEasing.standard
easing.type: Easing.BezierSpline
} }
+50 -54
View File
@@ -6,31 +6,54 @@ import QtQuick.Templates
BusyIndicator { BusyIndicator {
id: root id: root
enum AnimType {
Advance = 0,
Retreat
}
enum AnimState { enum AnimState {
Stopped, Stopped,
Running, Running,
Completing Completing
} }
enum AnimType {
Advance = 0,
Retreat
}
property real implicitSize: Appearance.font.size.normal * 3
property real strokeWidth: Appearance.padding.small * 0.8
property color fgColour: DynamicColors.palette.m3primary
property color bgColour: DynamicColors.palette.m3secondaryContainer
property alias type: manager.indeterminateAnimationType
readonly property alias progress: manager.progress
property real internalStrokeWidth: strokeWidth
property int animState property int animState
property color bgColour: DynamicColors.palette.m3secondaryContainer
property color fgColour: DynamicColors.palette.m3primary
property real implicitSize: Appearance.font.size.normal * 3
property real internalStrokeWidth: strokeWidth
readonly property alias progress: manager.progress
property real strokeWidth: Appearance.padding.small * 0.8
property alias type: manager.indeterminateAnimationType
padding: 0
implicitWidth: implicitSize
implicitHeight: implicitSize implicitHeight: implicitSize
implicitWidth: implicitSize
padding: 0
contentItem: CircularProgress {
anchors.fill: parent
bgColour: root.bgColour
fgColour: root.fgColour
padding: root.padding
rotation: manager.rotation
startAngle: manager.startFraction * 360
strokeWidth: root.internalStrokeWidth
value: manager.endFraction - manager.startFraction
}
states: State {
name: "stopped"
when: !root.running
PropertyChanges {
root.internalStrokeWidth: root.strokeWidth / 3
root.opacity: 0
}
}
transitions: Transition {
Anim {
duration: manager.completeEndDuration * Appearance.anim.durations.scale
properties: "opacity,internalStrokeWidth"
}
}
Component.onCompleted: { Component.onCompleted: {
if (running) { if (running) {
@@ -38,7 +61,6 @@ BusyIndicator {
running = true; running = true;
} }
} }
onRunningChanged: { onRunningChanged: {
if (running) { if (running) {
manager.completeEndProgress = 0; manager.completeEndProgress = 0;
@@ -49,55 +71,29 @@ BusyIndicator {
} }
} }
states: State {
name: "stopped"
when: !root.running
PropertyChanges {
root.opacity: 0
root.internalStrokeWidth: root.strokeWidth / 3
}
}
transitions: Transition {
Anim {
properties: "opacity,internalStrokeWidth"
duration: manager.completeEndDuration * Appearance.anim.durations.scale
}
}
contentItem: CircularProgress {
anchors.fill: parent
strokeWidth: root.internalStrokeWidth
fgColour: root.fgColour
bgColour: root.bgColour
padding: root.padding
rotation: manager.rotation
startAngle: manager.startFraction * 360
value: manager.endFraction - manager.startFraction
}
CircularIndicatorManager { CircularIndicatorManager {
id: manager id: manager
} }
NumberAnimation { NumberAnimation {
running: root.animState !== CircularIndicator.Stopped
loops: Animation.Infinite
target: manager
property: "progress"
from: 0
to: 1
duration: manager.duration * Appearance.anim.durations.scale duration: manager.duration * Appearance.anim.durations.scale
from: 0
loops: Animation.Infinite
property: "progress"
running: root.animState !== CircularIndicator.Stopped
target: manager
to: 1
} }
NumberAnimation { NumberAnimation {
duration: manager.completeEndDuration * Appearance.anim.durations.scale
from: 0
property: "completeEndProgress"
running: root.animState === CircularIndicator.Completing running: root.animState === CircularIndicator.Completing
target: manager target: manager
property: "completeEndProgress"
from: 0
to: 1 to: 1
duration: manager.completeEndDuration * Appearance.anim.durations.scale
onFinished: { onFinished: {
if (root.animState === CircularIndicator.Completing) if (root.animState === CircularIndicator.Completing)
root.animState = CircularIndicator.Stopped; root.animState = CircularIndicator.Stopped;
+29 -30
View File
@@ -5,63 +5,62 @@ import qs.Config
Shape { Shape {
id: root id: root
property real value readonly property real arcRadius: (size - padding - strokeWidth) / 2
property color bgColour: DynamicColors.palette.m3secondaryContainer
property color fgColour: DynamicColors.palette.m3primary
readonly property real gapAngle: ((spacing + strokeWidth) / (arcRadius || 1)) * (180 / Math.PI)
property int padding: 0
readonly property real size: Math.min(width, height)
property int spacing: Appearance.spacing.small
property int startAngle: -90 property int startAngle: -90
property int strokeWidth: Appearance.padding.smaller property int strokeWidth: Appearance.padding.smaller
property int padding: 0
property int spacing: Appearance.spacing.small
property color fgColour: DynamicColors.palette.m3primary
property color bgColour: DynamicColors.palette.m3secondaryContainer
readonly property real size: Math.min(width, height)
readonly property real arcRadius: (size - padding - strokeWidth) / 2
readonly property real vValue: value || 1 / 360 readonly property real vValue: value || 1 / 360
readonly property real gapAngle: ((spacing + strokeWidth) / (arcRadius || 1)) * (180 / Math.PI) property real value
preferredRendererType: Shape.CurveRenderer
asynchronous: true asynchronous: true
preferredRendererType: Shape.CurveRenderer
ShapePath { ShapePath {
capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap
fillColor: "transparent" fillColor: "transparent"
strokeColor: root.bgColour strokeColor: root.bgColour
strokeWidth: root.strokeWidth strokeWidth: root.strokeWidth
capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap
PathAngleArc {
startAngle: root.startAngle + 360 * root.vValue + root.gapAngle
sweepAngle: Math.max(-root.gapAngle, 360 * (1 - root.vValue) - root.gapAngle * 2)
radiusX: root.arcRadius
radiusY: root.arcRadius
centerX: root.size / 2
centerY: root.size / 2
}
Behavior on strokeColor { Behavior on strokeColor {
CAnim { CAnim {
duration: Appearance.anim.durations.large duration: Appearance.anim.durations.large
} }
} }
PathAngleArc {
centerX: root.size / 2
centerY: root.size / 2
radiusX: root.arcRadius
radiusY: root.arcRadius
startAngle: root.startAngle + 360 * root.vValue + root.gapAngle
sweepAngle: Math.max(-root.gapAngle, 360 * (1 - root.vValue) - root.gapAngle * 2)
}
} }
ShapePath { ShapePath {
capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap
fillColor: "transparent" fillColor: "transparent"
strokeColor: root.fgColour strokeColor: root.fgColour
strokeWidth: root.strokeWidth strokeWidth: root.strokeWidth
capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap
PathAngleArc {
startAngle: root.startAngle
sweepAngle: 360 * root.vValue
radiusX: root.arcRadius
radiusY: root.arcRadius
centerX: root.size / 2
centerY: root.size / 2
}
Behavior on strokeColor { Behavior on strokeColor {
CAnim { CAnim {
duration: Appearance.anim.durations.large duration: Appearance.anim.durations.large
} }
} }
PathAngleArc {
centerX: root.size / 2
centerY: root.size / 2
radiusX: root.arcRadius
radiusY: root.arcRadius
startAngle: root.startAngle
sweepAngle: 360 * root.vValue
}
} }
} }
+2 -3
View File
@@ -10,18 +10,17 @@ IconImage {
required property color color required property color color
asynchronous: true asynchronous: true
layer.enabled: true layer.enabled: true
layer.effect: Coloriser { layer.effect: Coloriser {
sourceColor: analyser.dominantColour
colorizationColor: root.color colorizationColor: root.color
sourceColor: analyser.dominantColour
} }
layer.onEnabledChanged: { layer.onEnabledChanged: {
if (layer.enabled && status === Image.Ready) if (layer.enabled && status === Image.Ready)
analyser.requestUpdate(); analyser.requestUpdate();
} }
onStatusChanged: { onStatusChanged: {
if (layer.enabled && status === Image.Ready) if (layer.enabled && status === Image.Ready)
analyser.requestUpdate(); analyser.requestUpdate();
+3 -2
View File
@@ -4,10 +4,11 @@ import QtQuick.Effects
MultiEffect { MultiEffect {
property color sourceColor: "black" property color sourceColor: "black"
colorization: 1
brightness: 1 - sourceColor.hslLightness brightness: 1 - sourceColor.hslLightness
colorization: 1
Behavior on colorizationColor { Behavior on colorizationColor {
CAnim {} CAnim {
}
} }
} }
+28 -36
View File
@@ -5,77 +5,69 @@ import qs.Config
Slider { Slider {
id: root id: root
required property real peak
property color nonPeakColor: DynamicColors.tPalette.m3primary property color nonPeakColor: DynamicColors.tPalette.m3primary
required property real peak
property color peakColor: DynamicColors.palette.m3primary property color peakColor: DynamicColors.palette.m3primary
background: Item { background: Item {
CustomRect { CustomRect {
anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.topMargin: root.implicitHeight / 3
anchors.bottomMargin: root.implicitHeight / 3 anchors.bottomMargin: root.implicitHeight / 3
anchors.left: parent.left
implicitWidth: root.handle.x - root.implicitHeight anchors.top: parent.top
anchors.topMargin: root.implicitHeight / 3
bottomRightRadius: root.implicitHeight / 15
color: root.nonPeakColor color: root.nonPeakColor
implicitWidth: root.handle.x - root.implicitHeight
radius: 1000 radius: 1000
topRightRadius: root.implicitHeight / 15 topRightRadius: root.implicitHeight / 15
bottomRightRadius: root.implicitHeight / 15
CustomRect { CustomRect {
anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top
bottomRightRadius: root.implicitHeight / 15
color: root.peakColor
implicitWidth: parent.width * root.peak implicitWidth: parent.width * root.peak
radius: 1000 radius: 1000
topRightRadius: root.implicitHeight / 15 topRightRadius: root.implicitHeight / 15
bottomRightRadius: root.implicitHeight / 15
color: root.peakColor
Behavior on implicitWidth { Behavior on implicitWidth {
Anim { duration: 50 } Anim {
duration: 50
}
} }
} }
} }
CustomRect { CustomRect {
anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.topMargin: root.implicitHeight / 3
anchors.bottomMargin: root.implicitHeight / 3 anchors.bottomMargin: root.implicitHeight / 3
anchors.right: parent.right
implicitWidth: root.implicitWidth - root.handle.x - root.handle.implicitWidth - root.implicitHeight anchors.top: parent.top
anchors.topMargin: root.implicitHeight / 3
Component.onCompleted: { bottomLeftRadius: root.implicitHeight / 15
console.log(root.handle.x, implicitWidth)
}
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
implicitWidth: root.implicitWidth - root.handle.x - root.handle.implicitWidth - root.implicitHeight
radius: 1000 radius: 1000
topLeftRadius: root.implicitHeight / 15 topLeftRadius: root.implicitHeight / 15
bottomLeftRadius: root.implicitHeight / 15
}
}
Component.onCompleted: {
console.log(root.handle.x, implicitWidth);
}
}
}
handle: CustomRect { handle: CustomRect {
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.palette.m3primary
implicitHeight: 15
implicitWidth: 5
radius: 1000
x: root.visualPosition * root.availableWidth - implicitWidth / 2 x: root.visualPosition * root.availableWidth - implicitWidth / 2
implicitWidth: 5
implicitHeight: 15
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.palette.m3primary
radius: 1000
MouseArea { MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }
} }
+20 -16
View File
@@ -3,20 +3,22 @@ import QtQuick.Controls.Basic
BusyIndicator { BusyIndicator {
id: control id: control
property color color: delegate.color
property int busySize: 64 property int busySize: 64
property color color: delegate.color
contentItem: Item { contentItem: Item {
implicitWidth: control.busySize
implicitHeight: control.busySize implicitHeight: control.busySize
implicitWidth: control.busySize
Item { Item {
id: item id: item
x: parent.width / 2 - (control.busySize / 2)
y: parent.height / 2 - (control.busySize / 2)
width: control.busySize
height: control.busySize height: control.busySize
opacity: control.running ? 1 : 0 opacity: control.running ? 1 : 0
width: control.busySize
x: parent.width / 2 - (control.busySize / 2)
y: parent.height / 2 - (control.busySize / 2)
Behavior on opacity { Behavior on opacity {
OpacityAnimator { OpacityAnimator {
@@ -25,29 +27,31 @@ BusyIndicator {
} }
RotationAnimator { RotationAnimator {
target: item
running: control.visible && control.running
from: 0
to: 360
loops: Animation.Infinite
duration: 1250 duration: 1250
from: 0
loops: Animation.Infinite
running: control.visible && control.running
target: item
to: 360
} }
Repeater { Repeater {
id: repeater id: repeater
model: 6 model: 6
CustomRect { CustomRect {
id: delegate id: delegate
x: item.width / 2 - width / 2
y: item.height / 2 - height / 2
implicitWidth: 10
implicitHeight: 10
radius: 5
color: control.color
required property int index required property int index
color: control.color
implicitHeight: 10
implicitWidth: 10
radius: 5
x: item.width / 2 - width / 2
y: item.height / 2 - height / 2
transform: [ transform: [
Translate { Translate {
y: -Math.min(item.width, item.height) * 0.5 + 5 y: -Math.min(item.width, item.height) * 0.5 + 5
+10 -12
View File
@@ -4,30 +4,28 @@ import QtQuick.Controls
Button { Button {
id: control id: control
required property color textColor
required property color bgColor required property color bgColor
property int radius: 4 property int radius: 4
required property color textColor
contentItem: CustomText { background: CustomRect {
text: control.text color: control.bgColor
opacity: control.enabled ? 1.0 : 0.5 opacity: control.enabled ? 1.0 : 0.5
radius: control.radius
}
contentItem: CustomText {
color: control.textColor color: control.textColor
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
opacity: control.enabled ? 1.0 : 0.5
text: control.text
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
background: CustomRect {
opacity: control.enabled ? 1.0 : 0.5
radius: control.radius
color: control.bgColor
}
StateLayer { StateLayer {
radius: control.radius
function onClicked(): void { function onClicked(): void {
control.clicked(); control.clicked();
} }
radius: control.radius
} }
} }
+14 -16
View File
@@ -5,35 +5,33 @@ import qs.Config
CheckBox { CheckBox {
id: control id: control
property int checkWidth: 20
property int checkHeight: 20 property int checkHeight: 20
property int checkWidth: 20
contentItem: CustomText {
anchors.left: parent.left
anchors.leftMargin: control.checkWidth + control.leftPadding + 8
anchors.verticalCenter: parent.verticalCenter
font.pointSize: control.font.pointSize
text: control.text
}
indicator: CustomRect { indicator: CustomRect {
implicitWidth: control.checkWidth
implicitHeight: control.checkHeight
// x: control.leftPadding // x: control.leftPadding
// y: parent.implicitHeight / 2 - implicitHeight / 2 // y: parent.implicitHeight / 2 - implicitHeight / 2
border.color: control.checked ? DynamicColors.palette.m3primary : "transparent" border.color: control.checked ? DynamicColors.palette.m3primary : "transparent"
color: DynamicColors.palette.m3surfaceVariant color: DynamicColors.palette.m3surfaceVariant
implicitHeight: control.checkHeight
implicitWidth: control.checkWidth
radius: 4 radius: 4
CustomRect { CustomRect {
implicitWidth: control.checkWidth - (x * 2) color: DynamicColors.palette.m3primary
implicitHeight: control.checkHeight - (y * 2) implicitHeight: control.checkHeight - (y * 2)
implicitWidth: control.checkWidth - (x * 2)
radius: 3
visible: control.checked
x: 4 x: 4
y: 4 y: 4
radius: 3
color: DynamicColors.palette.m3primary
visible: control.checked
} }
} }
contentItem: CustomText {
text: control.text
font.pointSize: control.font.pointSize
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: control.checkWidth + control.leftPadding + 8
}
} }
+2 -1
View File
@@ -7,6 +7,7 @@ ClippingRectangle {
color: "transparent" color: "transparent"
Behavior on color { Behavior on color {
CAnim {} CAnim {
}
} }
} }
+25 -27
View File
@@ -6,50 +6,48 @@ RadioButton {
id: root id: root
font.pointSize: 12 font.pointSize: 12
implicitWidth: implicitIndicatorWidth + implicitContentWidth + contentItem.anchors.leftMargin
implicitHeight: Math.max(implicitIndicatorHeight, implicitContentHeight) implicitHeight: Math.max(implicitIndicatorHeight, implicitContentHeight)
implicitWidth: implicitIndicatorWidth + implicitContentWidth + contentItem.anchors.leftMargin
contentItem: CustomText {
anchors.left: outerCircle.right
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
font.pointSize: root.font.pointSize
text: root.text
}
indicator: Rectangle { indicator: Rectangle {
id: outerCircle id: outerCircle
implicitWidth: 16 anchors.verticalCenter: parent.verticalCenter
implicitHeight: 16
radius: 1000
color: "transparent"
border.color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant border.color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant
border.width: 2 border.width: 2
anchors.verticalCenter: parent.verticalCenter color: "transparent"
implicitHeight: 16
implicitWidth: 16
radius: 1000
Behavior on border.color {
CAnim {
}
}
StateLayer { StateLayer {
anchors.margins: -7
color: root.checked ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3primary
z: -1
function onClicked(): void { function onClicked(): void {
root.click(); root.click();
} }
anchors.margins: -7
color: root.checked ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3primary
z: -1
} }
CustomRect { CustomRect {
anchors.centerIn: parent anchors.centerIn: parent
implicitWidth: 8
implicitHeight: 8
radius: 1000
color: Qt.alpha(DynamicColors.palette.m3primary, root.checked ? 1 : 0) color: Qt.alpha(DynamicColors.palette.m3primary, root.checked ? 1 : 0)
} implicitHeight: 8
implicitWidth: 8
Behavior on border.color { radius: 1000
CAnim {}
} }
} }
contentItem: CustomText {
text: root.text
font.pointSize: root.font.pointSize
anchors.verticalCenter: parent.verticalCenter
anchors.left: outerCircle.right
anchors.leftMargin: 10
}
} }
+2 -1
View File
@@ -6,6 +6,7 @@ Rectangle {
color: "transparent" color: "transparent"
Behavior on color { Behavior on color {
CAnim {} CAnim {
}
} }
} }
+95 -94
View File
@@ -5,11 +5,62 @@ import QtQuick.Templates
ScrollBar { ScrollBar {
id: root id: root
required property Flickable flickable property bool _updatingFromFlickable: false
property bool shouldBeActive property bool _updatingFromUser: false
property real nonAnimPosition
property bool animating property bool animating
required property Flickable flickable
property real nonAnimPosition
property bool shouldBeActive
implicitWidth: 8
contentItem: CustomRect {
anchors.left: parent.left
anchors.right: parent.right
color: DynamicColors.palette.m3secondary
opacity: {
if (root.size === 1)
return 0;
if (fullMouse.pressed)
return 1;
if (mouse.containsMouse)
return 0.8;
if (root.policy === ScrollBar.AlwaysOn || root.shouldBeActive)
return 0.6;
return 0;
}
radius: 1000
Behavior on opacity {
Anim {
}
}
MouseArea {
id: mouse
acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
}
}
Behavior on position {
enabled: !fullMouse.pressed
Anim {
}
}
Component.onCompleted: {
if (flickable) {
const contentHeight = flickable.contentHeight;
const height = flickable.height;
if (contentHeight > height) {
nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height)));
}
}
}
onHoveredChanged: { onHoveredChanged: {
if (hovered) if (hovered)
shouldBeActive = true; shouldBeActive = true;
@@ -17,9 +68,6 @@ ScrollBar {
shouldBeActive = flickable.moving; shouldBeActive = flickable.moving;
} }
property bool _updatingFromFlickable: false
property bool _updatingFromUser: false
// Sync nonAnimPosition with Qt's automatic position binding // Sync nonAnimPosition with Qt's automatic position binding
onPositionChanged: { onPositionChanged: {
if (_updatingFromUser) { if (_updatingFromUser) {
@@ -37,7 +85,6 @@ ScrollBar {
// Sync nonAnimPosition with flickable when not animating // Sync nonAnimPosition with flickable when not animating
Connections { Connections {
target: flickable
function onContentYChanged() { function onContentYChanged() {
if (!animating && !fullMouse.pressed) { if (!animating && !fullMouse.pressed) {
_updatingFromFlickable = true; _updatingFromFlickable = true;
@@ -51,111 +98,32 @@ ScrollBar {
_updatingFromFlickable = false; _updatingFromFlickable = false;
} }
} }
}
Component.onCompleted: { target: flickable
if (flickable) {
const contentHeight = flickable.contentHeight;
const height = flickable.height;
if (contentHeight > height) {
nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height)));
}
}
}
implicitWidth: 8
contentItem: CustomRect {
anchors.left: parent.left
anchors.right: parent.right
opacity: {
if (root.size === 1)
return 0;
if (fullMouse.pressed)
return 1;
if (mouse.containsMouse)
return 0.8;
if (root.policy === ScrollBar.AlwaysOn || root.shouldBeActive)
return 0.6;
return 0;
}
radius: 1000
color: DynamicColors.palette.m3secondary
MouseArea {
id: mouse
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
acceptedButtons: Qt.NoButton
}
Behavior on opacity {
Anim {}
}
} }
Connections { Connections {
target: root.flickable
function onMovingChanged(): void { function onMovingChanged(): void {
if (root.flickable.moving) if (root.flickable.moving)
root.shouldBeActive = true; root.shouldBeActive = true;
else else
hideDelay.restart(); hideDelay.restart();
} }
target: root.flickable
} }
Timer { Timer {
id: hideDelay id: hideDelay
interval: 600 interval: 600
onTriggered: root.shouldBeActive = root.flickable.moving || root.hovered onTriggered: root.shouldBeActive = root.flickable.moving || root.hovered
} }
CustomMouseArea { CustomMouseArea {
id: fullMouse id: fullMouse
anchors.fill: parent
preventStealing: true
onPressed: event => {
root.animating = true;
root._updatingFromUser = true;
const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2));
root.nonAnimPosition = newPos;
// Update flickable position
// Map scrollbar position [0, 1-size] to contentY [0, maxContentY]
if (root.flickable) {
const contentHeight = root.flickable.contentHeight;
const height = root.flickable.height;
if (contentHeight > height) {
const maxContentY = contentHeight - height;
const maxPos = 1 - root.size;
const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0;
root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY));
}
}
}
onPositionChanged: event => {
root._updatingFromUser = true;
const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2));
root.nonAnimPosition = newPos;
// Update flickable position
// Map scrollbar position [0, 1-size] to contentY [0, maxContentY]
if (root.flickable) {
const contentHeight = root.flickable.contentHeight;
const height = root.flickable.height;
if (contentHeight > height) {
const maxContentY = contentHeight - height;
const maxPos = 1 - root.size;
const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0;
root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY));
}
}
}
function onWheel(event: WheelEvent): void { function onWheel(event: WheelEvent): void {
root.animating = true; root.animating = true;
root._updatingFromUser = true; root._updatingFromUser = true;
@@ -178,11 +146,44 @@ ScrollBar {
} }
} }
} }
}
Behavior on position { anchors.fill: parent
enabled: !fullMouse.pressed preventStealing: true
Anim {} onPositionChanged: event => {
root._updatingFromUser = true;
const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2));
root.nonAnimPosition = newPos;
// Update flickable position
// Map scrollbar position [0, 1-size] to contentY [0, maxContentY]
if (root.flickable) {
const contentHeight = root.flickable.contentHeight;
const height = root.flickable.height;
if (contentHeight > height) {
const maxContentY = contentHeight - height;
const maxPos = 1 - root.size;
const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0;
root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY));
}
}
}
onPressed: event => {
root.animating = true;
root._updatingFromUser = true;
const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2));
root.nonAnimPosition = newPos;
// Update flickable position
// Map scrollbar position [0, 1-size] to contentY [0, maxContentY]
if (root.flickable) {
const contentHeight = root.flickable.contentHeight;
const height = root.flickable.height;
if (contentHeight > height) {
const maxContentY = contentHeight - height;
const maxPos = 1 - root.size;
const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0;
root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY));
}
}
}
} }
} }
+12 -19
View File
@@ -7,45 +7,38 @@ Slider {
background: Item { background: Item {
CustomRect { CustomRect {
anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top
implicitWidth: root.handle.x - root.implicitHeight / 2 bottomRightRadius: root.implicitHeight / 6
color: DynamicColors.palette.m3primary color: DynamicColors.palette.m3primary
implicitWidth: root.handle.x - root.implicitHeight / 2
radius: 1000 radius: 1000
topRightRadius: root.implicitHeight / 6 topRightRadius: root.implicitHeight / 6
bottomRightRadius: root.implicitHeight / 6
} }
CustomRect { CustomRect {
anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top
implicitWidth: parent.width - root.handle.x - root.handle.implicitWidth - root.implicitHeight / 2 bottomLeftRadius: root.implicitHeight / 6
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
implicitWidth: parent.width - root.handle.x - root.handle.implicitWidth - root.implicitHeight / 2
radius: 1000 radius: 1000
topLeftRadius: root.implicitHeight / 6 topLeftRadius: root.implicitHeight / 6
bottomLeftRadius: root.implicitHeight / 6
} }
} }
handle: CustomRect { handle: CustomRect {
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.palette.m3primary
implicitHeight: 15
implicitWidth: 5
radius: 1000
x: root.visualPosition * root.availableWidth - implicitWidth / 2 x: root.visualPosition * root.availableWidth - implicitWidth / 2
implicitWidth: 5
implicitHeight: 15
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.palette.m3primary
radius: 1000
MouseArea { MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }
} }
+63 -58
View File
@@ -8,49 +8,49 @@ Switch {
property int cLayer: 1 property int cLayer: 1
implicitWidth: implicitIndicatorWidth
implicitHeight: implicitIndicatorHeight implicitHeight: implicitIndicatorHeight
implicitWidth: implicitIndicatorWidth
indicator: CustomRect { indicator: CustomRect {
radius: 1000
color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer) color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer)
implicitWidth: implicitHeight * 1.7
implicitHeight: 13 + 7 * 2 implicitHeight: 13 + 7 * 2
implicitWidth: implicitHeight * 1.7
radius: 1000
CustomRect { CustomRect {
readonly property real nonAnimWidth: root.pressed ? implicitHeight * 1.3 : implicitHeight readonly property real nonAnimWidth: root.pressed ? implicitHeight * 1.3 : implicitHeight
radius: 1000
color: root.checked ? DynamicColors.palette.m3onPrimary : DynamicColors.layer(DynamicColors.palette.m3outline, root.cLayer + 1)
x: root.checked ? parent.implicitWidth - nonAnimWidth - 10 / 2 : 10 / 2
implicitWidth: nonAnimWidth
implicitHeight: parent.implicitHeight - 10
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: root.checked ? DynamicColors.palette.m3onPrimary : DynamicColors.layer(DynamicColors.palette.m3outline, root.cLayer + 1)
implicitHeight: parent.implicitHeight - 10
implicitWidth: nonAnimWidth
radius: 1000
x: root.checked ? parent.implicitWidth - nonAnimWidth - 10 / 2 : 10 / 2
Behavior on implicitWidth {
Anim {
}
}
Behavior on x {
Anim {
}
}
CustomRect { CustomRect {
anchors.fill: parent anchors.fill: parent
radius: parent.radius
color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurface color: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurface
opacity: root.pressed ? 0.1 : root.hovered ? 0.08 : 0 opacity: root.pressed ? 0.1 : root.hovered ? 0.08 : 0
radius: parent.radius
Behavior on opacity { Behavior on opacity {
Anim {} Anim {
}
} }
} }
Shape { Shape {
id: icon id: icon
property point start1: {
if (root.pressed)
return Qt.point(width * 0.1, height / 2);
if (root.checked)
return Qt.point(width * 0.15, height / 2);
return Qt.point(width * 0.15, height * 0.15);
}
property point end1: { property point end1: {
if (root.pressed) { if (root.pressed) {
if (root.checked) if (root.checked)
@@ -61,6 +61,20 @@ Switch {
return Qt.point(width * 0.4, height * 0.7); return Qt.point(width * 0.4, height * 0.7);
return Qt.point(width * 0.85, height * 0.85); return Qt.point(width * 0.85, height * 0.85);
} }
property point end2: {
if (root.pressed)
return Qt.point(width, height / 2);
if (root.checked)
return Qt.point(width * 0.85, height * 0.2);
return Qt.point(width * 0.85, height * 0.15);
}
property point start1: {
if (root.pressed)
return Qt.point(width * 0.1, height / 2);
if (root.checked)
return Qt.point(width * 0.15, height / 2);
return Qt.point(width * 0.15, height * 0.15);
}
property point start2: { property point start2: {
if (root.pressed) { if (root.pressed) {
if (root.checked) if (root.checked)
@@ -71,68 +85,59 @@ Switch {
return Qt.point(width * 0.4, height * 0.7); return Qt.point(width * 0.4, height * 0.7);
return Qt.point(width * 0.15, height * 0.85); return Qt.point(width * 0.15, height * 0.85);
} }
property point end2: {
if (root.pressed)
return Qt.point(width, height / 2);
if (root.checked)
return Qt.point(width * 0.85, height * 0.2);
return Qt.point(width * 0.85, height * 0.15);
}
anchors.centerIn: parent anchors.centerIn: parent
width: height asynchronous: true
height: parent.implicitHeight - Appearance.padding.small * 2 height: parent.implicitHeight - Appearance.padding.small * 2
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
asynchronous: true width: height
Behavior on end1 {
PropAnim {
}
}
Behavior on end2 {
PropAnim {
}
}
Behavior on start1 {
PropAnim {
}
}
Behavior on start2 {
PropAnim {
}
}
ShapePath { ShapePath {
strokeWidth: Appearance.font.size.larger * 0.15
strokeColor: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3surfaceContainerHighest
fillColor: "transparent"
capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap
fillColor: "transparent"
startX: icon.start1.x startX: icon.start1.x
startY: icon.start1.y startY: icon.start1.y
strokeColor: root.checked ? DynamicColors.palette.m3primary : DynamicColors.palette.m3surfaceContainerHighest
strokeWidth: Appearance.font.size.larger * 0.15
Behavior on strokeColor {
CAnim {
}
}
PathLine { PathLine {
x: icon.end1.x x: icon.end1.x
y: icon.end1.y y: icon.end1.y
} }
PathMove { PathMove {
x: icon.start2.x x: icon.start2.x
y: icon.start2.y y: icon.start2.y
} }
PathLine { PathLine {
x: icon.end2.x x: icon.end2.x
y: icon.end2.y y: icon.end2.y
} }
Behavior on strokeColor {
CAnim {}
} }
} }
Behavior on start1 {
PropAnim {}
}
Behavior on end1 {
PropAnim {}
}
Behavior on start2 {
PropAnim {}
}
Behavior on end2 {
PropAnim {}
}
}
Behavior on x {
Anim {}
}
Behavior on implicitWidth {
Anim {}
}
} }
} }
+16 -13
View File
@@ -7,42 +7,45 @@ Text {
id: root id: root
property bool animate: false property bool animate: false
property string animateProp: "scale"
property real animateFrom: 0
property real animateTo: 1
property int animateDuration: 400 property int animateDuration: 400
property real animateFrom: 0
property string animateProp: "scale"
property real animateTo: 1
renderType: Text.NativeRendering
textFormat: Text.PlainText
color: DynamicColors.palette.m3onSurface color: DynamicColors.palette.m3onSurface
font.family: Appearance.font.family.sans font.family: Appearance.font.family.sans
font.pointSize: 12 font.pointSize: 12
renderType: Text.NativeRendering
textFormat: Text.PlainText
Behavior on color { Behavior on color {
CAnim {} CAnim {
}
} }
Behavior on text { Behavior on text {
enabled: root.animate enabled: root.animate
SequentialAnimation { SequentialAnimation {
Anim { Anim {
to: root.animateFrom
easing.bezierCurve: MaterialEasing.standardAccel easing.bezierCurve: MaterialEasing.standardAccel
to: root.animateFrom
} }
PropertyAction {}
PropertyAction {
}
Anim { Anim {
to: root.animateTo
easing.bezierCurve: MaterialEasing.standardDecel easing.bezierCurve: MaterialEasing.standardDecel
to: root.animateTo
} }
} }
} }
component Anim: NumberAnimation { component Anim: NumberAnimation {
target: root
property: root.animateProp.split(",").length === 1 ? root.animateProp : ""
properties: root.animateProp.split(",").length > 1 ? root.animateProp : ""
duration: root.animateDuration / 2 duration: root.animateDuration / 2
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
properties: root.animateProp.split(",").length > 1 ? root.animateProp : ""
property: root.animateProp.split(",").length === 1 ? root.animateProp : ""
target: root
} }
} }
+24 -23
View File
@@ -7,27 +7,34 @@ import qs.Config
TextField { TextField {
id: root id: root
background: null
color: DynamicColors.palette.m3onSurface color: DynamicColors.palette.m3onSurface
placeholderTextColor: DynamicColors.palette.m3outline cursorVisible: !readOnly
font.family: Appearance.font.family.sans font.family: Appearance.font.family.sans
font.pointSize: Appearance.font.size.smaller font.pointSize: Appearance.font.size.smaller
placeholderTextColor: DynamicColors.palette.m3outline
renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering
cursorVisible: !readOnly
background: null
Behavior on color {
CAnim {
}
}
cursorDelegate: CustomRect { cursorDelegate: CustomRect {
id: cursor id: cursor
property bool disableBlink property bool disableBlink
implicitWidth: 2
color: DynamicColors.palette.m3primary color: DynamicColors.palette.m3primary
implicitWidth: 2
radius: Appearance.rounding.normal radius: Appearance.rounding.normal
Connections { Behavior on opacity {
target: root Anim {
duration: Appearance.anim.durations.small
}
}
Connections {
function onCursorPositionChanged(): void { function onCursorPositionChanged(): void {
if (root.activeFocus && root.cursorVisible) { if (root.activeFocus && root.cursorVisible) {
cursor.opacity = 1; cursor.opacity = 1;
@@ -35,40 +42,34 @@ TextField {
enableBlink.restart(); enableBlink.restart();
} }
} }
target: root
} }
Timer { Timer {
id: enableBlink id: enableBlink
interval: 100 interval: 100
onTriggered: cursor.disableBlink = false onTriggered: cursor.disableBlink = false
} }
Timer { Timer {
running: root.activeFocus && root.cursorVisible && !cursor.disableBlink
repeat: true
triggeredOnStart: true
interval: 500 interval: 500
repeat: true
running: root.activeFocus && root.cursorVisible && !cursor.disableBlink
triggeredOnStart: true
onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1 onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1
} }
Binding { Binding {
when: !root.activeFocus || !root.cursorVisible
cursor.opacity: 0 cursor.opacity: 0
} when: !root.activeFocus || !root.cursorVisible
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.small
} }
} }
}
Behavior on color {
CAnim {}
}
Behavior on placeholderTextColor { Behavior on placeholderTextColor {
CAnim {} CAnim {
}
} }
} }
+10 -8
View File
@@ -4,20 +4,22 @@ import qs.Components
ToolTip { ToolTip {
id: root id: root
property bool extraVisibleCondition: true
property bool alternativeVisibleCondition: false
readonly property bool internalVisibleCondition: (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition
verticalPadding: 5
horizontalPadding: 10
background: null
property bool alternativeVisibleCondition: false
property bool extraVisibleCondition: true
readonly property bool internalVisibleCondition: (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition
background: null
horizontalPadding: 10
verticalPadding: 5
visible: internalVisibleCondition visible: internalVisibleCondition
contentItem: CustomTooltipContent { contentItem: CustomTooltipContent {
id: contentItem id: contentItem
text: root.text
shown: root.internalVisibleCondition
horizontalPadding: root.horizontalPadding horizontalPadding: root.horizontalPadding
shown: root.internalVisibleCondition
text: root.text
verticalPadding: root.verticalPadding verticalPadding: root.verticalPadding
} }
} }
+30 -23
View File
@@ -4,43 +4,50 @@ import qs.Config
Item { Item {
id: root id: root
required property string text
property bool shown: false
property real horizontalPadding: 10
property real verticalPadding: 5
implicitWidth: tooltipTextObject.implicitWidth + 2 * root.horizontalPadding
implicitHeight: tooltipTextObject.implicitHeight + 2 * root.verticalPadding
property real horizontalPadding: 10
property bool isVisible: backgroundRectangle.implicitHeight > 0 property bool isVisible: backgroundRectangle.implicitHeight > 0
property bool shown: false
required property string text
property real verticalPadding: 5
implicitHeight: tooltipTextObject.implicitHeight + 2 * root.verticalPadding
implicitWidth: tooltipTextObject.implicitWidth + 2 * root.horizontalPadding
Rectangle { Rectangle {
id: backgroundRectangle id: backgroundRectangle
clip: true
color: DynamicColors.tPalette.m3inverseSurface ?? "#3C4043"
implicitHeight: shown ? (tooltipTextObject.implicitHeight + 2 * root.verticalPadding) : 0
implicitWidth: shown ? (tooltipTextObject.implicitWidth + 2 * root.horizontalPadding) : 0
opacity: shown ? 1 : 0
radius: 8
Behavior on implicitHeight {
Anim {
}
}
Behavior on implicitWidth {
Anim {
}
}
Behavior on opacity {
Anim {
}
}
anchors { anchors {
bottom: root.bottom bottom: root.bottom
horizontalCenter: root.horizontalCenter horizontalCenter: root.horizontalCenter
} }
color: DynamicColors.tPalette.m3inverseSurface ?? "#3C4043"
radius: 8
opacity: shown ? 1 : 0
implicitWidth: shown ? (tooltipTextObject.implicitWidth + 2 * root.horizontalPadding) : 0
implicitHeight: shown ? (tooltipTextObject.implicitHeight + 2 * root.verticalPadding) : 0
clip: true
Behavior on implicitWidth {
Anim {}
}
Behavior on implicitHeight {
Anim {}
}
Behavior on opacity {
Anim {}
}
CustomText { CustomText {
id: tooltipTextObject id: tooltipTextObject
anchors.centerIn: parent anchors.centerIn: parent
text: root.text
color: DynamicColors.palette.m3inverseOnSurface ?? "#FFFFFF" color: DynamicColors.palette.m3inverseOnSurface ?? "#FFFFFF"
text: root.text
wrapMode: Text.Wrap wrapMode: Text.Wrap
} }
} }
+5 -4
View File
@@ -3,15 +3,16 @@ import QtQuick
import QtQuick.Effects import QtQuick.Effects
RectangularShadow { RectangularShadow {
property int level
property real dp: [0, 1, 3, 6, 8, 12][level] property real dp: [0, 1, 3, 6, 8, 12][level]
property int level
color: Qt.alpha(DynamicColors.palette.m3shadow, 0.7)
blur: (dp * 5) ** 0.7 blur: (dp * 5) ** 0.7
spread: -dp * 0.3 + (dp * 0.1) ** 2 color: Qt.alpha(DynamicColors.palette.m3shadow, 0.7)
offset.y: dp / 2 offset.y: dp / 2
spread: -dp * 0.3 + (dp * 0.1) ** 2
Behavior on dp { Behavior on dp {
Anim {} Anim {
}
} }
} }
+19 -23
View File
@@ -4,24 +4,33 @@ import QtQuick
CustomRect { CustomRect {
required property int extra required property int extra
anchors.right: parent.right
anchors.margins: 8 anchors.margins: 8
anchors.right: parent.right
color: DynamicColors.palette.m3tertiary color: DynamicColors.palette.m3tertiary
radius: 8
implicitWidth: count.implicitWidth + 8 * 2
implicitHeight: count.implicitHeight + 4 * 2 implicitHeight: count.implicitHeight + 4 * 2
implicitWidth: count.implicitWidth + 8 * 2
opacity: extra > 0 ? 1 : 0 opacity: extra > 0 ? 1 : 0
radius: 8
scale: extra > 0 ? 1 : 0.5 scale: extra > 0 ? 1 : 0.5
Behavior on opacity {
Anim {
duration: MaterialEasing.expressiveEffectsTime
}
}
Behavior on scale {
Anim {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
}
}
Elevation { Elevation {
anchors.fill: parent anchors.fill: parent
radius: parent.radius
opacity: parent.opacity
z: -1
level: 2 level: 2
opacity: parent.opacity
radius: parent.radius
z: -1
} }
CustomText { CustomText {
@@ -29,20 +38,7 @@ CustomRect {
anchors.centerIn: parent anchors.centerIn: parent
animate: parent.opacity > 0 animate: parent.opacity > 0
text: qsTr("+%1").arg(parent.extra)
color: DynamicColors.palette.m3onTertiary color: DynamicColors.palette.m3onTertiary
} text: qsTr("+%1").arg(parent.extra)
Behavior on opacity {
Anim {
duration: MaterialEasing.expressiveEffectsTime
}
}
Behavior on scale {
Anim {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
}
} }
} }
+28 -31
View File
@@ -5,10 +5,10 @@ import qs.Config
Slider { Slider {
id: root id: root
required property string icon
property real oldValue
property bool initialized
property color color: DynamicColors.palette.m3secondary property color color: DynamicColors.palette.m3secondary
required property string icon
property bool initialized
property real oldValue
orientation: Qt.Vertical orientation: Qt.Vertical
@@ -19,45 +19,41 @@ Slider {
CustomRect { CustomRect {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
y: root.handle.y
implicitHeight: parent.height - y
color: root.color color: root.color
implicitHeight: parent.height - y
radius: parent.radius radius: parent.radius
y: root.handle.y
} }
} }
handle: Item { handle: Item {
id: handle id: handle
property alias moving: icon.moving property alias moving: icon.moving
y: root.visualPosition * (root.availableHeight - height)
implicitWidth: root.width
implicitHeight: root.width implicitHeight: root.width
implicitWidth: root.width
y: root.visualPosition * (root.availableHeight - height)
Elevation { Elevation {
anchors.fill: parent anchors.fill: parent
radius: rect.radius
level: handleInteraction.containsMouse ? 2 : 1 level: handleInteraction.containsMouse ? 2 : 1
radius: rect.radius
} }
CustomRect { CustomRect {
id: rect id: rect
anchors.fill: parent anchors.fill: parent
color: DynamicColors.palette.m3inverseSurface color: DynamicColors.palette.m3inverseSurface
radius: Appearance.rounding.full radius: Appearance.rounding.full
MouseArea { MouseArea {
id: handleInteraction id: handleInteraction
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
} }
MaterialIcon { MaterialIcon {
@@ -72,17 +68,17 @@ Slider {
font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material; font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material;
} }
text: root.icon
color: DynamicColors.palette.m3inverseOnSurface
anchors.centerIn: parent anchors.centerIn: parent
color: DynamicColors.palette.m3inverseOnSurface
text: root.icon
onMovingChanged: anim.restart() onMovingChanged: anim.restart()
Binding { Binding {
id: binding id: binding
target: icon
property: "text" property: "text"
target: icon
value: Math.round(root.value * 100) value: Math.round(root.value * 100)
when: false when: false
} }
@@ -91,29 +87,35 @@ Slider {
id: anim id: anim
Anim { Anim {
target: icon
property: "scale"
to: 0
duration: Appearance.anim.durations.normal / 2 duration: Appearance.anim.durations.normal / 2
easing.bezierCurve: Appearance.anim.curves.standardAccel easing.bezierCurve: Appearance.anim.curves.standardAccel
property: "scale"
target: icon
to: 0
} }
ScriptAction { ScriptAction {
script: icon.update() script: icon.update()
} }
Anim { Anim {
target: icon
property: "scale"
to: 1
duration: Appearance.anim.durations.normal / 2 duration: Appearance.anim.durations.normal / 2
easing.bezierCurve: Appearance.anim.curves.standardDecel easing.bezierCurve: Appearance.anim.curves.standardDecel
property: "scale"
target: icon
to: 1
} }
} }
} }
} }
} }
Behavior on value {
Anim {
duration: Appearance.anim.durations.large
}
}
onPressedChanged: handle.moving = pressed onPressedChanged: handle.moving = pressed
onValueChanged: { onValueChanged: {
if (!initialized) { if (!initialized) {
initialized = true; initialized = true;
@@ -130,15 +132,10 @@ Slider {
id: stateChangeDelay id: stateChangeDelay
interval: 500 interval: 500
onTriggered: { onTriggered: {
if (!root.pressed) if (!root.pressed)
handle.moving = false; handle.moving = false;
} }
} }
Behavior on value {
Anim {
duration: Appearance.anim.durations.large
}
}
} }
+29 -30
View File
@@ -10,55 +10,59 @@ CustomRect {
Text Text
} }
property alias icon: label.text
property bool checked
property bool toggle
property real padding: type === IconButton.Text ? 10 / 2 : 7
property alias font: label.font
property int type: IconButton.Filled
property bool disabled
property alias stateLayer: stateLayer
property alias label: label
property alias radiusAnim: radiusAnim
property bool internalChecked
property color activeColour: type === IconButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondary property color activeColour: type === IconButton.Filled ? DynamicColors.palette.m3primary : DynamicColors.palette.m3secondary
property color activeOnColour: type === IconButton.Filled ? DynamicColors.palette.m3onPrimary : type === IconButton.Tonal ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3primary
property bool checked
property bool disabled
property color disabledColour: Qt.alpha(DynamicColors.palette.m3onSurface, 0.1)
property color disabledOnColour: Qt.alpha(DynamicColors.palette.m3onSurface, 0.38)
property alias font: label.font
property alias icon: label.text
property color inactiveColour: { property color inactiveColour: {
if (!toggle && type === IconButton.Filled) if (!toggle && type === IconButton.Filled)
return DynamicColors.palette.m3primary; return DynamicColors.palette.m3primary;
return type === IconButton.Filled ? DynamicColors.tPalette.m3surfaceContainer : DynamicColors.palette.m3secondaryContainer; return type === IconButton.Filled ? DynamicColors.tPalette.m3surfaceContainer : DynamicColors.palette.m3secondaryContainer;
} }
property color activeOnColour: type === IconButton.Filled ? DynamicColors.palette.m3onPrimary : type === IconButton.Tonal ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3primary
property color inactiveOnColour: { property color inactiveOnColour: {
if (!toggle && type === IconButton.Filled) if (!toggle && type === IconButton.Filled)
return DynamicColors.palette.m3onPrimary; return DynamicColors.palette.m3onPrimary;
return type === IconButton.Tonal ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurfaceVariant; return type === IconButton.Tonal ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurfaceVariant;
} }
property color disabledColour: Qt.alpha(DynamicColors.palette.m3onSurface, 0.1) property bool internalChecked
property color disabledOnColour: Qt.alpha(DynamicColors.palette.m3onSurface, 0.38) property alias label: label
property real padding: type === IconButton.Text ? 10 / 2 : 7
property alias radiusAnim: radiusAnim
property alias stateLayer: stateLayer
property bool toggle
property int type: IconButton.Filled
signal clicked signal clicked
onCheckedChanged: internalChecked = checked
radius: internalChecked ? 6 : implicitHeight / 2 * Math.min(1, 1)
color: type === IconButton.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour color: type === IconButton.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour
implicitWidth: implicitHeight
implicitHeight: label.implicitHeight + padding * 2 implicitHeight: label.implicitHeight + padding * 2
implicitWidth: implicitHeight
radius: internalChecked ? 6 : implicitHeight / 2 * Math.min(1, 1)
Behavior on radius {
Anim {
id: radiusAnim
}
}
onCheckedChanged: internalChecked = checked
StateLayer { StateLayer {
id: stateLayer id: stateLayer
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
disabled: root.disabled
function onClicked(): void { function onClicked(): void {
if (root.toggle) if (root.toggle)
root.internalChecked = !root.internalChecked; root.internalChecked = !root.internalChecked;
root.clicked(); root.clicked();
} }
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
disabled: root.disabled
} }
MaterialIcon { MaterialIcon {
@@ -69,13 +73,8 @@ CustomRect {
fill: !root.toggle || root.internalChecked ? 1 : 0 fill: !root.toggle || root.internalChecked ? 1 : 0
Behavior on fill { Behavior on fill {
Anim {}
}
}
Behavior on radius {
Anim { Anim {
id: radiusAnim }
} }
} }
} }
+1 -1
View File
@@ -2,8 +2,8 @@ import Quickshell
import QtQuick import QtQuick
ShaderEffect { ShaderEffect {
required property Item source
required property Item maskSource required property Item maskSource
required property Item source
fragmentShader: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/shaders/opacitymask.frag.qsb`) fragmentShader: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/shaders/opacitymask.frag.qsb`)
} }
+19 -18
View File
@@ -4,8 +4,8 @@ import QtQuick
MouseArea { MouseArea {
id: root id: root
property bool disabled
property color color: DynamicColors.palette.m3onSurface property color color: DynamicColors.palette.m3onSurface
property bool disabled
property real radius: parent?.radius ?? 0 property real radius: parent?.radius ?? 0
property alias rect: hoverLayer property alias rect: hoverLayer
@@ -13,11 +13,11 @@ MouseArea {
} }
anchors.fill: parent anchors.fill: parent
enabled: !disabled
cursorShape: disabled ? undefined : Qt.PointingHandCursor cursorShape: disabled ? undefined : Qt.PointingHandCursor
enabled: !disabled
hoverEnabled: true hoverEnabled: true
onClicked: event => !disabled && onClicked(event)
onPressed: event => { onPressed: event => {
if (disabled) if (disabled)
return; return;
@@ -31,40 +31,42 @@ MouseArea {
rippleAnim.restart(); rippleAnim.restart();
} }
onClicked: event => !disabled && onClicked(event)
SequentialAnimation { SequentialAnimation {
id: rippleAnim id: rippleAnim
property real radius
property real x property real x
property real y property real y
property real radius
PropertyAction { PropertyAction {
target: ripple
property: "x" property: "x"
target: ripple
value: rippleAnim.x value: rippleAnim.x
} }
PropertyAction { PropertyAction {
target: ripple
property: "y" property: "y"
target: ripple
value: rippleAnim.y value: rippleAnim.y
} }
PropertyAction { PropertyAction {
target: ripple
property: "opacity" property: "opacity"
target: ripple
value: 0.08 value: 0.08
} }
Anim { Anim {
target: ripple
properties: "implicitWidth,implicitHeight"
from: 0
to: rippleAnim.radius * 2
easing.bezierCurve: MaterialEasing.standardDecel easing.bezierCurve: MaterialEasing.standardDecel
} from: 0
Anim { properties: "implicitWidth,implicitHeight"
target: ripple target: ripple
to: rippleAnim.radius * 2
}
Anim {
property: "opacity" property: "opacity"
target: ripple
to: 0 to: 0
} }
} }
@@ -74,17 +76,16 @@ MouseArea {
anchors.fill: parent anchors.fill: parent
border.pixelAligned: false border.pixelAligned: false
color: Qt.alpha(root.color, root.disabled ? 0 : root.pressed ? 0.1 : root.containsMouse ? 0.08 : 0) color: Qt.alpha(root.color, root.disabled ? 0 : root.pressed ? 0.1 : root.containsMouse ? 0.08 : 0)
radius: root.radius radius: root.radius
CustomRect { CustomRect {
id: ripple id: ripple
radius: 1000 border.pixelAligned: false
color: root.color color: root.color
opacity: 0 opacity: 0
border.pixelAligned: false radius: 1000
transform: Translate { transform: Translate {
x: -ripple.width / 2 x: -ripple.width / 2
+29 -31
View File
@@ -11,20 +11,6 @@ CustomRect {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
implicitHeight: layout.implicitHeight + Appearance.padding.smaller * 2
radius: Appearance.rounding.normal
color: {
if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3successContainer;
if (root.modelData.type === Toast.Warning)
return DynamicColors.palette.m3secondary;
if (root.modelData.type === Toast.Error)
return DynamicColors.palette.m3errorContainer;
return DynamicColors.palette.m3surface;
}
border.width: 1
border.color: { border.color: {
let colour = DynamicColors.palette.m3outlineVariant; let colour = DynamicColors.palette.m3outlineVariant;
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
@@ -35,26 +21,42 @@ CustomRect {
colour = DynamicColors.palette.m3error; colour = DynamicColors.palette.m3error;
return Qt.alpha(colour, 0.3); return Qt.alpha(colour, 0.3);
} }
border.width: 1
color: {
if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3successContainer;
if (root.modelData.type === Toast.Warning)
return DynamicColors.palette.m3secondary;
if (root.modelData.type === Toast.Error)
return DynamicColors.palette.m3errorContainer;
return DynamicColors.palette.m3surface;
}
implicitHeight: layout.implicitHeight + Appearance.padding.smaller * 2
radius: Appearance.rounding.normal
Behavior on border.color {
CAnim {
}
}
Elevation { Elevation {
anchors.fill: parent anchors.fill: parent
radius: parent.radius
opacity: parent.opacity
z: -1
level: 3 level: 3
opacity: parent.opacity
radius: parent.radius
z: -1
} }
RowLayout { RowLayout {
id: layout id: layout
anchors.fill: parent anchors.fill: parent
anchors.margins: Appearance.padding.smaller
anchors.leftMargin: Appearance.padding.normal anchors.leftMargin: Appearance.padding.normal
anchors.margins: Appearance.padding.smaller
anchors.rightMargin: Appearance.padding.normal anchors.rightMargin: Appearance.padding.normal
spacing: Appearance.spacing.normal spacing: Appearance.spacing.normal
CustomRect { CustomRect {
radius: Appearance.rounding.normal
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3success; return DynamicColors.palette.m3success;
@@ -64,15 +66,14 @@ CustomRect {
return DynamicColors.palette.m3error; return DynamicColors.palette.m3error;
return DynamicColors.palette.m3surfaceContainerHigh; return DynamicColors.palette.m3surfaceContainerHigh;
} }
implicitWidth: implicitHeight
implicitHeight: icon.implicitHeight + Appearance.padding.smaller * 2 implicitHeight: icon.implicitHeight + Appearance.padding.smaller * 2
implicitWidth: implicitHeight
radius: Appearance.rounding.normal
MaterialIcon { MaterialIcon {
id: icon id: icon
anchors.centerIn: parent anchors.centerIn: parent
text: root.modelData.icon
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3onSuccess; return DynamicColors.palette.m3onSuccess;
@@ -83,6 +84,7 @@ CustomRect {
return DynamicColors.palette.m3onSurfaceVariant; return DynamicColors.palette.m3onSurfaceVariant;
} }
font.pointSize: Math.round(Appearance.font.size.large * 1.2) font.pointSize: Math.round(Appearance.font.size.large * 1.2)
text: root.modelData.icon
} }
} }
@@ -94,7 +96,6 @@ CustomRect {
id: title id: title
Layout.fillWidth: true Layout.fillWidth: true
text: root.modelData.title
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3onSuccessContainer; return DynamicColors.palette.m3onSuccessContainer;
@@ -104,14 +105,13 @@ CustomRect {
return DynamicColors.palette.m3onErrorContainer; return DynamicColors.palette.m3onErrorContainer;
return DynamicColors.palette.m3onSurface; return DynamicColors.palette.m3onSurface;
} }
font.pointSize: Appearance.font.size.normal
elide: Text.ElideRight elide: Text.ElideRight
font.pointSize: Appearance.font.size.normal
text: root.modelData.title
} }
CustomText { CustomText {
Layout.fillWidth: true Layout.fillWidth: true
textFormat: Text.StyledText
text: root.modelData.message
color: { color: {
if (root.modelData.type === Toast.Success) if (root.modelData.type === Toast.Success)
return DynamicColors.palette.m3onSuccessContainer; return DynamicColors.palette.m3onSuccessContainer;
@@ -121,13 +121,11 @@ CustomRect {
return DynamicColors.palette.m3onErrorContainer; return DynamicColors.palette.m3onErrorContainer;
return DynamicColors.palette.m3onSurface; return DynamicColors.palette.m3onSurface;
} }
opacity: 0.8
elide: Text.ElideRight elide: Text.ElideRight
opacity: 0.8
text: root.modelData.message
textFormat: Text.StyledText
} }
} }
} }
Behavior on border.color {
CAnim {}
}
} }
+39 -40
View File
@@ -9,10 +9,9 @@ import qs.Config
Item { Item {
id: root id: root
readonly property int spacing: Appearance.spacing.small
property bool flag property bool flag
readonly property int spacing: Appearance.spacing.small
implicitWidth: Config.utilities.sizes.toastWidth - Appearance.padding.normal * 2
implicitHeight: { implicitHeight: {
let h = -spacing; let h = -spacing;
for (let i = 0; i < repeater.count; i++) { for (let i = 0; i < repeater.count; i++) {
@@ -22,6 +21,7 @@ Item {
} }
return h; return h;
} }
implicitWidth: Config.utilities.sizes.toastWidth - Appearance.padding.normal * 2
Repeater { Repeater {
id: repeater id: repeater
@@ -40,10 +40,12 @@ Item {
} }
return toasts; return toasts;
} }
onValuesChanged: root.flagChanged() onValuesChanged: root.flagChanged()
} }
ToastWrapper {} ToastWrapper {
}
} }
component ToastWrapper: MouseArea { component ToastWrapper: MouseArea {
@@ -51,7 +53,6 @@ Item {
required property int index required property int index
required property Toast modelData required property Toast modelData
readonly property bool previewHidden: { readonly property bool previewHidden: {
let extraHidden = 0; let extraHidden = 0;
for (let i = 0; i < index; i++) for (let i = 0; i < index; i++)
@@ -60,14 +61,8 @@ Item {
return index >= Config.utilities.maxToasts + extraHidden; return index >= Config.utilities.maxToasts + extraHidden;
} }
onPreviewHiddenChanged: { acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
if (initAnim.running && previewHidden) anchors.bottom: parent.bottom
initAnim.stop();
}
opacity: modelData.closed || previewHidden ? 0 : 1
scale: modelData.closed || previewHidden ? 0.7 : 1
anchors.bottomMargin: { anchors.bottomMargin: {
root.flag; // Force update root.flag; // Force update
let y = 0; let y = 0;
@@ -78,43 +73,62 @@ Item {
} }
return y; return y;
} }
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom
implicitHeight: toastInner.implicitHeight implicitHeight: toastInner.implicitHeight
opacity: modelData.closed || previewHidden ? 0 : 1
scale: modelData.closed || previewHidden ? 0.7 : 1
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton Behavior on anchors.bottomMargin {
onClicked: modelData.close() Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Component.onCompleted: modelData.lock(this) Component.onCompleted: modelData.lock(this)
onClicked: modelData.close()
onPreviewHiddenChanged: {
if (initAnim.running && previewHidden)
initAnim.stop();
}
Anim { Anim {
id: initAnim id: initAnim
Component.onCompleted: running = !toast.previewHidden
target: toast
properties: "opacity,scale"
from: 0
to: 1
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
from: 0
properties: "opacity,scale"
target: toast
to: 1
Component.onCompleted: running = !toast.previewHidden
} }
ParallelAnimation { ParallelAnimation {
running: toast.modelData.closed running: toast.modelData.closed
onStarted: toast.anchors.bottomMargin = toast.anchors.bottomMargin
onFinished: toast.modelData.unlock(toast) onFinished: toast.modelData.unlock(toast)
onStarted: toast.anchors.bottomMargin = toast.anchors.bottomMargin
Anim { Anim {
target: toast
property: "opacity" property: "opacity"
target: toast
to: 0 to: 0
} }
Anim { Anim {
target: toast
property: "scale" property: "scale"
target: toast
to: 0.7 to: 0.7
} }
} }
@@ -124,20 +138,5 @@ Item {
modelData: toast.modelData modelData: toast.modelData
} }
Behavior on opacity {
Anim {}
}
Behavior on scale {
Anim {}
}
Behavior on anchors.bottomMargin {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
} }
} }
+2 -1
View File
@@ -1,7 +1,8 @@
import Quickshell.Io import Quickshell.Io
JsonObject { JsonObject {
property Accents accents: Accents {} property Accents accents: Accents {
}
component Accents: JsonObject { component Accents: JsonObject {
property string primary: "#4080ff" property string primary: "#4080ff"
+3 -3
View File
@@ -3,12 +3,12 @@ pragma Singleton
import Quickshell import Quickshell
Singleton { Singleton {
readonly property AppearanceConf.Anim anim: Config.appearance.anim
readonly property AppearanceConf.FontStuff font: Config.appearance.font
readonly property AppearanceConf.Padding padding: Config.appearance.padding
// Literally just here to shorten accessing stuff :woe: // Literally just here to shorten accessing stuff :woe:
// Also kinda so I can keep accessing it with `Appearance.xxx` instead of `Conf.appearance.xxx` // Also kinda so I can keep accessing it with `Appearance.xxx` instead of `Conf.appearance.xxx`
readonly property AppearanceConf.Rounding rounding: Config.appearance.rounding readonly property AppearanceConf.Rounding rounding: Config.appearance.rounding
readonly property AppearanceConf.Spacing spacing: Config.appearance.spacing readonly property AppearanceConf.Spacing spacing: Config.appearance.spacing
readonly property AppearanceConf.Padding padding: Config.appearance.padding
readonly property AppearanceConf.FontStuff font: Config.appearance.font
readonly property AppearanceConf.Anim anim: Config.appearance.anim
readonly property AppearanceConf.Transparency transparency: Config.appearance.transparency readonly property AppearanceConf.Transparency transparency: Config.appearance.transparency
} }
+69 -68
View File
@@ -1,94 +1,95 @@
import Quickshell.Io import Quickshell.Io
JsonObject { JsonObject {
property Rounding rounding: Rounding {} property Anim anim: Anim {
property Spacing spacing: Spacing {} }
property Padding padding: Padding {} property FontStuff font: FontStuff {
property FontStuff font: FontStuff {} }
property Anim anim: Anim {} property Padding padding: Padding {
property Transparency transparency: Transparency {} }
property Rounding rounding: Rounding {
component Rounding: JsonObject { }
property real scale: 1 property Spacing spacing: Spacing {
property int small: 12 * scale }
property int normal: 17 * scale property Transparency transparency: Transparency {
property int large: 25 * scale
property int full: 1000 * scale
} }
component Spacing: JsonObject { component Anim: JsonObject {
property real scale: 1 property AnimCurves curves: AnimCurves {
property int small: 7 * scale
property int smaller: 10 * scale
property int normal: 12 * scale
property int larger: 15 * scale
property int large: 20 * scale
} }
property AnimDurations durations: AnimDurations {
component Padding: JsonObject {
property real scale: 1
property int small: 5 * scale
property int smaller: 7 * scale
property int normal: 10 * scale
property int larger: 12 * scale
property int large: 15 * scale
} }
property real mediaGifSpeedAdjustment: 300
component FontFamily: JsonObject { property real sessionGifSpeed: 0.7
property string sans: "Segoe UI Variable Text"
property string mono: "CaskaydiaCove NF"
property string material: "Material Symbols Rounded"
property string clock: "Rubik"
} }
component FontSize: JsonObject {
property real scale: 1
property int small: 11 * scale
property int smaller: 12 * scale
property int normal: 13 * scale
property int larger: 15 * scale
property int large: 18 * scale
property int extraLarge: 28 * scale
}
component FontStuff: JsonObject {
property FontFamily family: FontFamily {}
property FontSize size: FontSize {}
}
component AnimCurves: JsonObject { component AnimCurves: JsonObject {
property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1] property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1]
property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1] property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1]
property list<real> emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1] property list<real> emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1]
property list<real> expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1, 1, 1]
property list<real> expressiveEffects: [0.34, 0.8, 0.34, 1, 1, 1]
property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.9, 1, 1]
property list<real> standard: [0.2, 0, 0, 1, 1, 1] property list<real> standard: [0.2, 0, 0, 1, 1, 1]
property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1] property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1]
property list<real> standardDecel: [0, 0, 0, 1, 1, 1] property list<real> standardDecel: [0, 0, 0, 1, 1, 1]
property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.9, 1, 1]
property list<real> expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1, 1, 1]
property list<real> expressiveEffects: [0.34, 0.8, 0.34, 1, 1, 1]
} }
component AnimDurations: JsonObject { component AnimDurations: JsonObject {
property real scale: 1
property int small: 200 * scale
property int normal: 400 * scale
property int large: 600 * scale
property int extraLarge: 1000 * scale
property int expressiveFastSpatial: 350 * scale
property int expressiveDefaultSpatial: 500 * scale property int expressiveDefaultSpatial: 500 * scale
property int expressiveEffects: 200 * scale property int expressiveEffects: 200 * scale
property int expressiveFastSpatial: 350 * scale
property int extraLarge: 1000 * scale
property int large: 600 * scale
property int normal: 400 * scale
property real scale: 1
property int small: 200 * scale
} }
component FontFamily: JsonObject {
component Anim: JsonObject { property string clock: "Rubik"
property real mediaGifSpeedAdjustment: 300 property string material: "Material Symbols Rounded"
property real sessionGifSpeed: 0.7 property string mono: "CaskaydiaCove NF"
property AnimCurves curves: AnimCurves {} property string sans: "Segoe UI Variable Text"
property AnimDurations durations: AnimDurations {} }
component FontSize: JsonObject {
property int extraLarge: 28 * scale
property int large: 18 * scale
property int larger: 15 * scale
property int normal: 13 * scale
property real scale: 1
property int small: 11 * scale
property int smaller: 12 * scale
}
component FontStuff: JsonObject {
property FontFamily family: FontFamily {
}
property FontSize size: FontSize {
}
}
component Padding: JsonObject {
property int large: 15 * scale
property int larger: 12 * scale
property int normal: 10 * scale
property real scale: 1
property int small: 5 * scale
property int smaller: 7 * scale
}
component Rounding: JsonObject {
property int full: 1000 * scale
property int large: 25 * scale
property int normal: 17 * scale
property real scale: 1
property int small: 12 * scale
}
component Spacing: JsonObject {
property int large: 20 * scale
property int larger: 15 * scale
property int normal: 12 * scale
property real scale: 1
property int small: 7 * scale
property int smaller: 10 * scale
} }
component Transparency: JsonObject { component Transparency: JsonObject {
property bool enabled: false
property real base: 0.85 property real base: 0.85
property bool enabled: false
property real layers: 0.4 property real layers: 0.4
} }
} }
+1 -1
View File
@@ -2,6 +2,6 @@ import Quickshell.Io
import qs.Config import qs.Config
JsonObject { JsonObject {
property int wallFadeDuration: MaterialEasing.standardTime
property bool enabled: true property bool enabled: true
property int wallFadeDuration: MaterialEasing.standardTime
} }
+6 -6
View File
@@ -2,9 +2,6 @@ import Quickshell.Io
JsonObject { JsonObject {
property bool autoHide: false property bool autoHide: false
property int rounding: 8
property Popouts popouts: Popouts {}
property list<var> entries: [ property list<var> entries: [
{ {
id: "workspaces", id: "workspaces",
@@ -59,14 +56,17 @@ JsonObject {
enabled: true enabled: true
}, },
] ]
property Popouts popouts: Popouts {
}
property int rounding: 8
component Popouts: JsonObject { component Popouts: JsonObject {
property bool tray: true
property bool audio: true
property bool activeWindow: true property bool activeWindow: true
property bool resources: true property bool audio: true
property bool clock: true property bool clock: true
property bool network: true property bool network: true
property bool resources: true
property bool tray: true
property bool upower: true property bool upower: true
} }
} }
+209 -197
View File
@@ -4,27 +4,27 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import ZShell import ZShell
import QtQuick import QtQuick
import qs.Modules as Modules
import qs.Helpers import qs.Helpers
import qs.Paths import qs.Paths
Singleton { Singleton {
id: root id: root
property alias appearance: adapter.appearance
property alias background: adapter.background property alias background: adapter.background
property alias barConfig: adapter.barConfig property alias barConfig: adapter.barConfig
property alias colors: adapter.colors
property alias dashboard: adapter.dashboard
property alias general: adapter.general
property alias launcher: adapter.launcher
property alias lock: adapter.lock property alias lock: adapter.lock
property alias overview: adapter.overview
property alias services: adapter.services
property alias notifs: adapter.notifs property alias notifs: adapter.notifs
property alias osd: adapter.osd
property alias overview: adapter.overview
property bool recentlySaved: false
property alias services: adapter.services
property alias sidebar: adapter.sidebar property alias sidebar: adapter.sidebar
property alias utilities: adapter.utilities property alias utilities: adapter.utilities
property alias general: adapter.general
property alias dashboard: adapter.dashboard
property alias appearance: adapter.appearance
property alias osd: adapter.osd
property alias launcher: adapter.launcher
property alias colors: adapter.colors
function save(): void { function save(): void {
saveTimer.restart(); saveTimer.restart();
@@ -32,42 +32,71 @@ Singleton {
recentSaveCooldown.restart(); recentSaveCooldown.restart();
} }
property bool recentlySaved: false function serializeAppearance(): var {
return {
ElapsedTimer { rounding: {
id: timer scale: appearance.rounding.scale
},
spacing: {
scale: appearance.spacing.scale
},
padding: {
scale: appearance.padding.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: 300,
sessionGifSpeed: 0.7,
durations: {
scale: appearance.anim.durations.scale
}
},
transparency: {
enabled: appearance.transparency.enabled,
base: appearance.transparency.base,
layers: appearance.transparency.layers
}
};
} }
Timer { function serializeBackground(): var {
id: saveTimer return {
wallFadeDuration: background.wallFadeDuration,
interval: 500 enabled: background.enabled
onTriggered: { };
timer.restart();
try {
let config = {};
try {
config = JSON.parse(fileView.text());
} catch (e) {
config = {};
} }
config = root.serializeConfig(); function serializeBar(): var {
return {
fileView.setText(JSON.stringify(config, null, 4)); autoHide: barConfig.autoHide,
} catch (e) { rounding: barConfig.rounding,
Toaster.toast(qsTr("Failed to serialize config"), e.message, "settings_alert", Toast.Error); 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
};
} }
Timer { function serializeColors(): var {
id: recentSaveCooldown return {
schemeType: colors.schemeType
interval: 2000 };
onTriggered: {
root.recentlySaved = false;
}
} }
function serializeConfig(): var { function serializeConfig(): var {
@@ -85,36 +114,28 @@ Singleton {
background: serializeBackground(), background: serializeBackground(),
launcher: serializeLauncher(), launcher: serializeLauncher(),
colors: serializeColors() colors: serializeColors()
} };
} }
function serializeBar(): var { function serializeDashboard(): var {
return { return {
autoHide: barConfig.autoHide, enabled: dashboard.enabled,
rounding: barConfig.rounding, mediaUpdateInterval: dashboard.mediaUpdateInterval,
popouts: { dragThreshold: dashboard.dragThreshold,
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 serializeLock(): var {
return {
recolorLogo: lock.recolorLogo,
enableFprint: lock.enableFprint,
maxFprintTries: lock.maxFprintTries,
blurAmount: lock.blurAmount,
sizes: { sizes: {
heightMult: lock.sizes.heightMult, tabIndicatorHeight: dashboard.sizes.tabIndicatorHeight,
ratio: lock.sizes.ratio, tabIndicatorSpacing: dashboard.sizes.tabIndicatorSpacing,
centerWidth: lock.sizes.centerWidth 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,
mediaVisualiserSize: dashboard.sizes.mediaVisualiserSize,
resourceSize: dashboard.sizes.resourceSize
} }
}; };
} }
@@ -135,25 +156,48 @@ Singleton {
terminal: general.apps.terminal, terminal: general.apps.terminal,
audio: general.apps.audio, audio: general.apps.audio,
playback: general.apps.playback, playback: general.apps.playback,
explorer: general.apps.explorer, explorer: general.apps.explorer
}, },
idle: { idle: {
timouts: general.idle.timeouts timouts: general.idle.timeouts
} }
} };
} }
function serializeServices(): var { function serializeLauncher(): var {
return { return {
weatherLocation: services.weatherLocation, maxAppsShown: launcher.maxAppsShown,
useFahrenheit: services.useFahrenheit, maxWallpapers: launcher.maxWallpapers,
useTwelveHourClock: services.useTwelveHourClock, actionPrefix: launcher.actionPrefix,
gpuType: services.gpuType, specialPrefix: launcher.specialPrefix,
audioIncrement: services.audioIncrement, useFuzzy: {
brightnessIncrement: services.brightnessIncrement, apps: launcher.useFuzzy.apps,
maxVolume: services.maxVolume, actions: launcher.useFuzzy.actions,
defaultPlayer: services.defaultPlayer, schemes: launcher.useFuzzy.schemes,
playerAliases: services.playerAliases 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,
maxFprintTries: lock.maxFprintTries,
blurAmount: lock.blurAmount,
sizes: {
heightMult: lock.sizes.heightMult,
ratio: lock.sizes.ratio,
centerWidth: lock.sizes.centerWidth
}
}; };
} }
@@ -173,6 +217,34 @@ Singleton {
}; };
} }
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 serializeServices(): var {
return {
weatherLocation: services.weatherLocation,
useFahrenheit: services.useFahrenheit,
useTwelveHourClock: services.useTwelveHourClock,
gpuType: services.gpuType,
audioIncrement: services.audioIncrement,
brightnessIncrement: services.brightnessIncrement,
maxVolume: services.maxVolume,
defaultPlayer: services.defaultPlayer,
playerAliases: services.playerAliases
};
}
function serializeSidebar(): var { function serializeSidebar(): var {
return { return {
enabled: sidebar.enabled, enabled: sidebar.enabled,
@@ -210,113 +282,42 @@ Singleton {
}; };
} }
function serializeDashboard(): var { ElapsedTimer {
return { id: timer
enabled: dashboard.enabled,
mediaUpdateInterval: dashboard.mediaUpdateInterval,
dragThreshold: dashboard.dragThreshold,
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,
mediaVisualiserSize: dashboard.sizes.mediaVisualiserSize,
resourceSize: dashboard.sizes.resourceSize
}
};
} }
function serializeOsd(): var { Timer {
return { id: saveTimer
enabled: osd.enabled,
hideDelay: osd.hideDelay, interval: 500
enableBrightness: osd.enableBrightness,
enableMicrophone: osd.enableMicrophone, onTriggered: {
allMonBrightness: osd.allMonBrightness, timer.restart();
sizes: { try {
sliderWidth: osd.sizes.sliderWidth, let config = {};
sliderHeight: osd.sizes.sliderHeight try {
} config = JSON.parse(fileView.text());
}; } catch (e) {
config = {};
} }
function serializeLauncher(): var { config = root.serializeConfig();
return {
maxAppsShown: launcher.maxAppsShown, fileView.setText(JSON.stringify(config, null, 4));
maxWallpapers: launcher.maxWallpapers, } catch (e) {
actionPrefix: launcher.actionPrefix, Toaster.toast(qsTr("Failed to serialize config"), e.message, "settings_alert", Toast.Error);
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 serializeBackground(): var { Timer {
return { id: recentSaveCooldown
wallFadeDuration: background.wallFadeDuration,
enabled: background.enabled
}
}
function serializeAppearance(): var { interval: 2000
return {
rounding: {
scale: appearance.rounding.scale
},
spacing: {
scale: appearance.spacing.scale
},
padding: {
scale: appearance.padding.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: 300,
sessionGifSpeed: 0.7,
durations: {
scale: appearance.anim.durations.scale
}
},
transparency: {
enabled: appearance.transparency.enabled,
base: appearance.transparency.base,
layers: appearance.transparency.layers
}
};
}
function serializeColors(): var { onTriggered: {
return { root.recentlySaved = false;
schemeType: colors.schemeType,
} }
} }
@@ -324,7 +325,6 @@ Singleton {
id: fileView id: fileView
path: `${Paths.config}/config.json` path: `${Paths.config}/config.json`
watchChanges: true watchChanges: true
onFileChanged: { onFileChanged: {
@@ -335,7 +335,10 @@ Singleton {
reload(); reload();
} }
} }
onLoadFailed: err => {
if (err !== FileViewError.FileNotFound)
Toaster.toast(qsTr("Failed to read config"), FileViewError.toString(err), "settings_alert", Toast.Warning);
}
onLoaded: { onLoaded: {
ModeScheduler.checkStartup(); ModeScheduler.checkStartup();
try { try {
@@ -351,30 +354,39 @@ Singleton {
Toaster.toast(qsTr("Failed to load config"), e.message, "settings_alert", Toast.Error); Toaster.toast(qsTr("Failed to load config"), e.message, "settings_alert", Toast.Error);
} }
} }
onLoadFailed: err => {
if ( err !== FileViewError.FileNotFound )
Toaster.toast(qsTr("Failed to read config"), FileViewError.toString(err), "settings_alert", Toast.Warning);
}
onSaveFailed: err => Toaster.toast(qsTr("Failed to save config"), FileViewError.toString(err), "settings_alert", Toast.Error) onSaveFailed: err => Toaster.toast(qsTr("Failed to save config"), FileViewError.toString(err), "settings_alert", Toast.Error)
JsonAdapter { JsonAdapter {
id: adapter id: adapter
property BackgroundConfig background: BackgroundConfig {}
property BarConfig barConfig: BarConfig {} property AppearanceConf appearance: AppearanceConf {
property LockConf lock: LockConf {} }
property Overview overview: Overview {} property BackgroundConfig background: BackgroundConfig {
property Services services: Services {} }
property NotifConfig notifs: NotifConfig {} property BarConfig barConfig: BarConfig {
property SidebarConfig sidebar: SidebarConfig {} }
property UtilConfig utilities: UtilConfig {} property Colors colors: Colors {
property General general: General {} }
property DashboardConfig dashboard: DashboardConfig {} property DashboardConfig dashboard: DashboardConfig {
property AppearanceConf appearance: AppearanceConf {} }
property Osd osd: Osd {} property General general: General {
property Launcher launcher: Launcher {} }
property Colors colors: Colors {} property Launcher launcher: Launcher {
}
property LockConf lock: LockConf {
}
property NotifConfig notifs: NotifConfig {
}
property Osd osd: Osd {
}
property Overview overview: Overview {
}
property Services services: Services {
}
property SidebarConfig sidebar: SidebarConfig {
}
property UtilConfig utilities: UtilConfig {
}
} }
} }
} }
+11 -10
View File
@@ -1,24 +1,25 @@
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 int dragThreshold: 50 property Sizes sizes: Sizes {
property Sizes sizes: Sizes {} }
component Sizes: JsonObject { component Sizes: JsonObject {
readonly property int tabIndicatorHeight: 3
readonly property int tabIndicatorSpacing: 5
readonly property int infoWidth: 200
readonly property int infoIconSize: 25
readonly property int dateTimeWidth: 110 readonly property int dateTimeWidth: 110
readonly property int mediaWidth: 200 readonly property int infoIconSize: 25
readonly property int infoWidth: 200
readonly property int mediaCoverArtSize: 150
readonly property int mediaProgressSweep: 180 readonly property int mediaProgressSweep: 180
readonly property int mediaProgressThickness: 8 readonly property int mediaProgressThickness: 8
readonly property int resourceProgessThickness: 10
readonly property int weatherWidth: 250
readonly property int mediaCoverArtSize: 150
readonly property int mediaVisualiserSize: 80 readonly property int mediaVisualiserSize: 80
readonly property int mediaWidth: 200
readonly property int resourceProgessThickness: 10
readonly property int resourceSize: 200 readonly property int resourceSize: 200
readonly property int tabIndicatorHeight: 3
readonly property int tabIndicatorSpacing: 5
readonly property int weatherWidth: 250
} }
} }
+193 -191
View File
@@ -11,24 +11,22 @@ import qs.Paths
Singleton { Singleton {
id: root id: root
property bool showPreview readonly property M3Palette current: M3Palette {
property string scheme }
property bool currentLight
property string flavour property string flavour
readonly property bool light: showPreview ? previewLight : currentLight readonly property bool light: showPreview ? previewLight : currentLight
property bool currentLight
property bool previewLight
readonly property M3Palette palette: showPreview ? preview : current readonly property M3Palette palette: showPreview ? preview : current
readonly property M3TPalette tPalette: M3TPalette {} readonly property M3Palette preview: M3Palette {
readonly property M3Palette current: M3Palette {}
readonly property M3Palette preview: M3Palette {}
readonly property Transparency transparency: Transparency {}
readonly property alias wallLuminance: analyser.luminance
function getLuminance(c: color): real {
if (c.r == 0 && c.g == 0 && c.b == 0)
return 0;
return Math.sqrt(0.299 * (c.r ** 2) + 0.587 * (c.g ** 2) + 0.114 * (c.b ** 2));
} }
property bool previewLight
property string scheme
property bool showPreview
readonly property M3TPalette tPalette: M3TPalette {
}
readonly property Transparency transparency: Transparency {
}
readonly property alias wallLuminance: analyser.luminance
function alterColor(c: color, a: real, layer: int): color { function alterColor(c: color, a: real, layer: int): color {
const luminance = getLuminance(c); const luminance = getLuminance(c);
@@ -42,6 +40,12 @@ Singleton {
return Qt.rgba(r, g, b, a); return Qt.rgba(r, g, b, a);
} }
function getLuminance(c: color): real {
if (c.r == 0 && c.g == 0 && c.b == 0)
return 0;
return Math.sqrt(0.299 * (c.r ** 2) + 0.587 * (c.g ** 2) + 0.114 * (c.b ** 2));
}
function layer(c: color, layer: var): color { function layer(c: color, layer: var): color {
if (!transparency.enabled) if (!transparency.enabled)
return c; return c;
@@ -49,12 +53,6 @@ Singleton {
return layer === 0 ? Qt.alpha(c, transparency.base) : alterColor(c, transparency.layers, layer ?? 1); return layer === 0 ? Qt.alpha(c, transparency.base) : alterColor(c, transparency.layers, layer ?? 1);
} }
function on(c: color): color {
if (c.hslLightness < 0.5)
return Qt.hsla(c.hslHue, c.hslSaturation, 0.9, 1);
return Qt.hsla(c.hslHue, c.hslSaturation, 0.1, 1);
}
function load(data: string, isPreview: bool): void { function load(data: string, isPreview: bool): void {
const colors = isPreview ? preview : current; const colors = isPreview ? preview : current;
const scheme = JSON.parse(data); const scheme = JSON.parse(data);
@@ -74,9 +72,16 @@ Singleton {
} }
} }
function on(c: color): color {
if (c.hslLightness < 0.5)
return Qt.hsla(c.hslHue, c.hslSaturation, 0.9, 1);
return Qt.hsla(c.hslHue, c.hslSaturation, 0.1, 1);
}
FileView { FileView {
path: `${Paths.state}/scheme.json` path: `${Paths.state}/scheme.json`
watchChanges: true watchChanges: true
onFileChanged: reload() onFileChanged: reload()
onLoaded: root.load(text(), false) onLoaded: root.load(text(), false)
} }
@@ -87,192 +92,189 @@ Singleton {
source: WallpaperPath.currentWallpaperPath source: WallpaperPath.currentWallpaperPath
} }
component Transparency: QtObject {
readonly property bool enabled: Appearance.transparency.enabled
readonly property real base: Appearance.transparency.base - (root.light ? 0.1 : 0)
readonly property real layers: Appearance.transparency.layers
}
component M3TPalette: QtObject {
readonly property color m3primary_paletteKeyColor: root.layer(root.palette.m3primary_paletteKeyColor)
readonly property color m3secondary_paletteKeyColor: root.layer(root.palette.m3secondary_paletteKeyColor)
readonly property color m3tertiary_paletteKeyColor: root.layer(root.palette.m3tertiary_paletteKeyColor)
readonly property color m3neutral_paletteKeyColor: root.layer(root.palette.m3neutral_paletteKeyColor)
readonly property color m3neutral_variant_paletteKeyColor: root.layer(root.palette.m3neutral_variant_paletteKeyColor)
readonly property color m3background: root.layer(root.palette.m3background, 0)
readonly property color m3onBackground: root.layer(root.palette.m3onBackground)
readonly property color m3surface: root.layer(root.palette.m3surface, 0)
readonly property color m3surfaceDim: root.layer(root.palette.m3surfaceDim, 0)
readonly property color m3surfaceBright: root.layer(root.palette.m3surfaceBright, 0)
readonly property color m3surfaceContainerLowest: root.layer(root.palette.m3surfaceContainerLowest)
readonly property color m3surfaceContainerLow: root.layer(root.palette.m3surfaceContainerLow)
readonly property color m3surfaceContainer: root.layer(root.palette.m3surfaceContainer)
readonly property color m3surfaceContainerHigh: root.layer(root.palette.m3surfaceContainerHigh)
readonly property color m3surfaceContainerHighest: root.layer(root.palette.m3surfaceContainerHighest)
readonly property color m3onSurface: root.layer(root.palette.m3onSurface)
readonly property color m3surfaceVariant: root.layer(root.palette.m3surfaceVariant, 0)
readonly property color m3onSurfaceVariant: root.layer(root.palette.m3onSurfaceVariant)
readonly property color m3inverseSurface: root.layer(root.palette.m3inverseSurface, 0)
readonly property color m3inverseOnSurface: root.layer(root.palette.m3inverseOnSurface)
readonly property color m3outline: root.layer(root.palette.m3outline)
readonly property color m3outlineVariant: root.layer(root.palette.m3outlineVariant)
readonly property color m3shadow: root.layer(root.palette.m3shadow)
readonly property color m3scrim: root.layer(root.palette.m3scrim)
readonly property color m3surfaceTint: root.layer(root.palette.m3surfaceTint)
readonly property color m3primary: root.layer(root.palette.m3primary)
readonly property color m3onPrimary: root.layer(root.palette.m3onPrimary)
readonly property color m3primaryContainer: root.layer(root.palette.m3primaryContainer)
readonly property color m3onPrimaryContainer: root.layer(root.palette.m3onPrimaryContainer)
readonly property color m3inversePrimary: root.layer(root.palette.m3inversePrimary)
readonly property color m3secondary: root.layer(root.palette.m3secondary)
readonly property color m3onSecondary: root.layer(root.palette.m3onSecondary)
readonly property color m3secondaryContainer: root.layer(root.palette.m3secondaryContainer)
readonly property color m3onSecondaryContainer: root.layer(root.palette.m3onSecondaryContainer)
readonly property color m3tertiary: root.layer(root.palette.m3tertiary)
readonly property color m3onTertiary: root.layer(root.palette.m3onTertiary)
readonly property color m3tertiaryContainer: root.layer(root.palette.m3tertiaryContainer)
readonly property color m3onTertiaryContainer: root.layer(root.palette.m3onTertiaryContainer)
readonly property color m3error: root.layer(root.palette.m3error)
readonly property color m3onError: root.layer(root.palette.m3onError)
readonly property color m3errorContainer: root.layer(root.palette.m3errorContainer)
readonly property color m3onErrorContainer: root.layer(root.palette.m3onErrorContainer)
readonly property color m3success: root.layer(root.palette.m3success)
readonly property color m3onSuccess: root.layer(root.palette.m3onSuccess)
readonly property color m3successContainer: root.layer(root.palette.m3successContainer)
readonly property color m3onSuccessContainer: root.layer(root.palette.m3onSuccessContainer)
readonly property color m3primaryFixed: root.layer(root.palette.m3primaryFixed)
readonly property color m3primaryFixedDim: root.layer(root.palette.m3primaryFixedDim)
readonly property color m3onPrimaryFixed: root.layer(root.palette.m3onPrimaryFixed)
readonly property color m3onPrimaryFixedVariant: root.layer(root.palette.m3onPrimaryFixedVariant)
readonly property color m3secondaryFixed: root.layer(root.palette.m3secondaryFixed)
readonly property color m3secondaryFixedDim: root.layer(root.palette.m3secondaryFixedDim)
readonly property color m3onSecondaryFixed: root.layer(root.palette.m3onSecondaryFixed)
readonly property color m3onSecondaryFixedVariant: root.layer(root.palette.m3onSecondaryFixedVariant)
readonly property color m3tertiaryFixed: root.layer(root.palette.m3tertiaryFixed)
readonly property color m3tertiaryFixedDim: root.layer(root.palette.m3tertiaryFixedDim)
readonly property color m3onTertiaryFixed: root.layer(root.palette.m3onTertiaryFixed)
readonly property color m3onTertiaryFixedVariant: root.layer(root.palette.m3onTertiaryFixedVariant)
}
component M3Palette: QtObject {
property color m3primary_paletteKeyColor: "#a8627b"
property color m3secondary_paletteKeyColor: "#8e6f78"
property color m3tertiary_paletteKeyColor: "#986e4c"
property color m3neutral_paletteKeyColor: "#807477"
property color m3neutral_variant_paletteKeyColor: "#837377"
property color m3background: "#191114"
property color m3onBackground: "#efdfe2"
property color m3surface: "#191114"
property color m3surfaceDim: "#191114"
property color m3surfaceBright: "#403739"
property color m3surfaceContainerLowest: "#130c0e"
property color m3surfaceContainerLow: "#22191c"
property color m3surfaceContainer: "#261d20"
property color m3surfaceContainerHigh: "#31282a"
property color m3surfaceContainerHighest: "#3c3235"
property color m3onSurface: "#efdfe2"
property color m3surfaceVariant: "#514347"
property color m3onSurfaceVariant: "#d5c2c6"
property color m3inverseSurface: "#efdfe2"
property color m3inverseOnSurface: "#372e30"
property color m3outline: "#9e8c91"
property color m3outlineVariant: "#514347"
property color m3shadow: "#000000"
property color m3scrim: "#000000"
property color m3surfaceTint: "#ffb0ca"
property color m3primary: "#ffb0ca"
property color m3onPrimary: "#541d34"
property color m3primaryContainer: "#6f334a"
property color m3onPrimaryContainer: "#ffd9e3"
property color m3inversePrimary: "#8b4a62"
property color m3secondary: "#e2bdc7"
property color m3onSecondary: "#422932"
property color m3secondaryContainer: "#5a3f48"
property color m3onSecondaryContainer: "#ffd9e3"
property color m3tertiary: "#f0bc95"
property color m3onTertiary: "#48290c"
property color m3tertiaryContainer: "#b58763"
property color m3onTertiaryContainer: "#000000"
property color m3error: "#ffb4ab"
property color m3onError: "#690005"
property color m3errorContainer: "#93000a"
property color m3onErrorContainer: "#ffdad6"
property color m3success: "#B5CCBA"
property color m3onSuccess: "#213528"
property color m3successContainer: "#374B3E"
property color m3onSuccessContainer: "#D1E9D6"
property color m3primaryFixed: "#ffd9e3"
property color m3primaryFixedDim: "#ffb0ca"
property color m3onPrimaryFixed: "#39071f"
property color m3onPrimaryFixedVariant: "#6f334a"
property color m3secondaryFixed: "#ffd9e3"
property color m3secondaryFixedDim: "#e2bdc7"
property color m3onSecondaryFixed: "#2b151d"
property color m3onSecondaryFixedVariant: "#5a3f48"
property color m3tertiaryFixed: "#ffdcc3"
property color m3tertiaryFixedDim: "#f0bc95"
property color m3onTertiaryFixed: "#2f1500"
property color m3onTertiaryFixedVariant: "#623f21"
}
component M3MaccchiatoPalette: QtObject { component M3MaccchiatoPalette: QtObject {
property color m3primary_paletteKeyColor: "#6a73ac" property color m3background: "#131317"
property color m3secondary_paletteKeyColor: "#72758e" property color m3error: "#ffb4ab"
property color m3tertiary_paletteKeyColor: "#9b6592" property color m3errorContainer: "#93000a"
property color m3inverseOnSurface: "#303034"
property color m3inversePrimary: "#525b92"
property color m3inverseSurface: "#e4e1e7"
property color m3neutral_paletteKeyColor: "#77767b" property color m3neutral_paletteKeyColor: "#77767b"
property color m3neutral_variant_paletteKeyColor: "#767680" property color m3neutral_variant_paletteKeyColor: "#767680"
property color m3background: "#131317"
property color m3onBackground: "#e4e1e7" property color m3onBackground: "#e4e1e7"
property color m3onError: "#690005"
property color m3onErrorContainer: "#ffdad6"
property color m3onPrimary: "#232c60"
property color m3onPrimaryContainer: "#ffffff"
property color m3onPrimaryFixed: "#0b154b"
property color m3onPrimaryFixedVariant: "#3a4378"
property color m3onSecondary: "#2c2f44"
property color m3onSecondaryContainer: "#b1b3ce"
property color m3onSecondaryFixed: "#171a2e"
property color m3onSecondaryFixedVariant: "#42455c"
property color m3onSuccess: "#213528"
property color m3onSuccessContainer: "#D1E9D6"
property color m3onSurface: "#e4e1e7"
property color m3onSurfaceVariant: "#c6c5d1"
property color m3onTertiary: "#4c1f48"
property color m3onTertiaryContainer: "#000000"
property color m3onTertiaryFixed: "#340831"
property color m3onTertiaryFixedVariant: "#66365f"
property color m3outline: "#90909a"
property color m3outlineVariant: "#46464f"
property color m3primary: "#bac3ff"
property color m3primaryContainer: "#6a73ac"
property color m3primaryFixed: "#dee0ff"
property color m3primaryFixedDim: "#bac3ff"
property color m3primary_paletteKeyColor: "#6a73ac"
property color m3scrim: "#000000"
property color m3secondary: "#c3c5e0"
property color m3secondaryContainer: "#42455c"
property color m3secondaryFixed: "#dfe1fd"
property color m3secondaryFixedDim: "#c3c5e0"
property color m3secondary_paletteKeyColor: "#72758e"
property color m3shadow: "#000000"
property color m3success: "#B5CCBA"
property color m3successContainer: "#374B3E"
property color m3surface: "#131317" property color m3surface: "#131317"
property color m3surfaceDim: "#131317"
property color m3surfaceBright: "#39393d" property color m3surfaceBright: "#39393d"
property color m3surfaceContainerLowest: "#0e0e12"
property color m3surfaceContainerLow: "#1b1b1f"
property color m3surfaceContainer: "#1f1f23" property color m3surfaceContainer: "#1f1f23"
property color m3surfaceContainerHigh: "#2a2a2e" property color m3surfaceContainerHigh: "#2a2a2e"
property color m3surfaceContainerHighest: "#353438" property color m3surfaceContainerHighest: "#353438"
property color m3onSurface: "#e4e1e7" property color m3surfaceContainerLow: "#1b1b1f"
property color m3surfaceVariant: "#46464f" property color m3surfaceContainerLowest: "#0e0e12"
property color m3onSurfaceVariant: "#c6c5d1" property color m3surfaceDim: "#131317"
property color m3inverseSurface: "#e4e1e7"
property color m3inverseOnSurface: "#303034"
property color m3outline: "#90909a"
property color m3outlineVariant: "#46464f"
property color m3shadow: "#000000"
property color m3scrim: "#000000"
property color m3surfaceTint: "#bac3ff" property color m3surfaceTint: "#bac3ff"
property color m3primary: "#bac3ff" property color m3surfaceVariant: "#46464f"
property color m3onPrimary: "#232c60"
property color m3primaryContainer: "#6a73ac"
property color m3onPrimaryContainer: "#ffffff"
property color m3inversePrimary: "#525b92"
property color m3secondary: "#c3c5e0"
property color m3onSecondary: "#2c2f44"
property color m3secondaryContainer: "#42455c"
property color m3onSecondaryContainer: "#b1b3ce"
property color m3tertiary: "#f1b3e5" property color m3tertiary: "#f1b3e5"
property color m3onTertiary: "#4c1f48"
property color m3tertiaryContainer: "#b77ead" property color m3tertiaryContainer: "#b77ead"
property color m3onTertiaryContainer: "#000000"
property color m3error: "#ffb4ab"
property color m3onError: "#690005"
property color m3errorContainer: "#93000a"
property color m3onErrorContainer: "#ffdad6"
property color m3primaryFixed: "#dee0ff"
property color m3primaryFixedDim: "#bac3ff"
property color m3onPrimaryFixed: "#0b154b"
property color m3onPrimaryFixedVariant: "#3a4378"
property color m3secondaryFixed: "#dfe1fd"
property color m3secondaryFixedDim: "#c3c5e0"
property color m3onSecondaryFixed: "#171a2e"
property color m3onSecondaryFixedVariant: "#42455c"
property color m3tertiaryFixed: "#ffd7f4" property color m3tertiaryFixed: "#ffd7f4"
property color m3tertiaryFixedDim: "#f1b3e5" property color m3tertiaryFixedDim: "#f1b3e5"
property color m3onTertiaryFixed: "#340831" property color m3tertiary_paletteKeyColor: "#9b6592"
property color m3onTertiaryFixedVariant: "#66365f" }
property color m3success: "#B5CCBA" component M3Palette: QtObject {
property color m3background: "#191114"
property color m3error: "#ffb4ab"
property color m3errorContainer: "#93000a"
property color m3inverseOnSurface: "#372e30"
property color m3inversePrimary: "#8b4a62"
property color m3inverseSurface: "#efdfe2"
property color m3neutral_paletteKeyColor: "#807477"
property color m3neutral_variant_paletteKeyColor: "#837377"
property color m3onBackground: "#efdfe2"
property color m3onError: "#690005"
property color m3onErrorContainer: "#ffdad6"
property color m3onPrimary: "#541d34"
property color m3onPrimaryContainer: "#ffd9e3"
property color m3onPrimaryFixed: "#39071f"
property color m3onPrimaryFixedVariant: "#6f334a"
property color m3onSecondary: "#422932"
property color m3onSecondaryContainer: "#ffd9e3"
property color m3onSecondaryFixed: "#2b151d"
property color m3onSecondaryFixedVariant: "#5a3f48"
property color m3onSuccess: "#213528" property color m3onSuccess: "#213528"
property color m3successContainer: "#374B3E"
property color m3onSuccessContainer: "#D1E9D6" property color m3onSuccessContainer: "#D1E9D6"
property color m3onSurface: "#efdfe2"
property color m3onSurfaceVariant: "#d5c2c6"
property color m3onTertiary: "#48290c"
property color m3onTertiaryContainer: "#000000"
property color m3onTertiaryFixed: "#2f1500"
property color m3onTertiaryFixedVariant: "#623f21"
property color m3outline: "#9e8c91"
property color m3outlineVariant: "#514347"
property color m3primary: "#ffb0ca"
property color m3primaryContainer: "#6f334a"
property color m3primaryFixed: "#ffd9e3"
property color m3primaryFixedDim: "#ffb0ca"
property color m3primary_paletteKeyColor: "#a8627b"
property color m3scrim: "#000000"
property color m3secondary: "#e2bdc7"
property color m3secondaryContainer: "#5a3f48"
property color m3secondaryFixed: "#ffd9e3"
property color m3secondaryFixedDim: "#e2bdc7"
property color m3secondary_paletteKeyColor: "#8e6f78"
property color m3shadow: "#000000"
property color m3success: "#B5CCBA"
property color m3successContainer: "#374B3E"
property color m3surface: "#191114"
property color m3surfaceBright: "#403739"
property color m3surfaceContainer: "#261d20"
property color m3surfaceContainerHigh: "#31282a"
property color m3surfaceContainerHighest: "#3c3235"
property color m3surfaceContainerLow: "#22191c"
property color m3surfaceContainerLowest: "#130c0e"
property color m3surfaceDim: "#191114"
property color m3surfaceTint: "#ffb0ca"
property color m3surfaceVariant: "#514347"
property color m3tertiary: "#f0bc95"
property color m3tertiaryContainer: "#b58763"
property color m3tertiaryFixed: "#ffdcc3"
property color m3tertiaryFixedDim: "#f0bc95"
property color m3tertiary_paletteKeyColor: "#986e4c"
}
component M3TPalette: QtObject {
readonly property color m3background: root.layer(root.palette.m3background, 0)
readonly property color m3error: root.layer(root.palette.m3error)
readonly property color m3errorContainer: root.layer(root.palette.m3errorContainer)
readonly property color m3inverseOnSurface: root.layer(root.palette.m3inverseOnSurface)
readonly property color m3inversePrimary: root.layer(root.palette.m3inversePrimary)
readonly property color m3inverseSurface: root.layer(root.palette.m3inverseSurface, 0)
readonly property color m3neutral_paletteKeyColor: root.layer(root.palette.m3neutral_paletteKeyColor)
readonly property color m3neutral_variant_paletteKeyColor: root.layer(root.palette.m3neutral_variant_paletteKeyColor)
readonly property color m3onBackground: root.layer(root.palette.m3onBackground)
readonly property color m3onError: root.layer(root.palette.m3onError)
readonly property color m3onErrorContainer: root.layer(root.palette.m3onErrorContainer)
readonly property color m3onPrimary: root.layer(root.palette.m3onPrimary)
readonly property color m3onPrimaryContainer: root.layer(root.palette.m3onPrimaryContainer)
readonly property color m3onPrimaryFixed: root.layer(root.palette.m3onPrimaryFixed)
readonly property color m3onPrimaryFixedVariant: root.layer(root.palette.m3onPrimaryFixedVariant)
readonly property color m3onSecondary: root.layer(root.palette.m3onSecondary)
readonly property color m3onSecondaryContainer: root.layer(root.palette.m3onSecondaryContainer)
readonly property color m3onSecondaryFixed: root.layer(root.palette.m3onSecondaryFixed)
readonly property color m3onSecondaryFixedVariant: root.layer(root.palette.m3onSecondaryFixedVariant)
readonly property color m3onSuccess: root.layer(root.palette.m3onSuccess)
readonly property color m3onSuccessContainer: root.layer(root.palette.m3onSuccessContainer)
readonly property color m3onSurface: root.layer(root.palette.m3onSurface)
readonly property color m3onSurfaceVariant: root.layer(root.palette.m3onSurfaceVariant)
readonly property color m3onTertiary: root.layer(root.palette.m3onTertiary)
readonly property color m3onTertiaryContainer: root.layer(root.palette.m3onTertiaryContainer)
readonly property color m3onTertiaryFixed: root.layer(root.palette.m3onTertiaryFixed)
readonly property color m3onTertiaryFixedVariant: root.layer(root.palette.m3onTertiaryFixedVariant)
readonly property color m3outline: root.layer(root.palette.m3outline)
readonly property color m3outlineVariant: root.layer(root.palette.m3outlineVariant)
readonly property color m3primary: root.layer(root.palette.m3primary)
readonly property color m3primaryContainer: root.layer(root.palette.m3primaryContainer)
readonly property color m3primaryFixed: root.layer(root.palette.m3primaryFixed)
readonly property color m3primaryFixedDim: root.layer(root.palette.m3primaryFixedDim)
readonly property color m3primary_paletteKeyColor: root.layer(root.palette.m3primary_paletteKeyColor)
readonly property color m3scrim: root.layer(root.palette.m3scrim)
readonly property color m3secondary: root.layer(root.palette.m3secondary)
readonly property color m3secondaryContainer: root.layer(root.palette.m3secondaryContainer)
readonly property color m3secondaryFixed: root.layer(root.palette.m3secondaryFixed)
readonly property color m3secondaryFixedDim: root.layer(root.palette.m3secondaryFixedDim)
readonly property color m3secondary_paletteKeyColor: root.layer(root.palette.m3secondary_paletteKeyColor)
readonly property color m3shadow: root.layer(root.palette.m3shadow)
readonly property color m3success: root.layer(root.palette.m3success)
readonly property color m3successContainer: root.layer(root.palette.m3successContainer)
readonly property color m3surface: root.layer(root.palette.m3surface, 0)
readonly property color m3surfaceBright: root.layer(root.palette.m3surfaceBright, 0)
readonly property color m3surfaceContainer: root.layer(root.palette.m3surfaceContainer)
readonly property color m3surfaceContainerHigh: root.layer(root.palette.m3surfaceContainerHigh)
readonly property color m3surfaceContainerHighest: root.layer(root.palette.m3surfaceContainerHighest)
readonly property color m3surfaceContainerLow: root.layer(root.palette.m3surfaceContainerLow)
readonly property color m3surfaceContainerLowest: root.layer(root.palette.m3surfaceContainerLowest)
readonly property color m3surfaceDim: root.layer(root.palette.m3surfaceDim, 0)
readonly property color m3surfaceTint: root.layer(root.palette.m3surfaceTint)
readonly property color m3surfaceVariant: root.layer(root.palette.m3surfaceVariant, 0)
readonly property color m3tertiary: root.layer(root.palette.m3tertiary)
readonly property color m3tertiaryContainer: root.layer(root.palette.m3tertiaryContainer)
readonly property color m3tertiaryFixed: root.layer(root.palette.m3tertiaryFixed)
readonly property color m3tertiaryFixedDim: root.layer(root.palette.m3tertiaryFixedDim)
readonly property color m3tertiary_paletteKeyColor: root.layer(root.palette.m3tertiary_paletteKeyColor)
}
component Transparency: QtObject {
readonly property real base: Appearance.transparency.base - (root.light ? 0.1 : 0)
readonly property bool enabled: Appearance.transparency.enabled
readonly property real layers: Appearance.transparency.layers
} }
} }
+16 -15
View File
@@ -2,28 +2,29 @@ import Quickshell.Io
import Quickshell import Quickshell
JsonObject { JsonObject {
property Apps apps: Apps {
}
property Color color: Color {
}
property Idle idle: Idle {
}
property string logo: "" property string logo: ""
property string wallpaperPath: Quickshell.env("HOME") + "/Pictures/Wallpapers" property string wallpaperPath: Quickshell.env("HOME") + "/Pictures/Wallpapers"
property Color color: Color {}
property Apps apps: Apps {}
property Idle idle: Idle {}
component Color: JsonObject {
property bool wallust: false
property bool schemeGeneration: true
property string mode: "dark"
property int scheduleDarkStart: 0
property int scheduleDarkEnd: 0
property bool neovimColors: false
}
component Apps: JsonObject { component Apps: JsonObject {
property list<string> terminal: ["kitty"]
property list<string> audio: ["pavucontrol"] property list<string> audio: ["pavucontrol"]
property list<string> playback: ["mpv"]
property list<string> explorer: ["dolphin"] property list<string> explorer: ["dolphin"]
property list<string> playback: ["mpv"]
property list<string> terminal: ["kitty"]
}
component Color: JsonObject {
property string mode: "dark"
property bool neovimColors: false
property int scheduleDarkEnd: 0
property int scheduleDarkStart: 0
property bool schemeGeneration: true
property bool wallust: false
} }
component Idle: JsonObject { component Idle: JsonObject {
property list<var> timeouts: [ property list<var> timeouts: [
{ {
+21 -21
View File
@@ -1,28 +1,7 @@
import Quickshell.Io import Quickshell.Io
JsonObject { JsonObject {
property int maxAppsShown: 10
property int maxWallpapers: 7
property string actionPrefix: ">" property string actionPrefix: ">"
property string specialPrefix: "@"
property Sizes sizes: Sizes {}
property UseFuzzy useFuzzy: UseFuzzy {}
component UseFuzzy: JsonObject {
property bool apps: false
property bool actions: false
property bool schemes: false
property bool variants: false
property bool wallpapers: false
}
component Sizes: JsonObject {
property int itemWidth: 600
property int itemHeight: 50
property int wallpaperWidth: 280
property int wallpaperHeight: 200
}
property list<var> actions: [ property list<var> actions: [
{ {
name: "Calculator", name: "Calculator",
@@ -81,4 +60,25 @@ JsonObject {
dangerous: false dangerous: false
}, },
] ]
property int maxAppsShown: 10
property int maxWallpapers: 7
property Sizes sizes: Sizes {
}
property string specialPrefix: "@"
property UseFuzzy useFuzzy: UseFuzzy {
}
component Sizes: JsonObject {
property int itemHeight: 50
property int itemWidth: 600
property int wallpaperHeight: 200
property int wallpaperWidth: 280
}
component UseFuzzy: JsonObject {
property bool actions: false
property bool apps: false
property bool schemes: false
property bool variants: false
property bool wallpapers: false
}
} }
+5 -4
View File
@@ -1,15 +1,16 @@
import Quickshell.Io import Quickshell.Io
JsonObject { JsonObject {
property bool recolorLogo: false property int blurAmount: 40
property bool enableFprint: true property bool enableFprint: true
property int maxFprintTries: 3 property int maxFprintTries: 3
property Sizes sizes: Sizes {} property bool recolorLogo: false
property int blurAmount: 40 property Sizes sizes: Sizes {
}
component Sizes: JsonObject { component Sizes: JsonObject {
property int centerWidth: 600
property real heightMult: 0.7 property real heightMult: 0.7
property real ratio: 16 / 9 property real ratio: 16 / 9
property int centerWidth: 600
} }
} }
+1 -2
View File
@@ -4,8 +4,6 @@ import Quickshell
Singleton { Singleton {
id: root id: root
property real scale: Appearance.anim.durations.scale
readonly property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1] readonly property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1]
readonly property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1] readonly property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1]
readonly property int emphasizedAccelTime: 200 * scale readonly property int emphasizedAccelTime: 200 * scale
@@ -18,6 +16,7 @@ Singleton {
readonly property int expressiveEffectsTime: 200 * scale readonly property int expressiveEffectsTime: 200 * scale
readonly property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.90, 1, 1] readonly property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.90, 1, 1]
readonly property int expressiveFastSpatialTime: 350 * scale readonly property int expressiveFastSpatialTime: 350 * scale
property real scale: Appearance.anim.durations.scale
readonly property list<real> standard: [0.2, 0, 0, 1, 1, 1] readonly property list<real> standard: [0.2, 0, 0, 1, 1, 1]
readonly property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1] readonly property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1]
readonly property int standardAccelTime: 200 * scale readonly property int standardAccelTime: 200 * scale
+8 -7
View File
@@ -1,18 +1,19 @@
import Quickshell.Io import Quickshell.Io
JsonObject { JsonObject {
property bool expire: true
property int defaultExpireTimeout: 5000
property real clearThreshold: 0.3
property int expandThreshold: 20
property bool actionOnClick: false property bool actionOnClick: false
property real clearThreshold: 0.3
property int defaultExpireTimeout: 5000
property int expandThreshold: 20
property bool expire: true
property int groupPreviewNum: 3 property int groupPreviewNum: 3
property bool openExpanded: false property bool openExpanded: false
property Sizes sizes: Sizes {} property Sizes sizes: Sizes {
}
component Sizes: JsonObject { component Sizes: JsonObject {
property int width: 400
property int image: 41
property int badge: 20 property int badge: 20
property int image: 41
property int width: 400
} }
} }
+6 -5
View File
@@ -1,15 +1,16 @@
import Quickshell.Io import Quickshell.Io
JsonObject { JsonObject {
property bool enabled: true property bool allMonBrightness: false
property int hideDelay: 3000
property bool enableBrightness: true property bool enableBrightness: true
property bool enableMicrophone: true property bool enableMicrophone: true
property bool allMonBrightness: false property bool enabled: true
property Sizes sizes: Sizes {} property int hideDelay: 3000
property Sizes sizes: Sizes {
}
component Sizes: JsonObject { component Sizes: JsonObject {
property int sliderWidth: 30
property int sliderHeight: 150 property int sliderHeight: 150
property int sliderWidth: 30
} }
} }
+2 -2
View File
@@ -1,8 +1,8 @@
import Quickshell.Io import Quickshell.Io
JsonObject { JsonObject {
property int rows: 2
property int columns: 5 property int columns: 5
property real scale: 0.16
property bool enable: false property bool enable: false
property int rows: 2
property real scale: 0.16
} }
+5 -5
View File
@@ -2,18 +2,18 @@ import Quickshell.Io
import QtQuick import QtQuick
JsonObject { JsonObject {
property string weatherLocation: ""
property bool useFahrenheit: false
property bool useTwelveHourClock: Qt.locale().timeFormat(Locale.ShortFormat).toLowerCase().includes("a")
property string gpuType: ""
property real audioIncrement: 0.1 property real audioIncrement: 0.1
property real brightnessIncrement: 0.1 property real brightnessIncrement: 0.1
property real maxVolume: 1.0
property string defaultPlayer: "Spotify" property string defaultPlayer: "Spotify"
property string gpuType: ""
property real maxVolume: 1.0
property list<var> playerAliases: [ property list<var> playerAliases: [
{ {
"from": "com.github.th_ch.youtube_music", "from": "com.github.th_ch.youtube_music",
"to": "YT Music" "to": "YT Music"
} }
] ]
property bool useFahrenheit: false
property bool useTwelveHourClock: Qt.locale().timeFormat(Locale.ShortFormat).toLowerCase().includes("a")
property string weatherLocation: ""
} }
+2 -1
View File
@@ -2,7 +2,8 @@ import Quickshell.Io
JsonObject { JsonObject {
property bool enabled: true property bool enabled: true
property Sizes sizes: Sizes {} property Sizes sizes: Sizes {
}
component Sizes: JsonObject { component Sizes: JsonObject {
property int width: 430 property int width: 430
+1 -1
View File
@@ -1,7 +1,7 @@
import Quickshell.Io import Quickshell.Io
JsonObject { JsonObject {
property bool enabled: false
property real base: 0.85 property real base: 0.85
property bool enabled: false
property real layers: 0.4 property real layers: 0.4
} }
+14 -14
View File
@@ -3,31 +3,31 @@ import Quickshell.Io
JsonObject { JsonObject {
property bool enabled: true property bool enabled: true
property int maxToasts: 4 property int maxToasts: 4
property Sizes sizes: Sizes {
property Sizes sizes: Sizes {} }
property Toasts toasts: Toasts {} property Toasts toasts: Toasts {
property Vpn vpn: Vpn {} }
property Vpn vpn: Vpn {
}
component Sizes: JsonObject { component Sizes: JsonObject {
property int width: 430
property int toastWidth: 430 property int toastWidth: 430
property int width: 430
} }
component Toasts: JsonObject { component Toasts: JsonObject {
property bool configLoaded: true
property bool chargingChanged: true
property bool gameModeChanged: true
property bool dndChanged: true
property bool audioOutputChanged: true
property bool audioInputChanged: true property bool audioInputChanged: true
property bool audioOutputChanged: true
property bool capsLockChanged: true property bool capsLockChanged: true
property bool numLockChanged: true property bool chargingChanged: true
property bool configLoaded: true
property bool dndChanged: true
property bool gameModeChanged: true
property bool kbLayoutChanged: true property bool kbLayoutChanged: true
property bool kbLimit: true property bool kbLimit: true
property bool vpnChanged: true
property bool nowPlaying: false property bool nowPlaying: false
property bool numLockChanged: true
property bool vpnChanged: true
} }
component Vpn: JsonObject { component Vpn: JsonObject {
property bool enabled: false property bool enabled: false
property list<var> provider: ["netbird"] property list<var> provider: ["netbird"]
+1 -1
View File
@@ -1,6 +1,6 @@
import Quickshell.Io import Quickshell.Io
JsonObject { JsonObject {
property string textColor: "black"
property string inactiveTextColor: "white" property string inactiveTextColor: "white"
property string textColor: "black"
} }
+60 -67
View File
@@ -10,9 +10,7 @@ import QtQuick
Singleton { Singleton {
id: root id: root
property string previousSinkName: "" readonly property bool muted: !!sink?.audio?.muted
property string previousSourceName: ""
readonly property var nodes: Pipewire.nodes.values.reduce((acc, node) => { readonly property var nodes: Pipewire.nodes.values.reduce((acc, node) => {
if (!node.isStream) { if (!node.isStream) {
if (node.isSink) if (node.isSink)
@@ -29,73 +27,23 @@ Singleton {
sinks: [], sinks: [],
streams: [] streams: []
}) })
property string previousSinkName: ""
readonly property list<PwNode> sinks: nodes.sinks property string previousSourceName: ""
readonly property list<PwNode> sources: nodes.sources
readonly property list<PwNode> streams: nodes.streams
readonly property PwNode sink: Pipewire.defaultAudioSink readonly property PwNode sink: Pipewire.defaultAudioSink
readonly property list<PwNode> sinks: nodes.sinks
readonly property PwNode source: Pipewire.defaultAudioSource readonly property PwNode source: Pipewire.defaultAudioSource
readonly property bool muted: !!sink?.audio?.muted
readonly property real volume: sink?.audio?.volume ?? 0
readonly property bool sourceMuted: !!source?.audio?.muted readonly property bool sourceMuted: !!source?.audio?.muted
readonly property real sourceVolume: source?.audio?.volume ?? 0 readonly property real sourceVolume: source?.audio?.volume ?? 0
readonly property list<PwNode> sources: nodes.sources
function setVolume(newVolume: real): void { readonly property list<PwNode> streams: nodes.streams
if (sink?.ready && sink?.audio) { readonly property real volume: sink?.audio?.volume ?? 0
sink.audio.muted = false;
sink.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume));
}
}
function incrementVolume(amount: real): void {
setVolume(volume + (amount || Config.services.audioIncrement));
}
function decrementVolume(amount: real): void {
setVolume(volume - (amount || Config.services.audioIncrement));
}
function setSourceVolume(newVolume: real): void {
if (source?.ready && source?.audio) {
source.audio.muted = false;
source.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume));
}
}
function incrementSourceVolume(amount: real): void {
setSourceVolume(sourceVolume + (amount || Config.services.audioIncrement));
}
function decrementSourceVolume(amount: real): void { function decrementSourceVolume(amount: real): void {
setSourceVolume(sourceVolume - (amount || Config.services.audioIncrement)); setSourceVolume(sourceVolume - (amount || Config.services.audioIncrement));
} }
function setAudioSink(newSink: PwNode): void { function decrementVolume(amount: real): void {
Pipewire.preferredDefaultAudioSink = newSink; setVolume(volume - (amount || Config.services.audioIncrement));
}
function setAudioSource(newSource: PwNode): void {
Pipewire.preferredDefaultAudioSource = newSource;
}
function setStreamVolume(stream: PwNode, newVolume: real): void {
if (stream?.ready && stream?.audio) {
stream.audio.muted = false;
stream.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume));
}
}
function setStreamMuted(stream: PwNode, muted: bool): void {
if (stream?.ready && stream?.audio) {
stream.audio.muted = muted;
}
}
function getStreamVolume(stream: PwNode): real {
return stream?.audio?.volume ?? 0;
} }
function getStreamMuted(stream: PwNode): bool { function getStreamMuted(stream: PwNode): bool {
@@ -109,6 +57,57 @@ Singleton {
return stream.applicationName || stream.description || stream.name || qsTr("Unknown Application"); return stream.applicationName || stream.description || stream.name || qsTr("Unknown Application");
} }
function getStreamVolume(stream: PwNode): real {
return stream?.audio?.volume ?? 0;
}
function incrementSourceVolume(amount: real): void {
setSourceVolume(sourceVolume + (amount || Config.services.audioIncrement));
}
function incrementVolume(amount: real): void {
setVolume(volume + (amount || Config.services.audioIncrement));
}
function setAudioSink(newSink: PwNode): void {
Pipewire.preferredDefaultAudioSink = newSink;
}
function setAudioSource(newSource: PwNode): void {
Pipewire.preferredDefaultAudioSource = newSource;
}
function setSourceVolume(newVolume: real): void {
if (source?.ready && source?.audio) {
source.audio.muted = false;
source.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume));
}
}
function setStreamMuted(stream: PwNode, muted: bool): void {
if (stream?.ready && stream?.audio) {
stream.audio.muted = muted;
}
}
function setStreamVolume(stream: PwNode, newVolume: real): void {
if (stream?.ready && stream?.audio) {
stream.audio.muted = false;
stream.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume));
}
}
function setVolume(newVolume: real): void {
if (sink?.ready && sink?.audio) {
sink.audio.muted = false;
sink.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume));
}
}
Component.onCompleted: {
previousSinkName = sink?.description || sink?.name || qsTr("Unknown Device");
previousSourceName = source?.description || source?.name || qsTr("Unknown Device");
}
onSinkChanged: { onSinkChanged: {
if (!sink?.ready) if (!sink?.ready)
return; return;
@@ -120,7 +119,6 @@ Singleton {
previousSinkName = newSinkName; previousSinkName = newSinkName;
} }
onSourceChanged: { onSourceChanged: {
if (!source?.ready) if (!source?.ready)
return; return;
@@ -133,11 +131,6 @@ Singleton {
previousSourceName = newSourceName; previousSourceName = newSourceName;
} }
Component.onCompleted: {
previousSinkName = sink?.description || sink?.name || qsTr("Unknown Device");
previousSourceName = source?.description || source?.name || qsTr("Unknown Device");
}
PwObjectTracker { PwObjectTracker {
objects: [...root.sinks, ...root.sources, ...root.streams] objects: [...root.sinks, ...root.sources, ...root.streams]
} }
+133 -130
View File
@@ -7,67 +7,52 @@ import QtQuick
Singleton { Singleton {
id: root id: root
Component.onCompleted: {
// Trigger ethernet device detection after initialization
Qt.callLater(() => {
getEthernetDevices();
});
// Load saved connections on startup
Nmcli.loadSavedConnections(() => {
root.savedConnections = Nmcli.savedConnections;
root.savedConnectionSsids = Nmcli.savedConnectionSsids;
});
// Get initial WiFi status
Nmcli.getWifiStatus(enabled => {
root.wifiEnabled = enabled;
});
// Sync networks from Nmcli on startup
Qt.callLater(() => {
syncNetworksFromNmcli();
}, 100);
}
readonly property list<AccessPoint> networks: []
readonly property AccessPoint active: networks.find(n => n.active) ?? null readonly property AccessPoint active: networks.find(n => n.active) ?? null
property bool wifiEnabled: true
readonly property bool scanning: Nmcli.scanning
property list<var> ethernetDevices: []
readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null
property int ethernetDeviceCount: 0 property int ethernetDeviceCount: 0
property bool ethernetProcessRunning: false
property var ethernetDeviceDetails: null property var ethernetDeviceDetails: null
property list<var> ethernetDevices: []
property bool ethernetProcessRunning: false
readonly property list<AccessPoint> networks: []
property var pendingConnection: null
property list<string> savedConnectionSsids: []
property list<string> savedConnections: []
readonly property bool scanning: Nmcli.scanning
property bool wifiEnabled: true
property var wirelessDeviceDetails: null property var wirelessDeviceDetails: null
function enableWifi(enabled: bool): void {
Nmcli.enableWifi(enabled, result => {
if (result.success) {
root.getWifiStatus();
Nmcli.getNetworks(() => {
syncNetworksFromNmcli();
});
}
});
}
function toggleWifi(): void {
Nmcli.toggleWifi(result => {
if (result.success) {
root.getWifiStatus();
Nmcli.getNetworks(() => {
syncNetworksFromNmcli();
});
}
});
}
function rescanWifi(): void {
Nmcli.rescanWifi();
}
property var pendingConnection: null
signal connectionFailed(string ssid) signal connectionFailed(string ssid)
function cidrToSubnetMask(cidr: string): string {
// Convert CIDR notation (e.g., "24") to subnet mask (e.g., "255.255.255.0")
const cidrNum = parseInt(cidr);
if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) {
return "";
}
const mask = (0xffffffff << (32 - cidrNum)) >>> 0;
const octets = [(mask >>> 24) & 0xff, (mask >>> 16) & 0xff, (mask >>> 8) & 0xff, mask & 0xff];
return octets.join(".");
}
function connectEthernet(connectionName: string, interfaceName: string): void {
Nmcli.connectEthernet(connectionName, interfaceName, result => {
if (result.success) {
getEthernetDevices();
// Refresh device details after connection
Qt.callLater(() => {
const activeDevice = root.ethernetDevices.find(function (d) {
return d.connected;
});
if (activeDevice && activeDevice.interface) {
updateEthernetDeviceDetails(activeDevice.interface);
}
}, 1000);
}
});
}
function connectToNetwork(ssid: string, password: string, bssid: string, callback: var): void { function connectToNetwork(ssid: string, password: string, bssid: string, callback: var): void {
// Set up pending connection tracking if callback provided // Set up pending connection tracking if callback provided
if (callback) { if (callback) {
@@ -132,6 +117,18 @@ Singleton {
}, bssid); }, bssid);
} }
function disconnectEthernet(connectionName: string): void {
Nmcli.disconnectEthernet(connectionName, result => {
if (result.success) {
getEthernetDevices();
// Clear device details after disconnection
Qt.callLater(() => {
root.ethernetDeviceDetails = null;
});
}
});
}
function disconnectFromNetwork(): void { function disconnectFromNetwork(): void {
// Try to disconnect - use connection name if available, otherwise use device // Try to disconnect - use connection name if available, otherwise use device
Nmcli.disconnectFromNetwork(); Nmcli.disconnectFromNetwork();
@@ -143,6 +140,17 @@ Singleton {
}, 500); }, 500);
} }
function enableWifi(enabled: bool): void {
Nmcli.enableWifi(enabled, result => {
if (result.success) {
root.getWifiStatus();
Nmcli.getNetworks(() => {
syncNetworksFromNmcli();
});
}
});
}
function forgetNetwork(ssid: string): void { function forgetNetwork(ssid: string): void {
// Delete the connection profile for this network // Delete the connection profile for this network
// This will remove the saved password and connection settings // This will remove the saved password and connection settings
@@ -158,18 +166,28 @@ Singleton {
}); });
} }
property list<string> savedConnections: [] function getEthernetDevices(): void {
property list<string> savedConnectionSsids: [] root.ethernetProcessRunning = true;
Nmcli.getEthernetInterfaces(interfaces => {
root.ethernetDevices = Nmcli.ethernetDevices;
root.ethernetDeviceCount = Nmcli.ethernetDevices.length;
root.ethernetProcessRunning = false;
});
}
// Sync saved connections from Nmcli when they're updated function getWifiStatus(): void {
Connections { Nmcli.getWifiStatus(enabled => {
target: Nmcli root.wifiEnabled = enabled;
function onSavedConnectionsChanged() { });
root.savedConnections = Nmcli.savedConnections;
} }
function onSavedConnectionSsidsChanged() {
root.savedConnectionSsids = Nmcli.savedConnectionSsids; function hasSavedProfile(ssid: string): bool {
// Use Nmcli's hasSavedProfile which has the same logic
return Nmcli.hasSavedProfile(ssid);
} }
function rescanWifi(): void {
Nmcli.rescanWifi();
} }
function syncNetworksFromNmcli(): void { function syncNetworksFromNmcli(): void {
@@ -216,66 +234,12 @@ Singleton {
} }
} }
component AccessPoint: QtObject { function toggleWifi(): void {
required property var lastIpcObject Nmcli.toggleWifi(result => {
readonly property string ssid: lastIpcObject.ssid
readonly property string bssid: lastIpcObject.bssid
readonly property int strength: lastIpcObject.strength
readonly property int frequency: lastIpcObject.frequency
readonly property bool active: lastIpcObject.active
readonly property string security: lastIpcObject.security
readonly property bool isSecure: security.length > 0
}
Component {
id: apComp
AccessPoint {}
}
function hasSavedProfile(ssid: string): bool {
// Use Nmcli's hasSavedProfile which has the same logic
return Nmcli.hasSavedProfile(ssid);
}
function getWifiStatus(): void {
Nmcli.getWifiStatus(enabled => {
root.wifiEnabled = enabled;
});
}
function getEthernetDevices(): void {
root.ethernetProcessRunning = true;
Nmcli.getEthernetInterfaces(interfaces => {
root.ethernetDevices = Nmcli.ethernetDevices;
root.ethernetDeviceCount = Nmcli.ethernetDevices.length;
root.ethernetProcessRunning = false;
});
}
function connectEthernet(connectionName: string, interfaceName: string): void {
Nmcli.connectEthernet(connectionName, interfaceName, result => {
if (result.success) { if (result.success) {
getEthernetDevices(); root.getWifiStatus();
// Refresh device details after connection Nmcli.getNetworks(() => {
Qt.callLater(() => { syncNetworksFromNmcli();
const activeDevice = root.ethernetDevices.find(function (d) {
return d.connected;
});
if (activeDevice && activeDevice.interface) {
updateEthernetDeviceDetails(activeDevice.interface);
}
}, 1000);
}
});
}
function disconnectEthernet(connectionName: string): void {
Nmcli.disconnectEthernet(connectionName, result => {
if (result.success) {
getEthernetDevices();
// Clear device details after disconnection
Qt.callLater(() => {
root.ethernetDeviceDetails = null;
}); });
} }
}); });
@@ -295,22 +259,50 @@ Singleton {
}); });
} }
function cidrToSubnetMask(cidr: string): string { Component.onCompleted: {
// Convert CIDR notation (e.g., "24") to subnet mask (e.g., "255.255.255.0") // Trigger ethernet device detection after initialization
const cidrNum = parseInt(cidr); Qt.callLater(() => {
if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) { getEthernetDevices();
return ""; });
// Load saved connections on startup
Nmcli.loadSavedConnections(() => {
root.savedConnections = Nmcli.savedConnections;
root.savedConnectionSsids = Nmcli.savedConnectionSsids;
});
// Get initial WiFi status
Nmcli.getWifiStatus(enabled => {
root.wifiEnabled = enabled;
});
// Sync networks from Nmcli on startup
Qt.callLater(() => {
syncNetworksFromNmcli();
}, 100);
} }
const mask = (0xffffffff << (32 - cidrNum)) >>> 0; // Sync saved connections from Nmcli when they're updated
const octets = [(mask >>> 24) & 0xff, (mask >>> 16) & 0xff, (mask >>> 8) & 0xff, mask & 0xff]; Connections {
function onSavedConnectionSsidsChanged() {
root.savedConnectionSsids = Nmcli.savedConnectionSsids;
}
return octets.join("."); function onSavedConnectionsChanged() {
root.savedConnections = Nmcli.savedConnections;
}
target: Nmcli
}
Component {
id: apComp
AccessPoint {
}
} }
Process { Process {
running: true
command: ["nmcli", "m"] command: ["nmcli", "m"]
running: true
stdout: SplitParser { stdout: SplitParser {
onRead: { onRead: {
Nmcli.getNetworks(() => { Nmcli.getNetworks(() => {
@@ -320,4 +312,15 @@ Singleton {
} }
} }
} }
component AccessPoint: QtObject {
readonly property bool active: lastIpcObject.active
readonly property string bssid: lastIpcObject.bssid
readonly property int frequency: lastIpcObject.frequency
readonly property bool isSecure: security.length > 0
required property var lastIpcObject
readonly property string security: lastIpcObject.security
readonly property string ssid: lastIpcObject.ssid
readonly property int strength: lastIpcObject.strength
}
} }
+755 -749
View File
File diff suppressed because it is too large Load Diff
+137 -136
View File
@@ -16,14 +16,13 @@ import qs.Config
Singleton { Singleton {
id: root id: root
property alias dnd: props.dnd
property list<Notif> list: [] property list<Notif> list: []
property bool loaded
readonly property list<Notif> notClosed: list.filter(n => !n.closed) readonly property list<Notif> notClosed: list.filter(n => !n.closed)
readonly property list<Notif> popups: list.filter(n => n.popup) readonly property list<Notif> popups: list.filter(n => n.popup)
property alias dnd: props.dnd
property alias server: server property alias server: server
property bool loaded
onListChanged: { onListChanged: {
if (loaded) { if (loaded) {
saveTimer.restart(); saveTimer.restart();
@@ -37,7 +36,9 @@ Singleton {
Timer { Timer {
id: saveTimer id: saveTimer
interval: 1000 interval: 1000
onTriggered: storage.setText(JSON.stringify(root.notClosed.map(n => ({ onTriggered: storage.setText(JSON.stringify(root.notClosed.map(n => ({
time: n.time, time: n.time,
id: n.id, id: n.id,
@@ -51,7 +52,7 @@ Singleton {
resident: n.resident, resident: n.resident,
hasActionIcons: n.hasActionIcons, hasActionIcons: n.hasActionIcons,
actions: n.actions actions: n.actions
})))); }))))
} }
PersistentProperties { PersistentProperties {
@@ -65,12 +66,12 @@ Singleton {
NotificationServer { NotificationServer {
id: server id: server
keepOnReload: false
actionsSupported: true actionsSupported: true
bodyHyperlinksSupported: true bodyHyperlinksSupported: true
bodyImagesSupported: true bodyImagesSupported: true
bodyMarkupSupported: true bodyMarkupSupported: true
imageSupported: true imageSupported: true
keepOnReload: false
persistenceSupported: true persistenceSupported: true
onNotification: notif => { onNotification: notif => {
@@ -86,15 +87,8 @@ Singleton {
FileView { FileView {
id: storage id: storage
path: `${Paths.state}/notifs.json`
onLoaded: { path: `${Paths.state}/notifs.json`
const data = JSON.parse(text());
for (const notif of data)
root.list.push(notifComp.createObject(root, notif));
root.list.sort((a, b) => b.time - a.time);
root.loaded = true;
}
onLoadFailed: err => { onLoadFailed: err => {
if (err === FileViewError.FileNotFound) { if (err === FileViewError.FileNotFound) {
@@ -102,11 +96,19 @@ Singleton {
setText("[]"); setText("[]");
} }
} }
onLoaded: {
const data = JSON.parse(text());
for (const notif of data)
root.list.push(notifComp.createObject(root, notif));
root.list.sort((a, b) => b.time - a.time);
root.loaded = true;
}
} }
CustomShortcut { CustomShortcut {
name: "clearnotifs"
description: "Clear all notifications" description: "Clear all notifications"
name: "clearnotifs"
onPressed: { onPressed: {
for (const notif of root.list.slice()) for (const notif of root.list.slice())
notif.close(); notif.close();
@@ -114,13 +116,19 @@ Singleton {
} }
IpcHandler { IpcHandler {
target: "notifs"
function clear(): void { function clear(): void {
for (const notif of root.list.slice()) for (const notif of root.list.slice())
notif.close(); notif.close();
} }
function disableDnd(): void {
props.dnd = false;
}
function enableDnd(): void {
props.dnd = true;
}
function isDndEnabled(): bool { function isDndEnabled(): bool {
return props.dnd; return props.dnd;
} }
@@ -129,80 +137,87 @@ Singleton {
props.dnd = !props.dnd; props.dnd = !props.dnd;
} }
function enableDnd(): void { target: "notifs"
props.dnd = true;
} }
function disableDnd(): void { Component {
props.dnd = false; id: notifComp
Notif {
} }
} }
component Notif: QtObject { component Notif: QtObject {
id: notif id: notif
property bool popup property list<var> actions
property bool closed
property var locks: new Set()
property date time: new Date()
readonly property string timeStr: {
const diff = Time.date.getTime() - time.getTime();
const m = Math.floor(diff / 60000);
if (m < 1)
return qsTr("now");
const h = Math.floor(m / 60);
const d = Math.floor(h / 24);
if (d > 0)
return `${d}d`;
if (h > 0)
return `${h}h`;
return `${m}m`;
}
property Notification notification
property string id
property string summary
property string body
property string appIcon property string appIcon
property string appName property string appName
property string image property string body
property real expireTimeout: 5 property bool closed
property int urgency: NotificationUrgency.Normal readonly property Connections conn: Connections {
property bool resident function onActionsChanged(): void {
property bool hasActionIcons notif.actions = notif.notification.actions.map(a => ({
property list<var> actions identifier: a.identifier,
text: a.text,
readonly property Timer timer: Timer { invoke: () => a.invoke()
property int totalTime: Config.notifs.defaultExpireTimeout }));
property int remainingTime: totalTime
property bool paused: false
running: !paused
repeat: true
interval: 50
onTriggered: {
remainingTime -= interval;
if ( remainingTime <= 0 ) {
remainingTime = 0;
notif.popup = false;
stop();
}
}
} }
function onAppIconChanged(): void {
notif.appIcon = notif.notification.appIcon;
}
function onAppNameChanged(): void {
notif.appName = notif.notification.appName;
}
function onBodyChanged(): void {
notif.body = notif.notification.body;
}
function onClosed(): void {
notif.close();
}
function onExpireTimeoutChanged(): void {
notif.expireTimeout = notif.notification.expireTimeout;
}
function onHasActionIconsChanged(): void {
notif.hasActionIcons = notif.notification.hasActionIcons;
}
function onImageChanged(): void {
notif.image = notif.notification.image;
if (notif.notification?.image)
notif.dummyImageLoader.active = true;
}
function onResidentChanged(): void {
notif.resident = notif.notification.resident;
}
function onSummaryChanged(): void {
notif.summary = notif.notification.summary;
}
function onUrgencyChanged(): void {
notif.urgency = notif.notification.urgency;
}
target: notif.notification
}
readonly property LazyLoader dummyImageLoader: LazyLoader { readonly property LazyLoader dummyImageLoader: LazyLoader {
active: false active: false
PanelWindow { PanelWindow {
implicitWidth: Config.notifs.sizes.image
implicitHeight: Config.notifs.sizes.image
color: "transparent" color: "transparent"
mask: Region {} implicitHeight: Config.notifs.sizes.image
implicitWidth: Config.notifs.sizes.image
mask: Region {
}
Image { Image {
function tryCache(): void { function tryCache(): void {
@@ -230,70 +245,71 @@ Singleton {
} }
anchors.fill: parent anchors.fill: parent
source: Qt.resolvedUrl(notif.image)
fillMode: Image.PreserveAspectCrop
cache: false
asynchronous: true asynchronous: true
cache: false
fillMode: Image.PreserveAspectCrop
opacity: 0 opacity: 0
source: Qt.resolvedUrl(notif.image)
onHeightChanged: tryCache()
onStatusChanged: tryCache() onStatusChanged: tryCache()
onWidthChanged: tryCache() onWidthChanged: tryCache()
onHeightChanged: tryCache()
} }
} }
} }
property real expireTimeout: 5
property bool hasActionIcons
property string id
property string image
property var locks: new Set()
property Notification notification
property bool popup
property bool resident
property string summary
property date time: new Date()
readonly property string timeStr: {
const diff = Time.date.getTime() - time.getTime();
const m = Math.floor(diff / 60000);
readonly property Connections conn: Connections { if (m < 1)
target: notif.notification return qsTr("now");
function onClosed(): void { const h = Math.floor(m / 60);
notif.close(); const d = Math.floor(h / 24);
if (d > 0)
return `${d}d`;
if (h > 0)
return `${h}h`;
return `${m}m`;
} }
readonly property Timer timer: Timer {
property bool paused: false
property int remainingTime: totalTime
property int totalTime: Config.notifs.defaultExpireTimeout
function onSummaryChanged(): void { interval: 50
notif.summary = notif.notification.summary; repeat: true
running: !paused
onTriggered: {
remainingTime -= interval;
if (remainingTime <= 0) {
remainingTime = 0;
notif.popup = false;
stop();
} }
function onBodyChanged(): void {
notif.body = notif.notification.body;
} }
function onAppIconChanged(): void {
notif.appIcon = notif.notification.appIcon;
} }
property int urgency: NotificationUrgency.Normal
function onAppNameChanged(): void { function close(): void {
notif.appName = notif.notification.appName; closed = true;
} if (locks.size === 0 && root.list.includes(this)) {
root.list = root.list.filter(n => n !== this);
function onImageChanged(): void { notification?.dismiss();
notif.image = notif.notification.image; destroy();
if (notif.notification?.image)
notif.dummyImageLoader.active = true;
}
function onExpireTimeoutChanged(): void {
notif.expireTimeout = notif.notification.expireTimeout;
}
function onUrgencyChanged(): void {
notif.urgency = notif.notification.urgency;
}
function onResidentChanged(): void {
notif.resident = notif.notification.resident;
}
function onHasActionIconsChanged(): void {
notif.hasActionIcons = notif.notification.hasActionIcons;
}
function onActionsChanged(): void {
notif.actions = notif.notification.actions.map(a => ({
identifier: a.identifier,
text: a.text,
invoke: () => a.invoke()
}));
} }
} }
@@ -307,15 +323,6 @@ Singleton {
close(); close();
} }
function close(): void {
closed = true;
if (locks.size === 0 && root.list.includes(this)) {
root.list = root.list.filter(n => n !== this);
notification?.dismiss();
destroy();
}
}
Component.onCompleted: { Component.onCompleted: {
if (!notification) if (!notification)
return; return;
@@ -339,10 +346,4 @@ Singleton {
})); }));
} }
} }
Component {
id: notifComp
Notif {}
}
} }
+9 -17
View File
@@ -13,8 +13,8 @@ import qs.Modules.Settings as Settings
Shape { Shape {
id: root id: root
required property Panels panels
required property Item bar required property Item bar
required property Panels panels
required property PersistentProperties visibilities required property PersistentProperties visibilities
anchors.fill: parent anchors.fill: parent
@@ -25,66 +25,58 @@ Shape {
Component.onCompleted: console.log(root.bar.implicitHeight, root.bar.anchors.topMargin) Component.onCompleted: console.log(root.bar.implicitHeight, root.bar.anchors.topMargin)
Osd.Background { Osd.Background {
wrapper: root.panels.osd
startX: root.width - root.panels.sidebar.width startX: root.width - root.panels.sidebar.width
startY: (root.height - wrapper.height) / 2 - rounding startY: (root.height - wrapper.height) / 2 - rounding
wrapper: root.panels.osd
} }
Modules.Background { Modules.Background {
wrapper: root.panels.popouts
invertBottomRounding: wrapper.x <= 0 invertBottomRounding: wrapper.x <= 0
startX: wrapper.x - 8 startX: wrapper.x - 8
startY: wrapper.y startY: wrapper.y
wrapper: root.panels.popouts
} }
Notifications.Background { Notifications.Background {
wrapper: root.panels.notifications
sidebar: sidebar sidebar: sidebar
startX: root.width startX: root.width
startY: 0 startY: 0
wrapper: root.panels.notifications
} }
Launcher.Background { Launcher.Background {
wrapper: root.panels.launcher
startX: (root.width - wrapper.width) / 2 - rounding startX: (root.width - wrapper.width) / 2 - rounding
startY: root.height startY: root.height
wrapper: root.panels.launcher
} }
Dashboard.Background { Dashboard.Background {
wrapper: root.panels.dashboard
startX: root.width - root.panels.dashboard.width - rounding startX: root.width - root.panels.dashboard.width - rounding
startY: 0 startY: 0
wrapper: root.panels.dashboard
} }
Utils.Background { Utils.Background {
wrapper: root.panels.utilities
sidebar: sidebar sidebar: sidebar
startX: root.width startX: root.width
startY: root.height startY: root.height
wrapper: root.panels.utilities
} }
Sidebar.Background { Sidebar.Background {
id: sidebar id: sidebar
wrapper: root.panels.sidebar
panels: root.panels panels: root.panels
startX: root.width startX: root.width
startY: root.panels.notifications.height startY: root.panels.notifications.height
wrapper: root.panels.sidebar
} }
Settings.Background { Settings.Background {
id: settings id: settings
wrapper: root.panels.settings
startX: (root.width - wrapper.width) / 2 - rounding startX: (root.width - wrapper.width) / 2 - rounding
startY: 0 startY: 0
wrapper: root.panels.settings
} }
} }
+69 -57
View File
@@ -15,21 +15,37 @@ import qs.Drawers
Variants { Variants {
model: Quickshell.screens model: Quickshell.screens
Scope { Scope {
id: scope id: scope
required property var modelData required property var modelData
PanelWindow { PanelWindow {
id: bar id: bar
property bool trayMenuVisible: false
screen: scope.modelData
color: "transparent"
property var root: Quickshell.shellDir
WlrLayershell.namespace: "ZShell-Bar" property var root: Quickshell.shellDir
property bool trayMenuVisible: false
WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.exclusionMode: ExclusionMode.Ignore
WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.sidebar || visibilities.dashboard ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.sidebar || visibilities.dashboard ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
WlrLayershell.namespace: "ZShell-Bar"
color: "transparent"
contentItem.focus: true contentItem.focus: true
screen: scope.modelData
mask: Region {
id: region
property list<Region> nullRegions: []
height: bar.screen.height - backgroundRect.implicitHeight
intersection: Intersection.Xor
regions: popoutRegions.instances
width: bar.width
x: 0
y: Config.barConfig.autoHide && !visibilities.bar ? 4 : 34
}
contentItem.Keys.onEscapePressed: { contentItem.Keys.onEscapePressed: {
if (Config.barConfig.autoHide) if (Config.barConfig.autoHide)
@@ -41,52 +57,41 @@ Variants {
PanelWindow { PanelWindow {
id: exclusionZone id: exclusionZone
WlrLayershell.namespace: "ZShell-Bar-Exclusion"
screen: bar.screen
WlrLayershell.layer: WlrLayer.Bottom
WlrLayershell.exclusionMode: Config.barConfig.autoHide ? ExclusionMode.Ignore : ExclusionMode.Auto WlrLayershell.exclusionMode: Config.barConfig.autoHide ? ExclusionMode.Ignore : ExclusionMode.Auto
anchors { WlrLayershell.layer: WlrLayer.Bottom
left: true WlrLayershell.namespace: "ZShell-Bar-Exclusion"
right: true
top: true
}
color: "transparent" color: "transparent"
implicitHeight: 34 implicitHeight: 34
screen: bar.screen
anchors {
left: true
right: true
top: true
}
} }
anchors { anchors {
top: true bottom: true
left: true left: true
right: true right: true
bottom: true top: true
}
mask: Region {
id: region
x: 0
y: Config.barConfig.autoHide && !visibilities.bar ? 4 : 34
property list<Region> nullRegions: []
width: bar.width
height: bar.screen.height - backgroundRect.implicitHeight
intersection: Intersection.Xor
regions: popoutRegions.instances
} }
Variants { Variants {
id: popoutRegions id: popoutRegions
model: panels.children model: panels.children
Region { Region {
required property Item modelData required property Item modelData
x: modelData.x
y: modelData.y + backgroundRect.implicitHeight
width: modelData.width
height: modelData.height height: modelData.height
intersection: Intersection.Subtract intersection: Intersection.Subtract
width: modelData.width
x: modelData.x
y: modelData.y + backgroundRect.implicitHeight
} }
} }
@@ -95,6 +100,7 @@ Variants {
active: visibilities.launcher || visibilities.sidebar || visibilities.dashboard || (panels.popouts.hasCurrent && panels.popouts.currentName.startsWith("traymenu")) active: visibilities.launcher || visibilities.sidebar || visibilities.dashboard || (panels.popouts.hasCurrent && panels.popouts.currentName.startsWith("traymenu"))
windows: [bar] windows: [bar]
onCleared: { onCleared: {
visibilities.launcher = false; visibilities.launcher = false;
visibilities.sidebar = false; visibilities.sidebar = false;
@@ -107,32 +113,33 @@ Variants {
PersistentProperties { PersistentProperties {
id: visibilities id: visibilities
property bool sidebar
property bool dashboard
property bool bar property bool bar
property bool osd property bool dashboard
property bool launcher property bool launcher
property bool notif: NotifServer.popups.length > 0 property bool notif: NotifServer.popups.length > 0
property bool osd
property bool settings property bool settings
property bool sidebar
Component.onCompleted: Visibilities.load(scope.modelData, this) Component.onCompleted: Visibilities.load(scope.modelData, this)
} }
Binding { Binding {
target: visibilities
property: "bar" property: "bar"
target: visibilities
value: visibilities.sidebar || visibilities.dashboard || visibilities.osd || visibilities.notif value: visibilities.sidebar || visibilities.dashboard || visibilities.osd || visibilities.notif
when: Config.barConfig.autoHide when: Config.barConfig.autoHide
} }
Item { Item {
anchors.fill: parent anchors.fill: parent
opacity: Appearance.transparency.enabled ? DynamicColors.transparency.base : 1
layer.enabled: true layer.enabled: true
opacity: Appearance.transparency.enabled ? DynamicColors.transparency.base : 1
layer.effect: MultiEffect { layer.effect: MultiEffect {
shadowEnabled: true
blurMax: 32 blurMax: 32
shadowColor: Qt.alpha(DynamicColors.palette.m3shadow, 1) shadowColor: Qt.alpha(DynamicColors.palette.m3shadow, 1)
shadowEnabled: true
} }
Border { Border {
@@ -141,55 +148,60 @@ Variants {
} }
Backgrounds { Backgrounds {
visibilities: visibilities
panels: panels
bar: backgroundRect bar: backgroundRect
panels: panels
visibilities: visibilities
} }
} }
Interactions { Interactions {
id: mouseArea id: mouseArea
screen: scope.modelData
popouts: panels.popouts
visibilities: visibilities
panels: panels
bar: barLoader
anchors.fill: parent anchors.fill: parent
bar: barLoader
panels: panels
popouts: panels.popouts
screen: scope.modelData
visibilities: visibilities
Panels { Panels {
id: panels id: panels
screen: scope.modelData
bar: backgroundRect bar: backgroundRect
screen: scope.modelData
visibilities: visibilities visibilities: visibilities
} }
CustomRect { CustomRect {
id: backgroundRect id: backgroundRect
property Wrapper popouts: panels.popouts property Wrapper popouts: panels.popouts
anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
implicitHeight: 34 anchors.top: parent.top
anchors.topMargin: Config.barConfig.autoHide && !visibilities.bar ? -30 : 0 anchors.topMargin: Config.barConfig.autoHide && !visibilities.bar ? -30 : 0
color: "transparent" color: "transparent"
implicitHeight: 34
radius: 0 radius: 0
Behavior on color {
CAnim {}
}
Behavior on anchors.topMargin { Behavior on anchors.topMargin {
Anim {} Anim {
}
}
Behavior on color {
CAnim {
}
} }
BarLoader { BarLoader {
id: barLoader id: barLoader
anchors.fill: parent anchors.fill: parent
popouts: panels.popouts
bar: bar bar: bar
visibilities: visibilities popouts: panels.popouts
screen: scope.modelData screen: scope.modelData
visibilities: visibilities
} }
} }
} }
+42 -45
View File
@@ -7,25 +7,18 @@ import qs.Modules as BarPopouts
CustomMouseArea { CustomMouseArea {
id: root id: root
required property ShellScreen screen
required property BarPopouts.Wrapper popouts
required property PersistentProperties visibilities
required property Panels panels
required property Item bar required property Item bar
property point dragStart
property bool dashboardShortcutActive property bool dashboardShortcutActive
property point dragStart
property bool osdShortcutActive property bool osdShortcutActive
required property Panels panels
required property BarPopouts.Wrapper popouts
required property ShellScreen screen
property bool utilitiesShortcutActive property bool utilitiesShortcutActive
required property PersistentProperties visibilities
function withinPanelHeight(panel: Item, x: real, y: real): bool { function inBottomPanel(panel: Item, x: real, y: real): bool {
const panelY = panel.y + bar.implicitHeight; return y > root.height - panel.height && withinPanelWidth(panel, x, y);
return y >= panelY && y <= panelY + panel.height;
}
function withinPanelWidth(panel: Item, x: real, y: real): bool {
const panelX = panel.x;
return x >= panelX && x <= panelX + panel.width;
} }
function inLeftPanel(panel: Item, x: real, y: real): bool { function inLeftPanel(panel: Item, x: real, y: real): bool {
@@ -40,16 +33,22 @@ CustomMouseArea {
return y < bar.implicitHeight + panel.height && withinPanelWidth(panel, x, y); return y < bar.implicitHeight + panel.height && withinPanelWidth(panel, x, y);
} }
function inBottomPanel(panel: Item, x: real, y: real): bool {
return y > root.height - panel.height && withinPanelWidth(panel, x, y);
}
function onWheel(event: WheelEvent): void { function onWheel(event: WheelEvent): void {
if (event.x < bar.implicitWidth) { if (event.x < bar.implicitWidth) {
bar.handleWheel(event.y, event.angleDelta); bar.handleWheel(event.y, event.angleDelta);
} }
} }
function withinPanelHeight(panel: Item, x: real, y: real): bool {
const panelY = panel.y + bar.implicitHeight;
return y >= panelY && y <= panelY + panel.height;
}
function withinPanelWidth(panel: Item, x: real, y: real): bool {
const panelX = panel.x;
return x >= panelX && x <= panelX + panel.width;
}
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
@@ -79,7 +78,6 @@ CustomMouseArea {
root.visibilities.bar = false; root.visibilities.bar = false;
} }
} }
onPositionChanged: event => { onPositionChanged: event => {
if (popouts.isDetached) if (popouts.isDetached)
return; return;
@@ -200,7 +198,22 @@ CustomMouseArea {
// Monitor individual visibility changes // Monitor individual visibility changes
Connections { Connections {
target: root.visibilities function onDashboardChanged() {
if (root.visibilities.dashboard) {
// Dashboard became visible, immediately check if this should be shortcut mode
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
if (!inDashboardArea) {
root.dashboardShortcutActive = true;
}
root.visibilities.sidebar = false;
root.popouts.hasCurrent = false;
} else {
// Dashboard hidden, clear shortcut flag
root.dashboardShortcutActive = false;
// root.visibilities.bar = false;
}
}
function onLauncherChanged() { function onLauncherChanged() {
// If launcher is hidden, clear shortcut flags for dashboard and OSD // If launcher is hidden, clear shortcut flags for dashboard and OSD
@@ -223,31 +236,6 @@ CustomMouseArea {
} }
} }
function onSidebarChanged() {
if ( root.visibilities.sidebar ) {
root.visibilities.dashboard = false;
root.popouts.hasCurrent = false;
}
}
function onDashboardChanged() {
if (root.visibilities.dashboard) {
// Dashboard became visible, immediately check if this should be shortcut mode
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
if (!inDashboardArea) {
root.dashboardShortcutActive = true;
}
root.visibilities.sidebar = false;
root.popouts.hasCurrent = false;
} else {
// Dashboard hidden, clear shortcut flag
root.dashboardShortcutActive = false;
// root.visibilities.bar = false;
}
}
function onOsdChanged() { function onOsdChanged() {
if (root.visibilities.osd) { if (root.visibilities.osd) {
// OSD became visible, immediately check if this should be shortcut mode // OSD became visible, immediately check if this should be shortcut mode
@@ -262,6 +250,13 @@ CustomMouseArea {
} }
} }
function onSidebarChanged() {
if (root.visibilities.sidebar) {
root.visibilities.dashboard = false;
root.popouts.hasCurrent = false;
}
}
function onUtilitiesChanged() { function onUtilitiesChanged() {
if (root.visibilities.utilities) { if (root.visibilities.utilities) {
// Utilities became visible, immediately check if this should be shortcut mode // Utilities became visible, immediately check if this should be shortcut mode
@@ -274,5 +269,7 @@ CustomMouseArea {
root.utilitiesShortcutActive = false; root.utilitiesShortcutActive = false;
} }
} }
target: root.visibilities
} }
} }
+32 -40
View File
@@ -15,46 +15,44 @@ import qs.Config
Item { Item {
id: root id: root
required property ShellScreen screen
required property Item bar required property Item bar
required property PersistentProperties visibilities
readonly property alias popouts: popouts
readonly property alias sidebar: sidebar
readonly property alias notifications: notifications
readonly property alias utilities: utilities
readonly property alias dashboard: dashboard readonly property alias dashboard: dashboard
readonly property alias osd: osd
readonly property alias toasts: toasts
readonly property alias launcher: launcher readonly property alias launcher: launcher
readonly property alias notifications: notifications
readonly property alias osd: osd
readonly property alias popouts: popouts
required property ShellScreen screen
readonly property alias settings: settings readonly property alias settings: settings
readonly property alias sidebar: sidebar
readonly property alias toasts: toasts
readonly property alias utilities: utilities
required property PersistentProperties visibilities
anchors.fill: parent anchors.fill: parent
// anchors.margins: 8 // anchors.margins: 8
anchors.topMargin: Config.barConfig.autoHide && !visibilities.bar ? 0 : bar.implicitHeight anchors.topMargin: Config.barConfig.autoHide && !visibilities.bar ? 0 : bar.implicitHeight
Behavior on anchors.topMargin { Behavior on anchors.topMargin {
Anim {} Anim {
}
} }
Osd.Wrapper { Osd.Wrapper {
id: osd id: osd
anchors.right: parent.right
anchors.rightMargin: sidebar.width
anchors.verticalCenter: parent.verticalCenter
clip: sidebar.width > 0 clip: sidebar.width > 0
screen: root.screen screen: root.screen
visibilities: root.visibilities visibilities: root.visibilities
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: sidebar.width
} }
Modules.Wrapper { Modules.Wrapper {
id: popouts id: popouts
screen: root.screen
anchors.top: parent.top anchors.top: parent.top
screen: root.screen
x: { x: {
const off = currentCenter - nonAnimWidth / 2; const off = currentCenter - nonAnimWidth / 2;
const diff = root.width - Math.floor(off + nonAnimWidth); const diff = root.width - Math.floor(off + nonAnimWidth);
@@ -68,69 +66,63 @@ Item {
id: toasts id: toasts
anchors.bottom: sidebar.visible ? parent.bottom : utilities.top anchors.bottom: sidebar.visible ? parent.bottom : utilities.top
anchors.right: sidebar.left
anchors.margins: Appearance.padding.normal anchors.margins: Appearance.padding.normal
anchors.right: sidebar.left
} }
Notifications.Wrapper { Notifications.Wrapper {
id: notifications id: notifications
visibilities: root.visibilities
panels: root
anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top
panels: root
visibilities: root.visibilities
} }
Launcher.Wrapper { Launcher.Wrapper {
id: launcher id: launcher
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
panels: root
screen: root.screen screen: root.screen
visibilities: root.visibilities visibilities: root.visibilities
panels: root
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
} }
Utils.Wrapper { Utils.Wrapper {
id: utilities id: utilities
visibilities: root.visibilities
sidebar: sidebar
popouts: popouts
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
popouts: popouts
sidebar: sidebar
visibilities: root.visibilities
} }
Dashboard.Wrapper { Dashboard.Wrapper {
id: dashboard id: dashboard
visibilities: root.visibilities
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
visibilities: root.visibilities
} }
Sidebar.Wrapper { Sidebar.Wrapper {
id: sidebar id: sidebar
visibilities: root.visibilities
panels: root
anchors.top: notifications.bottom
anchors.bottom: utilities.top anchors.bottom: utilities.top
anchors.right: parent.right anchors.right: parent.right
anchors.top: notifications.bottom
panels: root
visibilities: root.visibilities
} }
Settings.Wrapper { Settings.Wrapper {
id: settings id: settings
visibilities: root.visibilities
panels: root
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
panels: root
visibilities: root.visibilities
} }
} }
+12 -9
View File
@@ -3,28 +3,31 @@ import QtQuick.Effects
Item { Item {
id: root id: root
property real radius property real radius
Rectangle { Rectangle {
id: shadowRect id: shadowRect
anchors.fill: root anchors.fill: root
radius: root.radius
layer.enabled: true
color: "black" color: "black"
layer.enabled: true
radius: root.radius
visible: false visible: false
} }
MultiEffect { MultiEffect {
id: effects id: effects
source: shadowRect
anchors.fill: shadowRect anchors.fill: shadowRect
shadowBlur: 2.0 autoPaddingEnabled: true
shadowEnabled: true
shadowOpacity: 1
shadowColor: "black"
maskSource: shadowRect
maskEnabled: true maskEnabled: true
maskInverted: true maskInverted: true
autoPaddingEnabled: true maskSource: shadowRect
shadowBlur: 2.0
shadowColor: "black"
shadowEnabled: true
shadowOpacity: 1
source: shadowRect
} }
} }
+12 -8
View File
@@ -11,33 +11,35 @@ Scope {
LazyLoader { LazyLoader {
id: root id: root
property bool freeze
property bool closing property bool closing
property bool freeze
Variants { Variants {
model: Quickshell.screens model: Quickshell.screens
PanelWindow { PanelWindow {
id: win id: win
color: "transparent"
required property ShellScreen modelData required property ShellScreen modelData
screen: modelData
WlrLayershell.namespace: "areapicker"
WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.exclusionMode: ExclusionMode.Ignore
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: root.closing ? WlrKeyboardFocus.None : WlrKeyboardFocus.Exclusive WlrLayershell.keyboardFocus: root.closing ? WlrKeyboardFocus.None : WlrKeyboardFocus.Exclusive
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.namespace: "areapicker"
color: "transparent"
mask: root.closing ? empty : null mask: root.closing ? empty : null
screen: modelData
anchors { anchors {
top: true
bottom: true bottom: true
left: true left: true
right: true right: true
top: true
} }
Region { Region {
id: empty id: empty
} }
Picker { Picker {
@@ -49,8 +51,6 @@ Scope {
} }
IpcHandler { IpcHandler {
target: "picker"
function open(): void { function open(): void {
root.freeze = false; root.freeze = false;
root.closing = false; root.closing = false;
@@ -62,10 +62,13 @@ Scope {
root.closing = false; root.closing = false;
root.activeAsync = true; root.activeAsync = true;
} }
target: "picker"
} }
CustomShortcut { CustomShortcut {
name: "screenshot" name: "screenshot"
onPressed: { onPressed: {
root.freeze = false; root.freeze = false;
root.closing = false; root.closing = false;
@@ -75,6 +78,7 @@ Scope {
CustomShortcut { CustomShortcut {
name: "screenshotFreeze" name: "screenshotFreeze"
onPressed: { onPressed: {
root.freeze = true; root.freeze = true;
root.closing = false; root.closing = false;
+38 -34
View File
@@ -10,12 +10,14 @@ import qs.Components
Singleton { Singleton {
id: root id: root
property bool appleDisplayPresent: false
property list<var> ddcMonitors: [] property list<var> ddcMonitors: []
readonly property list<Monitor> monitors: variants.instances readonly property list<Monitor> monitors: variants.instances
property bool appleDisplayPresent: false
function getMonitorForScreen(screen: ShellScreen): var { function decreaseBrightness(): void {
return monitors.find(m => m.modelData === screen); const monitor = getMonitor("active");
if (monitor)
monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement);
} }
function getMonitor(query: string): var { function getMonitor(query: string): var {
@@ -41,18 +43,16 @@ Singleton {
return monitors.find(m => m.modelData.name === query); return monitors.find(m => m.modelData.name === query);
} }
function getMonitorForScreen(screen: ShellScreen): var {
return monitors.find(m => m.modelData === screen);
}
function increaseBrightness(): void { function increaseBrightness(): void {
const monitor = getMonitor("active"); const monitor = getMonitor("active");
if (monitor) if (monitor)
monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement); monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement);
} }
function decreaseBrightness(): void {
const monitor = getMonitor("active");
if (monitor)
monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement);
}
onMonitorsChanged: { onMonitorsChanged: {
ddcMonitors = []; ddcMonitors = [];
ddcProc.running = true; ddcProc.running = true;
@@ -63,12 +63,14 @@ Singleton {
model: Quickshell.screens model: Quickshell.screens
Monitor {} Monitor {
}
} }
Process { Process {
running: true
command: ["sh", "-c", "asdbctl get"] // To avoid warnings if asdbctl is not installed command: ["sh", "-c", "asdbctl get"] // To avoid warnings if asdbctl is not installed
running: true
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: root.appleDisplayPresent = text.trim().length > 0 onStreamFinished: root.appleDisplayPresent = text.trim().length > 0
} }
@@ -78,6 +80,7 @@ Singleton {
id: ddcProc id: ddcProc
command: ["ddcutil", "detect", "--brief"] command: ["ddcutil", "detect", "--brief"]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: root.ddcMonitors = text.trim().split("\n\n").filter(d => d.startsWith("Display ")).map(d => ({ onStreamFinished: root.ddcMonitors = text.trim().split("\n\n").filter(d => d.startsWith("Display ")).map(d => ({
busNum: d.match(/I2C bus:[ ]*\/dev\/i2c-([0-9]+)/)[1], busNum: d.match(/I2C bus:[ ]*\/dev\/i2c-([0-9]+)/)[1],
@@ -87,20 +90,20 @@ Singleton {
} }
CustomShortcut { CustomShortcut {
name: "brightnessUp"
description: "Increase brightness" description: "Increase brightness"
name: "brightnessUp"
onPressed: root.increaseBrightness() onPressed: root.increaseBrightness()
} }
CustomShortcut { CustomShortcut {
name: "brightnessDown"
description: "Decrease brightness" description: "Decrease brightness"
name: "brightnessDown"
onPressed: root.decreaseBrightness() onPressed: root.decreaseBrightness()
} }
IpcHandler { IpcHandler {
target: "brightness"
function get(): real { function get(): real {
return getFor("active"); return getFor("active");
} }
@@ -149,18 +152,15 @@ Singleton {
return `Set monitor ${monitor.modelData.name} brightness to ${+monitor.brightness.toFixed(2)}`; return `Set monitor ${monitor.modelData.name} brightness to ${+monitor.brightness.toFixed(2)}`;
} }
target: "brightness"
} }
component Monitor: QtObject { component Monitor: QtObject {
id: monitor id: monitor
required property ShellScreen modelData
readonly property bool isDdc: root.ddcMonitors.some(m => m.connector === modelData.name)
readonly property string busNum: root.ddcMonitors.find(m => m.connector === modelData.name)?.busNum ?? ""
readonly property bool isAppleDisplay: root.appleDisplayPresent && modelData.model.startsWith("StudioDisplay")
property real brightness property real brightness
property real queuedBrightness: NaN readonly property string busNum: root.ddcMonitors.find(m => m.connector === modelData.name)?.busNum ?? ""
readonly property Process initProc: Process { readonly property Process initProc: Process {
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
@@ -174,9 +174,13 @@ Singleton {
} }
} }
} }
readonly property bool isAppleDisplay: root.appleDisplayPresent && modelData.model.startsWith("StudioDisplay")
readonly property bool isDdc: root.ddcMonitors.some(m => m.connector === modelData.name)
required property ShellScreen modelData
property real queuedBrightness: NaN
readonly property Timer timer: Timer { readonly property Timer timer: Timer {
interval: 500 interval: 500
onTriggered: { onTriggered: {
if (!isNaN(monitor.queuedBrightness)) { if (!isNaN(monitor.queuedBrightness)) {
monitor.setBrightness(monitor.queuedBrightness); monitor.setBrightness(monitor.queuedBrightness);
@@ -185,6 +189,17 @@ Singleton {
} }
} }
function initBrightness(): void {
if (isAppleDisplay)
initProc.command = ["asdbctl", "get"];
else if (isDdc)
initProc.command = ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"];
else
initProc.command = ["sh", "-c", "echo a b c $(brightnessctl g) $(brightnessctl m)"];
initProc.running = true;
}
function setBrightness(value: real): void { function setBrightness(value: real): void {
value = Math.max(0, Math.min(1, value)); value = Math.max(0, Math.min(1, value));
const rounded = Math.round(value * 100); const rounded = Math.round(value * 100);
@@ -209,18 +224,7 @@ Singleton {
timer.restart(); timer.restart();
} }
function initBrightness(): void {
if (isAppleDisplay)
initProc.command = ["asdbctl", "get"];
else if (isDdc)
initProc.command = ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"];
else
initProc.command = ["sh", "-c", "echo a b c $(brightnessctl g) $(brightnessctl m)"];
initProc.running = true;
}
onBusNumChanged: initBrightness()
Component.onCompleted: initBrightness() Component.onCompleted: initBrightness()
onBusNumChanged: initBrightness()
} }
} }
+3 -3
View File
@@ -12,17 +12,17 @@ Image {
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
Connections { Connections {
target: QsWindow.window
function onDevicePixelRatioChanged(): void { function onDevicePixelRatioChanged(): void {
manager.updateSource(); manager.updateSource();
} }
target: QsWindow.window
} }
CachingImageManager { CachingImageManager {
id: manager id: manager
item: root
cacheDir: Qt.resolvedUrl(Paths.imagecache) cacheDir: Qt.resolvedUrl(Paths.imagecache)
item: root
} }
} }
+48 -50
View File
@@ -10,6 +10,53 @@ Singleton {
property int displayYear: new Date().getFullYear() property int displayYear: new Date().getFullYear()
readonly property int weekStartDay: 1 // 0 = Sunday, 1 = Monday readonly property int weekStartDay: 1 // 0 = Sunday, 1 = Monday
function getISOWeekNumber(date: var): int {
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
const dayNum = d.getUTCDay() || 7;
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
}
function getWeekNumbers(month: int, year: int): var {
const days = getWeeksForMonth(month, year);
const weekNumbers = [];
let lastWeekNumber = -1;
for (let i = 0; i < days.length; i++) {
// Only add week numbers for days that belong to the current month
if (days[i].isCurrentMonth) {
const dayDate = new Date(days[i].year, days[i].month, days[i].day);
const weekNumber = getISOWeekNumber(dayDate);
// Only push if this is a new week
if (weekNumber !== lastWeekNumber) {
weekNumbers.push(weekNumber);
lastWeekNumber = weekNumber;
}
}
}
return weekNumbers;
}
function getWeekStartIndex(month: int, year: int): int {
const today = new Date();
if (today.getMonth() !== month || today.getFullYear() !== year) {
return 0;
}
const days = getWeeksForMonth(month, year);
for (let i = 0; i < days.length; i++) {
if (days[i].isToday) {
// Return the start index of the week containing today
return Math.floor(i / 7) * 7;
}
}
return 0;
}
function getWeeksForMonth(month: int, year: int): var { function getWeeksForMonth(month: int, year: int): var {
const firstDayOfMonth = new Date(year, month, 1); const firstDayOfMonth = new Date(year, month, 1);
const lastDayOfMonth = new Date(year, month + 1, 0); const lastDayOfMonth = new Date(year, month + 1, 0);
@@ -43,57 +90,8 @@ Singleton {
return days; return days;
} }
function getWeekNumbers(month: int, year: int): var {
const days = getWeeksForMonth(month, year);
const weekNumbers = [];
let lastWeekNumber = -1;
for (let i = 0; i < days.length; i++) {
// Only add week numbers for days that belong to the current month
if (days[i].isCurrentMonth) {
const dayDate = new Date(days[i].year, days[i].month, days[i].day);
const weekNumber = getISOWeekNumber(dayDate);
// Only push if this is a new week
if (weekNumber !== lastWeekNumber) {
weekNumbers.push(weekNumber);
lastWeekNumber = weekNumber;
}
}
}
return weekNumbers;
}
function getISOWeekNumber(date: var): int {
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
const dayNum = d.getUTCDay() || 7;
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
}
function isDateToday(date: var): bool { function isDateToday(date: var): bool {
const today = new Date(); const today = new Date();
return date.getDate() === today.getDate() && return date.getDate() === today.getDate() && date.getMonth() === today.getMonth() && date.getFullYear() === today.getFullYear();
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear();
}
function getWeekStartIndex(month: int, year: int): int {
const today = new Date();
if (today.getMonth() !== month || today.getFullYear() !== year) {
return 0;
}
const days = getWeeksForMonth(month, year);
for (let i = 0; i < days.length; i++) {
if (days[i].isToday) {
// Return the start index of the week containing today
return Math.floor(i / 7) * 7;
}
}
return 0;
} }
} }
+1
View File
@@ -10,6 +10,7 @@ Singleton {
JsonObject { JsonObject {
id: adapter id: adapter
property bool hasNotifications: false property bool hasNotifications: false
} }
} }
+30 -32
View File
@@ -11,43 +11,38 @@ import qs.Components
Singleton { Singleton {
id: root id: root
property string activeName
readonly property HyprlandToplevel activeToplevel: Hyprland.activeToplevel
readonly property int activeWsId: focusedWorkspace?.id ?? 1
property string applicationDir: "/usr/share/applications/"
readonly property bool capsLock: keyboard?.capsLock ?? false
readonly property string defaultKbLayout: keyboard?.layout.split(",")[0] ?? "??"
property string desktopName: ""
readonly property alias devices: extras.devices
readonly property alias extras: extras
readonly property HyprlandMonitor focusedMonitor: Hyprland.focusedMonitor
readonly property HyprlandWorkspace focusedWorkspace: Hyprland.focusedWorkspace
property bool hadKeyboard
readonly property string kbLayout: kbMap.get(kbLayoutFull) ?? "??"
readonly property string kbLayoutFull: keyboard?.activeKeymap ?? "Unknown"
readonly property var kbMap: new Map()
readonly property HyprKeyboard keyboard: extras.devices.keyboards.find(kb => kb.main) ?? null
readonly property var monitors: Hyprland.monitors
readonly property bool numLock: keyboard?.numLock ?? false
readonly property alias options: extras.options
readonly property var toplevels: Hyprland.toplevels readonly property var toplevels: Hyprland.toplevels
readonly property var workspaces: Hyprland.workspaces readonly property var workspaces: Hyprland.workspaces
readonly property var monitors: Hyprland.monitors
readonly property HyprlandToplevel activeToplevel: Hyprland.activeToplevel
readonly property HyprlandWorkspace focusedWorkspace: Hyprland.focusedWorkspace
readonly property HyprlandMonitor focusedMonitor: Hyprland.focusedMonitor
readonly property int activeWsId: focusedWorkspace?.id ?? 1
property string activeName
property string applicationDir: "/usr/share/applications/"
property string desktopName: ""
readonly property HyprKeyboard keyboard: extras.devices.keyboards.find(kb => kb.main) ?? null
readonly property bool capsLock: keyboard?.capsLock ?? false
readonly property bool numLock: keyboard?.numLock ?? false
readonly property string defaultKbLayout: keyboard?.layout.split(",")[0] ?? "??"
readonly property string kbLayoutFull: keyboard?.activeKeymap ?? "Unknown"
readonly property string kbLayout: kbMap.get(kbLayoutFull) ?? "??"
readonly property var kbMap: new Map()
readonly property alias extras: extras
readonly property alias options: extras.options
readonly property alias devices: extras.devices
property bool hadKeyboard
signal configReloaded signal configReloaded
function getActiveScreen(): ShellScreen {
return Quickshell.screens.find(screen => root.monitorFor(screen) === root.focusedMonitor)
}
function dispatch(request: string): void { function dispatch(request: string): void {
Hyprland.dispatch(request); Hyprland.dispatch(request);
} }
function getActiveScreen(): ShellScreen {
return Quickshell.screens.find(screen => root.monitorFor(screen) === root.focusedMonitor);
}
function monitorFor(screen: ShellScreen): HyprlandMonitor { function monitorFor(screen: ShellScreen): HyprlandMonitor {
return Hyprland.monitorFor(screen); return Hyprland.monitorFor(screen);
} }
@@ -63,8 +58,6 @@ Singleton {
// } // }
Connections { Connections {
target: Hyprland
function onRawEvent(event: HyprlandEvent): void { function onRawEvent(event: HyprlandEvent): void {
const n = event.name; const n = event.name;
if (n.endsWith("v2")) if (n.endsWith("v2"))
@@ -92,6 +85,8 @@ Singleton {
// Qt.callLater( root.updateActiveWindow ); // Qt.callLater( root.updateActiveWindow );
} }
} }
target: Hyprland
} }
FileView { FileView {
@@ -116,6 +111,7 @@ Singleton {
id: kbLayoutFile id: kbLayoutFile
path: Quickshell.env("ZSHELL_XKB_RULES_PATH") || "/usr/share/X11/xkb/rules/base.lst" path: Quickshell.env("ZSHELL_XKB_RULES_PATH") || "/usr/share/X11/xkb/rules/base.lst"
onLoaded: { onLoaded: {
const layoutMatch = text().match(/! layout\n([\s\S]*?)\n\n/); const layoutMatch = text().match(/! layout\n([\s\S]*?)\n\n/);
if (layoutMatch) { if (layoutMatch) {
@@ -146,20 +142,22 @@ Singleton {
} }
IpcHandler { IpcHandler {
target: "hypr"
function refreshDevices(): void { function refreshDevices(): void {
extras.refreshDevices(); extras.refreshDevices();
} }
target: "hypr"
} }
CustomShortcut { CustomShortcut {
name: "refreshDevices" name: "refreshDevices"
onPressed: extras.refreshDevices() onPressed: extras.refreshDevices()
onReleased: extras.refreshDevices() onReleased: extras.refreshDevices()
} }
HyprExtras { HyprExtras {
id: extras id: extras
} }
} }
+61 -62
View File
@@ -8,37 +8,6 @@ import QtQuick
Singleton { Singleton {
id: root id: root
readonly property var weatherIcons: ({
"0": "clear_day",
"1": "clear_day",
"2": "partly_cloudy_day",
"3": "cloud",
"45": "foggy",
"48": "foggy",
"51": "rainy",
"53": "rainy",
"55": "rainy",
"56": "rainy",
"57": "rainy",
"61": "rainy",
"63": "rainy",
"65": "rainy",
"66": "rainy",
"67": "rainy",
"71": "cloudy_snowing",
"73": "cloudy_snowing",
"75": "snowing_heavy",
"77": "cloudy_snowing",
"80": "rainy",
"81": "rainy",
"82": "rainy",
"85": "cloudy_snowing",
"86": "snowing_heavy",
"95": "thunderstorm",
"96": "thunderstorm",
"99": "thunderstorm"
})
readonly property var categoryIcons: ({ readonly property var categoryIcons: ({
WebBrowser: "web", WebBrowser: "web",
Printing: "print", Printing: "print",
@@ -78,13 +47,36 @@ Singleton {
System: "host", System: "host",
Office: "content_paste" Office: "content_paste"
}) })
readonly property var weatherIcons: ({
function getAppIcon(name: string, fallback: string): string { "0": "clear_day",
const icon = DesktopEntries.heuristicLookup(name)?.icon; "1": "clear_day",
if (fallback !== "undefined") "2": "partly_cloudy_day",
return Quickshell.iconPath(icon, fallback); "3": "cloud",
return Quickshell.iconPath(icon); "45": "foggy",
} "48": "foggy",
"51": "rainy",
"53": "rainy",
"55": "rainy",
"56": "rainy",
"57": "rainy",
"61": "rainy",
"63": "rainy",
"65": "rainy",
"66": "rainy",
"67": "rainy",
"71": "cloudy_snowing",
"73": "cloudy_snowing",
"75": "snowing_heavy",
"77": "cloudy_snowing",
"80": "rainy",
"81": "rainy",
"82": "rainy",
"85": "cloudy_snowing",
"86": "snowing_heavy",
"95": "thunderstorm",
"96": "thunderstorm",
"99": "thunderstorm"
})
function getAppCategoryIcon(name: string, fallback: string): string { function getAppCategoryIcon(name: string, fallback: string): string {
const categories = DesktopEntries.heuristicLookup(name)?.categories; const categories = DesktopEntries.heuristicLookup(name)?.categories;
@@ -96,6 +88,33 @@ Singleton {
return fallback; return fallback;
} }
function getAppIcon(name: string, fallback: string): string {
const icon = DesktopEntries.heuristicLookup(name)?.icon;
if (fallback !== "undefined")
return Quickshell.iconPath(icon, fallback);
return Quickshell.iconPath(icon);
}
function getBluetoothIcon(icon: string): string {
if (icon.includes("headset") || icon.includes("headphones"))
return "headphones";
if (icon.includes("audio"))
return "speaker";
if (icon.includes("phone"))
return "smartphone";
if (icon.includes("mouse"))
return "mouse";
if (icon.includes("keyboard"))
return "keyboard";
return "bluetooth";
}
function getMicVolumeIcon(volume: real, isMuted: bool): string {
if (!isMuted && volume > 0)
return "mic";
return "mic_off";
}
function getNetworkIcon(strength: int, isSecure = false): string { function getNetworkIcon(strength: int, isSecure = false): string {
if (isSecure) { if (isSecure) {
if (strength >= 80) if (strength >= 80)
@@ -120,26 +139,6 @@ Singleton {
} }
} }
function getBluetoothIcon(icon: string): string {
if (icon.includes("headset") || icon.includes("headphones"))
return "headphones";
if (icon.includes("audio"))
return "speaker";
if (icon.includes("phone"))
return "smartphone";
if (icon.includes("mouse"))
return "mouse";
if (icon.includes("keyboard"))
return "keyboard";
return "bluetooth";
}
function getWeatherIcon(code: string): string {
if (weatherIcons.hasOwnProperty(code))
return weatherIcons[code];
return "air";
}
function getNotifIcon(summary: string, urgency: int): string { function getNotifIcon(summary: string, urgency: int): string {
summary = summary.toLowerCase(); summary = summary.toLowerCase();
if (summary.includes("reboot")) if (summary.includes("reboot"))
@@ -179,9 +178,9 @@ Singleton {
return "volume_mute"; return "volume_mute";
} }
function getMicVolumeIcon(volume: real, isMuted: bool): string { function getWeatherIcon(code: string): string {
if (!isMuted && volume > 0) if (weatherIcons.hasOwnProperty(code))
return "mic"; return weatherIcons[code];
return "mic_off"; return "air";
} }
} }
+14 -11
View File
@@ -26,16 +26,25 @@ Singleton {
IdleInhibitor { IdleInhibitor {
enabled: props.enabled enabled: props.enabled
window: PanelWindow { window: PanelWindow {
implicitWidth: 0
implicitHeight: 0
color: "transparent" color: "transparent"
mask: Region {} implicitHeight: 0
implicitWidth: 0
mask: Region {
}
} }
} }
IpcHandler { IpcHandler {
target: "idleInhibitor" function disable(): void {
props.enabled = false;
}
function enable(): void {
props.enabled = true;
}
function isEnabled(): bool { function isEnabled(): bool {
return props.enabled; return props.enabled;
@@ -45,12 +54,6 @@ Singleton {
props.enabled = !props.enabled; props.enabled = !props.enabled;
} }
function enable(): void { target: "idleInhibitor"
props.enabled = true;
}
function disable(): void {
props.enabled = false;
}
} }
} }
+6 -6
View File
@@ -6,13 +6,13 @@ import qs.Helpers
Singleton { Singleton {
function getInitialTitle(callback) { function getInitialTitle(callback) {
let activeWindow = Hypr.activeToplevel.title let activeWindow = Hypr.activeToplevel.title;
let activeClass = Hypr.activeToplevel.lastIpcObject.class.toString() let activeClass = Hypr.activeToplevel.lastIpcObject.class.toString();
let regex = new RegExp(activeClass, "i") let regex = new RegExp(activeClass, "i");
console.log("ActiveWindow", activeWindow, "ActiveClass", activeClass, "Regex", regex) console.log("ActiveWindow", activeWindow, "ActiveClass", activeClass, "Regex", regex);
const evalTitle = activeWindow.match(regex) const evalTitle = activeWindow.match(regex);
callback(evalTitle) callback(evalTitle);
} }
} }
+28 -28
View File
@@ -10,29 +10,8 @@ import qs.Paths
Singleton { Singleton {
id: root id: root
readonly property int darkStart: Config.general.color.scheduleDarkStart
readonly property int darkEnd: Config.general.color.scheduleDarkEnd readonly property int darkEnd: Config.general.color.scheduleDarkEnd
readonly property int darkStart: Config.general.color.scheduleDarkStart
Timer {
id: darkModeTimer
interval: 5000
running: true
repeat: true
onTriggered: {
if ( darkStart === darkEnd )
return;
var now = new Date();
if ( now.getHours() >= darkStart || now.getHours() < darkEnd ) {
if ( DynamicColors.light )
applyDarkMode();
} else {
if ( !DynamicColors.light )
applyLightMode();
}
}
}
function applyDarkMode() { function applyDarkMode() {
if (Config.general.color.schemeGeneration) { if (Config.general.color.schemeGeneration) {
@@ -43,11 +22,11 @@ Singleton {
Config.general.color.mode = "dark"; Config.general.color.mode = "dark";
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-dark'"]) Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-dark'"]);
Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Light.colors/color_scheme_path=\\1Dark.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]) Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Light.colors/color_scheme_path=\\1Dark.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]);
Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"tokyodark\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]) Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"tokyodark\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]);
if (Config.general.color.wallust) if (Config.general.color.wallust)
Wallust.generateColors(WallpaperPath.currentWallpaperPath); Wallust.generateColors(WallpaperPath.currentWallpaperPath);
@@ -62,12 +41,12 @@ Singleton {
Config.general.color.mode = "light"; Config.general.color.mode = "light";
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-light'"]) Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-light'"]);
Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Dark.colors/color_scheme_path=\\1Light.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]) Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Dark.colors/color_scheme_path=\\1Light.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]);
if (Config.general.color.neovimColors) if (Config.general.color.neovimColors)
Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"onelight\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]) Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"onelight\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]);
if (Config.general.color.wallust) if (Config.general.color.wallust)
Wallust.generateColors(WallpaperPath.currentWallpaperPath); Wallust.generateColors(WallpaperPath.currentWallpaperPath);
@@ -83,4 +62,25 @@ Singleton {
applyLightMode(); applyLightMode();
} }
} }
Timer {
id: darkModeTimer
interval: 5000
repeat: true
running: true
onTriggered: {
if (darkStart === darkEnd)
return;
var now = new Date();
if (now.getHours() >= darkStart || now.getHours() < darkEnd) {
if (DynamicColors.light)
applyDarkMode();
} else {
if (!DynamicColors.light)
applyLightMode();
}
}
}
} }
+1 -1
View File
@@ -6,6 +6,6 @@ import Quickshell.Networking
Singleton { Singleton {
id: root id: root
property list<NetworkDevice> devices: Networking.devices.values
property NetworkDevice activeDevice: devices.find(d => d.connected) property NetworkDevice activeDevice: devices.find(d => d.connected)
property list<NetworkDevice> devices: Networking.devices.values
} }
+89 -98
View File
@@ -12,27 +12,6 @@ import qs.Helpers
MouseArea { MouseArea {
id: root id: root
required property LazyLoader loader
required property ShellScreen screen
property bool onClient
property real realBorderWidth: onClient ? (Hypr.options["general:border_size"] ?? 1) : 2
property real realRounding: onClient ? (Hypr.options["decoration:rounding"] ?? 0) : 0
property real ssx
property real ssy
property real sx: 0
property real sy: 0
property real ex: screen.width
property real ey: screen.height
property real rsx: Math.min(sx, ex)
property real rsy: Math.min(sy, ey)
property real sw: Math.abs(sx - ex)
property real sh: Math.abs(sy - ey)
property list<var> clients: { property list<var> clients: {
const mon = Hypr.monitorFor(screen); const mon = Hypr.monitorFor(screen);
if (!mon) if (!mon)
@@ -47,6 +26,21 @@ MouseArea {
return (bc.pinned - ac.pinned) || ((bc.fullscreen !== 0) - (ac.fullscreen !== 0)) || (bc.floating - ac.floating); return (bc.pinned - ac.pinned) || ((bc.fullscreen !== 0) - (ac.fullscreen !== 0)) || (bc.floating - ac.floating);
}); });
} }
property real ex: screen.width
property real ey: screen.height
required property LazyLoader loader
property bool onClient
property real realBorderWidth: onClient ? (Hypr.options["general:border_size"] ?? 1) : 2
property real realRounding: onClient ? (Hypr.options["decoration:rounding"] ?? 0) : 0
property real rsx: Math.min(sx, ex)
property real rsy: Math.min(sy, ey)
required property ShellScreen screen
property real sh: Math.abs(sy - ey)
property real ssx
property real ssy
property real sw: Math.abs(sx - ex)
property real sx: 0
property real sy: 0
function checkClientRects(x: real, y: real): void { function checkClientRects(x: real, y: real): void {
for (const client of clients) { for (const client of clients) {
@@ -76,12 +70,41 @@ MouseArea {
closeAnim.start(); closeAnim.start();
} }
onClientsChanged: checkClientRects(mouseX, mouseY)
anchors.fill: parent anchors.fill: parent
opacity: 0
hoverEnabled: true
cursorShape: Qt.CrossCursor cursorShape: Qt.CrossCursor
focus: true
hoverEnabled: true
opacity: 0
Behavior on opacity {
Anim {
duration: 300
}
}
Behavior on rsx {
enabled: !root.pressed
ExAnim {
}
}
Behavior on rsy {
enabled: !root.pressed
ExAnim {
}
}
Behavior on sh {
enabled: !root.pressed
ExAnim {
}
}
Behavior on sw {
enabled: !root.pressed
ExAnim {
}
}
Component.onCompleted: { Component.onCompleted: {
Hypr.extras.refreshOptions(); Hypr.extras.refreshOptions();
@@ -106,25 +129,8 @@ MouseArea {
ey = screen.height / 2 + 100; ey = screen.height / 2 + 100;
} }
} }
Keys.onEscapePressed: closeAnim.start()
onPressed: event => { onClientsChanged: checkClientRects(mouseX, mouseY)
ssx = event.x;
ssy = event.y;
}
onReleased: {
if (closeAnim.running)
return;
if (root.loader.freeze) {
save();
} else {
overlay.visible = border.visible = false;
screencopy.visible = false;
screencopy.active = true;
}
}
onPositionChanged: event => { onPositionChanged: event => {
const x = event.x; const x = event.x;
const y = event.y; const y = event.y;
@@ -139,44 +145,62 @@ MouseArea {
checkClientRects(x, y); checkClientRects(x, y);
} }
} }
onPressed: event => {
ssx = event.x;
ssy = event.y;
}
onReleased: {
if (closeAnim.running)
return;
focus: true if (root.loader.freeze) {
Keys.onEscapePressed: closeAnim.start() save();
} else {
overlay.visible = border.visible = false;
screencopy.visible = false;
screencopy.active = true;
}
}
SequentialAnimation { SequentialAnimation {
id: closeAnim id: closeAnim
PropertyAction { PropertyAction {
target: root.loader
property: "closing" property: "closing"
target: root.loader
value: true value: true
} }
ParallelAnimation { ParallelAnimation {
Anim { Anim {
target: root
property: "opacity"
to: 0
duration: 300 duration: 300
} property: "opacity"
ExAnim {
target: root target: root
properties: "rsx,rsy"
to: 0 to: 0
} }
ExAnim { ExAnim {
properties: "rsx,rsy"
target: root target: root
to: 0
}
ExAnim {
property: "sw" property: "sw"
target: root
to: root.screen.width to: root.screen.width
} }
ExAnim { ExAnim {
target: root
property: "sh" property: "sh"
target: root
to: root.screen.height to: root.screen.height
} }
} }
PropertyAction { PropertyAction {
target: root.loader
property: "activeAsync" property: "activeAsync"
target: root.loader
value: false value: false
} }
} }
@@ -184,14 +208,12 @@ MouseArea {
Loader { Loader {
id: screencopy id: screencopy
anchors.fill: parent
active: root.loader.freeze active: root.loader.freeze
anchors.fill: parent
asynchronous: true asynchronous: true
sourceComponent: ScreencopyView { sourceComponent: ScreencopyView {
captureSource: root.screen captureSource: root.screen
paintCursor: false paintCursor: false
onHasContentChanged: { onHasContentChanged: {
@@ -208,15 +230,14 @@ MouseArea {
anchors.fill: parent anchors.fill: parent
color: "white" color: "white"
layer.enabled: true
opacity: 0.3 opacity: 0.3
radius: root.realRounding radius: root.realRounding
layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {
maskSource: selectionWrapper
maskEnabled: true maskEnabled: true
maskInverted: true maskInverted: true
maskSource: selectionWrapper
maskSpreadAtMin: 1 maskSpreadAtMin: 1
maskThresholdMin: 0.5 maskThresholdMin: 0.5
} }
@@ -232,60 +253,30 @@ MouseArea {
Rectangle { Rectangle {
id: selectionRect id: selectionRect
implicitHeight: root.sh
implicitWidth: root.sw
radius: root.realRounding radius: root.realRounding
x: root.rsx x: root.rsx
y: root.rsy y: root.rsy
implicitWidth: root.sw
implicitHeight: root.sh
} }
} }
Rectangle { Rectangle {
id: border id: border
color: "transparent"
radius: root.realRounding > 0 ? root.realRounding + root.realBorderWidth : 0
border.width: root.realBorderWidth
border.color: DynamicColors.palette.m3primary border.color: DynamicColors.palette.m3primary
border.width: root.realBorderWidth
color: "transparent"
implicitHeight: selectionRect.implicitHeight + root.realBorderWidth * 2
implicitWidth: selectionRect.implicitWidth + root.realBorderWidth * 2
radius: root.realRounding > 0 ? root.realRounding + root.realBorderWidth : 0
x: selectionRect.x - root.realBorderWidth x: selectionRect.x - root.realBorderWidth
y: selectionRect.y - root.realBorderWidth y: selectionRect.y - root.realBorderWidth
implicitWidth: selectionRect.implicitWidth + root.realBorderWidth * 2
implicitHeight: selectionRect.implicitHeight + root.realBorderWidth * 2
Behavior on border.color { Behavior on border.color {
Anim {}
}
}
Behavior on opacity {
Anim { Anim {
duration: 300
} }
} }
Behavior on rsx {
enabled: !root.pressed
ExAnim {}
}
Behavior on rsy {
enabled: !root.pressed
ExAnim {}
}
Behavior on sw {
enabled: !root.pressed
ExAnim {}
}
Behavior on sh {
enabled: !root.pressed
ExAnim {}
} }
component ExAnim: Anim { component ExAnim: Anim {
+22 -18
View File
@@ -11,8 +11,8 @@ import qs.Components
Singleton { Singleton {
id: root id: root
readonly property list<MprisPlayer> list: Mpris.players.values
readonly property MprisPlayer active: props.manualActive ?? list.find(p => getIdentity(p) === Config.services.defaultPlayer) ?? list[0] ?? null readonly property MprisPlayer active: props.manualActive ?? list.find(p => getIdentity(p) === Config.services.defaultPlayer) ?? list[0] ?? null
readonly property list<MprisPlayer> list: Mpris.players.values
property alias manualActive: props.manualActive property alias manualActive: props.manualActive
function getIdentity(player: MprisPlayer): string { function getIdentity(player: MprisPlayer): string {
@@ -21,13 +21,13 @@ Singleton {
} }
Connections { Connections {
target: active
function onPostTrackChanged() { function onPostTrackChanged() {
if (!Config.utilities.toasts.nowPlaying) { if (!Config.utilities.toasts.nowPlaying) {
return; return;
} }
} }
target: active
} }
PersistentProperties { PersistentProperties {
@@ -39,8 +39,9 @@ Singleton {
} }
CustomShortcut { CustomShortcut {
name: "mediaToggle"
description: "Toggle media playback" description: "Toggle media playback"
name: "mediaToggle"
onPressed: { onPressed: {
const active = root.active; const active = root.active;
if (active && active.canTogglePlaying) if (active && active.canTogglePlaying)
@@ -49,8 +50,9 @@ Singleton {
} }
CustomShortcut { CustomShortcut {
name: "mediaPrev"
description: "Previous track" description: "Previous track"
name: "mediaPrev"
onPressed: { onPressed: {
const active = root.active; const active = root.active;
if (active && active.canGoPrevious) if (active && active.canGoPrevious)
@@ -59,8 +61,9 @@ Singleton {
} }
CustomShortcut { CustomShortcut {
name: "mediaNext"
description: "Next track" description: "Next track"
name: "mediaNext"
onPressed: { onPressed: {
const active = root.active; const active = root.active;
if (active && active.canGoNext) if (active && active.canGoNext)
@@ -69,14 +72,13 @@ Singleton {
} }
CustomShortcut { CustomShortcut {
name: "mediaStop"
description: "Stop media playback" description: "Stop media playback"
name: "mediaStop"
onPressed: root.active?.stop() onPressed: root.active?.stop()
} }
IpcHandler { IpcHandler {
target: "mpris"
function getActive(prop: string): string { function getActive(prop: string): string {
const active = root.active; const active = root.active;
return active ? active[prop] ?? "Invalid property" : "No active player"; return active ? active[prop] ?? "Invalid property" : "No active player";
@@ -86,10 +88,10 @@ Singleton {
return root.list.map(p => root.getIdentity(p)).join("\n"); return root.list.map(p => root.getIdentity(p)).join("\n");
} }
function play(): void { function next(): void {
const active = root.active; const active = root.active;
if (active?.canPlay) if (active?.canGoNext)
active.play(); active.next();
} }
function pause(): void { function pause(): void {
@@ -98,6 +100,12 @@ Singleton {
active.pause(); active.pause();
} }
function play(): void {
const active = root.active;
if (active?.canPlay)
active.play();
}
function playPause(): void { function playPause(): void {
const active = root.active; const active = root.active;
if (active?.canTogglePlaying) if (active?.canTogglePlaying)
@@ -110,14 +118,10 @@ Singleton {
active.previous(); active.previous();
} }
function next(): void {
const active = root.active;
if (active?.canGoNext)
active.next();
}
function stop(): void { function stop(): void {
root.active?.stop(); root.active?.stop();
} }
target: "mpris"
} }
} }
+12 -12
View File
@@ -11,10 +11,15 @@ import qs.Paths
Searcher { Searcher {
id: root id: root
property bool showPreview: false property string actualCurrent: WallpaperPath.currentWallpaperPath
readonly property string current: showPreview ? previewPath : actualCurrent readonly property string current: showPreview ? previewPath : actualCurrent
property string previewPath property string previewPath
property string actualCurrent: WallpaperPath.currentWallpaperPath property bool showPreview: false
function preview(path: string): void {
previewPath = path;
showPreview = true;
}
function setWallpaper(path: string): void { function setWallpaper(path: string): void {
actualCurrent = path; actualCurrent = path;
@@ -22,28 +27,23 @@ Searcher {
Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/LockScreenBg.py")} --input_image=${root.actualCurrent} --output_path=${Paths.state}/lockscreen_bg.png`]); Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/LockScreenBg.py")} --input_image=${root.actualCurrent} --output_path=${Paths.state}/lockscreen_bg.png`]);
} }
function preview(path: string): void {
previewPath = path;
showPreview = true;
}
function stopPreview(): void { function stopPreview(): void {
showPreview = false; showPreview = false;
Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/SchemeColorGen.py")} --path=${root.actualCurrent} --thumbnail=${Paths.cache}/imagecache/thumbnail.jpg --output=${Paths.state}/scheme.json --scheme=${Config.colors.schemeType}`]); Quickshell.execDetached(["sh", "-c", `python3 ${Quickshell.shellPath("scripts/SchemeColorGen.py")} --path=${root.actualCurrent} --thumbnail=${Paths.cache}/imagecache/thumbnail.jpg --output=${Paths.state}/scheme.json --scheme=${Config.colors.schemeType}`]);
} }
list: wallpapers.entries
key: "relativePath"
useFuzzy: true
extraOpts: useFuzzy ? ({}) : ({ extraOpts: useFuzzy ? ({}) : ({
forward: false forward: false
}) })
key: "relativePath"
list: wallpapers.entries
useFuzzy: true
FileSystemModel { FileSystemModel {
id: wallpapers id: wallpapers
recursive: true
path: Config.general.wallpaperPath
filter: FileSystemModel.Images filter: FileSystemModel.Images
path: Config.general.wallpaperPath
recursive: true
} }
} }
+18 -19
View File
@@ -4,18 +4,7 @@ import "../scripts/fuzzysort.js" as Fuzzy
import QtQuick import QtQuick
Singleton { Singleton {
required property list<QtObject> list
property string key: "name"
property bool useFuzzy: false
property var extraOpts: ({}) property var extraOpts: ({})
// Extra stuff for fuzzy
property list<string> keys: [key]
property list<real> weights: [1]
readonly property var fzf: useFuzzy ? [] : new Fzf.Finder(list, Object.assign({
selector
}, extraOpts))
readonly property list<var> fuzzyPrepped: useFuzzy ? list.map(e => { readonly property list<var> fuzzyPrepped: useFuzzy ? list.map(e => {
const obj = { const obj = {
_item: e _item: e
@@ -24,15 +13,16 @@ Singleton {
obj[k] = Fuzzy.prepare(e[k]); obj[k] = Fuzzy.prepare(e[k]);
return obj; return obj;
}) : [] }) : []
readonly property var fzf: useFuzzy ? [] : new Fzf.Finder(list, Object.assign({
selector
}, extraOpts))
property string key: "name"
function transformSearch(search: string): string { // Extra stuff for fuzzy
return search; property list<string> keys: [key]
} required property list<QtObject> list
property bool useFuzzy: false
function selector(item: var): string { property list<real> weights: [1]
// Only for fzf
return item[key];
}
function query(search: string): list<var> { function query(search: string): list<var> {
search = transformSearch(search); search = transformSearch(search);
@@ -52,4 +42,13 @@ Singleton {
return b.score - a.score; return b.score - a.score;
}).map(r => r.item); }).map(r => r.item);
} }
function selector(item: var): string {
// Only for fzf
return item[key];
}
function transformSearch(search: string): string {
return search;
}
} }
+11 -9
View File
@@ -8,22 +8,22 @@ import QtQuick
Singleton { Singleton {
id: root id: root
property string osName property bool isDefaultLogo: true
property string osPrettyName
property string osId property string osId
property list<string> osIdLike property list<string> osIdLike
property string osLogo property string osLogo
property bool isDefaultLogo: true property string osName
property string osPrettyName
readonly property string shell: Quickshell.env("SHELL").split("/").pop()
property string uptime property string uptime
readonly property string user: Quickshell.env("USER") readonly property string user: Quickshell.env("USER")
readonly property string wm: Quickshell.env("XDG_CURRENT_DESKTOP") || Quickshell.env("XDG_SESSION_DESKTOP") readonly property string wm: Quickshell.env("XDG_CURRENT_DESKTOP") || Quickshell.env("XDG_SESSION_DESKTOP")
readonly property string shell: Quickshell.env("SHELL").split("/").pop()
FileView { FileView {
id: osRelease id: osRelease
path: "/etc/os-release" path: "/etc/os-release"
onLoaded: { onLoaded: {
const lines = text().split("\n"); const lines = text().split("\n");
@@ -46,17 +46,18 @@ Singleton {
} }
Connections { Connections {
target: Config.general
function onLogoChanged(): void { function onLogoChanged(): void {
osRelease.reload(); osRelease.reload();
} }
target: Config.general
} }
Timer { Timer {
running: true
repeat: true
interval: 15000 interval: 15000
repeat: true
running: true
onTriggered: fileUptime.reload() onTriggered: fileUptime.reload()
} }
@@ -64,6 +65,7 @@ Singleton {
id: fileUptime id: fileUptime
path: "/proc/uptime" path: "/proc/uptime"
onLoaded: { onLoaded: {
const up = parseInt(text().split(" ")[0] ?? 0); const up = parseInt(text().split(" ")[0] ?? 0);
+23 -16
View File
@@ -8,25 +8,23 @@ import qs.Config
Singleton { Singleton {
id: root id: root
property string autoGpuType: "NONE"
property real cpuPerc property real cpuPerc
property real cpuTemp property real cpuTemp
readonly property string gpuType: Config.services.gpuType.toUpperCase() || autoGpuType property real gpuMemTotal: 0
property string autoGpuType: "NONE" property real gpuMemUsed
property real gpuPerc property real gpuPerc
property real gpuTemp property real gpuTemp
property real gpuMemUsed readonly property string gpuType: Config.services.gpuType.toUpperCase() || autoGpuType
property real gpuMemTotal: 0
property real memUsed
property real memTotal
readonly property real memPerc: memTotal > 0 ? memUsed / memTotal : 0
property real storageUsed
property real storageTotal
property real storagePerc: storageTotal > 0 ? storageUsed / storageTotal : 0
property real lastCpuIdle property real lastCpuIdle
property real lastCpuTotal property real lastCpuTotal
readonly property real memPerc: memTotal > 0 ? memUsed / memTotal : 0
property real memTotal
property real memUsed
property int refCount property int refCount
property real storagePerc: storageTotal > 0 ? storageUsed / storageTotal : 0
property real storageTotal
property real storageUsed
function formatKib(kib: real): var { function formatKib(kib: real): var {
const mib = 1024; const mib = 1024;
@@ -55,10 +53,11 @@ Singleton {
} }
Timer { Timer {
running: root.refCount > 0
interval: 3000 interval: 3000
repeat: true repeat: true
running: root.refCount > 0
triggeredOnStart: true triggeredOnStart: true
onTriggered: { onTriggered: {
stat.reload(); stat.reload();
meminfo.reload(); meminfo.reload();
@@ -72,6 +71,7 @@ Singleton {
id: stat id: stat
path: "/proc/stat" path: "/proc/stat"
onLoaded: { onLoaded: {
const data = text().match(/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/); const data = text().match(/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/);
if (data) { if (data) {
@@ -93,6 +93,7 @@ Singleton {
id: meminfo id: meminfo
path: "/proc/meminfo" path: "/proc/meminfo"
onLoaded: { onLoaded: {
const data = text(); const data = text();
root.memTotal = parseInt(data.match(/MemTotal: *(\d+)/)[1], 10) || 1; root.memTotal = parseInt(data.match(/MemTotal: *(\d+)/)[1], 10) || 1;
@@ -104,6 +105,7 @@ Singleton {
id: storage id: storage
command: ["sh", "-c", "df | grep '^/dev/' | awk '{print $1, $3, $4}'"] command: ["sh", "-c", "df | grep '^/dev/' | awk '{print $1, $3, $4}'"]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
const deviceMap = new Map(); const deviceMap = new Map();
@@ -145,8 +147,9 @@ Singleton {
Process { Process {
id: gpuTypeCheck id: gpuTypeCheck
running: !Config.services.gpuType
command: ["sh", "-c", "if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then echo NVIDIA; elif ls /sys/class/drm/card*/device/gpu_busy_percent 2>/dev/null | grep -q .; then echo GENERIC; else echo NONE; fi"] command: ["sh", "-c", "if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then echo NVIDIA; elif ls /sys/class/drm/card*/device/gpu_busy_percent 2>/dev/null | grep -q .; then echo GENERIC; else echo NONE; fi"]
running: !Config.services.gpuType
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: root.autoGpuType = text.trim() onStreamFinished: root.autoGpuType = text.trim()
} }
@@ -154,12 +157,14 @@ Singleton {
Process { Process {
id: oneshotMem id: oneshotMem
command: ["nvidia-smi", "--query-gpu=memory.total", "--format=csv,noheader,nounits"] command: ["nvidia-smi", "--query-gpu=memory.total", "--format=csv,noheader,nounits"]
running: root.gpuType === "NVIDIA" && root.gpuMemTotal === 0 running: root.gpuType === "NVIDIA" && root.gpuMemTotal === 0
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
root.gpuMemTotal = Number(this.text.trim()) root.gpuMemTotal = Number(this.text.trim());
oneshotMem.running = false oneshotMem.running = false;
} }
} }
} }
@@ -168,6 +173,7 @@ Singleton {
id: gpuUsage id: gpuUsage
command: root.gpuType === "GENERIC" ? ["sh", "-c", "cat /sys/class/drm/card*/device/gpu_busy_percent"] : root.gpuType === "NVIDIA" ? ["nvidia-smi", "--query-gpu=utilization.gpu,temperature.gpu,memory.used", "--format=csv,noheader,nounits"] : ["echo"] command: root.gpuType === "GENERIC" ? ["sh", "-c", "cat /sys/class/drm/card*/device/gpu_busy_percent"] : root.gpuType === "NVIDIA" ? ["nvidia-smi", "--query-gpu=utilization.gpu,temperature.gpu,memory.used", "--format=csv,noheader,nounits"] : ["echo"]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
if (root.gpuType === "GENERIC") { if (root.gpuType === "GENERIC") {
@@ -195,6 +201,7 @@ Singleton {
LANG: "C.UTF-8", LANG: "C.UTF-8",
LC_ALL: "C.UTF-8" LC_ALL: "C.UTF-8"
}) })
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
let cpuTemp = text.match(/(?:Package id [0-9]+|Tdie):\s+((\+|-)[0-9.]+)(°| )C/); let cpuTemp = text.match(/(?:Package id [0-9]+|Tdie):\s+((\+|-)[0-9.]+)(°| )C/);
+173 -171
View File
@@ -6,18 +6,10 @@ import Quickshell
Singleton { Singleton {
id: root id: root
property real scoreThreshold: 0.2 property list<DesktopEntry> entryList: []
property var preppedIcons: []
// Manual overrides for tricky apps property var preppedIds: []
property var substitutions: ({ property var preppedNames: []
"code-url-handler": "visual-studio-code",
"Code": "visual-studio-code",
"gnome-tweaks": "org.gnome.tweaks",
"pavucontrol-qt": "pavucontrol",
"wps": "wps-office2019-kprometheus",
"wpsoffice": "wps-office2019-kprometheus",
"footclient": "foot"
})
// Dynamic fixups // Dynamic fixups
property var regexSubstitutions: [ property var regexSubstitutions: [
@@ -38,156 +30,33 @@ Singleton {
"replace": "system-lock-screen" "replace": "system-lock-screen"
} }
] ]
property real scoreThreshold: 0.2
property list<DesktopEntry> entryList: [] // Manual overrides for tricky apps
property var preppedNames: [] property var substitutions: ({
property var preppedIcons: [] "code-url-handler": "visual-studio-code",
property var preppedIds: [] "Code": "visual-studio-code",
"gnome-tweaks": "org.gnome.tweaks",
"pavucontrol-qt": "pavucontrol",
"wps": "wps-office2019-kprometheus",
"wpsoffice": "wps-office2019-kprometheus",
"footclient": "foot"
})
Component.onCompleted: refreshEntries() function checkCleanMatch(str) {
if (!str || str.length <= 3)
Connections {
target: DesktopEntries.applications
function onValuesChanged() {
refreshEntries();
}
}
function refreshEntries() {
if (typeof DesktopEntries === 'undefined')
return;
const values = Array.from(DesktopEntries.applications.values);
if (values) {
entryList = values.sort((a, b) => a.name.localeCompare(b.name));
updatePreppedData();
}
}
function updatePreppedData() {
if (typeof FuzzySort === 'undefined')
return;
const list = Array.from(entryList);
preppedNames = list.map(a => ({
name: FuzzySort.prepare(`${a.name} `), entry: a}));
preppedIcons = list.map(a => ({
name: FuzzySort.prepare(`${a.icon} `),
entry: a
}));
preppedIds = list.map(a => ({
name: FuzzySort.prepare(`${a.id} `),
entry: a
}));
}
function iconForAppId(appId, fallbackName) {
const fallback = fallbackName || "application-x-executable";
if (!appId)
return iconFromName(fallback, fallback);
const entry = findAppEntry(appId);
if (entry) {
return iconFromName(entry.icon, fallback);
}
return iconFromName(appId, fallback);
}
// Robust lookup strategy
function findAppEntry(str) {
if (!str || str.length === 0)
return null; return null;
let result = null;
if (result = checkHeuristic(str))
return result;
if (result = checkSubstitutions(str))
return result;
if (result = checkRegex(str))
return result;
if (result = checkSimpleTransforms(str))
return result;
if (result = checkFuzzySearch(str))
return result;
if (result = checkCleanMatch(str))
return result;
return null;
}
function iconFromName(iconName, fallbackName) {
const fallback = fallbackName || "application-x-executable";
try {
if (iconName && typeof Quickshell !== 'undefined' && Quickshell.iconPath) {
const p = Quickshell.iconPath(iconName, fallback);
if (p && p !== "")
return p;
}
} catch (e) {}
try {
return Quickshell.iconPath ? (Quickshell.iconPath(fallback, true) || "") : "";
} catch (e2) {
return "";
}
}
function distroLogoPath() {
try {
return (typeof OSInfo !== 'undefined' && OSInfo.distroIconPath) ? OSInfo.distroIconPath : "";
} catch (e) {
return "";
}
}
// --- Lookup Helpers ---
function checkHeuristic(str) {
if (typeof DesktopEntries !== 'undefined' && DesktopEntries.heuristicLookup) {
const entry = DesktopEntries.heuristicLookup(str);
if (entry)
return entry;
}
return null;
}
function checkSubstitutions(str) {
let effectiveStr = substitutions[str];
if (!effectiveStr)
effectiveStr = substitutions[str.toLowerCase()];
if (effectiveStr && effectiveStr !== str) {
return findAppEntry(effectiveStr);
}
return null;
}
function checkRegex(str) {
for (let i = 0; i < regexSubstitutions.length; i++) {
const sub = regexSubstitutions[i];
const replaced = str.replace(sub.regex, sub.replace);
if (replaced !== str) {
return findAppEntry(replaced);
}
}
return null;
}
function checkSimpleTransforms(str) {
if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId) if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId)
return null; return null;
const lower = str.toLowerCase(); // Aggressive fallback: strip all separators
const cleanStr = str.toLowerCase().replace(/[\.\-_]/g, '');
const list = Array.from(entryList);
const variants = [str, lower, getFromReverseDomain(str), getFromReverseDomain(str)?.toLowerCase(), normalizeWithHyphens(str), str.replace(/_/g, '-').toLowerCase(), str.replace(/-/g, '_').toLowerCase()]; for (let i = 0; i < list.length; i++) {
const entry = list[i];
for (let i = 0; i < variants.length; i++) { const cleanId = (entry.id || "").toLowerCase().replace(/[\.\-_]/g, '');
const variant = variants[i]; if (cleanId.includes(cleanStr) || cleanStr.includes(cleanId)) {
if (variant) {
const entry = DesktopEntries.byId(variant);
if (entry)
return entry; return entry;
} }
} }
@@ -227,26 +96,89 @@ Singleton {
return null; return null;
} }
function checkCleanMatch(str) { // --- Lookup Helpers ---
if (!str || str.length <= 3)
function checkHeuristic(str) {
if (typeof DesktopEntries !== 'undefined' && DesktopEntries.heuristicLookup) {
const entry = DesktopEntries.heuristicLookup(str);
if (entry)
return entry;
}
return null; return null;
}
function checkRegex(str) {
for (let i = 0; i < regexSubstitutions.length; i++) {
const sub = regexSubstitutions[i];
const replaced = str.replace(sub.regex, sub.replace);
if (replaced !== str) {
return findAppEntry(replaced);
}
}
return null;
}
function checkSimpleTransforms(str) {
if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId) if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId)
return null; return null;
// Aggressive fallback: strip all separators const lower = str.toLowerCase();
const cleanStr = str.toLowerCase().replace(/[\.\-_]/g, '');
const list = Array.from(entryList);
for (let i = 0; i < list.length; i++) { const variants = [str, lower, getFromReverseDomain(str), getFromReverseDomain(str)?.toLowerCase(), normalizeWithHyphens(str), str.replace(/_/g, '-').toLowerCase(), str.replace(/-/g, '_').toLowerCase()];
const entry = list[i];
const cleanId = (entry.id || "").toLowerCase().replace(/[\.\-_]/g, ''); for (let i = 0; i < variants.length; i++) {
if (cleanId.includes(cleanStr) || cleanStr.includes(cleanId)) { const variant = variants[i];
if (variant) {
const entry = DesktopEntries.byId(variant);
if (entry)
return entry; return entry;
} }
} }
return null; return null;
} }
function checkSubstitutions(str) {
let effectiveStr = substitutions[str];
if (!effectiveStr)
effectiveStr = substitutions[str.toLowerCase()];
if (effectiveStr && effectiveStr !== str) {
return findAppEntry(effectiveStr);
}
return null;
}
function distroLogoPath() {
try {
return (typeof OSInfo !== 'undefined' && OSInfo.distroIconPath) ? OSInfo.distroIconPath : "";
} catch (e) {
return "";
}
}
// Robust lookup strategy
function findAppEntry(str) {
if (!str || str.length === 0)
return null;
let result = null;
if (result = checkHeuristic(str))
return result;
if (result = checkSubstitutions(str))
return result;
if (result = checkRegex(str))
return result;
if (result = checkSimpleTransforms(str))
return result;
if (result = checkFuzzySearch(str))
return result;
if (result = checkCleanMatch(str))
return result;
return null;
}
function fuzzyQuery(search, preppedData) { function fuzzyQuery(search, preppedData) {
if (!search || !preppedData || preppedData.length === 0) if (!search || !preppedData || preppedData.length === 0)
return []; return [];
@@ -256,6 +188,18 @@ Singleton {
}).map(r => r.obj.entry); }).map(r => r.obj.entry);
} }
function getFromReverseDomain(str) {
if (!str)
return "";
return str.split('.').slice(-1)[0];
}
// Deprecated shim
function guessIcon(str) {
const entry = findAppEntry(str);
return entry ? entry.icon : "image-missing";
}
function iconExists(iconName) { function iconExists(iconName) {
if (!iconName || iconName.length === 0) if (!iconName || iconName.length === 0)
return false; return false;
@@ -266,10 +210,34 @@ Singleton {
return path && path.length > 0 && !path.includes("image-missing"); return path && path.length > 0 && !path.includes("image-missing");
} }
function getFromReverseDomain(str) { function iconForAppId(appId, fallbackName) {
if (!str) const fallback = fallbackName || "application-x-executable";
if (!appId)
return iconFromName(fallback, fallback);
const entry = findAppEntry(appId);
if (entry) {
return iconFromName(entry.icon, fallback);
}
return iconFromName(appId, fallback);
}
function iconFromName(iconName, fallbackName) {
const fallback = fallbackName || "application-x-executable";
try {
if (iconName && typeof Quickshell !== 'undefined' && Quickshell.iconPath) {
const p = Quickshell.iconPath(iconName, fallback);
if (p && p !== "")
return p;
}
} catch (e) {}
try {
return Quickshell.iconPath ? (Quickshell.iconPath(fallback, true) || "") : "";
} catch (e2) {
return ""; return "";
return str.split('.').slice(-1)[0]; }
} }
function normalizeWithHyphens(str) { function normalizeWithHyphens(str) {
@@ -278,9 +246,43 @@ Singleton {
return str.toLowerCase().replace(/\s+/g, "-"); return str.toLowerCase().replace(/\s+/g, "-");
} }
// Deprecated shim function refreshEntries() {
function guessIcon(str) { if (typeof DesktopEntries === 'undefined')
const entry = findAppEntry(str); return;
return entry ? entry.icon : "image-missing";
const values = Array.from(DesktopEntries.applications.values);
if (values) {
entryList = values.sort((a, b) => a.name.localeCompare(b.name));
updatePreppedData();
}
}
function updatePreppedData() {
if (typeof FuzzySort === 'undefined')
return;
const list = Array.from(entryList);
preppedNames = list.map(a => ({
name: FuzzySort.prepare(`${a.name} `),
entry: a
}));
preppedIcons = list.map(a => ({
name: FuzzySort.prepare(`${a.icon} `),
entry: a
}));
preppedIds = list.map(a => ({
name: FuzzySort.prepare(`${a.id} `),
entry: a
}));
}
Component.onCompleted: refreshEntries()
Connections {
function onValuesChanged() {
refreshEntries();
}
target: DesktopEntries.applications
} }
} }
+6 -6
View File
@@ -3,17 +3,16 @@ pragma Singleton
import Quickshell import Quickshell
Singleton { Singleton {
property alias enabled: clock.enabled readonly property string amPmStr: timeComponents[2] ?? ""
readonly property date date: clock.date readonly property date date: clock.date
property alias enabled: clock.enabled
readonly property string hourStr: timeComponents[0] ?? ""
readonly property int hours: clock.hours readonly property int hours: clock.hours
readonly property string minuteStr: timeComponents[1] ?? ""
readonly property int minutes: clock.minutes readonly property int minutes: clock.minutes
readonly property int seconds: clock.seconds readonly property int seconds: clock.seconds
readonly property string timeStr: format("hh:mm")
readonly property list<string> timeComponents: timeStr.split(":") readonly property list<string> timeComponents: timeStr.split(":")
readonly property string hourStr: timeComponents[0] ?? "" readonly property string timeStr: format("hh:mm")
readonly property string minuteStr: timeComponents[1] ?? ""
readonly property string amPmStr: timeComponents[2] ?? ""
function format(fmt: string): string { function format(fmt: string): string {
return Qt.formatDateTime(clock.date, fmt); return Qt.formatDateTime(clock.date, fmt);
@@ -21,6 +20,7 @@ Singleton {
SystemClock { SystemClock {
id: clock id: clock
precision: SystemClock.Seconds precision: SystemClock.Seconds
} }
} }
+1 -2
View File
@@ -3,11 +3,10 @@ pragma Singleton
import Quickshell import Quickshell
import Quickshell.Services.UPower import Quickshell.Services.UPower
Singleton { Singleton {
id: root id: root
readonly property list<UPowerDevice> devices: UPower.devices.values readonly property list<UPowerDevice> devices: UPower.devices.values
readonly property bool onBattery: UPower.onBattery
readonly property UPowerDevice displayDevice: UPower.displayDevice readonly property UPowerDevice displayDevice: UPower.displayDevice
readonly property bool onBattery: UPower.onBattery
} }
+5 -5
View File
@@ -3,14 +3,14 @@ pragma Singleton
import Quickshell import Quickshell
Singleton { Singleton {
property var screens: new Map()
property var bars: new Map() property var bars: new Map()
property var screens: new Map()
function load(screen: ShellScreen, visibilities: var): void {
screens.set(Hypr.monitorFor(screen), visibilities);
}
function getForActive(): PersistentProperties { function getForActive(): PersistentProperties {
return screens.get(Hypr.focusedMonitor); return screens.get(Hypr.focusedMonitor);
} }
function load(screen: ShellScreen, visibilities: var): void {
screens.set(Hypr.monitorFor(screen), visibilities);
}
} }
+5 -2
View File
@@ -12,13 +12,16 @@ Singleton {
FileView { FileView {
id: fileView id: fileView
path: `${Paths.state}/wallpaper_path.json`
path: `${Paths.state}/wallpaper_path.json`
watchChanges: true watchChanges: true
onFileChanged: reload()
onAdapterUpdated: writeAdapter() onAdapterUpdated: writeAdapter()
onFileChanged: reload()
JsonAdapter { JsonAdapter {
id: adapter id: adapter
property string currentWallpaperPath: "" property string currentWallpaperPath: ""
property string lockscreenBg: `${Paths.state}/lockscreen_bg.png` property string lockscreenBg: `${Paths.state}/lockscreen_bg.png`
} }
+16 -16
View File
@@ -11,10 +11,17 @@ import qs.Paths
Searcher { Searcher {
id: root id: root
property bool showPreview: false property string actualCurrent: WallpaperPath.currentWallpaperPath
readonly property string current: showPreview ? previewPath : actualCurrent readonly property string current: showPreview ? previewPath : actualCurrent
property string previewPath property string previewPath
property string actualCurrent: WallpaperPath.currentWallpaperPath property bool showPreview: false
function preview(path: string): void {
previewPath = path;
if (Config.general.color.schemeGeneration)
Quickshell.execDetached(["sh", "-c", `zshell-cli scheme generate --image-path ${previewPath} --thumbnail-path ${Paths.cache}/imagecache/thumbnail.jpg --output ${Paths.state}/scheme.json --scheme ${Config.colors.schemeType} --mode ${Config.general.color.mode}`]);
showPreview = true;
}
function setWallpaper(path: string): void { function setWallpaper(path: string): void {
actualCurrent = path; actualCurrent = path;
@@ -24,39 +31,32 @@ Searcher {
Quickshell.execDetached(["sh", "-c", `zshell-cli wallpaper lockscreen --input-image=${root.actualCurrent} --output-path=${Paths.state}/lockscreen_bg.png --blur-amount=${Config.lock.blurAmount}`]); Quickshell.execDetached(["sh", "-c", `zshell-cli wallpaper lockscreen --input-image=${root.actualCurrent} --output-path=${Paths.state}/lockscreen_bg.png --blur-amount=${Config.lock.blurAmount}`]);
} }
function preview(path: string): void {
previewPath = path;
if ( Config.general.color.schemeGeneration )
Quickshell.execDetached(["sh", "-c", `zshell-cli scheme generate --image-path ${previewPath} --thumbnail-path ${Paths.cache}/imagecache/thumbnail.jpg --output ${Paths.state}/scheme.json --scheme ${Config.colors.schemeType} --mode ${Config.general.color.mode}`]);
showPreview = true;
}
function stopPreview(): void { function stopPreview(): void {
showPreview = false; showPreview = false;
if (Config.general.color.schemeGeneration) if (Config.general.color.schemeGeneration)
Quickshell.execDetached(["sh", "-c", `zshell-cli scheme generate --image-path ${root.actualCurrent} --thumbnail-path ${Paths.cache}/imagecache/thumbnail.jpg --output ${Paths.state}/scheme.json --scheme ${Config.colors.schemeType} --mode ${Config.general.color.mode}`]); Quickshell.execDetached(["sh", "-c", `zshell-cli scheme generate --image-path ${root.actualCurrent} --thumbnail-path ${Paths.cache}/imagecache/thumbnail.jpg --output ${Paths.state}/scheme.json --scheme ${Config.colors.schemeType} --mode ${Config.general.color.mode}`]);
} }
list: wallpapers.entries
key: "relativePath"
useFuzzy: true
extraOpts: useFuzzy ? ({}) : ({ extraOpts: useFuzzy ? ({}) : ({
forward: false forward: false
}) })
key: "relativePath"
list: wallpapers.entries
useFuzzy: true
IpcHandler { IpcHandler {
target: "wallpaper"
function set(path: string): void { function set(path: string): void {
root.setWallpaper(path); root.setWallpaper(path);
} }
target: "wallpaper"
} }
FileSystemModel { FileSystemModel {
id: wallpapers id: wallpapers
recursive: true
path: Config.general.wallpaperPath
filter: FileSystemModel.Images filter: FileSystemModel.Images
path: Config.general.wallpaperPath
recursive: true
} }
} }
+1
View File
@@ -19,6 +19,7 @@ Singleton {
Process { Process {
id: wallustProc id: wallustProc
command: ["wallust", "run", root.args, `--palette=${root.mode}`, "--ignore-sequence=cursor", `${root.threshold}`] command: ["wallust", "run", root.args, `--palette=${root.mode}`, "--ignore-sequence=cursor", `${root.threshold}`]
running: false running: false
} }
+48 -48
View File
@@ -8,44 +8,20 @@ import qs.Config
Singleton { Singleton {
id: root id: root
property string city readonly property var cachedCities: new Map()
property string loc
property var cc property var cc
property string city
readonly property string description: cc?.weatherDesc ?? qsTr("No weather")
readonly property string feelsLike: `${cc?.feelsLikeC ?? 0}°C`
property list<var> forecast property list<var> forecast
property list<var> hourlyForecast property list<var> hourlyForecast
readonly property string icon: cc ? Icons.getWeatherIcon(cc.weatherCode) : "cloud_alert"
readonly property string description: cc?.weatherDesc ?? qsTr("No weather")
readonly property string temp: `${cc?.tempC ?? 0}°C`
readonly property string feelsLike: `${cc?.feelsLikeC ?? 0}°C`
readonly property int humidity: cc?.humidity ?? 0 readonly property int humidity: cc?.humidity ?? 0
readonly property real windSpeed: cc?.windSpeed ?? 0 readonly property string icon: cc ? Icons.getWeatherIcon(cc.weatherCode) : "cloud_alert"
property string loc
readonly property string sunrise: cc ? Qt.formatDateTime(new Date(cc.sunrise), "h:mm") : "--:--" readonly property string sunrise: cc ? Qt.formatDateTime(new Date(cc.sunrise), "h:mm") : "--:--"
readonly property string sunset: cc ? Qt.formatDateTime(new Date(cc.sunset), "h:mm") : "--:--" readonly property string sunset: cc ? Qt.formatDateTime(new Date(cc.sunset), "h:mm") : "--:--"
readonly property string temp: `${cc?.tempC ?? 0}°C`
readonly property var cachedCities: new Map() readonly property real windSpeed: cc?.windSpeed ?? 0
function reload(): void {
const configLocation = Config.services.weatherLocation;
if (configLocation) {
if (configLocation.indexOf(",") !== -1 && !isNaN(parseFloat(configLocation.split(",")[0]))) {
loc = configLocation;
fetchCityFromCoords(configLocation);
} else {
fetchCoordsFromCity(configLocation);
}
} else if (!loc || timer.elapsed() > 900) {
Requests.get("https://ipinfo.io/json", text => {
const response = JSON.parse(text);
if (response.loc) {
loc = response.loc;
city = response.city ?? "";
timer.restart();
}
});
}
}
function fetchCityFromCoords(coords: string): void { function fetchCityFromCoords(coords: string): void {
if (cachedCities.has(coords)) { if (cachedCities.has(coords)) {
@@ -140,21 +116,6 @@ Singleton {
}); });
} }
function toFahrenheit(celcius: real): real {
return celcius * 9 / 5 + 32;
}
function getWeatherUrl(): string {
if (!loc || loc.indexOf(",") === -1)
return "";
const [lat, lon] = loc.split(",");
const baseUrl = "https://api.open-meteo.com/v1/forecast";
const params = ["latitude=" + lat, "longitude=" + lon, "hourly=weather_code,temperature_2m", "daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset", "current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,weather_code,wind_speed_10m", "timezone=auto", "forecast_days=7"];
return baseUrl + "?" + params.join("&");
}
function getWeatherCondition(code: string): string { function getWeatherCondition(code: string): string {
const conditions = { const conditions = {
"0": "Clear", "0": "Clear",
@@ -189,17 +150,56 @@ Singleton {
return conditions[code] || "Unknown"; return conditions[code] || "Unknown";
} }
function getWeatherUrl(): string {
if (!loc || loc.indexOf(",") === -1)
return "";
const [lat, lon] = loc.split(",");
const baseUrl = "https://api.open-meteo.com/v1/forecast";
const params = ["latitude=" + lat, "longitude=" + lon, "hourly=weather_code,temperature_2m", "daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset", "current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,weather_code,wind_speed_10m", "timezone=auto", "forecast_days=7"];
return baseUrl + "?" + params.join("&");
}
function reload(): void {
const configLocation = Config.services.weatherLocation;
if (configLocation) {
if (configLocation.indexOf(",") !== -1 && !isNaN(parseFloat(configLocation.split(",")[0]))) {
loc = configLocation;
fetchCityFromCoords(configLocation);
} else {
fetchCoordsFromCity(configLocation);
}
} else if (!loc || timer.elapsed() > 900) {
Requests.get("https://ipinfo.io/json", text => {
const response = JSON.parse(text);
if (response.loc) {
loc = response.loc;
city = response.city ?? "";
timer.restart();
}
});
}
}
function toFahrenheit(celcius: real): real {
return celcius * 9 / 5 + 32;
}
onLocChanged: fetchWeatherData() onLocChanged: fetchWeatherData()
// Refresh current location hourly // Refresh current location hourly
Timer { Timer {
interval: 3600000 // 1 hour interval: 3600000 // 1 hour
running: true
repeat: true repeat: true
running: true
onTriggered: fetchWeatherData() onTriggered: fetchWeatherData()
} }
ElapsedTimer { ElapsedTimer {
id: timer id: timer
} }
} }
+52 -416
View File
@@ -1,420 +1,56 @@
import Quickshell.Io import Quickshell.Io
JsonObject { JsonObject {
property list<var> week_0: [ property list<var> week_0: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_1: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_10: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_11: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_12: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_13: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_14: [0, 0, 0, 0, 0, 0,]
] property list<var> week_15: [0, 0, 0, 0, 0, 0,]
property list<var> week_1: [ property list<var> week_16: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_17: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_18: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_19: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_2: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_20: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_21: [0, 0, 0, 0, 0, 0,]
] property list<var> week_22: [0, 0, 0, 0, 0, 0,]
property list<var> week_2: [ property list<var> week_23: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_24: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_25: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_26: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_27: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_28: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_29: [0, 0, 0, 0, 0, 0,]
] property list<var> week_3: [0, 0, 0, 0, 0, 0,]
property list<var> week_3: [ property list<var> week_30: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_31: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_32: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_33: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_34: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_35: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_36: [0, 0, 0, 0, 0, 0,]
] property list<var> week_37: [0, 0, 0, 0, 0, 0,]
property list<var> week_4: [ property list<var> week_38: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_39: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_4: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_40: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_41: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_42: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_43: [0, 0, 0, 0, 0, 0,]
] property list<var> week_44: [0, 0, 0, 0, 0, 0,]
property list<var> week_5: [ property list<var> week_45: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_46: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_47: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_48: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_49: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_5: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_50: [0, 0, 0, 0, 0, 0,]
] property list<var> week_51: [0, 0, 0, 0, 0, 0,]
property list<var> week_6: [ property list<var> week_6: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_7: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_8: [0, 0, 0, 0, 0, 0,]
0, property list<var> week_9: [0, 0, 0, 0, 0, 0,]
0,
0,
0,
]
property list<var> week_7: [
0,
0,
0,
0,
0,
0,
]
property list<var> week_8: [
0,
0,
0,
0,
0,
0,
]
property list<var> week_9: [
0,
0,
0,
0,
0,
0,
]
property list<var> week_10:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_11:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_12:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_13:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_14:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_15:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_16:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_17:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_18:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_19:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_20:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_21:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_22:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_23:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_24:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_25:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_26:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_27:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_28:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_29:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_30:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_31:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_32:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_33:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_34:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_35:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_36:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_37:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_38:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_39:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_40:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_41:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_42:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_43:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_44:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_45:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_46:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_47:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_48:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_49:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_50:[
0,
0,
0,
0,
0,
0,
]
property list<var> week_51:[
0,
0,
0,
0,
0,
0,
]
} }
+166 -135
View File
@@ -14,66 +14,63 @@ import qs.Helpers
Item { Item {
id: root id: root
implicitWidth: layout.implicitWidth + 5 * 2
implicitHeight: layout.implicitHeight + 5 * 2
readonly property int topMargin: 0
readonly property int rounding: 6 readonly property int rounding: 6
readonly property int topMargin: 0
required property var wrapper required property var wrapper
implicitHeight: layout.implicitHeight + 5 * 2
implicitWidth: layout.implicitWidth + 5 * 2
ColumnLayout { ColumnLayout {
id: layout id: layout
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
implicitWidth: stack.currentItem ? stack.currentItem.childrenRect.height : 0 implicitWidth: stack.currentItem ? stack.currentItem.childrenRect.height : 0
spacing: 12 spacing: 12
RowLayout { RowLayout {
id: tabBar id: tabBar
spacing: 6
Layout.fillWidth: true
property int tabHeight: 36 property int tabHeight: 36
Layout.fillWidth: true
spacing: 6
CustomClippingRect { CustomClippingRect {
radius: 6
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: tabBar.tabHeight Layout.preferredHeight: tabBar.tabHeight
color: stack.currentIndex === 0 ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer color: stack.currentIndex === 0 ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
radius: 6
StateLayer { StateLayer {
function onClicked(): void { function onClicked(): void {
stack.currentIndex = 0; stack.currentIndex = 0;
} }
CustomText { CustomText {
text: qsTr("Volumes")
anchors.centerIn: parent anchors.centerIn: parent
color: stack.currentIndex === 0 ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3primary color: stack.currentIndex === 0 ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3primary
text: qsTr("Volumes")
} }
} }
} }
CustomClippingRect { CustomClippingRect {
radius: 6
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: tabBar.tabHeight Layout.preferredHeight: tabBar.tabHeight
color: stack.currentIndex === 1 ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer color: stack.currentIndex === 1 ? DynamicColors.palette.m3primary : DynamicColors.tPalette.m3surfaceContainer
radius: 6
StateLayer { StateLayer {
function onClicked(): void { function onClicked(): void {
stack.currentIndex = 1; stack.currentIndex = 1;
} }
CustomText { CustomText {
text: qsTr("Devices")
anchors.centerIn: parent anchors.centerIn: parent
color: stack.currentIndex === 1 ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3primary color: stack.currentIndex === 1 ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3primary
text: qsTr("Devices")
} }
} }
} }
@@ -81,175 +78,245 @@ Item {
StackLayout { StackLayout {
id: stack id: stack
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: currentIndex === 0 ? vol.childrenRect.height : dev.childrenRect.height Layout.preferredHeight: currentIndex === 0 ? vol.childrenRect.height : dev.childrenRect.height
currentIndex: 0 currentIndex: 0
VolumesTab { id: vol }
DevicesTab { id: dev }
Behavior on currentIndex { Behavior on currentIndex {
SequentialAnimation { SequentialAnimation {
ParallelAnimation { ParallelAnimation {
Anim { Anim {
target: stack
property: "opacity"
to: 0
duration: MaterialEasing.expressiveEffectsTime duration: MaterialEasing.expressiveEffectsTime
property: "opacity"
target: stack
to: 0
} }
Anim { Anim {
target: stack
property: "scale"
to: 0.9
duration: MaterialEasing.expressiveEffectsTime duration: MaterialEasing.expressiveEffectsTime
property: "scale"
target: stack
to: 0.9
} }
} }
PropertyAction {} PropertyAction {
}
ParallelAnimation { ParallelAnimation {
Anim { Anim {
target: stack
property: "opacity"
to: 1
duration: MaterialEasing.expressiveEffectsTime duration: MaterialEasing.expressiveEffectsTime
property: "opacity"
target: stack
to: 1
} }
Anim { Anim {
target: stack
property: "scale"
to: 1
duration: MaterialEasing.expressiveEffectsTime duration: MaterialEasing.expressiveEffectsTime
} property: "scale"
} target: stack
to: 1
} }
} }
} }
} }
VolumesTab {
id: vol
}
DevicesTab {
id: dev
}
}
}
component DevicesTab: ColumnLayout {
spacing: 12
ButtonGroup {
id: sinks
}
ButtonGroup {
id: sources
}
CustomText {
font.weight: 500
text: qsTr("Output device")
}
Repeater {
model: Audio.sinks
CustomRadioButton {
required property PwNode modelData
ButtonGroup.group: sinks
checked: Audio.sink?.id === modelData.id
text: modelData.description
onClicked: Audio.setAudioSink(modelData)
}
}
CustomText {
Layout.topMargin: 10
font.weight: 500
text: qsTr("Input device")
}
Repeater {
model: Audio.sources
CustomRadioButton {
required property PwNode modelData
ButtonGroup.group: sources
checked: Audio.source?.id === modelData.id
text: modelData.description
onClicked: Audio.setAudioSource(modelData)
}
}
}
component VolumesTab: ColumnLayout { component VolumesTab: ColumnLayout {
spacing: 12 spacing: 12
CustomRect { CustomRect {
Layout.topMargin: root.topMargin
Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding radius: root.rounding
RowLayout { RowLayout {
id: outputVolume id: outputVolume
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right
anchors.margins: Appearance.spacing.smaller anchors.margins: Appearance.spacing.smaller
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 15 spacing: 15
CustomRect { CustomRect {
Layout.preferredWidth: 40
Layout.preferredHeight: 40
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: DynamicColors.palette.m3primary color: DynamicColors.palette.m3primary
radius: 1000 radius: 1000
MaterialIcon { MaterialIcon {
anchors.centerIn: parent anchors.centerIn: parent
color: DynamicColors.palette.m3onPrimary color: DynamicColors.palette.m3onPrimary
text: "speaker"
font.pointSize: 22 font.pointSize: 22
text: "speaker"
} }
} }
ColumnLayout { ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
CustomText { CustomText {
text: "Output Volume"
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillWidth: true
text: "Output Volume"
} }
CustomText { CustomText {
text: qsTr("%1").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`);
font.bold: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
font.bold: true
text: qsTr("%1").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`)
} }
} }
CustomMouseArea { CustomMouseArea {
Layout.bottomMargin: 5
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 10 Layout.preferredHeight: 10
Layout.bottomMargin: 5
CustomSlider { CustomSlider {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
implicitHeight: 10 implicitHeight: 10
value: Audio.volume value: Audio.volume
Behavior on value {
Anim {
}
}
onMoved: Audio.setVolume(value) onMoved: Audio.setVolume(value)
Behavior on value { Anim {} }
} }
} }
} }
} }
} }
CustomRect { CustomRect {
Layout.topMargin: root.topMargin
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding radius: root.rounding
RowLayout { RowLayout {
id: inputVolume id: inputVolume
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right
anchors.margins: Appearance.spacing.smaller anchors.margins: Appearance.spacing.smaller
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 15 spacing: 15
Rectangle { Rectangle {
Layout.preferredWidth: 40
Layout.preferredHeight: 40
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: DynamicColors.palette.m3primary color: DynamicColors.palette.m3primary
radius: 1000 radius: 1000
MaterialIcon { MaterialIcon {
anchors.centerIn: parent
anchors.alignWhenCentered: false anchors.alignWhenCentered: false
anchors.centerIn: parent
color: DynamicColors.palette.m3onPrimary color: DynamicColors.palette.m3onPrimary
text: "mic"
font.pointSize: 22 font.pointSize: 22
text: "mic"
} }
} }
ColumnLayout { ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
RowLayout { RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true
CustomText { CustomText {
text: "Input Volume"
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillWidth: true
text: "Input Volume"
} }
CustomText { CustomText {
text: qsTr("%1").arg(Audio.sourceMuted ? qsTr("Muted") : `${Math.round(Audio.sourceVolume * 100)}%`);
font.bold: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
font.bold: true
text: qsTr("%1").arg(Audio.sourceMuted ? qsTr("Muted") : `${Math.round(Audio.sourceVolume * 100)}%`)
} }
} }
CustomMouseArea { CustomMouseArea {
Layout.fillWidth: true
Layout.bottomMargin: 5 Layout.bottomMargin: 5
Layout.fillWidth: true
implicitHeight: 10 implicitHeight: 10
CustomSlider { CustomSlider {
@@ -257,9 +324,13 @@ Item {
anchors.right: parent.right anchors.right: parent.right
implicitHeight: 10 implicitHeight: 10
value: Audio.sourceVolume value: Audio.sourceVolume
onMoved: Audio.setSourceVolume(value)
Behavior on value { Anim {} } Behavior on value {
Anim {
}
}
onMoved: Audio.setSourceVolume(value)
} }
} }
} }
@@ -267,10 +338,9 @@ Item {
} }
Rectangle { Rectangle {
Layout.topMargin: root.topMargin
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 1 Layout.preferredHeight: 1
Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3outline color: DynamicColors.tPalette.m3outline
} }
@@ -280,39 +350,40 @@ Item {
CustomRect { CustomRect {
id: appBox id: appBox
Layout.topMargin: root.topMargin required property int index
required property var modelData
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding radius: root.rounding
required property var modelData
required property int index
RowLayout { RowLayout {
id: layoutVolume id: layoutVolume
anchors.fill: parent anchors.fill: parent
anchors.margins: Appearance.spacing.smaller anchors.margins: Appearance.spacing.smaller
spacing: 15 spacing: 15
CustomRect { CustomRect {
Layout.preferredWidth: 40
Layout.preferredHeight: 40
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: DynamicColors.palette.m3primary color: DynamicColors.palette.m3primary
radius: 1000 radius: 1000
MaterialIcon { MaterialIcon {
id: icon id: icon
anchors.centerIn: parent anchors.centerIn: parent
text: "volume_up"
font.pointSize: 22
color: DynamicColors.palette.m3onPrimary color: DynamicColors.palette.m3onPrimary
font.pointSize: 22
text: "volume_up"
StateLayer { StateLayer {
radius: 1000 radius: 1000
onClicked: { onClicked: {
appBox.modelData.audio.muted = !appBox.modelData.audio.muted; appBox.modelData.audio.muted = !appBox.modelData.audio.muted;
} }
@@ -326,42 +397,46 @@ Item {
TextMetrics { TextMetrics {
id: metrics id: metrics
text: Audio.getStreamName(appBox.modelData)
elide: Text.ElideRight elide: Text.ElideRight
elideWidth: root.width - 50 elideWidth: root.width - 50
text: Audio.getStreamName(appBox.modelData)
} }
RowLayout { RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true
CustomText { CustomText {
text: metrics.elidedText
elide: Text.ElideRight
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillHeight: true
Layout.fillWidth: true
elide: Text.ElideRight
text: metrics.elidedText
} }
CustomText { CustomText {
text: qsTr("%1").arg(appBox.modelData.audio.muted ? qsTr("Muted") : `${Math.round(appBox.modelData.audio.volume * 100)}%`);
font.bold: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.fillHeight: true
font.bold: true
text: qsTr("%1").arg(appBox.modelData.audio.muted ? qsTr("Muted") : `${Math.round(appBox.modelData.audio.volume * 100)}%`)
} }
} }
CustomMouseArea { CustomMouseArea {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillHeight: true
Layout.fillWidth: true
implicitHeight: 10 implicitHeight: 10
CustomSlider { CustomSlider {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
implicitHeight: 10 implicitHeight: 10
value: appBox.modelData.audio.volume value: appBox.modelData.audio.volume
onMoved: { onMoved: {
Audio.setStreamVolume(appBox.modelData, value) Audio.setStreamVolume(appBox.modelData, value);
} }
} }
} }
@@ -370,48 +445,4 @@ Item {
} }
} }
} }
component DevicesTab: ColumnLayout {
spacing: 12
ButtonGroup { id: sinks }
ButtonGroup { id: sources }
CustomText {
text: qsTr("Output device")
font.weight: 500
}
Repeater {
model: Audio.sinks
CustomRadioButton {
required property PwNode modelData
ButtonGroup.group: sinks
checked: Audio.sink?.id === modelData.id
onClicked: Audio.setAudioSink(modelData)
text: modelData.description
}
}
CustomText {
Layout.topMargin: 10
text: qsTr("Input device")
font.weight: 500
}
Repeater {
model: Audio.sources
CustomRadioButton {
required property PwNode modelData
ButtonGroup.group: sources
checked: Audio.source?.id === modelData.id
onClicked: Audio.setAudioSource(modelData)
text: modelData.description
}
}
}
} }
+36 -31
View File
@@ -9,13 +9,14 @@ import qs.Components
Item { Item {
id: root id: root
implicitWidth: expanded ? 300 : 150
anchors.top: parent.top
anchors.bottom: parent.bottom
property color barColor: DynamicColors.palette.m3primary
property bool expanded: false property bool expanded: false
property color textColor: DynamicColors.palette.m3onSurface property color textColor: DynamicColors.palette.m3onSurface
property color barColor: DynamicColors.palette.m3primary
anchors.bottom: parent.bottom
anchors.top: parent.top
implicitWidth: expanded ? 300 : 150
Behavior on implicitWidth { Behavior on implicitWidth {
NumberAnimation { NumberAnimation {
@@ -25,25 +26,26 @@ Item {
} }
Rectangle { Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.tPalette.m3surfaceContainer
height: 22 height: 22
radius: height / 2 radius: height / 2
color: DynamicColors.tPalette.m3surfaceContainer
Behavior on color { Behavior on color {
CAnim {} CAnim {
}
} }
Rectangle { Rectangle {
anchors.centerIn: parent anchors.centerIn: parent
width: parent.width
height: parent.height
radius: width / 2
color: "transparent"
border.color: "#30ffffff" border.color: "#30ffffff"
border.width: 0 border.width: 0
color: "transparent"
height: parent.height
radius: width / 2
width: parent.width
} }
RowLayout { RowLayout {
@@ -55,63 +57,66 @@ Item {
MaterialIcon { MaterialIcon {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: Audio.muted ? DynamicColors.palette.m3error : root.textColor
font.pixelSize: 18 font.pixelSize: 18
text: Audio.muted ? "volume_off" : "volume_up" text: Audio.muted ? "volume_off" : "volume_up"
color: Audio.muted ? DynamicColors.palette.m3error : root.textColor
} }
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
color: "#50ffffff"
implicitHeight: 4 implicitHeight: 4
radius: 20 radius: 20
color: "#50ffffff"
Rectangle { Rectangle {
id: sinkVolumeBar id: sinkVolumeBar
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
color: Audio.muted ? DynamicColors.palette.m3error : root.barColor
implicitWidth: parent.width * (Audio.volume ?? 0) implicitWidth: parent.width * (Audio.volume ?? 0)
radius: parent.radius radius: parent.radius
color: Audio.muted ? DynamicColors.palette.m3error : root.barColor
Behavior on color { Behavior on color {
CAnim {} CAnim {
}
}
anchors {
bottom: parent.bottom
left: parent.left
top: parent.top
} }
} }
} }
MaterialIcon { MaterialIcon {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: (Audio.sourceMuted ?? false) ? DynamicColors.palette.m3error : root.textColor
font.pixelSize: 18 font.pixelSize: 18
text: Audio.sourceMuted ? "mic_off" : "mic" text: Audio.sourceMuted ? "mic_off" : "mic"
color: ( Audio.sourceMuted ?? false ) ? DynamicColors.palette.m3error : root.textColor
} }
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
color: "#50ffffff"
implicitHeight: 4 implicitHeight: 4
radius: 20 radius: 20
color: "#50ffffff"
Rectangle { Rectangle {
id: sourceVolumeBar id: sourceVolumeBar
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
color: (Audio.sourceMuted ?? false) ? DynamicColors.palette.m3error : root.barColor
implicitWidth: parent.width * (Audio.sourceVolume ?? 0) implicitWidth: parent.width * (Audio.sourceVolume ?? 0)
radius: parent.radius radius: parent.radius
color: ( Audio.sourceMuted ?? false ) ? DynamicColors.palette.m3error : root.barColor
Behavior on color { Behavior on color {
CAnim {} CAnim {
}
}
anchors {
bottom: parent.bottom
left: parent.left
top: parent.top
} }
} }
} }
+19 -18
View File
@@ -6,21 +6,26 @@ import qs.Config
ShapePath { ShapePath {
id: root id: root
required property Wrapper wrapper readonly property bool flatten: wrapper.height < rounding * 2
property real ibr: invertBottomRounding ? -1 : 1
required property bool invertBottomRounding required property bool invertBottomRounding
readonly property real rounding: 8 readonly property real rounding: 8
readonly property bool flatten: wrapper.height < rounding * 2
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
property real ibr: invertBottomRounding ? -1 : 1 required property Wrapper wrapper
strokeWidth: -1
fillColor: DynamicColors.palette.m3surface fillColor: DynamicColors.palette.m3surface
strokeWidth: -1
Behavior on fillColor {
CAnim {
}
}
PathArc { PathArc {
relativeX: root.rounding
relativeY: root.roundingY
radiusX: root.rounding radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height) radiusY: Math.min(root.rounding, root.wrapper.height)
relativeX: root.rounding
relativeY: root.roundingY
} }
PathLine { PathLine {
@@ -29,11 +34,11 @@ ShapePath {
} }
PathArc { PathArc {
relativeX: root.rounding direction: root.invertBottomRounding ? PathArc.Clockwise : PathArc.Counterclockwise
relativeY: root.roundingY * root.ibr
radiusX: root.rounding radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height) radiusY: Math.min(root.rounding, root.wrapper.height)
direction: root.invertBottomRounding ? PathArc.Clockwise : PathArc.Counterclockwise relativeX: root.rounding
relativeY: root.roundingY * root.ibr
} }
PathLine { PathLine {
@@ -42,11 +47,11 @@ ShapePath {
} }
PathArc { PathArc {
relativeX: root.rounding direction: PathArc.Counterclockwise
relativeY: -root.roundingY
radiusX: root.rounding radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height) radiusY: Math.min(root.rounding, root.wrapper.height)
direction: PathArc.Counterclockwise relativeX: root.rounding
relativeY: -root.roundingY
} }
PathLine { PathLine {
@@ -55,13 +60,9 @@ ShapePath {
} }
PathArc { PathArc {
relativeX: root.rounding
relativeY: -root.roundingY
radiusX: root.rounding radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height) radiusY: Math.min(root.rounding, root.wrapper.height)
} relativeX: root.rounding
relativeY: -root.roundingY
Behavior on fillColor {
CAnim {}
} }
} }
+43 -18
View File
@@ -13,13 +13,12 @@ import qs.Modules.Network
RowLayout { RowLayout {
id: root id: root
anchors.fill: parent
readonly property int vPadding: 6
required property Wrapper popouts
required property PersistentProperties visibilities
required property PanelWindow bar required property PanelWindow bar
required property Wrapper popouts
required property ShellScreen screen required property ShellScreen screen
readonly property int vPadding: 6
required property PersistentProperties visibilities
function checkPopout(x: real): void { function checkPopout(x: real): void {
const ch = childAt(x, 2) as WrappedLoader; const ch = childAt(x, 2) as WrappedLoader;
@@ -38,7 +37,6 @@ 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.barConfig.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);
@@ -74,6 +72,8 @@ RowLayout {
} }
} }
anchors.fill: parent
CustomShortcut { CustomShortcut {
name: "toggle-overview" name: "toggle-overview"
@@ -92,6 +92,7 @@ RowLayout {
Repeater { Repeater {
id: repeater id: repeater
model: Config.barConfig.entries model: Config.barConfig.entries
DelegateChooser { DelegateChooser {
@@ -99,67 +100,87 @@ RowLayout {
DelegateChoice { DelegateChoice {
roleValue: "spacer" roleValue: "spacer"
delegate: WrappedLoader { delegate: WrappedLoader {
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
DelegateChoice { DelegateChoice {
roleValue: "workspaces" roleValue: "workspaces"
delegate: WrappedLoader { delegate: WrappedLoader {
sourceComponent: Workspaces { sourceComponent: Workspaces {
bar: root.bar bar: root.bar
} }
} }
} }
DelegateChoice { DelegateChoice {
roleValue: "audio" roleValue: "audio"
delegate: WrappedLoader { delegate: WrappedLoader {
sourceComponent: AudioWidget {} sourceComponent: AudioWidget {
} }
} }
}
DelegateChoice { DelegateChoice {
roleValue: "tray" roleValue: "tray"
delegate: WrappedLoader { delegate: WrappedLoader {
sourceComponent: TrayWidget { sourceComponent: TrayWidget {
bar: root.bar bar: root.bar
popouts: root.popouts
loader: root loader: root
popouts: root.popouts
} }
} }
} }
DelegateChoice { DelegateChoice {
roleValue: "resources" roleValue: "resources"
delegate: WrappedLoader { delegate: WrappedLoader {
sourceComponent: Resources {} sourceComponent: Resources {
} }
} }
}
DelegateChoice { DelegateChoice {
roleValue: "updates" roleValue: "updates"
delegate: WrappedLoader { delegate: WrappedLoader {
sourceComponent: UpdatesWidget {} sourceComponent: UpdatesWidget {
} }
} }
}
DelegateChoice { DelegateChoice {
roleValue: "notifBell" roleValue: "notifBell"
delegate: WrappedLoader { delegate: WrappedLoader {
sourceComponent: NotifBell { sourceComponent: NotifBell {
visibilities: root.visibilities
popouts: root.popouts popouts: root.popouts
visibilities: root.visibilities
} }
} }
} }
DelegateChoice { DelegateChoice {
roleValue: "clock" roleValue: "clock"
delegate: WrappedLoader { delegate: WrappedLoader {
sourceComponent: Clock { sourceComponent: Clock {
loader: root
popouts: root.popouts popouts: root.popouts
visibilities: root.visibilities visibilities: root.visibilities
loader: root
} }
} }
} }
DelegateChoice { DelegateChoice {
roleValue: "activeWindow" roleValue: "activeWindow"
delegate: WrappedLoader { delegate: WrappedLoader {
sourceComponent: WindowTitle { sourceComponent: WindowTitle {
bar: root bar: root
@@ -167,16 +188,22 @@ RowLayout {
} }
} }
} }
DelegateChoice { DelegateChoice {
roleValue: "upower" roleValue: "upower"
delegate: WrappedLoader { delegate: WrappedLoader {
sourceComponent: UPowerWidget {} sourceComponent: UPowerWidget {
} }
} }
}
DelegateChoice { DelegateChoice {
roleValue: "network" roleValue: "network"
delegate: WrappedLoader { delegate: WrappedLoader {
sourceComponent: NetworkWidget {} sourceComponent: NetworkWidget {
}
} }
} }
// DelegateChoice { // DelegateChoice {
@@ -195,9 +222,6 @@ RowLayout {
required property string id required property string id
required property int index required property int index
Layout.alignment: Qt.AlignVCenter
Layout.fillHeight: true
function findFirstEnabled(): Item { function findFirstEnabled(): Item {
const count = repeater.count; const count = repeater.count;
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
@@ -217,10 +241,11 @@ RowLayout {
return null; return null;
} }
Layout.alignment: Qt.AlignVCenter
Layout.fillHeight: true
Layout.leftMargin: findFirstEnabled() === this ? root.vPadding : 0 Layout.leftMargin: findFirstEnabled() === this ? root.vPadding : 0
Layout.rightMargin: findLastEnabled() === this ? root.vPadding : 0 Layout.rightMargin: findLastEnabled() === this ? root.vPadding : 0
visible: enabled
active: enabled active: enabled
visible: enabled
} }
} }
+6 -4
View File
@@ -18,20 +18,20 @@ Item {
CustomRect { CustomRect {
anchors.fill: parent anchors.fill: parent
color: Config.barConfig.autoHide && !root.visibilities.bar ? "transparent" : DynamicColors.palette.m3surface color: Config.barConfig.autoHide && !root.visibilities.bar ? "transparent" : DynamicColors.palette.m3surface
layer.enabled: true layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {
maskSource: mask
maskEnabled: true maskEnabled: true
maskInverted: true maskInverted: true
maskThresholdMin: 0.5 maskSource: mask
maskSpreadAtMin: 1 maskSpreadAtMin: 1
maskThresholdMin: 0.5
} }
} }
Item { Item {
id: mask id: mask
anchors.fill: parent anchors.fill: parent
layer.enabled: true layer.enabled: true
visible: false visible: false
@@ -41,8 +41,10 @@ Item {
anchors.topMargin: Config.barConfig.autoHide && !root.visibilities.bar ? 4 : root.bar.implicitHeight anchors.topMargin: Config.barConfig.autoHide && !root.visibilities.bar ? 4 : root.bar.implicitHeight
topLeftRadius: 8 topLeftRadius: 8
topRightRadius: 8 topRightRadius: 8
Behavior on anchors.topMargin { Behavior on anchors.topMargin {
Anim {} Anim {
}
} }
} }
} }
+10 -13
View File
@@ -10,17 +10,17 @@ RowLayout {
spacing: 12 spacing: 12
Rectangle { Rectangle {
Layout.preferredWidth: 40
Layout.preferredHeight: 40 Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: "transparent" color: "transparent"
radius: 1000 radius: 1000
MaterialIcon { MaterialIcon {
anchors.centerIn: parent anchors.centerIn: parent
text: "arrow_back_2" color: DynamicColors.palette.m3onSurface
fill: 1 fill: 1
font.pointSize: 24 font.pointSize: 24
color: DynamicColors.palette.m3onSurface text: "arrow_back_2"
} }
StateLayer { StateLayer {
@@ -36,30 +36,27 @@ RowLayout {
} }
CustomText { CustomText {
text: new Date(Calendar.displayYear, Calendar.displayMonth, 1).toLocaleDateString(
Qt.locale(),
"MMMM yyyy"
)
font.weight: 600
font.pointSize: 14
color: DynamicColors.palette.m3onSurface
Layout.fillWidth: true Layout.fillWidth: true
color: DynamicColors.palette.m3onSurface
font.pointSize: 14
font.weight: 600
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: new Date(Calendar.displayYear, Calendar.displayMonth, 1).toLocaleDateString(Qt.locale(), "MMMM yyyy")
} }
Rectangle { Rectangle {
Layout.preferredWidth: 40
Layout.preferredHeight: 40 Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: "transparent" color: "transparent"
radius: 1000 radius: 1000
MaterialIcon { MaterialIcon {
anchors.centerIn: parent anchors.centerIn: parent
text: "arrow_back_2" color: DynamicColors.palette.m3onSurface
fill: 1 fill: 1
font.pointSize: 24 font.pointSize: 24
rotation: 180 rotation: 180
color: DynamicColors.palette.m3onSurface text: "arrow_back_2"
} }
StateLayer { StateLayer {
+6 -6
View File
@@ -11,8 +11,8 @@ Item {
required property Item wrapper required property Item wrapper
implicitWidth: layout.childrenRect.width + layout.anchors.margins * 2
implicitHeight: layout.childrenRect.height + layout.anchors.margins * 2 implicitHeight: layout.childrenRect.height + layout.anchors.margins * 2
implicitWidth: layout.childrenRect.width + layout.anchors.margins * 2
ColumnLayout { ColumnLayout {
id: layout id: layout
@@ -59,17 +59,17 @@ Item {
DayOfWeekRow { DayOfWeekRow {
id: dayOfWeekRow id: dayOfWeekRow
locale: Qt.locale()
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 30 Layout.preferredHeight: 30
locale: Qt.locale()
} }
MonthGrid { MonthGrid {
locale: Qt.locale()
wrapper: root.wrapper
Layout.preferredWidth: childrenRect.width
Layout.preferredHeight: childrenRect.height Layout.preferredHeight: childrenRect.height
Layout.preferredWidth: childrenRect.width
locale: Qt.locale()
wrapper: root.wrapper
} }
} }
} }
+9 -12
View File
@@ -17,29 +17,26 @@ RowLayout {
model: 7 model: 7
Item { Item {
required property int index
Layout.fillWidth: true
Layout.preferredHeight: 30
readonly property string dayName: { readonly property string dayName: {
// Get the day name for this column // Get the day name for this column
const dayIndex = (index + Calendar.weekStartDay) % 7; const dayIndex = (index + Calendar.weekStartDay) % 7;
return root.locale.dayName(dayIndex, Locale.ShortFormat); return root.locale.dayName(dayIndex, Locale.ShortFormat);
} }
required property int index
Layout.fillWidth: true
Layout.preferredHeight: 30
CustomText { CustomText {
anchors.centerIn: parent anchors.centerIn: parent
text: parent.dayName
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: DynamicColors.palette.m3onSurfaceVariant color: DynamicColors.palette.m3onSurfaceVariant
opacity: 0.8
font.weight: 500
font.pointSize: 11 font.pointSize: 11
font.weight: 500
horizontalAlignment: Text.AlignHCenter
opacity: 0.8
text: parent.dayName
verticalAlignment: Text.AlignVCenter
} }
} }
} }
} }
+37 -27
View File
@@ -13,48 +13,49 @@ GridLayout {
required property var locale required property var locale
required property Item wrapper required property Item wrapper
columnSpacing: 4
columns: 7 columns: 7
rowSpacing: 4 rowSpacing: 4
columnSpacing: 4
uniformCellWidths: true
uniformCellHeights: true uniformCellHeights: true
uniformCellWidths: true
component Anim: NumberAnimation {
target: root
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
}
Repeater { Repeater {
id: repeater id: repeater
model: ScriptModel { model: ScriptModel {
values: Calendar.getWeeksForMonth(Calendar.displayMonth, Calendar.displayYear) values: Calendar.getWeeksForMonth(Calendar.displayMonth, Calendar.displayYear)
Behavior on values { Behavior on values {
SequentialAnimation { SequentialAnimation {
id: switchAnim id: switchAnim
ParallelAnimation { ParallelAnimation {
Anim { Anim {
property: "opacity"
from: 1.0 from: 1.0
property: "opacity"
to: 0.0 to: 0.0
} }
Anim { Anim {
property: "scale"
from: 1.0 from: 1.0
property: "scale"
to: 0.8 to: 0.8
} }
} }
PropertyAction {}
PropertyAction {
}
ParallelAnimation { ParallelAnimation {
Anim { Anim {
property: "opacity"
from: 0.0 from: 0.0
property: "opacity"
to: 1.0 to: 1.0
} }
Anim { Anim {
property: "scale"
from: 0.8 from: 0.8
property: "scale"
to: 1.0 to: 1.0
} }
} }
@@ -63,15 +64,11 @@ GridLayout {
} }
Rectangle { Rectangle {
required property var modelData
required property int index required property int index
required property var modelData
Layout.preferredWidth: 40
Layout.preferredHeight: width Layout.preferredHeight: width
Layout.preferredWidth: 40
radius: 1000
color: { color: {
if (modelData.isToday) { if (modelData.isToday) {
console.log(width); console.log(width);
@@ -79,39 +76,52 @@ GridLayout {
} }
return "transparent"; return "transparent";
} }
radius: 1000
Behavior on color { Behavior on color {
ColorAnimation { duration: 200 } ColorAnimation {
duration: 200
}
} }
CustomText { CustomText {
anchors.centerIn: parent anchors.centerIn: parent
text: parent.modelData.day.toString()
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
opacity: parent.modelData.isCurrentMonth ? 1.0 : 0.4
color: { color: {
if (parent.modelData.isToday) { if (parent.modelData.isToday) {
return DynamicColors.palette.m3onPrimaryContainer; return DynamicColors.palette.m3onPrimaryContainer;
} }
return DynamicColors.palette.m3onSurface; return DynamicColors.palette.m3onSurface;
} }
horizontalAlignment: Text.AlignHCenter
opacity: parent.modelData.isCurrentMonth ? 1.0 : 0.4
text: parent.modelData.day.toString()
verticalAlignment: Text.AlignVCenter
Behavior on color { Behavior on color {
ColorAnimation { duration: 200 } ColorAnimation {
duration: 200
}
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: 200 } NumberAnimation {
duration: 200
}
} }
} }
StateLayer { StateLayer {
color: DynamicColors.palette.m3onSurface color: DynamicColors.palette.m3onSurface
onClicked: { onClicked: {
console.log(`Selected date: ${parent.modelData.day}/${parent.modelData.month + 1}/${parent.modelData.year}`); console.log(`Selected date: ${parent.modelData.day}/${parent.modelData.month + 1}/${parent.modelData.year}`);
} }
} }
} }
} }
component Anim: NumberAnimation {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
target: root
}
} }
+10 -10
View File
@@ -10,10 +10,10 @@ import qs.Helpers
ColumnLayout { ColumnLayout {
id: root id: root
spacing: 4
readonly property var weekNumbers: Calendar.getWeekNumbers(Calendar.displayMonth, Calendar.displayYear) readonly property var weekNumbers: Calendar.getWeekNumbers(Calendar.displayMonth, Calendar.displayYear)
spacing: 4
Repeater { Repeater {
model: ScriptModel { model: ScriptModel {
values: root.weekNumbers values: root.weekNumbers
@@ -21,24 +21,24 @@ ColumnLayout {
Item { Item {
id: weekItem id: weekItem
Layout.preferredHeight: 40
Layout.preferredWidth: 20
Layout.alignment: Qt.AlignHCenter
required property int index required property int index
required property var modelData required property var modelData
Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: 40
Layout.preferredWidth: 20
CustomText { CustomText {
id: weekText id: weekText
anchors.centerIn: parent anchors.centerIn: parent
text: weekItem.modelData
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: DynamicColors.palette.m3onSurfaceVariant color: DynamicColors.palette.m3onSurfaceVariant
opacity: 0.5
font.pointSize: 10 font.pointSize: 10
horizontalAlignment: Text.AlignHCenter
opacity: 0.5
text: weekItem.modelData
verticalAlignment: Text.AlignVCenter
} }
} }
} }
+13 -10
View File
@@ -8,35 +8,38 @@ import qs.Components
Item { Item {
id: root id: root
required property PersistentProperties visibilities
required property Wrapper popouts
required property RowLayout loader
implicitWidth: timeText.contentWidth + 5 * 2 required property RowLayout loader
anchors.top: parent.top required property Wrapper popouts
required property PersistentProperties visibilities
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.top: parent.top
implicitWidth: timeText.contentWidth + 5 * 2
CustomRect { CustomRect {
anchors.bottomMargin: 3
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 3 anchors.topMargin: 3
anchors.bottomMargin: 3
radius: 4
color: "transparent" color: "transparent"
radius: 4
CustomText { CustomText {
id: timeText id: timeText
anchors.centerIn: parent anchors.centerIn: parent
text: Time.dateStr
color: DynamicColors.palette.m3onSurface color: DynamicColors.palette.m3onSurface
text: Time.dateStr
Behavior on color { Behavior on color {
CAnim {} CAnim {
}
} }
} }
StateLayer { StateLayer {
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onClicked: { onClicked: {
root.visibilities.dashboard = !root.visibilities.dashboard; root.visibilities.dashboard = !root.visibilities.dashboard;
} }
+17 -14
View File
@@ -13,12 +13,12 @@ import qs.Modules.UPower
Item { Item {
id: root id: root
required property Item wrapper
readonly property Popout currentPopout: content.children.find(c => c.shouldBeActive) ?? null
readonly property Item current: currentPopout?.item ?? null readonly property Item current: currentPopout?.item ?? null
readonly property Popout currentPopout: content.children.find(c => c.shouldBeActive) ?? null
required property Item wrapper
implicitWidth: (currentPopout?.implicitWidth ?? 0) + 5 * 2
implicitHeight: (currentPopout?.implicitHeight ?? 0) + 5 * 2 implicitHeight: (currentPopout?.implicitHeight ?? 0) + 5 * 2
implicitWidth: (currentPopout?.implicitWidth ?? 0) + 5 * 2
Item { Item {
id: content id: content
@@ -27,6 +27,7 @@ Item {
Popout { Popout {
name: "audio" name: "audio"
sourceComponent: AudioPopup { sourceComponent: AudioPopup {
wrapper: root.wrapper wrapper: root.wrapper
} }
@@ -34,6 +35,7 @@ Item {
Popout { Popout {
name: "resources" name: "resources"
sourceComponent: ResourcePopout { sourceComponent: ResourcePopout {
wrapper: root.wrapper wrapper: root.wrapper
} }
@@ -47,21 +49,21 @@ Item {
Popout { Popout {
id: trayMenu id: trayMenu
required property SystemTrayItem modelData
required property int index required property int index
required property SystemTrayItem modelData
name: `traymenu${index}` name: `traymenu${index}`
sourceComponent: trayMenuComponent sourceComponent: trayMenuComponent
Connections { Connections {
target: root.wrapper
function onHasCurrentChanged(): void { function onHasCurrentChanged(): void {
if (root.wrapper.hasCurrent && trayMenu.shouldBeActive) { if (root.wrapper.hasCurrent && trayMenu.shouldBeActive) {
trayMenu.sourceComponent = null; trayMenu.sourceComponent = null;
trayMenu.sourceComponent = trayMenuComponent; trayMenu.sourceComponent = trayMenuComponent;
} }
} }
target: root.wrapper
} }
Component { Component {
@@ -77,6 +79,7 @@ Item {
Popout { Popout {
name: "calendar" name: "calendar"
sourceComponent: CalendarPopup { sourceComponent: CalendarPopup {
wrapper: root.wrapper wrapper: root.wrapper
} }
@@ -86,8 +89,8 @@ Item {
name: "overview" name: "overview"
sourceComponent: OverviewPopout { sourceComponent: OverviewPopout {
wrapper: root.wrapper
screen: root.wrapper.screen screen: root.wrapper.screen
wrapper: root.wrapper
} }
} }
@@ -114,13 +117,12 @@ Item {
required property string name required property string name
readonly property bool shouldBeActive: root.wrapper.currentName === name readonly property bool shouldBeActive: root.wrapper.currentName === name
active: false
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 5 anchors.topMargin: 5
anchors.horizontalCenter: parent.horizontalCenter
opacity: 0 opacity: 0
scale: 0.8 scale: 0.8
active: false
states: State { states: State {
name: "active" name: "active"
@@ -132,7 +134,6 @@ Item {
popout.scale: 1 popout.scale: 1
} }
} }
transitions: [ transitions: [
Transition { Transition {
from: "active" from: "active"
@@ -140,12 +141,13 @@ Item {
SequentialAnimation { SequentialAnimation {
Anim { Anim {
properties: "opacity,scale"
duration: MaterialEasing.expressiveEffectsTime duration: MaterialEasing.expressiveEffectsTime
properties: "opacity,scale"
} }
PropertyAction { PropertyAction {
target: popout
property: "active" property: "active"
target: popout
} }
} }
}, },
@@ -155,9 +157,10 @@ Item {
SequentialAnimation { SequentialAnimation {
PropertyAction { PropertyAction {
target: popout
property: "active" property: "active"
target: popout
} }
Anim { Anim {
properties: "opacity,scale" properties: "opacity,scale"
} }
+4 -4
View File
@@ -9,12 +9,12 @@ CustomRect {
required property PersistentProperties visibilities required property PersistentProperties visibilities
anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.topMargin: 6
anchors.bottomMargin: 6 anchors.bottomMargin: 6
implicitWidth: 40 anchors.top: parent.top
anchors.topMargin: 6
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
implicitWidth: 40
radius: 1000 radius: 1000
StateLayer { StateLayer {
@@ -25,7 +25,7 @@ CustomRect {
MaterialIcon { MaterialIcon {
anchors.centerIn: parent anchors.centerIn: parent
text: "widgets"
color: DynamicColors.palette.m3onSurface color: DynamicColors.palette.m3onSurface
text: "widgets"
} }
} }
+18 -17
View File
@@ -6,19 +6,24 @@ import QtQuick.Shapes
ShapePath { ShapePath {
id: root id: root
required property Wrapper wrapper
readonly property real rounding: 8
readonly property bool flatten: wrapper.height < rounding * 2 readonly property bool flatten: wrapper.height < rounding * 2
readonly property real rounding: 8
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
required property Wrapper wrapper
strokeWidth: -1
fillColor: DynamicColors.palette.m3surface fillColor: DynamicColors.palette.m3surface
strokeWidth: -1
Behavior on fillColor {
CAnim {
}
}
PathArc { PathArc {
relativeX: root.rounding
relativeY: root.roundingY
radiusX: root.rounding radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height) radiusY: Math.min(root.rounding, root.wrapper.height)
relativeX: root.rounding
relativeY: root.roundingY
} }
PathLine { PathLine {
@@ -27,11 +32,11 @@ ShapePath {
} }
PathArc { PathArc {
relativeX: root.rounding direction: PathArc.Counterclockwise
relativeY: root.roundingY
radiusX: root.rounding radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height) radiusY: Math.min(root.rounding, root.wrapper.height)
direction: PathArc.Counterclockwise relativeX: root.rounding
relativeY: root.roundingY
} }
PathLine { PathLine {
@@ -40,11 +45,11 @@ ShapePath {
} }
PathArc { PathArc {
relativeX: root.rounding direction: PathArc.Counterclockwise
relativeY: -root.roundingY
radiusX: root.rounding radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height) radiusY: Math.min(root.rounding, root.wrapper.height)
direction: PathArc.Counterclockwise relativeX: root.rounding
relativeY: -root.roundingY
} }
PathLine { PathLine {
@@ -53,13 +58,9 @@ ShapePath {
} }
PathArc { PathArc {
relativeX: root.rounding
relativeY: -root.roundingY
radiusX: root.rounding radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height) radiusY: Math.min(root.rounding, root.wrapper.height)
} relativeX: root.rounding
relativeY: -root.roundingY
Behavior on fillColor {
CAnim {}
} }
} }
+23 -25
View File
@@ -10,25 +10,37 @@ import qs.Components
Item { Item {
id: root id: root
required property PersistentProperties visibilities
required property PersistentProperties state
readonly property real nonAnimWidth: view.implicitWidth + viewWrapper.anchors.margins * 2
readonly property real nonAnimHeight: view.implicitHeight + viewWrapper.anchors.margins * 2 readonly property real nonAnimHeight: view.implicitHeight + viewWrapper.anchors.margins * 2
readonly property real nonAnimWidth: view.implicitWidth + viewWrapper.anchors.margins * 2
required property PersistentProperties state
required property PersistentProperties visibilities
implicitWidth: nonAnimWidth
implicitHeight: nonAnimHeight implicitHeight: nonAnimHeight
implicitWidth: nonAnimWidth
Behavior on implicitHeight {
Anim {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
}
}
Behavior on implicitWidth {
Anim {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
}
}
ClippingRectangle { ClippingRectangle {
id: viewWrapper id: viewWrapper
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: Appearance.padding.smaller anchors.margins: Appearance.padding.smaller
anchors.right: parent.right
radius: 6 anchors.top: parent.top
color: "transparent" color: "transparent"
radius: 6
Item { Item {
id: view id: view
@@ -37,15 +49,15 @@ Item {
readonly property Item currentItem: row.children[currentIndex] readonly property Item currentItem: row.children[currentIndex]
anchors.fill: parent anchors.fill: parent
implicitWidth: currentItem.implicitWidth
implicitHeight: currentItem.implicitHeight implicitHeight: currentItem.implicitHeight
implicitWidth: currentItem.implicitWidth
RowLayout { RowLayout {
id: row id: row
Pane { Pane {
index: 0 index: 0
sourceComponent: Dash { sourceComponent: Dash {
state: root.state state: root.state
visibilities: root.visibilities visibilities: root.visibilities
@@ -55,20 +67,6 @@ Item {
} }
} }
Behavior on implicitWidth {
Anim {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
}
}
Behavior on implicitHeight {
Anim {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
}
}
component Pane: Loader { component Pane: Loader {
id: pane id: pane
+24 -24
View File
@@ -11,16 +11,14 @@ import qs.Modules.Dashboard.Dash
GridLayout { GridLayout {
id: root id: root
required property PersistentProperties visibilities
required property PersistentProperties state
readonly property bool dashboardVisible: visibilities.dashboard readonly property bool dashboardVisible: visibilities.dashboard
property int radius: 6 property int radius: 6
required property PersistentProperties state
required property PersistentProperties visibilities
rowSpacing: Appearance.spacing.smaller
columnSpacing: Appearance.spacing.smaller columnSpacing: Appearance.spacing.smaller
opacity: 0 opacity: 0
rowSpacing: Appearance.spacing.smaller
scale: 0.9 scale: 0.9
onDashboardVisibleChanged: { onDashboardVisibleChanged: {
@@ -33,28 +31,32 @@ GridLayout {
ParallelAnimation { ParallelAnimation {
id: openAnim id: openAnim
Anim { Anim {
target: root
property: "opacity" property: "opacity"
target: root
to: 1 to: 1
} }
Anim { Anim {
target: root
property: "scale" property: "scale"
target: root
to: 1 to: 1
} }
} }
ParallelAnimation { ParallelAnimation {
id: closeAnim id: closeAnim
Anim { Anim {
target: root
property: "opacity" property: "opacity"
target: root
to: 0 to: 0
} }
Anim { Anim {
target: root
property: "scale" property: "scale"
target: root
to: 0.9 to: 0.9
} }
} }
@@ -62,9 +64,8 @@ GridLayout {
Rect { Rect {
Layout.column: 2 Layout.column: 2
Layout.columnSpan: 3 Layout.columnSpan: 3
Layout.preferredWidth: user.implicitWidth
Layout.preferredHeight: user.implicitHeight Layout.preferredHeight: user.implicitHeight
Layout.preferredWidth: user.implicitWidth
radius: root.radius radius: root.radius
User { User {
@@ -75,14 +76,14 @@ GridLayout {
} }
Rect { Rect {
Layout.row: 0
Layout.columnSpan: 2 Layout.columnSpan: 2
Layout.preferredWidth: Config.dashboard.sizes.weatherWidth
Layout.fillHeight: true Layout.fillHeight: true
Layout.preferredWidth: Config.dashboard.sizes.weatherWidth
Layout.row: 0
radius: root.radius radius: root.radius
Weather {} Weather {
}
} }
// Rect { // Rect {
@@ -98,12 +99,11 @@ GridLayout {
// } // }
Rect { Rect {
Layout.row: 1
Layout.column: 0 Layout.column: 0
Layout.columnSpan: 3 Layout.columnSpan: 3
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: calendar.implicitHeight Layout.preferredHeight: calendar.implicitHeight
Layout.row: 1
radius: root.radius radius: root.radius
Calendar { Calendar {
@@ -114,30 +114,30 @@ GridLayout {
} }
Rect { Rect {
Layout.row: 1
Layout.column: 3 Layout.column: 3
Layout.columnSpan: 2 Layout.columnSpan: 2
Layout.preferredWidth: resources.implicitWidth
Layout.fillHeight: true Layout.fillHeight: true
Layout.preferredWidth: resources.implicitWidth
Layout.row: 1
radius: root.radius radius: root.radius
Resources { Resources {
id: resources id: resources
} }
} }
Rect { Rect {
Layout.row: 0
Layout.column: 5 Layout.column: 5
Layout.rowSpan: 2
Layout.preferredWidth: media.implicitWidth
Layout.fillHeight: true Layout.fillHeight: true
Layout.preferredWidth: media.implicitWidth
Layout.row: 0
Layout.rowSpan: 2
radius: root.radius radius: root.radius
Media { Media {
id: media id: media
} }
} }
+63 -75
View File
@@ -11,17 +11,9 @@ import qs.Modules
CustomMouseArea { CustomMouseArea {
id: root id: root
required property var state
readonly property int currMonth: state.currentDate.getMonth() readonly property int currMonth: state.currentDate.getMonth()
readonly property int currYear: state.currentDate.getFullYear() readonly property int currYear: state.currentDate.getFullYear()
required property var state
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: inner.implicitHeight + inner.anchors.margins * 2
acceptedButtons: Qt.MiddleButton
onClicked: root.state.currentDate = new Date()
function onWheel(event: WheelEvent): void { function onWheel(event: WheelEvent): void {
if (event.angleDelta.y > 0) if (event.angleDelta.y > 0)
@@ -30,6 +22,13 @@ CustomMouseArea {
root.state.currentDate = new Date(root.currYear, root.currMonth + 1, 1); root.state.currentDate = new Date(root.currYear, root.currMonth + 1, 1);
} }
acceptedButtons: Qt.MiddleButton
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: inner.implicitHeight + inner.anchors.margins * 2
onClicked: root.state.currentDate = new Date()
ColumnLayout { ColumnLayout {
id: inner id: inner
@@ -44,87 +43,85 @@ CustomMouseArea {
spacing: Appearance.spacing.small spacing: Appearance.spacing.small
Item { Item {
implicitWidth: implicitHeight
implicitHeight: prevMonthText.implicitHeight + Appearance.padding.small * 2 implicitHeight: prevMonthText.implicitHeight + Appearance.padding.small * 2
implicitWidth: implicitHeight
StateLayer { StateLayer {
id: prevMonthStateLayer id: prevMonthStateLayer
radius: Appearance.rounding.full
function onClicked(): void { function onClicked(): void {
root.state.currentDate = new Date(root.currYear, root.currMonth - 1, 1); root.state.currentDate = new Date(root.currYear, root.currMonth - 1, 1);
} }
radius: Appearance.rounding.full
} }
MaterialIcon { MaterialIcon {
id: prevMonthText id: prevMonthText
anchors.centerIn: parent anchors.centerIn: parent
text: "chevron_left"
color: DynamicColors.palette.m3tertiary color: DynamicColors.palette.m3tertiary
font.pointSize: Appearance.font.size.normal font.pointSize: Appearance.font.size.normal
font.weight: 700 font.weight: 700
text: "chevron_left"
} }
} }
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
implicitWidth: monthYearDisplay.implicitWidth + Appearance.padding.small * 2
implicitHeight: monthYearDisplay.implicitHeight + Appearance.padding.small * 2 implicitHeight: monthYearDisplay.implicitHeight + Appearance.padding.small * 2
implicitWidth: monthYearDisplay.implicitWidth + Appearance.padding.small * 2
StateLayer { StateLayer {
anchors.fill: monthYearDisplay function onClicked(): void {
anchors.margins: -Appearance.padding.small root.state.currentDate = new Date();
anchors.leftMargin: -Appearance.padding.normal }
anchors.rightMargin: -Appearance.padding.normal
radius: Appearance.rounding.full anchors.fill: monthYearDisplay
anchors.leftMargin: -Appearance.padding.normal
anchors.margins: -Appearance.padding.small
anchors.rightMargin: -Appearance.padding.normal
disabled: { disabled: {
const now = new Date(); const now = new Date();
return root.currMonth === now.getMonth() && root.currYear === now.getFullYear(); return root.currMonth === now.getMonth() && root.currYear === now.getFullYear();
} }
radius: Appearance.rounding.full
function onClicked(): void {
root.state.currentDate = new Date();
}
} }
CustomText { CustomText {
id: monthYearDisplay id: monthYearDisplay
anchors.centerIn: parent anchors.centerIn: parent
text: grid.title
color: DynamicColors.palette.m3primary color: DynamicColors.palette.m3primary
font.capitalization: Font.Capitalize
font.pointSize: Appearance.font.size.normal font.pointSize: Appearance.font.size.normal
font.weight: 500 font.weight: 500
font.capitalization: Font.Capitalize text: grid.title
} }
} }
Item { Item {
implicitWidth: implicitHeight
implicitHeight: nextMonthText.implicitHeight + Appearance.padding.small * 2 implicitHeight: nextMonthText.implicitHeight + Appearance.padding.small * 2
implicitWidth: implicitHeight
StateLayer { StateLayer {
id: nextMonthStateLayer id: nextMonthStateLayer
radius: Appearance.rounding.full
function onClicked(): void { function onClicked(): void {
root.state.currentDate = new Date(root.currYear, root.currMonth + 1, 1); root.state.currentDate = new Date(root.currYear, root.currMonth + 1, 1);
} }
radius: Appearance.rounding.full
} }
MaterialIcon { MaterialIcon {
id: nextMonthText id: nextMonthText
anchors.centerIn: parent anchors.centerIn: parent
text: "chevron_right"
color: DynamicColors.palette.m3tertiary color: DynamicColors.palette.m3tertiary
font.pointSize: Appearance.font.size.normal font.pointSize: Appearance.font.size.normal
font.weight: 700 font.weight: 700
text: "chevron_right"
} }
} }
} }
@@ -138,10 +135,10 @@ CustomMouseArea {
delegate: CustomText { delegate: CustomText {
required property var model required property var model
color: (model.day === 0) ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3onSurfaceVariant
font.weight: 500
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: model.shortName text: model.shortName
font.weight: 500
color: (model.day === 0) ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3onSurfaceVariant
} }
} }
@@ -152,29 +149,24 @@ CustomMouseArea {
MonthGrid { MonthGrid {
id: grid id: grid
month: root.currMonth
year: root.currYear
anchors.fill: parent anchors.fill: parent
spacing: 3
locale: Qt.locale("en_SE") locale: Qt.locale("en_SE")
month: root.currMonth
spacing: 3
year: root.currYear
delegate: Item { delegate: Item {
id: dayItem id: dayItem
required property var model required property var model
implicitWidth: implicitHeight
implicitHeight: text.implicitHeight + Appearance.padding.small * 2 implicitHeight: text.implicitHeight + Appearance.padding.small * 2
implicitWidth: implicitHeight
CustomText { CustomText {
id: text id: text
anchors.centerIn: parent anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
text: grid.locale.toString(dayItem.model.day)
color: { color: {
const dayOfWeek = dayItem.model.date.getUTCDay(); const dayOfWeek = dayItem.model.date.getUTCDay();
if (dayOfWeek === 6) if (dayOfWeek === 6)
@@ -182,9 +174,11 @@ CustomMouseArea {
return DynamicColors.palette.m3onSurfaceVariant; return DynamicColors.palette.m3onSurfaceVariant;
} }
opacity: dayItem.model.today || dayItem.model.month === grid.month ? 1 : 0.4
font.pointSize: Appearance.font.size.normal font.pointSize: Appearance.font.size.normal
font.weight: 500 font.weight: 500
horizontalAlignment: Text.AlignHCenter
opacity: dayItem.model.today || dayItem.model.month === grid.month ? 1 : 0.4
text: grid.locale.toString(dayItem.model.day)
} }
} }
} }
@@ -192,60 +186,54 @@ CustomMouseArea {
CustomRect { CustomRect {
id: todayIndicator id: todayIndicator
readonly property Item todayItem: grid.contentItem.children.find(c => c.model.today) ?? null
property Item today property Item today
readonly property Item todayItem: grid.contentItem.children.find(c => c.model.today) ?? null
onTodayItemChanged: { clip: true
if (todayItem) color: DynamicColors.palette.m3primary
today = todayItem; implicitHeight: today?.implicitHeight ?? 0
} implicitWidth: today?.implicitWidth ?? 0
opacity: todayItem ? 1 : 0
radius: Appearance.rounding.full
scale: todayItem ? 1 : 0.7
x: today ? today.x + (today.width - implicitWidth) / 2 : 0 x: today ? today.x + (today.width - implicitWidth) / 2 : 0
y: today?.y ?? 0 y: today?.y ?? 0
implicitWidth: today?.implicitWidth ?? 0
implicitHeight: today?.implicitHeight ?? 0
clip: true
radius: Appearance.rounding.full
color: DynamicColors.palette.m3primary
opacity: todayItem ? 1 : 0
scale: todayItem ? 1 : 0.7
Coloriser {
x: -todayIndicator.x
y: -todayIndicator.y
implicitWidth: grid.width
implicitHeight: grid.height
source: grid
sourceColor: DynamicColors.palette.m3onSurface
colorizationColor: DynamicColors.palette.m3onPrimary
}
Behavior on opacity { Behavior on opacity {
Anim {} Anim {
}
} }
Behavior on scale { Behavior on scale {
Anim {} Anim {
}
} }
Behavior on x { Behavior on x {
Anim { Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
} }
Behavior on y { Behavior on y {
Anim { Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
} }
} }
onTodayItemChanged: {
if (todayItem)
today = todayItem;
}
Coloriser {
colorizationColor: DynamicColors.palette.m3onPrimary
implicitHeight: grid.height
implicitWidth: grid.width
source: grid
sourceColor: DynamicColors.palette.m3onSurface
x: -todayIndicator.x
y: -todayIndicator.y
}
} }
} }
} }

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