Settings window #20

Merged
Zacharias-Brohn merged 83 commits from settingsWindow into main 2026-03-06 23:27:24 +01:00
19 changed files with 787 additions and 713 deletions
Showing only changes of commit ca04c7d2f1 - Show all commits
+135
View File
@@ -0,0 +1,135 @@
import QtQuick
import QtQuick.Layouts
import qs.Config
ColumnLayout {
id: root
default property alias content: contentColumn.data
property string description: ""
property bool expanded: false
property bool nested: false
property bool showBackground: false
required property string title
signal toggleRequested
Layout.fillWidth: true
spacing: Appearance.spacing.small
Item {
id: sectionHeaderItem
Layout.fillWidth: true
Layout.preferredHeight: Math.max(titleRow.implicitHeight + Appearance.padding.normal * 2, 48)
RowLayout {
id: titleRow
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.normal
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.normal
CustomText {
font.pointSize: Appearance.font.size.larger
font.weight: 500
text: root.title
}
Item {
Layout.fillWidth: true
}
MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.normal
rotation: root.expanded ? 180 : 0
text: "expand_more"
Behavior on rotation {
Anim {
duration: Appearance.anim.durations.small
easing.bezierCurve: Appearance.anim.curves.standard
}
}
}
}
StateLayer {
function onClicked(): void {
root.toggleRequested();
root.expanded = !root.expanded;
}
anchors.fill: parent
color: DynamicColors.palette.m3onSurface
radius: Appearance.rounding.normal
showHoverBackground: false
}
}
Item {
id: contentWrapper
Layout.fillWidth: true
Layout.preferredHeight: root.expanded ? (contentColumn.implicitHeight + Appearance.spacing.small * 2) : 0
clip: true
Behavior on Layout.preferredHeight {
Anim {
easing.bezierCurve: Appearance.anim.curves.standard
}
}
CustomRect {
id: backgroundRect
anchors.fill: parent
color: DynamicColors.transparency.enabled ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, root.nested ? 3 : 2) : (root.nested ? DynamicColors.palette.m3surfaceContainerHigh : DynamicColors.palette.m3surfaceContainer)
opacity: root.showBackground && root.expanded ? 1.0 : 0.0
radius: Appearance.rounding.normal
visible: root.showBackground
Behavior on opacity {
Anim {
easing.bezierCurve: Appearance.anim.curves.standard
}
}
}
ColumnLayout {
id: contentColumn
anchors.bottomMargin: Appearance.spacing.small
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.normal
opacity: root.expanded ? 1.0 : 0.0
spacing: Appearance.spacing.small
y: Appearance.spacing.small
Behavior on opacity {
Anim {
easing.bezierCurve: Appearance.anim.curves.standard
}
}
CustomText {
id: descriptionText
Layout.bottomMargin: root.description !== "" ? Appearance.spacing.small : 0
Layout.fillWidth: true
Layout.topMargin: root.description !== "" ? Appearance.spacing.smaller : 0
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.small
text: root.description
visible: root.description !== ""
wrapMode: Text.Wrap
}
}
}
}
+166
View File
@@ -0,0 +1,166 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Config
RowLayout {
id: root
property string displayText: root.value.toString()
property bool isEditing: false
property real max: Infinity
property real min: -Infinity
property alias repeatRate: timer.interval
property real step: 1
property real value
signal valueModified(value: real)
spacing: Appearance.spacing.small
onValueChanged: {
if (!root.isEditing) {
root.displayText = root.value.toString();
}
}
CustomTextField {
id: textField
inputMethodHints: Qt.ImhFormattedNumbersOnly
leftPadding: Appearance.padding.normal
padding: Appearance.padding.small
rightPadding: Appearance.padding.normal
text: root.isEditing ? text : root.displayText
background: CustomRect {
color: DynamicColors.tPalette.m3surfaceContainerHigh
implicitWidth: 100
radius: Appearance.rounding.small
}
validator: DoubleValidator {
bottom: root.min
decimals: root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0
top: root.max
}
onAccepted: {
const numValue = parseFloat(text);
if (!isNaN(numValue)) {
const clampedValue = Math.max(root.min, Math.min(root.max, numValue));
root.value = clampedValue;
root.displayText = clampedValue.toString();
root.valueModified(clampedValue);
} else {
text = root.displayText;
}
root.isEditing = false;
}
onActiveFocusChanged: {
if (activeFocus) {
root.isEditing = true;
} else {
root.isEditing = false;
root.displayText = root.value.toString();
}
}
onEditingFinished: {
if (text !== root.displayText) {
const numValue = parseFloat(text);
if (!isNaN(numValue)) {
const clampedValue = Math.max(root.min, Math.min(root.max, numValue));
root.value = clampedValue;
root.displayText = clampedValue.toString();
root.valueModified(clampedValue);
} else {
text = root.displayText;
}
}
root.isEditing = false;
}
}
CustomRect {
color: DynamicColors.palette.m3primary
implicitHeight: upIcon.implicitHeight + Appearance.padding.small * 2
implicitWidth: implicitHeight
radius: Appearance.rounding.small
StateLayer {
id: upState
function onClicked(): void {
let newValue = Math.min(root.max, root.value + root.step);
// Round to avoid floating point precision errors
const decimals = root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0;
newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals);
root.value = newValue;
root.displayText = newValue.toString();
root.valueModified(newValue);
}
color: DynamicColors.palette.m3onPrimary
onPressAndHold: timer.start()
onReleased: timer.stop()
}
MaterialIcon {
id: upIcon
anchors.centerIn: parent
color: DynamicColors.palette.m3onPrimary
text: "keyboard_arrow_up"
}
}
CustomRect {
color: DynamicColors.palette.m3primary
implicitHeight: downIcon.implicitHeight + Appearance.padding.small * 2
implicitWidth: implicitHeight
radius: Appearance.rounding.small
StateLayer {
id: downState
function onClicked(): void {
let newValue = Math.max(root.min, root.value - root.step);
// Round to avoid floating point precision errors
const decimals = root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0;
newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals);
root.value = newValue;
root.displayText = newValue.toString();
root.valueModified(newValue);
}
color: DynamicColors.palette.m3onPrimary
onPressAndHold: timer.start()
onReleased: timer.stop()
}
MaterialIcon {
id: downIcon
anchors.centerIn: parent
color: DynamicColors.palette.m3onPrimary
text: "keyboard_arrow_down"
}
}
Timer {
id: timer
interval: 100
repeat: true
triggeredOnStart: true
onTriggered: {
if (upState.pressed)
upState.onClicked();
else if (downState.pressed)
downState.onClicked();
}
}
}
+200
View File
@@ -0,0 +1,200 @@
import QtQuick
import QtQuick.Effects
Item {
id: root
property color color: DynamicColors.palette.m3onSurface
property int fadeStrengthAnimMs: 180
property real fadeStrengthIdle: 0.0
property real fadeStrengthMoving: 1.0
property alias font: elideText.font
property int gap: 40
property alias horizontalAlignment: elideText.horizontalAlignment
property bool leftFadeEnabled: false
property real leftFadeStrength: overflowing && leftFadeEnabled ? fadeStrengthMoving : fadeStrengthIdle
property int leftFadeWidth: 28
property bool marqueeEnabled: true
readonly property bool overflowing: metrics.width > root.width
property int pauseMs: 1200
property real pixelsPerSecond: 40
property real rightFadeStrength: overflowing ? fadeStrengthMoving : fadeStrengthIdle
property int rightFadeWidth: 28
property bool sliding: false
property alias text: elideText.text
function durationForDistance(px): int {
return Math.max(1, Math.round(Math.abs(px) / root.pixelsPerSecond * 1000));
}
clip: true
implicitHeight: elideText.implicitHeight
Behavior on leftFadeStrength {
Anim {
}
}
Behavior on rightFadeStrength {
Anim {
}
}
onTextChanged: strip.x = 0
onVisibleChanged: if (!visible)
strip.x = 0
onWidthChanged: strip.x = 0
TextMetrics {
id: metrics
font: elideText.font
text: elideText.text
}
CustomText {
id: elideText
anchors.verticalCenter: parent.verticalCenter
color: root.color
elide: Text.ElideRight
visible: !root.overflowing
width: root.width
}
Item {
id: marqueeViewport
anchors.fill: parent
clip: true
layer.enabled: true
visible: root.overflowing
layer.effect: OpacityMask {
maskSource: rightFadeMask
}
Item {
id: strip
anchors.verticalCenter: parent.verticalCenter
height: t1.implicitHeight
width: t1.width + root.gap + t2.width
x: 0
CustomText {
id: t1
color: root.color
text: elideText.text
}
CustomText {
id: t2
color: root.color
text: t1.text
x: t1.width + root.gap
}
}
SequentialAnimation {
id: marqueeAnim
loops: Animation.Infinite
running: root.marqueeEnabled && root.overflowing && root.visible
ScriptAction {
script: {
strip.x = 0;
root.sliding = false;
root.leftFadeEnabled = false;
}
}
PauseAnimation {
duration: root.pauseMs
}
ScriptAction {
script: {
root.sliding = true;
root.leftFadeEnabled = true;
}
}
Anim {
duration: root.durationForDistance(t1.width)
easing.bezierCurve: Easing.Linear
easing.type: Easing.Linear
from: 0
property: "x"
target: strip
to: -t1.width
}
ScriptAction {
script: {
root.leftFadeEnabled = false;
}
}
Anim {
duration: root.durationForDistance(root.gap)
easing.bezierCurve: Easing.Linear
easing.type: Easing.Linear
from: -t1.width
property: "x"
target: strip
to: -(t1.width + root.gap)
}
ScriptAction {
script: {
root.sliding = false;
strip.x = 0;
}
}
}
}
Rectangle {
id: rightFadeMask
readonly property real fadeStartPos: {
const w = Math.max(1, width);
return Math.max(0, Math.min(1, (w - root.rightFadeWidth) / w));
}
readonly property real leftFadeEndPos: {
const w = Math.max(1, width);
return Math.max(0, Math.min(1, root.leftFadeWidth / w));
}
anchors.fill: marqueeViewport
layer.enabled: true
visible: false
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop {
color: Qt.rgba(1, 1, 1, 1.0 - root.leftFadeStrength)
position: 0.0
}
GradientStop {
color: Qt.rgba(1, 1, 1, 1.0)
position: rightFadeMask.leftFadeEndPos
}
GradientStop {
color: Qt.rgba(1, 1, 1, 1.0)
position: rightFadeMask.fadeStartPos
}
GradientStop {
color: Qt.rgba(1, 1, 1, 1.0 - root.rightFadeStrength)
position: 1.0
}
}
}
}
+107
View File
@@ -0,0 +1,107 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Config
Elevation {
id: root
property MenuItem active: items[0] ?? null
property bool expanded
property list<MenuItem> items
signal itemSelected(item: MenuItem)
implicitHeight: root.expanded ? column.implicitHeight : 0
implicitWidth: Math.max(200, column.implicitWidth)
level: 2
opacity: root.expanded ? 1 : 0
radius: Appearance.rounding.small / 2
Behavior on implicitHeight {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.expressiveDefaultSpatial
}
}
CustomClippingRect {
anchors.fill: parent
color: DynamicColors.palette.m3surfaceContainer
radius: parent.radius
ColumnLayout {
id: column
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
Repeater {
model: root.items
CustomRect {
id: item
readonly property bool active: modelData === root.active
required property int index
required property MenuItem modelData
Layout.fillWidth: true
color: Qt.alpha(DynamicColors.palette.m3secondaryContainer, active ? 1 : 0)
implicitHeight: menuOptionRow.implicitHeight + Appearance.padding.normal * 2
implicitWidth: menuOptionRow.implicitWidth + Appearance.padding.normal * 2
StateLayer {
function onClicked(): void {
root.itemSelected(item.modelData);
root.active = item.modelData;
root.expanded = false;
}
color: item.active ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface
disabled: !root.expanded
}
RowLayout {
id: menuOptionRow
anchors.fill: parent
anchors.margins: Appearance.padding.normal
spacing: Appearance.spacing.small
MaterialIcon {
Layout.alignment: Qt.AlignVCenter
color: item.active ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurfaceVariant
text: item.modelData.icon
}
CustomText {
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
color: item.active ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface
text: item.modelData.text
}
Loader {
Layout.alignment: Qt.AlignVCenter
active: item.modelData.trailingIcon.length > 0
visible: active
sourceComponent: MaterialIcon {
color: item.active ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface
text: item.modelData.trailingIcon
}
}
}
}
}
}
}
}
+12
View File
@@ -0,0 +1,12 @@
import QtQuick
QtObject {
property string activeIcon: icon
property string activeText: text
property string icon
required property string text
property string trailingIcon
property var value
signal clicked
}
+50
View File
@@ -0,0 +1,50 @@
import QtQuick
import QtQuick.Layouts
import qs.Config
CustomRect {
id: root
required property string label
required property real max
required property real min
property var onValueModified: function (value) {}
property real step: 1
required property real value
Layout.fillWidth: true
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
implicitHeight: row.implicitHeight + Appearance.padding.large * 2
radius: Appearance.rounding.normal
Behavior on implicitHeight {
Anim {
}
}
RowLayout {
id: row
anchors.left: parent.left
anchors.margins: Appearance.padding.large
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.normal
CustomText {
Layout.fillWidth: true
text: root.label
}
CustomSpinBox {
max: root.max
min: root.min
step: root.step
value: root.value
onValueModified: value => {
root.onValueModified(value);
}
}
}
}
+4 -4
View File
@@ -28,7 +28,7 @@ Variants {
property bool trayMenuVisible: false
WlrLayershell.exclusionMode: ExclusionMode.Ignore
WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.sidebar || visibilities.dashboard ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.sidebar || visibilities.dashboard || visibilities.settings ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
WlrLayershell.namespace: "ZShell-Bar"
color: "transparent"
contentItem.focus: true
@@ -37,8 +37,6 @@ Variants {
mask: Region {
id: region
property list<Region> nullRegions: []
height: bar.screen.height - backgroundRect.implicitHeight
intersection: Intersection.Xor
regions: popoutRegions.instances
@@ -53,6 +51,7 @@ Variants {
visibilities.sidebar = false;
visibilities.dashboard = false;
visibilities.osd = false;
visibilities.settings = false;
}
PanelWindow {
@@ -98,7 +97,7 @@ Variants {
HyprlandFocusGrab {
id: focusGrab
active: visibilities.launcher || visibilities.sidebar || visibilities.dashboard || (panels.popouts.hasCurrent && panels.popouts.currentName.startsWith("traymenu"))
active: visibilities.launcher || visibilities.sidebar || visibilities.dashboard || visibilities.settings || (panels.popouts.hasCurrent && panels.popouts.currentName.startsWith("traymenu"))
windows: [bar]
onCleared: {
@@ -106,6 +105,7 @@ Variants {
visibilities.sidebar = false;
visibilities.dashboard = false;
visibilities.osd = false;
visibilities.settings = false;
panels.popouts.hasCurrent = false;
}
}
+5 -18
View File
@@ -3,7 +3,6 @@ import QtQuick
import QtQuick.Layouts
import qs.Helpers
import qs.Components
import qs.Paths
import qs.Modules
import qs.Config
import qs.Modules.Dashboard.Dash
@@ -86,18 +85,6 @@ GridLayout {
}
}
// Rect {
// Layout.row: 1
// Layout.preferredWidth: dateTime.implicitWidth
// Layout.fillHeight: true
//
// radius: root.radius
//
// DateTime {
// id: dateTime
// }
// }
Rect {
Layout.column: 0
Layout.columnSpan: 3
@@ -128,11 +115,11 @@ GridLayout {
}
Rect {
Layout.column: 5
Layout.fillHeight: true
Layout.preferredWidth: media.implicitWidth
Layout.row: 0
Layout.rowSpan: 2
Layout.column: 0
Layout.columnSpan: 5
Layout.fillWidth: true
Layout.preferredHeight: media.implicitHeight
Layout.row: 2
radius: root.radius
Media {
+108 -103
View File
@@ -1,12 +1,10 @@
import ZShell.Services
import QtQuick
import QtQuick.Layouts
import QtQuick.Shapes
import qs.Daemons
import qs.Components
import qs.Config
import qs.Helpers
import qs.Modules
import qs.Paths
Item {
id: root
@@ -15,10 +13,11 @@ Item {
const active = Players.active;
return active?.length ? active.position / active.length : 0;
}
property int rowHeight: Appearance.padding.large + Config.dashboard.sizes.mediaProgressThickness + Appearance.spacing.small
anchors.bottom: parent.bottom
anchors.top: parent.top
implicitWidth: Config.dashboard.sizes.mediaWidth
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: cover.height + rowHeight * 2
Behavior on playerProgress {
Anim {
@@ -35,10 +34,6 @@ Item {
onTriggered: Players.active?.positionChanged()
}
ServiceRef {
service: Audio.beatTracker
}
Shape {
preferredRendererType: Shape.CurveRenderer
@@ -85,114 +80,124 @@ Item {
}
}
CustomClippingRect {
id: cover
RowLayout {
id: layout
anchors.left: parent.left
anchors.margins: Appearance.padding.large + Config.dashboard.sizes.mediaProgressThickness + Appearance.spacing.small
anchors.right: parent.right
anchors.top: parent.top
color: DynamicColors.tPalette.m3surfaceContainerHigh
implicitHeight: width
radius: Infinity
implicitHeight: root.implicitHeight
MaterialIcon {
anchors.centerIn: parent
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: (parent.width * 0.4) || 1
grade: 200
text: "art_track"
}
CustomClippingRect {
id: cover
Image {
id: image
Layout.alignment: Qt.AlignLeft
Layout.bottomMargin: Appearance.padding.large + Config.dashboard.sizes.mediaProgressThickness + Appearance.spacing.small
Layout.leftMargin: Appearance.padding.large + Config.dashboard.sizes.mediaProgressThickness + Appearance.spacing.small
Layout.preferredHeight: Config.dashboard.sizes.mediaCoverArtSize
Layout.preferredWidth: Config.dashboard.sizes.mediaCoverArtSize
Layout.topMargin: Appearance.padding.large + Config.dashboard.sizes.mediaProgressThickness + Appearance.spacing.small
color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Infinity
anchors.fill: parent
asynchronous: true
fillMode: Image.PreserveAspectCrop
source: Players.active?.trackArtUrl ?? ""
sourceSize.height: height
sourceSize.width: width
}
}
CustomText {
id: title
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: cover.bottom
anchors.topMargin: Appearance.spacing.normal
animate: true
color: DynamicColors.palette.m3primary
elide: Text.ElideRight
font.pointSize: Appearance.font.size.normal
horizontalAlignment: Text.AlignHCenter
text: (Players.active?.trackTitle ?? qsTr("No media")) || qsTr("Unknown title")
width: parent.implicitWidth - Appearance.padding.large * 2
}
CustomText {
id: album
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: title.bottom
anchors.topMargin: Appearance.spacing.small
animate: true
color: DynamicColors.palette.m3outline
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
horizontalAlignment: Text.AlignHCenter
text: (Players.active?.trackAlbum ?? qsTr("No media")) || qsTr("Unknown album")
width: parent.implicitWidth - Appearance.padding.large * 2
}
CustomText {
id: artist
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: album.bottom
anchors.topMargin: Appearance.spacing.small
animate: true
color: DynamicColors.palette.m3secondary
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: (Players.active?.trackArtist ?? qsTr("No media")) || qsTr("Unknown artist")
width: parent.implicitWidth - Appearance.padding.large * 2
}
Row {
id: controls
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: artist.bottom
anchors.topMargin: Appearance.spacing.smaller
spacing: Appearance.spacing.small
Control {
function onClicked(): void {
Players.active?.previous();
MaterialIcon {
anchors.centerIn: parent
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: (parent.width * 0.4) || 1
grade: 200
text: "art_track"
}
canUse: Players.active?.canGoPrevious ?? false
icon: "skip_previous"
Image {
id: image
anchors.fill: parent
asynchronous: true
fillMode: Image.PreserveAspectCrop
source: Players.active?.trackArtUrl ?? ""
sourceSize.height: Math.floor(height)
sourceSize.width: Math.floor(width)
}
}
Control {
function onClicked(): void {
Players.active?.togglePlaying();
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
MarqueeText {
id: title
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
color: DynamicColors.palette.m3primary
font.pointSize: Appearance.font.size.normal
horizontalAlignment: Text.AlignHCenter
pauseMs: 4000
text: (Players.active?.trackTitle ?? qsTr("No media")) || qsTr("Unknown title")
width: parent.width - Appearance.padding.large * 4
}
canUse: Players.active?.canTogglePlaying ?? false
icon: Players.active?.isPlaying ? "pause" : "play_arrow"
}
CustomText {
id: album
Control {
function onClicked(): void {
Players.active?.next();
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: title.bottom
anchors.topMargin: Appearance.spacing.small
animate: true
color: DynamicColors.palette.m3outline
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
horizontalAlignment: Text.AlignHCenter
text: (Players.active?.trackAlbum ?? qsTr("No media")) || qsTr("Unknown album")
}
canUse: Players.active?.canGoNext ?? false
icon: "skip_next"
CustomText {
id: artist
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: album.bottom
anchors.topMargin: Appearance.spacing.small
animate: true
color: DynamicColors.palette.m3secondary
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: (Players.active?.trackArtist ?? qsTr("No media")) || qsTr("Unknown artist")
}
Row {
id: controls
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: artist.bottom
anchors.topMargin: Appearance.spacing.smaller
spacing: Appearance.spacing.small
Control {
function onClicked(): void {
Players.active?.previous();
}
canUse: Players.active?.canGoPrevious ?? false
icon: "skip_previous"
}
Control {
function onClicked(): void {
Players.active?.togglePlaying();
}
canUse: Players.active?.canTogglePlaying ?? false
icon: Players.active?.isPlaying ? "pause" : "play_arrow"
}
Control {
function onClicked(): void {
Players.active?.next();
}
canUse: Players.active?.canGoNext ?? false
icon: "skip_next"
}
}
}
}
-66
View File
@@ -1,66 +0,0 @@
import QtQuick
import QtQuick.Shapes
import qs.Components
import qs.Config
ShapePath {
id: root
readonly property bool flatten: wrapper.height < rounding * 2
readonly property real rounding: 8
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
required property Wrapper wrapper
fillColor: DynamicColors.palette.m3surface
strokeWidth: -1
Behavior on fillColor {
CAnim {
}
}
PathArc {
radiusX: root.rounding
radiusY: Math.min(root.roundingY, root.wrapper.height)
relativeX: root.rounding
relativeY: root.roundingY
}
PathLine {
relativeX: 0
relativeY: root.wrapper.height - root.roundingY * 2
}
PathArc {
direction: PathArc.Counterclockwise
radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height)
relativeX: root.rounding
relativeY: root.roundingY
}
PathLine {
relativeX: root.wrapper.width - root.rounding * 2
relativeY: 0
}
PathArc {
direction: PathArc.Counterclockwise
radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height)
relativeX: root.rounding
relativeY: -root.roundingY
}
PathLine {
relativeX: 0
relativeY: -(root.wrapper.height - root.roundingY * 2)
}
PathArc {
radiusX: root.rounding
radiusY: Math.min(root.rounding, root.wrapper.height)
relativeX: root.rounding
relativeY: -root.roundingY
}
}
-178
View File
@@ -1,178 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Modules as Modules
import qs.Config
import qs.Helpers
Item {
id: root
required property Item content
implicitHeight: clayout.contentHeight + Appearance.padding.smaller * 2
implicitWidth: clayout.contentWidth + Appearance.padding.smaller * 2
ListModel {
id: listModel
ListElement {
icon: "settings"
name: "General"
}
ListElement {
icon: "wallpaper"
name: "Wallpaper"
}
ListElement {
icon: "settop_component"
name: "Bar"
}
ListElement {
icon: "lock"
name: "Lockscreen"
}
ListElement {
icon: "build_circle"
name: "Services"
}
ListElement {
icon: "notifications"
name: "Notifications"
}
ListElement {
icon: "view_sidebar"
name: "Sidebar"
}
ListElement {
icon: "handyman"
name: "Utilities"
}
ListElement {
icon: "dashboard"
name: "Dashboard"
}
ListElement {
icon: "colors"
name: "Appearance"
}
ListElement {
icon: "display_settings"
name: "On screen display"
}
ListElement {
icon: "rocket_launch"
name: "Launcher"
}
ListElement {
icon: "colors"
name: "Colors"
}
}
CustomRect {
anchors.fill: parent
color: DynamicColors.tPalette.m3surfaceContainer
radius: 4
CustomListView {
id: clayout
anchors.centerIn: parent
contentHeight: contentItem.childrenRect.height
contentWidth: contentItem.childrenRect.width
highlightFollowsCurrentItem: false
implicitHeight: contentItem.childrenRect.height
implicitWidth: contentItem.childrenRect.width
model: listModel
spacing: 5
delegate: Category {
}
highlight: CustomRect {
color: DynamicColors.palette.m3primary
implicitHeight: clayout.currentItem?.implicitHeight ?? 0
implicitWidth: clayout.width
radius: 4
y: clayout.currentItem?.y ?? 0
Behavior on y {
Anim {
duration: Appearance.anim.durations.small
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
}
}
}
}
}
component Category: CustomRect {
id: categoryItem
required property string icon
required property int index
required property string name
implicitHeight: 42
implicitWidth: 200
radius: 4
RowLayout {
id: layout
anchors.left: parent.left
anchors.margins: Appearance.padding.smaller
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
MaterialIcon {
id: icon
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.fillHeight: true
Layout.preferredWidth: icon.contentWidth
color: categoryItem.index === clayout.currentIndex ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
font.pointSize: 22
text: categoryItem.icon
verticalAlignment: Text.AlignVCenter
}
CustomText {
id: text
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.fillHeight: true
Layout.fillWidth: true
Layout.leftMargin: Appearance.spacing.normal
color: categoryItem.index === clayout.currentIndex ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
text: categoryItem.name
verticalAlignment: Text.AlignVCenter
}
}
StateLayer {
id: layer
onClicked: {
root.content.currentCategory = categoryItem.name.toLowerCase();
clayout.currentIndex = categoryItem.index;
}
}
}
}
@@ -1,66 +0,0 @@
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Modules as Modules
import qs.Modules.Settings.Controls
import qs.Config
import qs.Helpers
CustomRect {
id: root
ColumnLayout {
id: clayout
anchors.left: parent.left
anchors.right: parent.right
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: colorLayout.implicitHeight
color: DynamicColors.tPalette.m3surfaceContainer
ColumnLayout {
id: colorLayout
anchors.left: parent.left
anchors.margins: Appearance.padding.large
anchors.right: parent.right
Settings {
name: "smth"
}
SettingSwitch {
name: "wallust"
object: Config.general.color
setting: "wallust"
}
}
}
}
component Settings: CustomRect {
id: settingsItem
required property string name
Layout.preferredHeight: 42
Layout.preferredWidth: 200
radius: 4
CustomText {
id: text
anchors.left: parent.left
anchors.margins: Appearance.padding.smaller
anchors.right: parent.right
font.bold: true
font.pointSize: 32
text: settingsItem.name
verticalAlignment: Text.AlignVCenter
}
}
}
@@ -1,13 +0,0 @@
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Modules as Modules
import qs.Config
import qs.Helpers
CustomRect {
id: root
}
-55
View File
@@ -1,55 +0,0 @@
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Modules as Modules
import qs.Config
import qs.Helpers
CustomRect {
id: root
ColumnLayout {
id: clayout
anchors.fill: parent
Settings {
name: "apps"
}
Item {
}
}
component Settings: CustomRect {
id: settingsItem
required property string name
implicitHeight: 42
implicitWidth: 200
radius: 4
RowLayout {
id: layout
anchors.left: parent.left
anchors.margins: Appearance.padding.smaller
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
CustomText {
id: text
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.fillHeight: true
Layout.fillWidth: true
Layout.leftMargin: Appearance.spacing.normal
text: settingsItem.name
verticalAlignment: Text.AlignVCenter
}
}
}
}
-102
View File
@@ -1,102 +0,0 @@
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Controls
import qs.Components
import qs.Modules as Modules
import qs.Modules.Settings.Categories as Cat
import qs.Config
import qs.Helpers
Item {
id: root
property string currentCategory: "general"
readonly property real nonAnimHeight: view.implicitHeight + viewWrapper.anchors.margins * 2
readonly property real nonAnimWidth: view.implicitWidth + 500 + viewWrapper.anchors.margins * 2
required property PersistentProperties visibilities
implicitHeight: nonAnimHeight
implicitWidth: nonAnimWidth
Connections {
function onCurrentCategoryChanged() {
stack.pop();
if (currentCategory === "general") {
stack.push(general);
} else if (currentCategory === "wallpaper") {
stack.push(background);
} else if (currentCategory === "appearance") {
stack.push(appearance);
}
}
target: root
}
ClippingRectangle {
id: viewWrapper
anchors.fill: parent
anchors.margins: Appearance.padding.smaller
color: "transparent"
Item {
id: view
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.top: parent.top
implicitHeight: layout.implicitHeight
implicitWidth: layout.implicitWidth
Categories {
id: layout
anchors.fill: parent
content: root
}
}
CustomClippingRect {
id: categoryContent
anchors.bottom: parent.bottom
anchors.left: view.right
anchors.leftMargin: Appearance.spacing.smaller
anchors.right: parent.right
anchors.top: parent.top
color: DynamicColors.tPalette.m3surfaceContainer
radius: 4
StackView {
id: stack
anchors.fill: parent
anchors.margins: Appearance.padding.smaller
initialItem: general
}
}
}
Component {
id: general
Cat.General {
}
}
Component {
id: background
Cat.Background {
}
}
Component {
id: appearance
Cat.Appearance {
}
}
}
@@ -1,36 +0,0 @@
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
RowLayout {
id: root
required property string name
required property var object
required property string setting
Layout.fillWidth: true
Layout.preferredHeight: 42
CustomText {
id: text
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
font.pointSize: 16
text: root.name
}
CustomSwitch {
id: cswitch
Layout.alignment: Qt.AlignRight
checked: root.object[root.setting]
onToggled: {
root.object[root.setting] = checked;
Config.save();
}
}
}
-11
View File
@@ -1,11 +0,0 @@
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Modules as Modules
import qs.Config
import qs.Helpers
Item {
}
-61
View File
@@ -1,61 +0,0 @@
import Quickshell
import QtQuick
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
required property var panels
required property PersistentProperties visibilities
implicitHeight: 0
implicitWidth: content.implicitWidth
visible: height > 0
states: State {
name: "visible"
when: root.visibilities.settings
PropertyChanges {
root.implicitHeight: content.implicitHeight
}
}
transitions: [
Transition {
from: ""
to: "visible"
Anim {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
property: "implicitHeight"
target: root
}
},
Transition {
from: "visible"
to: ""
Anim {
easing.bezierCurve: MaterialEasing.expressiveEffects
property: "implicitHeight"
target: root
}
}
]
Loader {
id: content
active: true
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
visible: true
sourceComponent: Content {
visibilities: root.visibilities
}
}
}
Binary file not shown.