Merge branch 'end-4:main' into main

This commit is contained in:
sin
2025-08-17 17:01:47 +00:00
committed by GitHub
22 changed files with 993 additions and 233 deletions
+195
View File
@@ -0,0 +1,195 @@
//@ pragma UseQApplication
//@ pragma Env QS_NO_RELOAD_POPUP=1
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Basic
//@ pragma Env QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000
// Adjust this to make the app smaller or larger
//@ pragma Env QT_SCALE_FACTOR=1
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Window
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
ApplicationWindow {
id: root
property int conflictCount: 0
onConflictCountChanged: {
if (conflictCount === 0) {
root.close();
}
}
property real contentPadding: 8
visible: true
onClosing: {
Qt.quit()
}
title: Translation.tr("Shell conflicts killer")
Component.onCompleted: {
Config.ready // Just read to force init
MaterialThemeLoader.reapplyTheme();
}
minimumWidth: 400
minimumHeight: 300
maximumWidth: 400
maximumHeight: 300
width: 400
height: 300
color: Appearance.m3colors.m3background
component ConflictingProgramGroup: ColumnLayout {
id: conflictGroup
required property list<string> programs
required property string description
visible: false
onVisibleChanged: {
conflictCount += visible ? 1 : -1
}
signal alwaysSelected()
Process {
running: true
command: ["pidof", ...conflictGroup.programs]
onExited: (exitCode, exitStatus) => {
if (exitCode === 0) {
conflictGroup.visible = true
}
}
}
StyledText {
text: conflictGroup.programs.join(", ")
font.pixelSize: Appearance.font.pixelSize.normal
}
StyledText {
font {
pixelSize: Appearance.font.pixelSize.smaller
italic: true
}
text: conflictGroup.description
color: Appearance.colors.colSubtext
}
RowLayout {
Layout.alignment: Qt.AlignRight
RippleButton {
colBackground: Appearance.colors.colLayer2
contentItem: StyledText {
text: Translation.tr("Always")
}
onClicked: {
Quickshell.execDetached(["killall", ...conflictGroup.programs])
conflictGroup.visible = false
conflictGroup.alwaysSelected()
}
}
RippleButton {
colBackground: Appearance.colors.colLayer2
contentItem: StyledText {
text: Translation.tr("Yes")
}
onClicked: {
Quickshell.execDetached(["killall", ...conflictGroup.programs])
conflictGroup.visible = false
}
}
RippleButton {
colBackground: Appearance.colors.colLayer2
contentItem: StyledText {
text: Translation.tr("No")
}
onClicked: conflictGroup.visible = false
}
}
}
ColumnLayout {
anchors {
fill: parent
margins: contentPadding
}
Item {
// Titlebar
visible: Config.options?.windows.showTitlebar
Layout.fillWidth: true
implicitHeight: Math.max(welcomeText.implicitHeight, windowControlsRow.implicitHeight)
StyledText {
id: welcomeText
anchors {
left: Config.options.windows.centerTitle ? undefined : parent.left
horizontalCenter: Config.options.windows.centerTitle ? parent.horizontalCenter : undefined
verticalCenter: parent.verticalCenter
leftMargin: 12
}
color: Appearance.colors.colOnLayer0
text: Translation.tr("Kill conflicting programs?")
font.pixelSize: Appearance.font.pixelSize.title
font.family: Appearance.font.family.title
}
RowLayout { // Window controls row
id: windowControlsRow
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
RippleButton {
buttonRadius: Appearance.rounding.full
implicitWidth: 35
implicitHeight: 35
onClicked: root.close()
contentItem: MaterialSymbol {
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
text: "close"
iconSize: 20
}
}
}
}
Rectangle {
// Content container
color: Appearance.m3colors.m3surfaceContainerLow
radius: Appearance.rounding.windowRounding - root.contentPadding
implicitHeight: contentColumn.implicitHeight
implicitWidth: contentColumn.implicitWidth
Layout.fillWidth: true
Layout.fillHeight: true
ColumnLayout {
id: contentColumn
anchors.fill: parent
spacing: 12
ConflictingProgramGroup {
id: kded6Group
Layout.alignment: Qt.AlignHCenter
Layout.fillHeight: false
programs: ["kded6"]
description: Translation.tr("Conflicts with the shell's system tray implementation")
onAlwaysSelected: Config.options.conflictKiller.autoKillTrays = true
}
ConflictingProgramGroup {
id: notificationDaemons
Layout.alignment: Qt.AlignHCenter
Layout.fillHeight: false
programs: ["mako", "dunst"]
description: Translation.tr("Conflicts with the shell's notification implementation")
onAlwaysSelected: Config.options.conflictKiller.autoKillNotificationDaemons = true
}
}
}
}
}
@@ -213,7 +213,7 @@ Variants {
ColumnLayout {
id: clockColumn
anchors.centerIn: parent
spacing: 0
spacing: 6
StyledText {
Layout.fillWidth: true
@@ -242,6 +242,20 @@ Variants {
styleColor: Appearance.colors.colShadow
text: DateTime.date
}
StyledText {
Layout.fillWidth: true
horizontalAlignment: bgRoot.textHorizontalAlignment
font {
family: Appearance.font.family.expressive
pixelSize: 20
weight: Font.DemiBold
}
color: bgRoot.colText
style: Text.Raised
visible: Config.options.background.mantra !== ""
styleColor: Appearance.colors.colShadow
text: Config.options.background.mantra
}
}
RowLayout {
@@ -2,9 +2,6 @@ import "./weather"
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import Quickshell.Services.UPower
import qs
import qs.services
@@ -50,58 +47,26 @@ Item { // Bar content region
border.color: Appearance.colors.colLayer0Border
}
MouseArea { // Left side | scroll to change brightness
FocusedScrollMouseArea { // Left side | scroll to change brightness
id: barLeftSideMouseArea
anchors.left: parent.left
implicitHeight: Appearance.sizes.baseBarHeight
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
right: middleSection.left
}
implicitWidth: leftSectionRowLayout.implicitWidth
height: Appearance.sizes.barHeight
width: (root.width - middleSection.width) / 2
property bool hovered: false
property real lastScrollX: 0
property real lastScrollY: 0
property bool trackingScroll: false
acceptedButtons: Qt.LeftButton
hoverEnabled: true
propagateComposedEvents: true
onEntered: event => {
barLeftSideMouseArea.hovered = true;
}
onExited: event => {
barLeftSideMouseArea.hovered = false;
barLeftSideMouseArea.trackingScroll = false;
}
implicitHeight: Appearance.sizes.baseBarHeight
onScrollDown: root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness - 0.05)
onScrollUp: root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness + 0.05)
onMovedAway: GlobalStates.osdBrightnessOpen = false
onPressed: event => {
if (event.button === Qt.LeftButton) {
if (event.button === Qt.LeftButton)
GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen;
}
}
// Scroll to change brightness
WheelHandler {
onWheel: event => {
if (event.angleDelta.y < 0)
root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness - 0.05);
else if (event.angleDelta.y > 0)
root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness + 0.05);
// Store the mouse position and start tracking
barLeftSideMouseArea.lastScrollX = event.x;
barLeftSideMouseArea.lastScrollY = event.y;
barLeftSideMouseArea.trackingScroll = true;
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
onPositionChanged: mouse => {
if (barLeftSideMouseArea.trackingScroll) {
const dx = mouse.x - barLeftSideMouseArea.lastScrollX;
const dy = mouse.y - barLeftSideMouseArea.lastScrollY;
if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) {
GlobalStates.osdBrightnessOpen = false;
barLeftSideMouseArea.trackingScroll = false;
}
}
}
// Visual content
ScrollHint {
reveal: barLeftSideMouseArea.hovered
@@ -162,7 +127,11 @@ Item { // Bar content region
RowLayout { // Middle section
id: middleSection
anchors.centerIn: parent
anchors {
top: parent.top
bottom: parent.bottom
horizontalCenter: parent.horizontalCenter
}
spacing: 4
BarGroup {
@@ -245,62 +214,32 @@ Item { // Bar content region
}
}
MouseArea { // Right side | scroll to change volume
FocusedScrollMouseArea { // Right side | scroll to change volume
id: barRightSideMouseArea
anchors.right: parent.right
anchors {
top: parent.top
bottom: parent.bottom
left: middleSection.right
right: parent.right
}
implicitWidth: rightSectionRowLayout.implicitWidth
implicitHeight: Appearance.sizes.baseBarHeight
height: Appearance.sizes.barHeight
width: (root.width - middleSection.width) / 2
property bool hovered: false
property real lastScrollX: 0
property real lastScrollY: 0
property bool trackingScroll: false
acceptedButtons: Qt.LeftButton
hoverEnabled: true
propagateComposedEvents: true
onEntered: event => {
barRightSideMouseArea.hovered = true;
onScrollDown: {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
Audio.sink.audio.volume -= step;
}
onExited: event => {
barRightSideMouseArea.hovered = false;
barRightSideMouseArea.trackingScroll = false;
onScrollUp: {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
Audio.sink.audio.volume = Math.min(1, Audio.sink.audio.volume + step);
}
onMovedAway: GlobalStates.osdVolumeOpen = false;
onPressed: event => {
if (event.button === Qt.LeftButton) {
GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen;
} else if (event.button === Qt.RightButton) {
MprisController.activePlayer.next();
}
}
// Scroll to change volume
WheelHandler {
onWheel: event => {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
if (event.angleDelta.y < 0)
Audio.sink.audio.volume -= step;
else if (event.angleDelta.y > 0)
Audio.sink.audio.volume = Math.min(1, Audio.sink.audio.volume + step);
// Store the mouse position and start tracking
barRightSideMouseArea.lastScrollX = event.x;
barRightSideMouseArea.lastScrollY = event.y;
barRightSideMouseArea.trackingScroll = true;
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
onPositionChanged: mouse => {
if (barRightSideMouseArea.trackingScroll) {
const dx = mouse.x - barRightSideMouseArea.lastScrollX;
const dy = mouse.y - barRightSideMouseArea.lastScrollY;
if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) {
GlobalStates.osdVolumeOpen = false;
barRightSideMouseArea.trackingScroll = false;
}
}
}
@@ -420,8 +359,8 @@ Item { // Bar content region
Layout.leftMargin: 8
Layout.fillHeight: true
active: Config.options.bar.weather.enable
sourceComponent: BarGroup {
implicitHeight: Appearance.sizes.baseBarHeight
WeatherBar {}
}
}
@@ -33,7 +33,7 @@ LazyLoader {
root.hoverTarget,
(root.hoverTarget.width - popupBackground.implicitWidth) / 2, 0
).x;
return Appearance.sizes.barHeight
return Appearance.sizes.verticalBarWidth
}
top: {
if (!Config.options.bar.vertical) return Appearance.sizes.barHeight;
@@ -42,7 +42,7 @@ LazyLoader {
(root.hoverTarget.height - popupBackground.implicitHeight) / 2, 0
).y;
}
right: Appearance.sizes.barHeight
right: Appearance.sizes.verticalBarWidth
bottom: Appearance.sizes.barHeight
}
WlrLayershell.namespace: "quickshell:popup"
@@ -5,6 +5,7 @@ import qs.modules.common.widgets
import QtQuick
import QtQuick.Layouts
import "../"
StyledPopup {
id: root
@@ -126,6 +126,7 @@ Singleton {
property real workspaceZoom: 1.07 // Relative to your screen, not wallpaper size
property bool enableSidebar: true
}
property string mantra: ""
}
property JsonObject bar: JsonObject {
@@ -183,6 +184,11 @@ Singleton {
property int suspend: 3
}
property JsonObject conflictKiller: JsonObject {
property bool autoKillNotificationDaemons: false
property bool autoKillTrays: false
}
property JsonObject dock: JsonObject {
property bool enable: false
property bool monochromeIcons: true
@@ -197,7 +203,7 @@ Singleton {
property JsonObject interactions: JsonObject {
property JsonObject scrolling: JsonObject {
property bool fasterTouchpadScroll: true // Enable faster scrolling with touchpad
property bool fasterTouchpadScroll: false // Enable faster scrolling with touchpad
property int mouseScrollDeltaThreshold: 120 // delta >= this then it gets detected as mouse scroll rather than touchpad
property int mouseScrollFactor: 120
property int touchpadScrollFactor: 450
@@ -280,6 +286,7 @@ Singleton {
property JsonObject time: JsonObject {
// https://doc.qt.io/qt-6/qtime.html#toString
property string format: "hh:mm"
property string shortDateFormat: "dd/MM"
property string dateFormat: "ddd, dd/MM"
property JsonObject pomodoro: JsonObject {
property string alertSound: ""
@@ -0,0 +1,63 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.UPower
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
MouseArea { // Right side | scroll to change volume
id: root
signal scrollUp(delta: int)
signal scrollDown(delta: int)
signal movedAway()
property bool hovered: false
property real lastScrollX: 0
property real lastScrollY: 0
property bool trackingScroll: false
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onEntered: {
root.hovered = true;
}
onExited: {
root.hovered = false;
root.trackingScroll = false;
}
onWheel: event => {
if (event.angleDelta.y < 0)
root.scrollDown(event.angleDelta.y);
else if (event.angleDelta.y > 0)
root.scrollUp(event.angleDelta.y);
// Store the mouse position and start tracking
root.lastScrollX = event.x;
root.lastScrollY = event.y;
root.trackingScroll = true;
}
onPositionChanged: mouse => {
if (root.trackingScroll) {
const dx = mouse.x - root.lastScrollX;
const dy = mouse.y - root.lastScrollY;
if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) {
root.movedAway();
root.trackingScroll = false;
}
}
}
onContainsMouseChanged: {
if (!root.containsMouse && root.trackingScroll) {
root.movedAway();
root.trackingScroll = false;
}
}
}
@@ -133,7 +133,7 @@ Button {
background: Rectangle {
id: buttonBackground
radius: root.buttonEffectiveRadius
implicitHeight: 50
implicitHeight: 30
color: root.buttonColor
Behavior on color {
@@ -111,21 +111,24 @@ Scope {
exclusionMode: ExclusionMode.Ignore
exclusiveZone: 0
margins {
top: Appearance.sizes.barHeight
bottom: Appearance.sizes.barHeight
left: (mediaControlsRoot.screen.width / 2) - (osdWidth / 2) - widgetWidth
}
implicitWidth: root.widgetWidth
implicitHeight: playerColumnLayout.implicitHeight
color: "transparent"
WlrLayershell.namespace: "quickshell:mediaControls"
anchors {
top: !Config.options.bar.bottom
bottom: Config.options.bar.bottom
left: true
top: !Config.options.bar.bottom || Config.options.bar.vertical
bottom: Config.options.bar.bottom && !Config.options.bar.vertical
left: !(Config.options.bar.vertical && Config.options.bar.bottom)
right: Config.options.bar.vertical && Config.options.bar.bottom
}
margins {
top: Config.options.bar.vertical ? ((mediaControlsRoot.screen.height / 2) - widgetHeight * 1.5) : Appearance.sizes.barHeight
bottom: Appearance.sizes.barHeight
left: Config.options.bar.vertical ? Appearance.sizes.barHeight : ((mediaControlsRoot.screen.width / 2) - (osdWidth / 2) - widgetWidth)
right: Appearance.sizes.barHeight
}
mask: Region {
item: playerColumnLayout
}
@@ -143,6 +146,8 @@ Scope {
required property MprisPlayer modelData
player: modelData
visualizerPoints: root.visualizerPoints
implicitWidth: widgetWidth
implicitHeight: widgetHeight
}
}
}
@@ -23,9 +23,6 @@ Item { // Player instance
property real maxVisualizerValue: 1000 // Max value in the data points
property int visualizerSmoothing: 2 // Number of points to average for smoothing
implicitWidth: widgetWidth
implicitHeight: widgetHeight
component TrackChangeButton: RippleButton {
implicitWidth: 24
implicitHeight: 24
@@ -1,9 +1,6 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import Quickshell.Services.UPower
import qs
import qs.services
@@ -48,57 +45,22 @@ Item { // Bar content region
border.color: Appearance.colors.colLayer0Border
}
MouseArea { // Top section | scroll to change brightness
FocusedScrollMouseArea { // Top section | scroll to change brightness
id: barTopSectionMouseArea
anchors.top: parent.top
implicitHeight: topSectionColumnLayout.implicitHeight
implicitWidth: Appearance.sizes.baseVerticalBarWidth
height: (root.height - middleSection.height) / 2
width: Appearance.sizes.verticalBarWidth
property bool hovered: false
property real lastScrollX: 0
property real lastScrollY: 0
property bool trackingScroll: false
acceptedButtons: Qt.LeftButton
hoverEnabled: true
propagateComposedEvents: true
onEntered: event => {
barTopSectionMouseArea.hovered = true;
}
onExited: event => {
barTopSectionMouseArea.hovered = false;
barTopSectionMouseArea.trackingScroll = false;
}
onScrollDown: root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness - 0.05)
onScrollUp: root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness + 0.05)
onMovedAway: GlobalStates.osdBrightnessOpen = false
onPressed: event => {
if (event.button === Qt.LeftButton) {
if (event.button === Qt.LeftButton)
GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen;
}
}
// Scroll to change brightness
WheelHandler {
onWheel: event => {
if (event.angleDelta.y < 0)
root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness - 0.05);
else if (event.angleDelta.y > 0)
root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness + 0.05);
// Store the mouse position and start tracking
barTopSectionMouseArea.lastScrollX = event.x;
barTopSectionMouseArea.lastScrollY = event.y;
barTopSectionMouseArea.trackingScroll = true;
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
onPositionChanged: mouse => {
if (barTopSectionMouseArea.trackingScroll) {
const dx = mouse.x - barTopSectionMouseArea.lastScrollX;
const dy = mouse.y - barTopSectionMouseArea.lastScrollY;
if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) {
GlobalStates.osdBrightnessOpen = false;
barTopSectionMouseArea.trackingScroll = false;
}
}
}
ColumnLayout { // Content
id: topSectionColumnLayout
anchors.fill: parent
@@ -156,6 +118,13 @@ Item { // Bar content region
Layout.fillWidth: true
Layout.fillHeight: false
}
HorizontalBarSeparator {}
VerticalMedia {
Layout.fillWidth: true
Layout.fillHeight: false
}
}
HorizontalBarSeparator {
@@ -197,14 +166,29 @@ Item { // Bar content region
Layout.fillHeight: false
}
BatteryIndicator {
HorizontalBarSeparator {}
VerticalDateWidget {
Layout.fillWidth: true
Layout.fillHeight: false
}
HorizontalBarSeparator {
visible: UPower.displayDevice.isLaptopBattery
}
BatteryIndicator {
visible: UPower.displayDevice.isLaptopBattery
Layout.fillWidth: true
Layout.fillHeight: false
}
}
}
MouseArea { // Bottom section | scroll to change volume
FocusedScrollMouseArea { // Bottom section | scroll to change volume
id: barBottomSectionMouseArea
anchors {
@@ -214,54 +198,21 @@ Item { // Bar content region
}
implicitWidth: Appearance.sizes.baseVerticalBarWidth
implicitHeight: bottomSectionColumnLayout.implicitHeight
width: Appearance.sizes.verticalBarWidth
property bool hovered: false
property real lastScrollX: 0
property real lastScrollY: 0
property bool trackingScroll: false
acceptedButtons: Qt.LeftButton
hoverEnabled: true
propagateComposedEvents: true
onEntered: event => {
barBottomSectionMouseArea.hovered = true;
onScrollDown: {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
Audio.sink.audio.volume -= step;
}
onExited: event => {
barBottomSectionMouseArea.hovered = false;
barBottomSectionMouseArea.trackingScroll = false;
onScrollUp: {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
Audio.sink.audio.volume = Math.min(1, Audio.sink.audio.volume + step);
}
onMovedAway: GlobalStates.osdVolumeOpen = false;
onPressed: event => {
if (event.button === Qt.LeftButton) {
GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen;
} else if (event.button === Qt.RightButton) {
MprisController.activePlayer.next();
}
}
// Scroll to change volume
WheelHandler {
onWheel: event => {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
if (event.angleDelta.y < 0)
Audio.sink.audio.volume -= step;
else if (event.angleDelta.y > 0)
Audio.sink.audio.volume = Math.min(1, Audio.sink.audio.volume + step);
// Store the mouse position and start tracking
barBottomSectionMouseArea.lastScrollX = event.x;
barBottomSectionMouseArea.lastScrollY = event.y;
barBottomSectionMouseArea.trackingScroll = true;
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
onPositionChanged: mouse => {
if (barBottomSectionMouseArea.trackingScroll) {
const dx = mouse.x - barBottomSectionMouseArea.lastScrollX;
const dy = mouse.y - barBottomSectionMouseArea.lastScrollY;
if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) {
GlobalStates.osdVolumeOpen = false;
barBottomSectionMouseArea.trackingScroll = false;
}
}
}
@@ -0,0 +1,64 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import QtQuick
import QtQuick.Shapes
import QtQuick.Layouts
import "../bar" as Bar
Item { // Full hitbox
id: root
implicitHeight: content.implicitHeight
implicitWidth: Appearance.sizes.verticalBarWidth
property var dayOfMonth: DateTime.shortDate.split(/[-\/]/)[0] // What if 🍔murica🦅? good question
property var monthOfYear: DateTime.shortDate.split(/[-\/]/)[1]
Item { // Boundaries for date numbers
id: content
anchors.centerIn: parent
implicitWidth: 24
implicitHeight: 30
Shape {
id: diagonalLine
property real padding: 4
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
ShapePath {
strokeWidth: 1.2
strokeColor: Appearance.colors.colSubtext
fillColor: "transparent"
startX: content.width - diagonalLine.padding
startY: diagonalLine.padding
PathLine {
x: diagonalLine.padding
y: content.height - diagonalLine.padding
}
}
}
StyledText {
id: dayText
anchors {
top: parent.top
left: parent.left
}
font.pixelSize: 13
color: Appearance.colors.colOnLayer1
text: dayOfMonth
}
StyledText {
id: monthText
anchors {
bottom: parent.bottom
right: parent.right
}
font.pixelSize: 13
color: Appearance.colors.colOnLayer1
text: monthOfYear
}
}
}
@@ -0,0 +1,102 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import qs
import qs.modules.common.functions
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.Mpris
import "../bar" as Bar
MouseArea {
id: root
property bool borderless: Config.options.bar.borderless
readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property string cleanedTitle: StringUtils.cleanMusicTitle(activePlayer?.trackTitle) || Translation.tr("No media")
Layout.fillHeight: true
implicitHeight: mediaCircProg.implicitHeight
implicitWidth: Appearance.sizes.verticalBarWidth
Timer {
running: activePlayer?.playbackState == MprisPlaybackState.Playing
interval: 1000
repeat: true
onTriggered: activePlayer.positionChanged()
}
acceptedButtons: Qt.MiddleButton | Qt.BackButton | Qt.ForwardButton | Qt.RightButton | Qt.LeftButton
hoverEnabled: true
onPressed: (event) => {
if (event.button === Qt.MiddleButton) {
activePlayer.togglePlaying();
} else if (event.button === Qt.BackButton) {
activePlayer.previous();
} else if (event.button === Qt.ForwardButton || event.button === Qt.RightButton) {
activePlayer.next();
} else if (event.button === Qt.LeftButton) {
GlobalStates.mediaControlsOpen = !GlobalStates.mediaControlsOpen
}
}
ClippedFilledCircularProgress {
id: mediaCircProg
anchors.centerIn: parent
implicitSize: 20
lineWidth: Appearance.rounding.unsharpen
value: activePlayer?.position / activePlayer?.length
colPrimary: Appearance.colors.colOnSecondaryContainer
enableAnimation: false
Item {
anchors.centerIn: parent
width: mediaCircProg.implicitSize
height: mediaCircProg.implicitSize
MaterialSymbol {
anchors.centerIn: parent
fill: 1
text: activePlayer?.isPlaying ? "pause" : "music_note"
iconSize: Appearance.font.pixelSize.normal
color: Appearance.m3colors.m3onSecondaryContainer
}
}
}
Bar.StyledPopup {
hoverTarget: root
active: GlobalStates.mediaControlsOpen ? false : root.containsMouse
ColumnLayout {
anchors.centerIn: parent
RowLayout {
spacing: 5
MaterialSymbol {
fill: 0
font.weight: Font.Medium
text: "music_note"
iconSize: Appearance.font.pixelSize.large
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
text: "Media"
font {
weight: Font.Medium
pixelSize: Appearance.font.pixelSize.normal
}
color: Appearance.colors.colOnSurfaceVariant
}
}
StyledText {
text: `${cleanedTitle}${activePlayer?.trackArtist ? '\n' + activePlayer.trackArtist : ''}`
}
}
}
}
@@ -98,4 +98,12 @@ Singleton {
}
}
}
IpcHandler {
target: "cliphistService"
function update(): void {
root.refresh()
}
}
}
@@ -0,0 +1,49 @@
pragma Singleton
import qs
import qs.modules.common
import qs.modules.common.functions
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property string killDialogQmlPath: FileUtils.trimFileProtocol(Quickshell.shellPath("killDialog.qml"))
function load() {
// dummy to force init
}
Connections {
target: Config
function onReadyChanged() {
if (Config.ready) checkConflictsProc.running = true
}
}
Process {
id: checkConflictsProc
command: ["bash", "-c", `echo "$(pidof kded6);$(pidof mako dunst)"`]
stdout: StdioCollector {
onStreamFinished: {
const output = this.text;
const conflictingTrays = output.split(";")[0].trim().length > 0;
const conflictingNotifications = output.split(";")[1].trim().length > 0;
var openDialog = false;
if (conflictingTrays) {
if (!Config.options.conflictKiller.autoKillTrays) openDialog = true;
else Quickshell.execDetached(["killall", "kded6"])
}
if (conflictingNotifications) {
if (!Config.options.conflictKiller.autoKillNotificationDaemons) openDialog = true;
else Quickshell.execDetached(["killall", "mako", "dunst"])
}
if (openDialog) {
Quickshell.execDetached(["qs", "-p", root.killDialogQmlPath])
}
}
}
}
}
@@ -14,6 +14,7 @@ Singleton {
precision: 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")
property string date: Qt.locale().toString(clock.date, Config.options?.time.dateFormat ?? "dddd, dd/MM")
property string collapsedCalendarFormat: Qt.locale().toString(clock.date, "dd MMMM yyyy")
property string uptime: "0h, 0m"
+4 -3
View File
@@ -54,10 +54,11 @@ ShellRoot {
// Force initialization of some singletons
Component.onCompleted: {
Cliphist.refresh()
FirstRunExperience.load()
Hyprsunset.load()
MaterialThemeLoader.reapplyTheme()
Hyprsunset.load()
FirstRunExperience.load()
ConflictKiller.load()
Cliphist.refresh()
}
LazyLoader { active: enableBar && Config.ready && !Config.options.bar.vertical; component: Bar {} }