Merge branch 'end-4:main' into clean-testing

This commit is contained in:
jwihardi
2025-10-11 20:18:53 -04:00
committed by GitHub
34 changed files with 1369 additions and 233 deletions
+27
View File
@@ -119,6 +119,17 @@ bind = Super+Alt, code:16, exec, ~/.config/hypr/hyprland/scripts/workspace_actio
bind = Super+Alt, code:17, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 8 # [hidden]
bind = Super+Alt, code:18, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 9 # [hidden]
bind = Super+Alt, code:19, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 10 # [hidden]
# keypad numbers
bind = Super+Alt, code:87, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 1 # [hidden]
bind = Super+Alt, code:88, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 2 # [hidden]
bind = Super+Alt, code:89, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 3 # [hidden]
bind = Super+Alt, code:83, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 4 # [hidden]
bind = Super+Alt, code:84, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 5 # [hidden]
bind = Super+Alt, code:85, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 6 # [hidden]
bind = Super+Alt, code:79, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 7 # [hidden]
bind = Super+Alt, code:80, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 8 # [hidden]
bind = Super+Alt, code:81, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 9 # [hidden]
bind = Super+Alt, code:90, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh movetoworkspacesilent 10 # [hidden]
# #/# bind = Super+Shift, Scroll ↑/↓,, # Send to workspace left/right
bind = Super+Shift, mouse_down, movetoworkspace, r-1 # [hidden]
@@ -152,6 +163,17 @@ bind = Super, code:16, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh
bind = Super, code:17, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 8 # [hidden]
bind = Super, code:18, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 9 # [hidden]
bind = Super, code:19, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 10 # [hidden]
# keypad numbers
bindp = Super, code:87, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 1 # [hidden]
bindp = Super, code:88, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 2 # [hidden]
bindp = Super, code:89, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 3 # [hidden]
bindp = Super, code:83, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 4 # [hidden]
bindp = Super, code:84, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 5 # [hidden]
bindp = Super, code:85, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 6 # [hidden]
bindp = Super, code:79, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 7 # [hidden]
bindp = Super, code:80, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 8 # [hidden]
bindp = Super, code:81, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 9 # [hidden]
bindp = Super, code:90, exec, ~/.config/hypr/hyprland/scripts/workspace_action.sh workspace 10 # [hidden]
#/# bind = Ctrl+Super, ←/→,, # Focus left/right
bind = Ctrl+Super, Right, workspace, r+1 # [hidden]
@@ -201,6 +223,11 @@ binde = Super, Minus, exec, qs -c $qsConfig ipc call zoom zoomOut # Zoom out
binde = Super, Equal, exec, qs -c $qsConfig ipc call zoom zoomIn # Zoom in
binde = Super, Minus, exec, qs -c $qsConfig ipc call TEST_ALIVE || ~/.config/hypr/hyprland/scripts/zoom.sh decrease 0.1 # [hidden] Zoom out
binde = Super, Equal, exec, qs -c $qsConfig ipc call TEST_ALIVE || ~/.config/hypr/hyprland/scripts/zoom.sh increase 0.1 # [hidden] Zoom in
# Zoom with keypad
binde = Super, code:82, exec, qs -c $qsConfig ipc call zoom zoomOut # Zoom out
binde = Super, code:86, exec, qs -c $qsConfig ipc call zoom zoomIn # Zoom in
binde = Super, code:82, exec, qs -c $qsConfig ipc call TEST_ALIVE || ~/.config/hypr/hyprland/scripts/zoom.sh decrease 0.1 # [hidden] Zoom out
binde = Super, code:86, exec, qs -c $qsConfig ipc call TEST_ALIVE || ~/.config/hypr/hyprland/scripts/zoom.sh increase 0.1 # [hidden] Zoom in
##! Media
bindl= Super+Shift, N, exec, playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` # Next track
@@ -14,6 +14,8 @@ import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import "./cookieClock"
Variants {
id: root
readonly property bool fixedClockPosition: Config.options.background.clock.fixedPosition
@@ -22,6 +24,7 @@ Variants {
readonly property real clockSizePadding: 20
readonly property real screenSizePadding: 50
readonly property string clockStyle: Config.options.background.clock.style
readonly property bool showCookieQuote: Config.options.background.showQuote && Config.options.background.quote !== "" && !GlobalStates.screenLocked && Config.options.background.clock.style === "cookie"
model: Quickshell.screens
PanelWindow {
@@ -314,7 +317,7 @@ Variants {
}
StyledText {
// Somehow gets fucked up if made a ClockText???
visible: Config.options.background.quote.length > 0
visible: Config.options.background.showQuote && Config.options.background.quote.length > 0
Layout.fillWidth: true
horizontalAlignment: bgRoot.textHorizontalAlignment
font {
@@ -333,10 +336,19 @@ Variants {
Loader {
id: cookieClockLoader
visible: root.clockStyle === "cookie"
visible: root.clockStyle === "cookie"
active: visible
sourceComponent: CookieClock {}
}
Loader {
id: cookieQuoteLoader
visible: root.showCookieQuote
active: visible
sourceComponent: CookieQuote {}
anchors.horizontalCenter: cookieClockLoader.horizontalCenter
}
}
Item {
@@ -410,7 +422,7 @@ Variants {
}
}
// Components
// ComponentsCookieClock {}
component ClockText: StyledText {
Layout.fillWidth: true
horizontalAlignment: bgRoot.textHorizontalAlignment
@@ -1,142 +0,0 @@
pragma ComponentBehavior: Bound
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
import QtQuick.Layouts
import Quickshell
import Qt5Compat.GraphicalEffects
Item {
id: root
property real implicitSize: 230
property real hourHandLength: 72
property real hourHandWidth: 16
property real minuteHandLength: 95
property real minuteHandWidth: 8
property real centerDotSize: 10
property real hourDotSize: minuteHandWidth
property color colShadow: Appearance.colors.colShadow
property color colBackground: Appearance.colors.colSecondaryContainer
property color colOnBackground: ColorUtils.mix(Appearance.colors.colPrimary, Appearance.colors.colSecondaryContainer, 0.5)
property color colHourHand: Appearance.colors.colPrimary
property color colMinuteHand: Appearance.colors.colSecondary
property color colOnHourHand: Appearance.colors.colOnPrimary
readonly property list<string> clockNumbers: DateTime.time.split(/[: ]/)
readonly property int clockHour: parseInt(clockNumbers[0]) % 12
readonly property int clockMinute: parseInt(clockNumbers[1])
implicitWidth: implicitSize
implicitHeight: implicitSize
DropShadow {
source: cookie
anchors.fill: source
horizontalOffset: 0
verticalOffset: 2
radius: 12
samples: radius * 2 + 1
color: root.colShadow
transparentBorder: true
}
MaterialCookie {
id: cookie
z: 0
implicitSize: root.implicitSize
amplitude: implicitSize / 70
sides: 12
color: root.colBackground
// 12 dots around the cookie
Repeater {
model: 12
Item {
required property int index
rotation: 360 / 12 * index
anchors.fill: parent
Rectangle {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: 10
}
implicitWidth: root.hourDotSize
implicitHeight: implicitWidth
radius: implicitWidth / 2
color: root.colOnBackground
opacity: 0.5
}
}
}
}
Column {
id: timeIndicators
z: 1
anchors.centerIn: cookie
spacing: -16
// Numbers
Repeater {
model: root.clockNumbers
delegate: StyledText {
required property string modelData
anchors.horizontalCenter: parent?.horizontalCenter
font {
pixelSize: modelData.match(/am|pm/i) ? 26 : 68
family: Appearance.font.family.expressive
weight: Font.Bold
}
color: root.colOnBackground
text: modelData.padStart(2, "0")
}
}
}
// Hour hand
Item {
anchors.fill: parent
z: 2
rotation: -90 + (360 / 12) * (root.clockHour + root.clockMinute / 60)
Rectangle {
anchors.verticalCenter: parent.verticalCenter
x: parent.width / 2 - hourHandWidth / 2
width: hourHandLength
height: hourHandWidth
radius: hourHandWidth / 2
color: root.colHourHand
}
}
// Minute hand
Item {
anchors.fill: parent
z: 3
rotation: -90 + (360 / 60) * root.clockMinute
Rectangle {
anchors.verticalCenter: parent.verticalCenter
x: parent.width / 2 - minuteHandWidth / 2
width: minuteHandLength
height: minuteHandWidth
radius: minuteHandWidth / 2
color: root.colMinuteHand
}
}
// Center dot
Rectangle {
z: 4
color: root.colOnHourHand
anchors.centerIn: parent
implicitWidth: centerDotSize
implicitHeight: implicitWidth
radius: implicitWidth / 2
}
}
@@ -0,0 +1,155 @@
pragma ComponentBehavior: Bound
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import "./dateIndicator"
import "./minuteMarks"
Item {
id: root
readonly property string clockStyle: Config.options.background.clock.style
property real implicitSize: 230
property color colShadow: Appearance.colors.colShadow
property color colBackground: Appearance.colors.colSecondaryContainer
property color colOnBackground: ColorUtils.mix(Appearance.colors.colSecondary, Appearance.colors.colSecondaryContainer, 0.15)
property color colBackgroundInfo: ColorUtils.mix(Appearance.colors.colPrimary, Appearance.colors.colSecondaryContainer, 0.55)
property color colHourHand: Appearance.colors.colPrimary
property color colMinuteHand: Appearance.colors.colSecondary
property color colSecondHand: Appearance.colors.colTertiary
readonly property list<string> clockNumbers: DateTime.time.split(/[: ]/)
readonly property int clockHour: parseInt(clockNumbers[0]) % 12
readonly property int clockMinute: DateTime.clock.minutes
readonly property int clockSecond: DateTime.clock.seconds
implicitWidth: implicitSize
implicitHeight: implicitSize
DropShadow {
source: cookie
anchors.fill: source
horizontalOffset: 0
verticalOffset: 2
radius: 12
samples: radius * 2 + 1
color: root.colShadow
transparentBorder: true
}
MaterialCookie {
id: cookie
z: 0
implicitSize: root.implicitSize
amplitude: implicitSize / 70
sides: Config.options.background.clock.cookie.sides
color: root.colBackground
constantlyRotate: Config.options.background.clock.cookie.constantlyRotate
}
// Hour/minutes numbers/dots/lines
MinuteMarks {
anchors.fill: parent
color: root.colOnBackground
}
// Stupid extra hour marks in the middle
FadeLoader {
id: hourMarksLoader
anchors.centerIn: parent
shown: Config.options.background.clock.cookie.hourMarks
sourceComponent: HourMarks {
implicitSize: 135 * (1.75 - 0.75 * hourMarksLoader.opacity)
color: root.colOnBackground
colOnBackground: ColorUtils.mix(root.colBackgroundInfo, root.colOnBackground, 0.5)
}
}
// Number column in the middle
FadeLoader {
id: timeColumnLoader
anchors.centerIn: parent
shown: Config.options.background.clock.cookie.timeIndicators
scale: 1.4 - 0.4 * timeColumnLoader.shown
Behavior on scale {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
sourceComponent: TimeColumn {
color: root.colBackgroundInfo
}
}
// Hour hand
FadeLoader {
anchors.fill: parent
z: 1
shown: Config.options.background.clock.cookie.hourHandStyle !== "hide"
sourceComponent: HourHand {
clockHour: root.clockHour
clockMinute: root.clockMinute
style: Config.options.background.clock.cookie.hourHandStyle
color: root.colHourHand
}
}
// Minute hand
FadeLoader {
anchors.fill: parent
z: 2
shown: Config.options.background.clock.cookie.minuteHandStyle !== "hide"
sourceComponent: MinuteHand {
anchors.fill: parent
clockMinute: root.clockMinute
style: Config.options.background.clock.cookie.minuteHandStyle
color: root.colMinuteHand
}
}
// Second hand
FadeLoader {
id: secondHandLoader
z: (Config.options.background.clock.cookie.secondHandStyle === "line") ? 2 : 3
shown: Config.options.time.secondPrecision && Config.options.background.clock.cookie.secondHandStyle !== "hide"
anchors.fill: parent
sourceComponent: SecondHand {
id: secondHand
clockSecond: root.clockSecond
style: Config.options.background.clock.cookie.secondHandStyle
color: root.colSecondHand
}
}
// Center dot
FadeLoader {
z: 4
anchors.centerIn: parent
shown: Config.options.background.clock.cookie.minuteHandStyle !== "bold"
sourceComponent: Rectangle {
color: Config.options.background.clock.cookie.minuteHandStyle === "medium" ? root.colBackground : root.colMinuteHand
implicitWidth: 6
implicitHeight: implicitWidth
radius: width / 2
}
}
// Date
FadeLoader {
anchors.fill: parent
shown: Config.options.background.clock.cookie.dateStyle !== "hide"
sourceComponent: DateIndicator {
color: root.colBackgroundInfo
style: Config.options.background.clock.cookie.dateStyle
}
}
}
@@ -0,0 +1,62 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import Qt5Compat.GraphicalEffects
Item {
id: root
readonly property string quoteText: Config.options.background.quote
implicitWidth: quoteBox.implicitWidth
implicitHeight: quoteBox.implicitHeight
anchors.bottom: parent.bottom
anchors.bottomMargin: -24
DropShadow {
source: quoteBox
anchors.fill: quoteBox
horizontalOffset: 0
verticalOffset: 2
radius: 12
samples: radius * 2 + 1
color: Appearance.colors.colShadow
transparentBorder: true
}
Rectangle {
id: quoteBox
implicitWidth: quoteStyledText.width + quoteIcon.width + 16 // for spacing on both sides
implicitHeight: quoteStyledText.height + 8
radius: Appearance.rounding.small
color: Appearance.colors.colSecondaryContainer
Row {
anchors.centerIn: parent
spacing: 4
MaterialSymbol {
id: quoteIcon
anchors.top: parent.top
iconSize: Appearance.font.pixelSize.huge
text: "format_quote"
color: Appearance.colors.colOnSecondaryContainer
}
StyledText {
id: quoteStyledText
horizontalAlignment: Text.AlignLeft
text: Config.options.background.quote
color: Appearance.colors.colOnSecondaryContainer
font {
family: Appearance.font.family.reading
pixelSize: Appearance.font.pixelSize.large
weight: Font.Normal
}
}
}
}
}
@@ -0,0 +1,37 @@
pragma ComponentBehavior: Bound
import qs.modules.common
import QtQuick
Item {
id: root
required property int clockHour
required property int clockMinute
property real handLength: 72
property real handWidth: 18
property string style: "fill"
property color color: Appearance.colors.colPrimary
property real fillColorAlpha: root.style === "hollow" ? 0 : 1
Behavior on fillColorAlpha {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
rotation: -90 + (360 / 12) * (root.clockHour + root.clockMinute / 60)
Rectangle {
anchors.verticalCenter: parent.verticalCenter
x: (parent.width - root.handWidth) / 2 - 15 * (root.style === "classic")
width: root.handLength
height: root.style === "classic" ? 8 : root.handWidth
radius: root.style === "classic" ? 2 : root.handWidth / 2
color : Qt.rgba(root.color.r, root.color.g, root.color.b, root.fillColorAlpha)
border.color: root.color
border.width: 4
Behavior on x {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
}
}
@@ -0,0 +1,50 @@
pragma ComponentBehavior: Bound
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
Item {
id: root
property real implicitSize: 135
property real markLength: 12
property real markWidth: 4
property color color: Appearance.colors.colOnSecondaryContainer
property color colOnBackground: Appearance.colors.colSecondaryContainer
property real padding: 8
Rectangle {
color: root.color
anchors.centerIn: parent
implicitWidth: root.implicitSize
implicitHeight: root.implicitSize
radius: width / 2
// Hour mark lines
Repeater {
model: 12
Item {
required property int index
anchors.fill: parent
rotation: 360 / 12 * index
Rectangle {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: root.padding
}
implicitWidth: root.markLength
implicitHeight: root.markWidth
radius: width / 2
color: root.colOnBackground
}
}
}
}
}
@@ -0,0 +1,43 @@
pragma ComponentBehavior: Bound
import qs.modules.common
import QtQuick
Item {
id: root
anchors.fill: parent
required property int clockMinute
property string style: "medium"
property real handLength: 95
property real handWidth: style === "bold" ? 18 : style === "medium" ? 12 : 5
property color color: Appearance.colors.colSecondary
rotation: -90 + (360 / 60) * root.clockMinute
Behavior on rotation {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
Rectangle {
anchors.verticalCenter: parent.verticalCenter
x: {
let position = parent.width / 2 - root.handWidth / 2;
if (root.style === "classic") position -= 15;
return position;
}
width: root.handLength
height: root.handWidth
radius: root.style === "classic" ? 2 : root.handWidth / 2
color: Appearance.colors.colSecondary
Behavior on height {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
Behavior on x {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
}
}
@@ -0,0 +1,67 @@
pragma ComponentBehavior: Bound
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
Item {
id: root
anchors.fill: parent
required property int clockSecond
property real handWidth: 2
property real handLength: 100
property real dotSize: 20
property string style: "hide"
property color color: Appearance.colors.colSecondary
rotation: (360 / 60 * clockSecond) + 90
Behavior on rotation {
enabled: Config.options.background.clock.cookie.constantlyRotate // Animating every second is expensive...
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Rectangle {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: 10
}
implicitWidth: root.style === "dot" ? root.dotSize : root.handLength
implicitHeight: root.style === "dot" ? root.dotSize : root.handWidth
radius: Math.min(width, height) / 2
color: root.color
Behavior on implicitHeight {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
Behavior on implicitWidth {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
}
// Classic style dot in the middle of the hand
FadeLoader {
id: classicDotLoader
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
shown: root.style === "classic"
Rectangle {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: 40
}
implicitWidth: root.style === "classic" ? 14 : 0
implicitHeight: implicitWidth
color: root.color
radius: Appearance.rounding.small
Behavior on implicitWidth {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
}
}
}
@@ -0,0 +1,43 @@
pragma ComponentBehavior: Bound
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
Column {
id: root
property list<string> clockNumbers: DateTime.time.split(/[: ]/)
property bool isEnabled: Config.options.background.clock.cookie.timeIndicators
property color color: Appearance.colors.colOnSecondaryContainer
property bool hourMarksEnabled: Config.options.background.clock.cookie.hourMarks
spacing: -16
Repeater {
model: root.clockNumbers
delegate: StyledText {
required property string modelData
text: modelData.padStart(2, "0")
property bool isAmPm: !text.match(/\d{2}/i)
property real numberSizeWithoutGlow: isAmPm ? 26 : 68
property real numberSizeWithGlow: isAmPm ? 20 : 40
property real numberSize: root.hourMarksEnabled ? numberSizeWithGlow : numberSizeWithoutGlow
anchors.horizontalCenter: root.horizontalCenter
color: root.color
font {
family: Appearance.font.family.expressive
weight: Font.Bold
pixelSize: numberSize
}
Behavior on numberSize {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
}
}
}
@@ -0,0 +1,36 @@
pragma ComponentBehavior: Bound
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
Item {
property int bubbleIndex: 0
property real targetSize: 0
MaterialCookie {
z: 5
sides: bubbleIndex === 0 ? 4 : 1
anchors.centerIn: parent
color: bubbleIndex === 0.0 ? Appearance.colors.colTertiaryContainer : Appearance.colors.colPrimaryContainer
implicitSize: targetSize
constantlyRotate: Config.options.background.clock.cookie.constantlyRotate
}
StyledText {
z: 6
anchors.centerIn: parent
text: bubbleIndex === 0.0 ? DateTime.date.substring(5, 7) : DateTime.date.substring(8, 10)
color: bubbleIndex === 0.0 ? Appearance.colors.colTertiary : Appearance.colors.colPrimary
opacity: root.style === "bubble" ? 1.0 : 0
font {
family: Appearance.font.family.expressive
pixelSize: 30
weight: 1000
}
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
}
}
@@ -0,0 +1,78 @@
pragma ComponentBehavior: Bound
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
Item {
id: root
property string style: "bubble"
property color color: Appearance.colors.colOnSecondaryContainer
property real dateSquareSize: 64
// Rotating date
FadeLoader {
anchors.fill: parent
shown: Config.options.background.clock.cookie.dateStyle === "border"
sourceComponent: RotatingDate {
color: root.color
}
}
// Rectangle date (only today's number) in right side of the clock
FadeLoader {
id: rectLoader
shown: root.style === "rect"
anchors {
verticalCenter: parent.verticalCenter
right: parent.right
rightMargin: 40 - rectLoader.opacity * 30
}
sourceComponent: RectangleDate {
color: ColorUtils.mix(root.color, Appearance.colors.colSecondaryContainerHover, 0.5)
radius: Appearance.rounding.small
implicitWidth: 45 * rectLoader.opacity
implicitHeight: 30 * rectLoader.opacity
}
}
// Bubble style: day of month
FadeLoader {
id: dayBubbleLoader
shown: root.style === "bubble"
property real targetSize: root.dateSquareSize * opacity
anchors {
left: parent.left
top: parent.top
}
sourceComponent: BubbleDate {
implicitWidth: dayBubbleLoader.targetSize
implicitHeight: dayBubbleLoader.targetSize
bubbleIndex: 0
targetSize: dayBubbleLoader.targetSize
}
}
// Bubble style: month
FadeLoader {
id: monthBubbleLoader
shown: root.style === "bubble"
property real targetSize: root.dateSquareSize * opacity
anchors {
right: parent.right
bottom: parent.bottom
}
sourceComponent: BubbleDate {
implicitWidth: monthBubbleLoader.targetSize
implicitHeight: monthBubbleLoader.targetSize
bubbleIndex: 1
targetSize: monthBubbleLoader.targetSize
}
}
}
@@ -0,0 +1,22 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
Rectangle {
id: rect
readonly property string dialStyle: Config.options.background.clock.cookie.dialNumberStyle
StyledText {
anchors.centerIn: parent
color: Appearance.colors.colSecondaryHover
text: Qt.locale().toString(DateTime.clock.date, "dd")
font {
family: Appearance.font.family.expressive
pixelSize: 20
weight: 1000
}
}
}
@@ -0,0 +1,51 @@
pragma ComponentBehavior: Bound
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
Item {
id: root
property string style: Config.options.background.clock.cookie.dateStyle
property color color: Appearance.colors.colOnSecondaryContainer
property real angleStep: 12 * Math.PI / 180
property string dateText: Qt.locale().toString(DateTime.clock.date, "ddd dd")
readonly property int clockSecond: DateTime.clock.seconds
readonly property string dialStyle: Config.options.background.clock.cookie.dialNumberStyle
readonly property bool timeIndicators: Config.options.background.clock.cookie.timeIndicators
property real radius: style === "border" ? 90 : 0
Behavior on radius {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
rotation: {
if (!Config.options.time.secondPrecision) return 0
else return (360 / 60 * clockSecond) + 180 - (angleStep / Math.PI * 180 * dateText.length) / 2
}
Repeater {
model: root.dateText.length
delegate: Text {
required property int index
property real angle: index * root.angleStep - Math.PI / 2
x: root.width / 2 + root.radius * Math.cos(angle) - width / 2
y: root.height / 2 + root.radius * Math.sin(angle) - height / 2
rotation: angle * 180 / Math.PI + 90
color: root.color
font {
family: Appearance.font.family.title
pixelSize: 30
weight: Font.DemiBold
}
text: root.dateText.charAt(index)
}
}
}
@@ -0,0 +1,49 @@
pragma ComponentBehavior: Bound
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
Item {
id: root
property real numberSize: 80
property real margins: 10
property color color: Appearance.colors.colOnSecondaryContainer
property int hours: 12
property int numbers: 4
property int fontSize: 80
Repeater {
model: root.numbers
Item {
id: numberItem
required property int index
rotation: 360 / root.numbers * (index + 1)
anchors.fill: parent
Item {
implicitWidth: root.numberSize
implicitHeight: implicitWidth
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
topMargin: root.margins
}
StyledText {
color: root.color
anchors.centerIn: parent
text: root.hours / root.numbers * (numberItem.index + 1)
rotation: -numberItem.rotation
font {
family: Appearance.font.family.reading
pixelSize: root.fontSize
weight: Font.Black
}
}
}
}
}
}
@@ -0,0 +1,34 @@
pragma ComponentBehavior: Bound
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
Item {
id: root
property real implicitSize: 12
property real margins: 10
property color color: Appearance.colors.colOnSecondaryContainer
Repeater {
model: 12
Item {
required property int index
anchors.fill: parent // Ensures rotation works properly
rotation: 360 / 12 * index
Rectangle {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: root.margins
}
implicitWidth: root.implicitSize
implicitHeight: implicitWidth
radius: implicitWidth / 2
color: root.color
}
}
}
}
@@ -0,0 +1,66 @@
pragma ComponentBehavior: Bound
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
Item {
id: root
property real numberSize: 80
property real margins: 10
property color color: Appearance.colors.colOnSecondaryContainer
property real hourLineSize: 4
property real minuteLineSize: 2
property real hourLineLength: 18
property real minuteLineLength: 7
property int hours: 12
property int minutes: 60
// Full dial style hour lines
Repeater {
model: root.hours
Item {
required property int index
rotation: 360 / root.hours * index
anchors.fill: parent
Rectangle {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: root.margins
}
implicitWidth: root.hourLineLength
implicitHeight: root.hourLineSize
radius: implicitWidth / 2
color: root.color
}
}
}
// Minute lines
Repeater {
model: root.minutes
Item {
required property int index
rotation: 360 / root.minutes * index
anchors.fill: parent
Rectangle {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: root.margins
}
implicitWidth: root.minuteLineLength
implicitHeight: root.minuteLineSize
radius: implicitWidth / 2
color: root.color
}
}
}
}
@@ -0,0 +1,48 @@
pragma ComponentBehavior: Bound
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
Item {
id: root
property color color: Appearance.colors.colOnSecondaryContainer
property string style: Config.options.background.clock.cookie.dialNumberStyle // "dots", "numbers", "full", "hide"
property string dateStyle : Config.options.background.clock.cookie.dateStyle
// 12 Dots
FadeLoader {
id: dotsLoader
anchors.fill: parent
shown: root.style === "dots"
sourceComponent: Dots {
color: root.color
margins: 46 - dotsLoader.opacity * 34
}
}
// 3-6-9-12 hour numbers (pls don't realize you can have more than 4 numbers)
FadeLoader {
id: bigHourNumbersLoader
anchors.fill: parent
shown: root.style === "numbers"
sourceComponent: BigHourNumbers {
numberSize: 80
color: root.color
margins: 20 - 10 * bigHourNumbersLoader.opacity
}
}
// Lines
FadeLoader {
id: linesLoader
anchors.fill: parent
shown: root.style === "full"
sourceComponent: Lines {
color: root.color
margins: 46 - linesLoader.opacity * 34
}
}
}
@@ -101,7 +101,7 @@ Item {
StyledPopup {
id: overflowPopup
hoverTarget: trayOverflowButton
active: root.trayOverflowOpen
active: root.trayOverflowOpen && root.unpinnedItems.length > 0
popupBackgroundMargin: 300 // This should be plenty... makes sure tooltips don't get cutoff (easily)
GridLayout {
@@ -129,10 +129,24 @@ Singleton {
property bool show: true
property string style: "cookie" // Options: "cookie", "digital"
property real scale: 1
property JsonObject cookie: JsonObject {
property int sides: 14
property string dialNumberStyle: "full" // Options: "dots" , "numbers", "full" , "none"
property string hourHandStyle: "fill" // Options: "classic", "fill", "hollow", "hide"
property string minuteHandStyle: "medium" // Options "classic", "thin", "medium", "bold", "hide"
property string secondHandStyle: "dot" // Options: "dot", "line" , "hide"
property string dateStyle: "bubble" // Options: "border", "rect", "bubble" , "hide"
property bool timeIndicators: true
property bool hourMarks: true
property bool dateInClock: true
property bool constantlyRotate: false
}
}
property string wallpaperPath: ""
property string thumbnailPath: ""
property string quote: ""
property bool showQuote: false
property bool hideWhenFullscreen: true
property JsonObject parallax: JsonObject {
property bool vertical: false
@@ -315,6 +329,7 @@ Singleton {
property JsonObject prefix: JsonObject {
property bool showDefaultActionsWithoutPrefix: true
property string action: "/"
property string app: ">"
property string clipboard: ";"
property string emojis: ":"
property string math: "="
@@ -359,6 +374,7 @@ Singleton {
property int focus: 1500
property int longBreak: 900
}
property bool secondPrecision: false
}
property JsonObject wallpaperSelector: JsonObject {
@@ -257,4 +257,32 @@ Singleton {
}
return false;
}
/**
* Removes the given prefix from the string if present.
* @param { string } str
* @param { string } prefix
* @returns { string }
*/
function cleanPrefix(str, prefix) {
if (str.startsWith(prefix)) {
return str.slice(prefix.length);
}
return str;
}
/**
* Removes the first matching prefix from the string if present.
* @param { string } str
* @param { string[] } prefixes
* @returns { string }
*/
function cleanOnePrefix(str, prefixes) {
for (let i = 0; i < prefixes.length; ++i) {
if (str.startsWith(prefixes[i])) {
return str.slice(prefixes[i].length);
}
}
return str;
}
}
@@ -0,0 +1,16 @@
import QtQuick
import qs.modules.common
import qs.modules.common.widgets
Loader {
id: root
property bool shown: true
opacity: shown ? 1 : 0
visible: opacity > 0
active: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
}
@@ -1,20 +1,39 @@
import QtQuick
import QtQuick.Shapes
import Quickshell
import qs.modules.common
Item {
id: root
property int sides: 12
property real sides: 12
property int implicitSize: 100
property real amplitude: implicitSize / 50
property int renderPoints: 360
property color color: "#605790"
property alias strokeWidth: shapePath.strokeWidth
property bool constantlyRotate: false
implicitWidth: implicitSize
implicitHeight: implicitSize
property real shapeRotation: 0
Loader {
active: constantlyRotate
sourceComponent: FrameAnimation {
running: true
onTriggered: {
shapeRotation += 0.05
}
}
}
Behavior on sides {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Shape {
id: shape
anchors.fill: parent
@@ -35,7 +54,8 @@ Item {
var radius = root.implicitSize / 2 - root.amplitude
for (var i = 0; i <= steps; i++) {
var angle = (i / steps) * 2 * Math.PI
var wave = Math.sin(angle * root.sides + Math.PI/2) * root.amplitude
var rotatedAngle = angle * root.sides + Math.PI/2 + (root.shapeRotation * root.constantlyRotate)
var wave = Math.sin(rotatedAngle) * root.amplitude
var x = Math.cos(angle) * (radius + wave) + cx
var y = Math.sin(angle) * (radius + wave) + cy
points.push(Qt.point(x, y))
@@ -45,6 +65,7 @@ Item {
path: pointsList
}
}
}
}
@@ -23,7 +23,7 @@ GroupButton {
colBackgroundActive: Appearance.colors.colSecondaryContainerActive
contentItem: RowLayout {
spacing: 4
spacing: 4 * (root.buttonText?.length > 0)
Loader {
Layout.alignment: Qt.AlignVCenter
@@ -42,7 +42,7 @@ GroupButton {
}
Item {
implicitWidth: textItem.implicitWidth
implicitWidth: root.buttonText?.length > 0 ? textItem.implicitWidth : 0
implicitHeight: textMetrics.height // Force height to that of regular text
TextMetrics {
@@ -21,9 +21,7 @@ Scope {
readonly property real osdWidth: Appearance.sizes.osdWidth
readonly property real widgetWidth: Appearance.sizes.mediaControlsWidth
readonly property real widgetHeight: Appearance.sizes.mediaControlsHeight
property real contentPadding: 13
property real popupRounding: Appearance.rounding.screenRounding - Appearance.sizes.elevationMargin + 1
property real artRounding: Appearance.rounding.verysmall
property list<real> visualizerPoints: []
property bool hasPlasmaIntegration: false
@@ -13,11 +13,11 @@ import Quickshell.Io
import Quickshell.Services.Mpris
Item { // Player instance
id: playerController
id: root
required property MprisPlayer player
property var artUrl: player?.trackArtUrl
property string artDownloadLocation: Directories.coverArt
property string artFileName: Qt.md5(artUrl) + ".jpg"
property string artFileName: Qt.md5(artUrl)
property string artFilePath: `${artDownloadLocation}/${artFileName}`
property color artDominantColor: ColorUtils.mix((colorQuantizer?.colors[0] ?? Appearance.colors.colPrimary), Appearance.colors.colPrimaryContainer, 0.8) || Appearance.m3colors.m3secondaryContainer
property bool downloaded: false
@@ -26,6 +26,8 @@ Item { // Player instance
property int visualizerSmoothing: 2 // Number of points to average for smoothing
property real radius
property string displayedArtFilePath: root.downloaded ? Qt.resolvedUrl(artFilePath) : ""
component TrackChangeButton: RippleButton {
implicitWidth: 24
implicitHeight: 24
@@ -49,37 +51,41 @@ Item { // Player instance
}
Timer { // Force update for revision
running: playerController.player?.playbackState == MprisPlaybackState.Playing
running: root.player?.playbackState == MprisPlaybackState.Playing
interval: Config.options.resources.updateInterval
repeat: true
onTriggered: {
playerController.player.positionChanged()
root.player.positionChanged()
}
}
onArtUrlChanged: {
if (playerController.artUrl.length == 0) {
playerController.artDominantColor = Appearance.m3colors.m3secondaryContainer
onArtFilePathChanged: {
if (root.artUrl.length == 0) {
root.artDominantColor = Appearance.m3colors.m3secondaryContainer
return;
}
// console.log("PlayerControl: Art URL changed to", playerController.artUrl)
// console.log("Download cmd:", coverArtDownloader.command.join(" "))
playerController.downloaded = false
// Binding does not work in Process
coverArtDownloader.targetFile = root.artUrl
coverArtDownloader.artFilePath = root.artFilePath
// Download
root.downloaded = false
coverArtDownloader.running = true
}
Process { // Cover art downloader
id: coverArtDownloader
property string targetFile: playerController.artUrl
property string targetFile: root.artUrl
property string artFilePath: root.artFilePath
command: [ "bash", "-c", `[ -f ${artFilePath} ] || curl -sSL '${targetFile}' -o '${artFilePath}'` ]
onExited: (exitCode, exitStatus) => {
playerController.downloaded = true
root.downloaded = true
}
}
ColorQuantizer {
id: colorQuantizer
source: playerController.downloaded ? Qt.resolvedUrl(artFilePath) : ""
source: root.displayedArtFilePath
depth: 0 // 2^0 = 1 color
rescaleSize: 1 // Rescale to 1x1 pixel for faster processing
}
@@ -96,7 +102,7 @@ Item { // Player instance
anchors.fill: parent
anchors.margins: Appearance.sizes.elevationMargin
color: blendedColors.colLayer0
radius: playerController.radius
radius: root.radius
layer.enabled: true
layer.effect: OpacityMask {
@@ -110,7 +116,7 @@ Item { // Player instance
Image {
id: blurredArt
anchors.fill: parent
source: playerController.downloaded ? Qt.resolvedUrl(artFilePath) : ""
source: root.displayedArtFilePath
sourceSize.width: background.width
sourceSize.height: background.height
fillMode: Image.PreserveAspectCrop
@@ -126,30 +132,30 @@ Item { // Player instance
Rectangle {
anchors.fill: parent
color: ColorUtils.transparentize(blendedColors.colLayer0, 0.3)
radius: playerController.radius
radius: root.radius
}
}
WaveVisualizer {
id: visualizerCanvas
anchors.fill: parent
live: playerController.player?.isPlaying
points: playerController.visualizerPoints
maxVisualizerValue: playerController.maxVisualizerValue
smoothing: playerController.visualizerSmoothing
live: root.player?.isPlaying
points: root.visualizerPoints
maxVisualizerValue: root.maxVisualizerValue
smoothing: root.visualizerSmoothing
color: blendedColors.colPrimary
}
RowLayout {
anchors.fill: parent
anchors.margins: root.contentPadding
anchors.margins: 13
spacing: 15
Rectangle { // Art background
id: artBackground
Layout.fillHeight: true
implicitWidth: height
radius: root.artRounding
radius: Appearance.rounding.verysmall
color: ColorUtils.transparentize(blendedColors.colLayer1, 0.5)
layer.enabled: true
@@ -166,7 +172,7 @@ Item { // Player instance
property int size: parent.height
anchors.fill: parent
source: playerController.downloaded ? Qt.resolvedUrl(artFilePath) : ""
source: root.displayedArtFilePath
fillMode: Image.PreserveAspectCrop
cache: false
antialiasing: true
@@ -188,7 +194,7 @@ Item { // Player instance
font.pixelSize: Appearance.font.pixelSize.large
color: blendedColors.colOnLayer0
elide: Text.ElideRight
text: StringUtils.cleanMusicTitle(playerController.player?.trackTitle) || "Untitled"
text: StringUtils.cleanMusicTitle(root.player?.trackTitle) || "Untitled"
animateChange: true
animationDistanceX: 6
animationDistanceY: 0
@@ -199,7 +205,7 @@ Item { // Player instance
font.pixelSize: Appearance.font.pixelSize.smaller
color: blendedColors.colSubtext
elide: Text.ElideRight
text: playerController.player?.trackArtist
text: root.player?.trackArtist
animateChange: true
animationDistanceX: 6
animationDistanceY: 0
@@ -217,7 +223,7 @@ Item { // Player instance
font.pixelSize: Appearance.font.pixelSize.small
color: blendedColors.colSubtext
elide: Text.ElideRight
text: `${StringUtils.friendlyTimeForSeconds(playerController.player?.position)} / ${StringUtils.friendlyTimeForSeconds(playerController.player?.length)}`
text: `${StringUtils.friendlyTimeForSeconds(root.player?.position)} / ${StringUtils.friendlyTimeForSeconds(root.player?.length)}`
}
RowLayout {
id: sliderRow
@@ -228,7 +234,7 @@ Item { // Player instance
}
TrackChangeButton {
iconName: "skip_previous"
onClicked: playerController.player?.previous()
onClicked: root.player?.previous()
}
Item {
id: progressBarContainer
@@ -238,15 +244,15 @@ Item { // Player instance
Loader {
id: sliderLoader
anchors.fill: parent
active: playerController.player?.canSeek ?? false
active: root.player?.canSeek ?? false
sourceComponent: StyledSlider {
configuration: StyledSlider.Configuration.Wavy
highlightColor: blendedColors.colPrimary
trackColor: blendedColors.colSecondaryContainer
handleColor: blendedColors.colPrimary
value: playerController.player?.position / playerController.player?.length
value: root.player?.position / root.player?.length
onMoved: {
playerController.player.position = value * playerController.player.length;
root.player.position = value * root.player.length;
}
}
}
@@ -258,12 +264,12 @@ Item { // Player instance
left: parent.left
right: parent.right
}
active: !(playerController.player?.canSeek ?? false)
active: !(root.player?.canSeek ?? false)
sourceComponent: StyledProgressBar {
wavy: playerController.player?.isPlaying
wavy: root.player?.isPlaying
highlightColor: blendedColors.colPrimary
trackColor: blendedColors.colSecondaryContainer
value: playerController.player?.position / playerController.player?.length
value: root.player?.position / root.player?.length
}
}
@@ -271,7 +277,7 @@ Item { // Player instance
}
TrackChangeButton {
iconName: "skip_next"
onClicked: playerController.player?.next()
onClicked: root.player?.next()
}
}
@@ -283,19 +289,19 @@ Item { // Player instance
property real size: 44
implicitWidth: size
implicitHeight: size
onClicked: playerController.player.togglePlaying();
onClicked: root.player.togglePlaying();
buttonRadius: playerController.player?.isPlaying ? Appearance?.rounding.normal : size / 2
colBackground: playerController.player?.isPlaying ? blendedColors.colPrimary : blendedColors.colSecondaryContainer
colBackgroundHover: playerController.player?.isPlaying ? blendedColors.colPrimaryHover : blendedColors.colSecondaryContainerHover
colRipple: playerController.player?.isPlaying ? blendedColors.colPrimaryActive : blendedColors.colSecondaryContainerActive
buttonRadius: root.player?.isPlaying ? Appearance?.rounding.normal : size / 2
colBackground: root.player?.isPlaying ? blendedColors.colPrimary : blendedColors.colSecondaryContainer
colBackgroundHover: root.player?.isPlaying ? blendedColors.colPrimaryHover : blendedColors.colSecondaryContainerHover
colRipple: root.player?.isPlaying ? blendedColors.colPrimaryActive : blendedColors.colSecondaryContainerActive
contentItem: MaterialSymbol {
iconSize: Appearance.font.pixelSize.huge
fill: 1
horizontalAlignment: Text.AlignHCenter
color: playerController.player?.isPlaying ? blendedColors.colOnPrimary : blendedColors.colOnSecondaryContainer
text: playerController.player?.isPlaying ? "pause" : "play_arrow"
color: root.player?.isPlaying ? blendedColors.colOnPrimary : blendedColors.colOnSecondaryContainer
text: root.player?.isPlaying ? "pause" : "play_arrow"
Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
@@ -327,7 +327,7 @@ Item { // Wrapper
///////////// Special cases ///////////////
if (root.searchingText.startsWith(Config.options.search.prefix.clipboard)) {
// Clipboard
const searchString = root.searchingText.slice(Config.options.search.prefix.clipboard.length);
const searchString = StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.clipboard);
return Cliphist.fuzzyQuery(searchString).map((entry, index, array) => {
const mightBlurImage = Cliphist.entryIsImage(entry) && root.clipboardWorkSafetyActive;
let shouldBlurImage = mightBlurImage;
@@ -365,7 +365,7 @@ Item { // Wrapper
}
else if (root.searchingText.startsWith(Config.options.search.prefix.emojis)) {
// Clipboard
const searchString = root.searchingText.slice(Config.options.search.prefix.emojis.length);
const searchString = StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.emojis);
return Emojis.fuzzyQuery(searchString).map(entry => {
return {
cliphistRawString: entry,
@@ -392,14 +392,20 @@ Item { // Wrapper
Quickshell.clipboardText = root.mathResult;
}
};
const appResultObjects = AppSearch.fuzzyQuery(StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.app)).map(entry => {
entry.clickActionName = Translation.tr("Launch");
entry.type = Translation.tr("App");
return entry;
})
const commandResultObject = {
name: searchingText.replace("file://", ""),
name: StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.shellCommand).replace("file://", ""),
clickActionName: Translation.tr("Run"),
type: Translation.tr("Run command"),
fontType: "monospace",
materialSymbol: 'terminal',
execute: () => {
let cleanedCommand = root.searchingText.replace("file://", "");
cleanedCommand = StringUtils.cleanPrefix(cleanedCommand, Config.options.search.prefix.shellCommand);
if (cleanedCommand.startsWith(Config.options.search.prefix.shellCommand)) {
cleanedCommand = cleanedCommand.slice(Config.options.search.prefix.shellCommand.length);
}
@@ -407,15 +413,12 @@ Item { // Wrapper
}
};
const webSearchResultObject = {
name: root.searchingText,
name: StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.webSearch),
clickActionName: Translation.tr("Search"),
type: Translation.tr("Search the web"),
materialSymbol: 'travel_explore',
execute: () => {
let query = root.searchingText;
if (query.startsWith(Config.options.search.prefix.webSearch)) {
query = query.slice(Config.options.search.prefix.webSearch.length);
}
let query = StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.webSearch);
let url = Config.options.search.engineBaseUrl + query;
for (let site of Config.options.search.excludedSites) {
url += ` -site:${site}`;
@@ -454,11 +457,7 @@ Item { // Wrapper
}
//////////////// Apps //////////////////
result = result.concat(AppSearch.fuzzyQuery(root.searchingText).map(entry => {
entry.clickActionName = Translation.tr("Launch");
entry.type = Translation.tr("App");
return entry;
}));
result = result.concat(appResultObjects);
////////// Launcher actions ////////////
result = result.concat(launcherActionObjects);
@@ -480,7 +479,15 @@ Item { // Wrapper
anchors.left: parent?.left
anchors.right: parent?.right
entry: modelData
query: root.searchingText.startsWith(Config.options.search.prefix.clipboard) ? root.searchingText.slice(Config.options.search.prefix.clipboard.length) : root.searchingText
query: StringUtils.cleanOnePrefix(root.searchingText, [
Config.options.search.prefix.action,
Config.options.search.prefix.app,
Config.options.search.prefix.clipboard,
Config.options.search.prefix.emojis,
Config.options.search.prefix.math,
Config.options.search.prefix.shellCommand,
Config.options.search.prefix.webSearch
])
}
}
}
@@ -62,7 +62,12 @@ Scope {
Loader {
id: sidebarCornerOpenInteractionLoader
active: (!cornerPanelWindow.fullscreen && Config.options.sidebar.cornerOpen.enable && (Config.options.sidebar.cornerOpen.bottom == cornerWidget.isBottom))
active: {
if (!Config.options.sidebar.cornerOpen.enable) return false;
if (!Config.options.bar.vertical && Config.options.sidebar.cornerOpen.bottom == Config.options.bar.bottom) return false;
if (cornerPanelWindow.fullscreen) return false;
return (Config.options.sidebar.cornerOpen.bottom == cornerWidget.isBottom);
}
anchors {
top: (cornerWidget.isTopLeft || cornerWidget.isTopRight) ? parent.top : undefined
bottom: (cornerWidget.isBottomLeft || cornerWidget.isBottomRight) ? parent.bottom : undefined
@@ -210,6 +210,18 @@ ContentPage {
icon: "nest_clock_farsight_analog"
title: Translation.tr("Time")
ConfigSwitch {
buttonIcon: "pace"
text: Translation.tr("Second precision")
checked: Config.options.time.secondPrecision
onCheckedChanged: {
Config.options.time.secondPrecision = checked;
}
StyledToolTip {
text: Translation.tr("Enable if you want clocks to show seconds accurately")
}
}
ContentSubsection {
title: Translation.tr("Format")
tooltip: ""
@@ -20,6 +20,7 @@ ContentPage {
Config.options.background.clock.show = checked;
}
}
ConfigSpinBox {
icon: "loupe"
@@ -50,11 +51,277 @@ ContentPage {
displayName: Translation.tr("Material cookie"),
icon: "cookie",
value: "cookie"
}
]
}
}
ContentSubsection {
visible: Config.options.background.clock.style === "cookie"
title: Translation.tr("Cookie clock settings")
ConfigSpinBox {
visible: Config.options.background.clock.style === "cookie"
icon: "add_triangle"
text: Translation.tr("Sides")
value: Config.options.background.clock.cookie.sides
from: 1
to: 36
stepSize: 1
onValueChanged: {
Config.options.background.clock.cookie.sides = value;
}
}
ConfigSwitch {
visible: Config.options.background.clock.style === "cookie"
buttonIcon: "autoplay"
text: Translation.tr("Constantly rotate")
checked: Config.options.background.clock.cookie.constantlyRotate
onCheckedChanged: {
Config.options.background.clock.cookie.constantlyRotate = checked;
}
StyledToolTip {
text: "Makes the clock always rotate. This is extremely expensive\n(expect 50% usage on Intel UHD Graphics) and thus impractical."
}
}
ConfigRow {
visible: Config.options.background.clock.style === "cookie"
ConfigSwitch {
enabled: Config.options.background.clock.style === "cookie" && Config.options.background.clock.cookie.dialNumberStyle === "dots" || Config.options.background.clock.cookie.dialNumberStyle === "full"
buttonIcon: "brightness_7"
text: Translation.tr("Hour marks")
checked: Config.options.background.clock.cookie.hourMarks
onEnabledChanged: {
checked = Config.options.background.clock.cookie.hourMarks;
}
onCheckedChanged: {
Config.options.background.clock.cookie.hourMarks = checked;
}
StyledToolTip {
text: "Can only be turned on using the 'Dots' or 'Full' dial style for aesthetic reasons"
}
}
ConfigSwitch {
enabled: Config.options.background.clock.style === "cookie" && Config.options.background.clock.cookie.dialNumberStyle !== "numbers"
buttonIcon: "timer_10"
text: Translation.tr("Digits in the middle")
checked: Config.options.background.clock.cookie.timeIndicators
onEnabledChanged: {
checked = Config.options.background.clock.cookie.timeIndicators;
}
onCheckedChanged: {
Config.options.background.clock.cookie.timeIndicators = checked;
}
StyledToolTip {
text: "Can't be turned on when using 'Numbers' dial style for aesthetic reasons"
}
}
}
}
ContentSubsection {
visible: Config.options.background.clock.style === "cookie"
title: Translation.tr("Dial style")
ConfigSelectionArray {
currentValue: Config.options.background.clock.cookie.dialNumberStyle
onSelected: newValue => {
Config.options.background.clock.cookie.dialNumberStyle = newValue;
if (newValue !== "dots" && newValue !== "full") {
Config.options.background.clock.cookie.hourMarks = false;
}
if (newValue === "numbers") {
Config.options.background.clock.cookie.timeIndicators = false;
}
}
options: [
{
displayName: "",
icon: "block",
value: "none"
},
{
displayName: Translation.tr("Dots"),
icon: "graph_6",
value: "dots"
},
{
displayName: Translation.tr("Full"),
icon: "history_toggle_off",
value: "full"
},
{
displayName: Translation.tr("Numbers"),
icon: "counter_1",
value: "numbers"
}
]
}
}
ContentSubsection {
visible: Config.options.background.clock.style === "cookie"
title: Translation.tr("Hour hand")
ConfigSelectionArray {
currentValue: Config.options.background.clock.cookie.hourHandStyle
onSelected: newValue => {
Config.options.background.clock.cookie.hourHandStyle = newValue;
}
options: [
{
displayName: "",
icon: "block",
value: "hide"
},
{
displayName: Translation.tr("Classic"),
icon: "radio",
value: "classic"
},
{
displayName: Translation.tr("Hollow"),
icon: "circle",
value: "hollow"
},
{
displayName: Translation.tr("Fill"),
icon: "eraser_size_5",
value: "fill"
},
]
}
}
ContentSubsection {
visible: Config.options.background.clock.style === "cookie"
title: Translation.tr("Minute hand")
ConfigSelectionArray {
currentValue: Config.options.background.clock.cookie.minuteHandStyle
onSelected: newValue => {
Config.options.background.clock.cookie.minuteHandStyle = newValue;
}
options: [
{
displayName: "",
icon: "block",
value: "hide"
},
{
displayName: Translation.tr("Classic"),
icon: "radio",
value: "classic"
},
{
displayName: Translation.tr("Thin"),
icon: "line_end",
value: "thin"
},
{
displayName: Translation.tr("Medium"),
icon: "eraser_size_2",
value: "medium"
},
{
displayName: Translation.tr("Bold"),
icon: "eraser_size_4",
value: "bold"
},
]
}
}
ContentSubsection {
visible: Config.options.background.clock.style === "cookie"
title: Translation.tr("Second hand")
ConfigSelectionArray {
currentValue: Config.options.background.clock.cookie.secondHandStyle
onSelected: newValue => {
Config.options.background.clock.cookie.secondHandStyle = newValue;
}
options: [
{
displayName: "",
icon: "block",
value: "hide"
},
{
displayName: Translation.tr("Classic"),
icon: "radio",
value: "classic"
},
{
displayName: Translation.tr("Line"),
icon: "line_end",
value: "line"
},
{
displayName: Translation.tr("Dot"),
icon: "adjust",
value: "dot"
},
]
}
}
ContentSubsection {
visible: Config.options.background.clock.style === "cookie"
title: Translation.tr("Date style")
ConfigSelectionArray {
currentValue: Config.options.background.clock.cookie.dateStyle
onSelected: newValue => {
Config.options.background.clock.cookie.dateStyle = newValue;
}
options: [
{
displayName: "",
icon: "block",
value: "hide"
},
{
displayName: Translation.tr("Bubble"),
icon: "bubble_chart",
value: "bubble"
},
{
displayName: Translation.tr("Border"),
icon: "rotate_right",
value: "border"
},
{
displayName: Translation.tr("Rect"),
icon: "rectangle",
value: "rect"
}
]
}
}
ContentSubsection {
title: Translation.tr("Quote settings")
ConfigSwitch {
buttonIcon: "format_quote"
text: Translation.tr("Show quote")
checked: Config.options.background.showQuote
onCheckedChanged: {
Config.options.background.showQuote = checked;
}
}
MaterialTextArea {
Layout.fillWidth: true
placeholderText: Translation.tr("Quote")
text: Config.options.background.quote
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.background.quote = text;
}
}
}
ContentSubsection {
title: Translation.tr("Wallpaper parallax")
@@ -121,7 +388,9 @@ ContentPage {
font.pixelSize: Appearance.font.pixelSize.smallie
text: Translation.tr("Press Super+G to toggle appearance")
}
Item { Layout.fillWidth: true }
Item {
Layout.fillWidth: true
}
RippleButtonWithIcon {
id: editorButton
buttonRadius: Appearance.rounding.full
@@ -231,7 +500,7 @@ ContentPage {
Config.options.lock.centerClock = checked;
}
}
ConfigSwitch {
buttonIcon: "info"
text: Translation.tr('Show "Locked" text')
@@ -264,8 +533,6 @@ ContentPage {
Config.options.lock.blur.extraZoom = value / 100;
}
}
}
}
@@ -473,5 +740,4 @@ ContentPage {
}
}
}
}
+4 -3
View File
@@ -14,6 +14,7 @@ Singleton {
property bool ready: Pipewire.defaultAudioSink?.ready ?? false
property PwNode sink: Pipewire.defaultAudioSink
property PwNode source: Pipewire.defaultAudioSource
readonly property real hardMaxValue: 2.00 // People keep joking about setting volume to 5172% so...
signal sinkProtectionTriggered(string reason);
@@ -38,9 +39,9 @@ Singleton {
if (newVolume - lastVolume > maxAllowedIncrease) {
sink.audio.volume = lastVolume;
root.sinkProtectionTriggered("Illegal increment");
} else if (newVolume > maxAllowed) {
root.sinkProtectionTriggered("Exceeded max allowed");
root.sinkProtectionTriggered(Translation.tr("Illegal increment"));
} else if (newVolume > maxAllowed || newVolume > root.hardMaxValue) {
root.sinkProtectionTriggered(Translation.tr("Exceeded max allowed"));
sink.audio.volume = Math.min(lastVolume, maxAllowed);
}
if (sink.ready && (isNaN(sink.audio.volume) || sink.audio.volume === undefined || sink.audio.volume === null)) {
+22 -16
View File
@@ -1,10 +1,10 @@
pragma Singleton
pragma ComponentBehavior: Bound
import qs
import qs.modules.common
import QtQuick
import Quickshell
import Quickshell.Io
pragma Singleton
pragma ComponentBehavior: Bound
/**
* A nice wrapper for date and time strings.
@@ -12,7 +12,11 @@ pragma ComponentBehavior: Bound
Singleton {
property var clock: SystemClock {
id: clock
precision: GlobalStates.screenLocked ? SystemClock.Seconds : SystemClock.Minutes // Hack to ensure clock is correct after waking up from suspend
precision: {
if (Config.options.time.secondPrecision || GlobalStates.screenLocked)
return SystemClock.Seconds;
return SystemClock.Minutes;
}
}
property string time: Qt.locale().toString(clock.date, Config.options?.time.format ?? "hh:mm")
property string shortDate: Qt.locale().toString(clock.date, Config.options?.time.shortDateFormat ?? "dd/MM")
@@ -25,22 +29,25 @@ Singleton {
running: true
repeat: true
onTriggered: {
fileUptime.reload()
const textUptime = fileUptime.text()
const uptimeSeconds = Number(textUptime.split(" ")[0] ?? 0)
fileUptime.reload();
const textUptime = fileUptime.text();
const uptimeSeconds = Number(textUptime.split(" ")[0] ?? 0);
// Convert seconds to days, hours, and minutes
const days = Math.floor(uptimeSeconds / 86400)
const hours = Math.floor((uptimeSeconds % 86400) / 3600)
const minutes = Math.floor((uptimeSeconds % 3600) / 60)
const days = Math.floor(uptimeSeconds / 86400);
const hours = Math.floor((uptimeSeconds % 86400) / 3600);
const minutes = Math.floor((uptimeSeconds % 3600) / 60);
// Build the formatted uptime string
let formatted = ""
if (days > 0) formatted += `${days}d`
if (hours > 0) formatted += `${formatted ? ", " : ""}${hours}h`
if (minutes > 0 || !formatted) formatted += `${formatted ? ", " : ""}${minutes}m`
uptime = formatted
interval = Config.options?.resources?.updateInterval ?? 3000
let formatted = "";
if (days > 0)
formatted += `${days}d`;
if (hours > 0)
formatted += `${formatted ? ", " : ""}${hours}h`;
if (minutes > 0 || !formatted)
formatted += `${formatted ? ", " : ""}${minutes}m`;
uptime = formatted;
interval = Config.options?.resources?.updateInterval ?? 3000;
}
}
@@ -49,5 +56,4 @@ Singleton {
path: "/proc/uptime"
}
}
@@ -32,6 +32,21 @@ Singleton {
Appearance.m3colors.darkmode = (Appearance.m3colors.m3background.hslLightness < 0.5)
}
function resetFilePathNextTime() {
resetFilePathNextWallpaperChange.enabled = true
}
Connections {
id: resetFilePathNextWallpaperChange
enabled: false
target: Config.options.background
onWallpaperPathChanged: {
root.filePath = ""
root.filePath = Directories.generatedMaterialThemePath
resetFilePathNextWallpaperChange.enabled = false
}
}
Timer {
id: delayedFileRead
interval: Config.options?.hacks?.arbitraryRaceConditionDelay ?? 100
@@ -54,5 +69,6 @@ Singleton {
const fileContent = themeFileView.text()
root.applyColors(fileContent)
}
onLoadFailed: root.resetFilePathNextTime();
}
}
+1 -1
View File
@@ -172,7 +172,7 @@ printf "${STY_CYAN}Press ${STY_BG_CYAN} Ctrl+Super+T ${STY_BG_CYAN} to select a
printf "${STY_CYAN}Press ${STY_BG_CYAN} Super+/ ${STY_CYAN} for a list of keybinds${STY_RESET}\n"
printf "\n"
printf "${STY_CYAN}For suggestions/hints after installation:${STY_RESET}\n"
printf "${STY_CYAN}${STY_UNDERLINE} https://end-4.github.io/dots-hyprland-wiki/en/ii-qs/01setup/#post-installation ${STY_RESET}\n"
printf "${STY_CYAN}${STY_UNDERLINE} https://ii.clsty.link/en/ii-qs/01setup/#post-installation ${STY_RESET}\n"
printf "\n"
case $existed_hypr_conf_firstrun in