mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-18 09:14:01 -04:00
widgets: share the lock editor with the desktop, adjust overlapping
face, share desktop clock widget with lock screen
This commit is contained in:
+1
-1
Submodule dank-qml-common updated: f5522736ed...149337aa6c
Generated
+3
-3
@@ -3,11 +3,11 @@
|
||||
"dank-qml-common": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1791150538,
|
||||
"narHash": "sha256-kqGf7c/98Fovm2ff7N9wffgBF0XMPLUHPLBRACJZ2wQ=",
|
||||
"lastModified": 1791166878,
|
||||
"narHash": "sha256-Ab3lkXkTOAiRpt3yuLb+5VpybO3ut8l0+/2Hq7VVBdk=",
|
||||
"owner": "AvengeMedia",
|
||||
"repo": "dank-qml-common",
|
||||
"rev": "f5522736ed2691484b5aa455bb1447c2b42415f4",
|
||||
"rev": "149337aa6c88a1a2360343ba9aef2d6954265746",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -735,7 +735,7 @@ function migrateLockScreenWidgets(settings) {
|
||||
if (present("lockScreenShowTime"))
|
||||
byId("lock_clock").enabled = !!settings.lockScreenShowTime;
|
||||
if (present("lockScreenClockStyle"))
|
||||
byId("lock_clock").config.style = settings.lockScreenClockStyle;
|
||||
byId("lock_clock").config.style = settings.lockScreenClockStyle === "vertical" ? "overlap" : "digital";
|
||||
if (present("lockScreenShowDate"))
|
||||
byId("lock_date").enabled = !!settings.lockScreenShowDate;
|
||||
byId("lock_auth").config.profileVisibility = settings.lockScreenShowProfileImage === false ? "never" : "always";
|
||||
|
||||
@@ -61,6 +61,8 @@ Item {
|
||||
|
||||
DesktopWidgetLayer {}
|
||||
|
||||
DesktopWidgetEditor {}
|
||||
|
||||
Lock {
|
||||
id: lock
|
||||
}
|
||||
|
||||
@@ -1874,6 +1874,11 @@ Item {
|
||||
return enabledBool ? `DESKTOP_WIDGET_SYNC_POSITION_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_SYNC_POSITION_DISABLED: ${instanceId}`;
|
||||
}
|
||||
|
||||
function edit(): string {
|
||||
DesktopWidgetRegistry.editing = true;
|
||||
return "DESKTOP_WIDGET_EDITOR_OPENED";
|
||||
}
|
||||
|
||||
target: "desktopWidget"
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import "../../DankCommon/Common/Hct.js" as Hct
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@@ -12,85 +13,140 @@ Item {
|
||||
|
||||
property string instanceId: ""
|
||||
property var instanceData: null
|
||||
property bool lockScreen: false
|
||||
property var lockHost: null
|
||||
readonly property var cfg: instanceData?.config ?? ({})
|
||||
|
||||
property string clockStyle: cfg.style ?? "analog"
|
||||
property bool forceSquare: clockStyle === "analog"
|
||||
readonly property string face: {
|
||||
switch (cfg.style ?? "analog") {
|
||||
case "analog":
|
||||
case "stacked":
|
||||
case "expressive":
|
||||
case "overlap":
|
||||
return cfg.style;
|
||||
}
|
||||
return "digital";
|
||||
}
|
||||
readonly property bool analog: face === "analog"
|
||||
readonly property bool resizable: true
|
||||
property bool forceSquare: analog
|
||||
readonly property real defaultScale: lockScreen ? 1.75 : 1
|
||||
|
||||
property real defaultWidth: {
|
||||
switch (clockStyle) {
|
||||
function baseWidth() {
|
||||
switch (face) {
|
||||
case "analog":
|
||||
return 200;
|
||||
case "stacked":
|
||||
return 100;
|
||||
default:
|
||||
case "overlap":
|
||||
return 160;
|
||||
case "expressive":
|
||||
return 240;
|
||||
}
|
||||
return 160;
|
||||
}
|
||||
property real defaultHeight: {
|
||||
switch (clockStyle) {
|
||||
|
||||
function baseHeight() {
|
||||
switch (face) {
|
||||
case "analog":
|
||||
case "overlap":
|
||||
return 200;
|
||||
case "stacked":
|
||||
return 160;
|
||||
default:
|
||||
return 70;
|
||||
case "expressive":
|
||||
return 120;
|
||||
}
|
||||
return 70;
|
||||
}
|
||||
|
||||
property real defaultWidth: baseWidth() * defaultScale
|
||||
property real defaultHeight: baseHeight() * defaultScale
|
||||
property real minWidth: {
|
||||
switch (clockStyle) {
|
||||
switch (face) {
|
||||
case "analog":
|
||||
return 120;
|
||||
case "stacked":
|
||||
return 70;
|
||||
default:
|
||||
return 100;
|
||||
case "overlap":
|
||||
return 80;
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
property real minHeight: {
|
||||
switch (clockStyle) {
|
||||
switch (face) {
|
||||
case "analog":
|
||||
return 120;
|
||||
case "stacked":
|
||||
case "overlap":
|
||||
return 100;
|
||||
default:
|
||||
return 45;
|
||||
}
|
||||
return 45;
|
||||
}
|
||||
|
||||
enabled: instanceData?.enabled ?? true
|
||||
property real transparency: cfg.transparency ?? 0.8
|
||||
property string colorMode: cfg.colorMode ?? "primary"
|
||||
property color customColor: cfg.customColor ?? "#ffffff"
|
||||
property bool showDate: cfg.showDate ?? true
|
||||
property bool showAnalogNumbers: cfg.showAnalogNumbers ?? false
|
||||
|
||||
readonly property real scaleFactor: Math.min(width, height) / 200
|
||||
|
||||
readonly property color accentColor: {
|
||||
if (colorMode === "primary")
|
||||
return Theme.primary;
|
||||
if (colorMode === "secondary")
|
||||
return Theme.secondary;
|
||||
if (colorMode === "custom")
|
||||
return customColor;
|
||||
return Theme.primary;
|
||||
}
|
||||
|
||||
readonly property color handColor: accentColor
|
||||
readonly property color handColorDim: Theme.withAlpha(accentColor, 0.65)
|
||||
readonly property color textColor: Theme.onSurface
|
||||
readonly property color subtleTextColor: Theme.onSurfaceVariant
|
||||
readonly property color backgroundColor: Theme.withAlpha(Theme.hostSurface, root.transparency)
|
||||
|
||||
readonly property real transparency: cfg.transparency ?? (lockScreen ? 0 : 0.8)
|
||||
readonly property string colorMode: cfg.colorMode ?? (lockScreen ? "default" : "primary")
|
||||
readonly property color customColor: cfg.customColor ?? "#ffffff"
|
||||
readonly property bool showDate: cfg.showDate ?? !lockScreen
|
||||
readonly property bool twoTone: cfg.twoTone ?? lockScreen
|
||||
readonly property bool showAnalogNumbers: cfg.showAnalogNumbers ?? false
|
||||
readonly property bool showAnalogSeconds: cfg.showAnalogSeconds ?? true
|
||||
readonly property bool showDigitalSeconds: cfg.showDigitalSeconds ?? false
|
||||
readonly property bool needsSeconds: clockStyle === "analog" ? showAnalogSeconds : showDigitalSeconds
|
||||
readonly property string formattedDate: {
|
||||
if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0)
|
||||
return systemClock.date?.toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat) ?? "";
|
||||
return systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? "";
|
||||
readonly property bool italic: face === "digital" && (cfg.italic ?? false)
|
||||
readonly property string fontFamily: cfg.fontFamily || (lockScreen ? SettingsData.lockScreenFontFamily : "")
|
||||
readonly property int weight: cfg.weight ?? 0
|
||||
readonly property int digitWeight: weight > 0 ? weight : Theme.fontWeightMedium
|
||||
|
||||
readonly property color accentColor: {
|
||||
if (lockHost)
|
||||
return lockHost.contentColor(colorMode, customColor);
|
||||
switch (colorMode) {
|
||||
case "secondary":
|
||||
return Theme.secondary;
|
||||
case "custom":
|
||||
return customColor;
|
||||
}
|
||||
return Theme.primary;
|
||||
}
|
||||
readonly property color minutesColor: twoTone ? Theme.primary : accentColor
|
||||
readonly property color dimColor: Theme.withAlpha(accentColor, 0.65)
|
||||
readonly property color backgroundColor: Theme.withAlpha(Theme.hostSurface, transparency)
|
||||
readonly property bool themedOverlap: lockScreen && colorMode === "default"
|
||||
readonly property var primaryHct: Hct.toHct(Theme.primary)
|
||||
readonly property color overlapFaceColor: {
|
||||
if (!themedOverlap)
|
||||
return accentColor;
|
||||
return Theme.isLightMode ? Hct.fromHct(primaryHct.hue, primaryHct.chroma, 65) : Theme.accentOnPrimaryContainer;
|
||||
}
|
||||
readonly property color overlapShadowColor: {
|
||||
if (themedOverlap)
|
||||
return Theme.isLightMode ? Hct.fromHct(primaryHct.hue, primaryHct.chroma, 30) : Theme.primaryContainer;
|
||||
const source = Hct.toHct(accentColor);
|
||||
return Hct.fromHct(source.hue, source.chroma, source.tone > 50 ? 30 : 80);
|
||||
}
|
||||
readonly property var contrastColors: {
|
||||
switch (face) {
|
||||
case "overlap":
|
||||
return [overlapFaceColor, overlapShadowColor];
|
||||
case "digital":
|
||||
case "stacked":
|
||||
case "expressive":
|
||||
return [accentColor, minutesColor];
|
||||
}
|
||||
return [accentColor];
|
||||
}
|
||||
|
||||
readonly property bool needsSeconds: analog ? showAnalogSeconds : showDigitalSeconds
|
||||
readonly property string hoursText: {
|
||||
const hours = systemClock.date?.getHours() ?? 0;
|
||||
const display = SettingsData.use24HourClock ? hours : (hours % 12 || 12);
|
||||
return SettingsData.use24HourClock || SettingsData.padHours12Hour ? String(display).padStart(2, "0") : String(display);
|
||||
}
|
||||
readonly property string minutesText: String(systemClock.date?.getMinutes() ?? 0).padStart(2, "0")
|
||||
readonly property string secondsText: String(systemClock.date?.getSeconds() ?? 0).padStart(2, "0")
|
||||
readonly property string meridiem: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM"
|
||||
readonly property string dateFormat: lockScreen ? SettingsData.lockDateFormat : SettingsData.clockDateFormat
|
||||
readonly property string formattedDate: systemClock.date?.toLocaleDateString(I18n.locale(), dateFormat || "ddd, MMM d") ?? ""
|
||||
|
||||
SystemClock {
|
||||
id: systemClock
|
||||
@@ -106,21 +162,38 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
component DigitText: StyledText {
|
||||
font.weight: root.digitWeight
|
||||
font.italic: root.italic
|
||||
font.family: root.fontFamily !== "" ? root.fontFamily : resolvedFontFamily
|
||||
font.features: ({
|
||||
"tnum": 1
|
||||
})
|
||||
color: root.accentColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: root.backgroundColor
|
||||
visible: root.clockStyle !== "analog"
|
||||
visible: !root.analog
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
anchors.margins: root.clockStyle === "analog" ? 0 : Theme.spacingM
|
||||
anchors.margins: root.analog ? 0 : Theme.spacingM
|
||||
sourceComponent: {
|
||||
if (root.clockStyle === "analog")
|
||||
switch (root.face) {
|
||||
case "analog":
|
||||
return analogClock;
|
||||
if (root.clockStyle === "stacked")
|
||||
case "stacked":
|
||||
return stackedClock;
|
||||
case "expressive":
|
||||
return expressiveClock;
|
||||
case "overlap":
|
||||
return overlapClock;
|
||||
}
|
||||
return digitalClock;
|
||||
}
|
||||
}
|
||||
@@ -140,117 +213,125 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: expressiveClock
|
||||
|
||||
DankClockFace {
|
||||
readonly property bool tallBox: height > width * 0.6
|
||||
|
||||
hours: root.hoursText
|
||||
minutes: root.minutesText
|
||||
seconds: root.showDigitalSeconds && !tallBox ? root.secondsText : ""
|
||||
dateText: root.showDate ? root.formattedDate : ""
|
||||
stacked: tallBox
|
||||
color: root.accentColor
|
||||
minutesColor: root.minutesColor
|
||||
supportingColor: root.dimColor
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: overlapClock
|
||||
|
||||
Item {
|
||||
DankOverlapClockFace {
|
||||
anchors.centerIn: parent
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
hours: root.hoursText
|
||||
minutes: root.minutesText
|
||||
color: root.overlapFaceColor
|
||||
shadowColor: root.overlapShadowColor
|
||||
fontFamily: root.fontFamily
|
||||
weight: root.weight > 0 ? root.weight : 1000
|
||||
scale: implicitWidth > 0 && implicitHeight > 0 ? Math.min(parent.width / implicitWidth, parent.height / implicitHeight) : 1
|
||||
renderScale: scale
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: digitalClock
|
||||
|
||||
Item {
|
||||
id: digitalRoot
|
||||
|
||||
property bool hasDate: root.showDate
|
||||
property bool hasAmPm: !SettingsData.use24HourClock
|
||||
property real verticalScale: hasDate && hasAmPm ? 0.55 : (hasDate || hasAmPm ? 0.65 : 0.8)
|
||||
property real baseSize: Math.min(height * verticalScale, width * 0.22)
|
||||
property real digitWidth: baseSize * 0.62
|
||||
property real smallSize: baseSize * 0.35
|
||||
|
||||
property string hoursStr: {
|
||||
const hours = SettingsData.use24HourClock ? systemClock.date?.getHours() ?? 0 : ((systemClock.date?.getHours() ?? 0) % 12 || 12);
|
||||
if (SettingsData.use24HourClock || SettingsData.padHours12Hour)
|
||||
return String(hours).padStart(2, '0');
|
||||
return String(hours);
|
||||
}
|
||||
property string minutesStr: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0')
|
||||
property string secondsStr: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0')
|
||||
readonly property bool hasAmPm: !SettingsData.use24HourClock
|
||||
readonly property real verticalScale: root.showDate && hasAmPm ? 0.55 : (root.showDate || hasAmPm ? 0.65 : 0.8)
|
||||
readonly property real baseSize: Math.min(height * verticalScale, width * 0.22)
|
||||
readonly property real digitWidth: baseSize * 0.62
|
||||
readonly property real smallSize: baseSize * 0.35
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 0
|
||||
|
||||
StyledText {
|
||||
DigitText {
|
||||
visible: root.showDate
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: root.formattedDate
|
||||
font.pixelSize: digitalRoot.smallSize
|
||||
color: Theme.withAlpha(root.accentColor, 0.7)
|
||||
color: root.dimColor
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 0
|
||||
|
||||
StyledText {
|
||||
visible: digitalRoot.hoursStr.length > 1
|
||||
width: digitalRoot.digitWidth
|
||||
text: digitalRoot.hoursStr.charAt(0)
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: root.accentColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Repeater {
|
||||
model: root.hoursText.split("")
|
||||
|
||||
DigitText {
|
||||
required property string modelData
|
||||
width: digitalRoot.digitWidth
|
||||
text: modelData
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
}
|
||||
}
|
||||
StyledText {
|
||||
width: digitalRoot.digitWidth
|
||||
text: digitalRoot.hoursStr.length > 1 ? digitalRoot.hoursStr.charAt(1) : digitalRoot.hoursStr.charAt(0)
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: root.accentColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
StyledText {
|
||||
|
||||
DigitText {
|
||||
text: ":"
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: root.accentColor
|
||||
}
|
||||
StyledText {
|
||||
width: digitalRoot.digitWidth
|
||||
text: digitalRoot.minutesStr.charAt(0)
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: root.accentColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
Repeater {
|
||||
model: root.minutesText.split("")
|
||||
|
||||
DigitText {
|
||||
required property string modelData
|
||||
width: digitalRoot.digitWidth
|
||||
text: modelData
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
color: root.minutesColor
|
||||
}
|
||||
}
|
||||
StyledText {
|
||||
width: digitalRoot.digitWidth
|
||||
text: digitalRoot.minutesStr.charAt(1)
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: root.accentColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
StyledText {
|
||||
|
||||
DigitText {
|
||||
visible: root.showDigitalSeconds
|
||||
text: ":"
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.withAlpha(root.accentColor, 0.7)
|
||||
color: root.dimColor
|
||||
}
|
||||
StyledText {
|
||||
visible: root.showDigitalSeconds
|
||||
width: digitalRoot.digitWidth
|
||||
text: digitalRoot.secondsStr.charAt(0)
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.withAlpha(root.accentColor, 0.7)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
StyledText {
|
||||
visible: root.showDigitalSeconds
|
||||
width: digitalRoot.digitWidth
|
||||
text: digitalRoot.secondsStr.charAt(1)
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.withAlpha(root.accentColor, 0.7)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
Repeater {
|
||||
model: root.showDigitalSeconds ? root.secondsText.split("") : []
|
||||
|
||||
DigitText {
|
||||
required property string modelData
|
||||
width: digitalRoot.digitWidth
|
||||
text: modelData
|
||||
font.pixelSize: digitalRoot.baseSize
|
||||
color: root.dimColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
visible: !SettingsData.use24HourClock
|
||||
DigitText {
|
||||
visible: digitalRoot.hasAmPm
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM"
|
||||
text: root.meridiem
|
||||
font.pixelSize: digitalRoot.smallSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.withAlpha(root.accentColor, 0.7)
|
||||
color: root.dimColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,14 +343,12 @@ Item {
|
||||
Item {
|
||||
id: stackedRoot
|
||||
|
||||
property bool hasSeconds: root.showDigitalSeconds
|
||||
property bool hasDate: root.showDate
|
||||
property bool hasAmPm: !SettingsData.use24HourClock
|
||||
property real extraContent: (hasSeconds ? 0.12 : 0) + (hasDate ? 0.08 : 0) + (hasAmPm ? 0.08 : 0)
|
||||
property real baseSize: height * (0.42 - extraContent * 0.5)
|
||||
property real digitWidth: baseSize * 0.58
|
||||
property real smallSize: baseSize * 0.5
|
||||
property real rowSpacing: -baseSize * 0.17
|
||||
readonly property bool hasAmPm: !SettingsData.use24HourClock
|
||||
readonly property real extraContent: (root.showDigitalSeconds ? 0.12 : 0) + (root.showDate ? 0.08 : 0) + (hasAmPm ? 0.08 : 0)
|
||||
readonly property real baseSize: height * (0.42 - extraContent * 0.5)
|
||||
readonly property real digitWidth: baseSize * 0.58
|
||||
readonly property real smallSize: baseSize * 0.5
|
||||
readonly property real rowSpacing: -baseSize * 0.17
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
@@ -283,34 +362,15 @@ Item {
|
||||
spacing: 0
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (SettingsData.use24HourClock)
|
||||
return String(systemClock.date?.getHours() ?? 0).padStart(2, '0').charAt(0);
|
||||
const hours = systemClock.date?.getHours() ?? 0;
|
||||
const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
|
||||
return String(display).padStart(2, '0').charAt(0);
|
||||
}
|
||||
font.pixelSize: stackedRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: root.accentColor
|
||||
width: stackedRoot.digitWidth
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
Repeater {
|
||||
model: root.hoursText.padStart(2, "0").split("")
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (SettingsData.use24HourClock)
|
||||
return String(systemClock.date?.getHours() ?? 0).padStart(2, '0').charAt(1);
|
||||
const hours = systemClock.date?.getHours() ?? 0;
|
||||
const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
|
||||
return String(display).padStart(2, '0').charAt(1);
|
||||
DigitText {
|
||||
required property string modelData
|
||||
width: stackedRoot.digitWidth
|
||||
text: modelData
|
||||
font.pixelSize: stackedRoot.baseSize
|
||||
}
|
||||
font.pixelSize: stackedRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: root.accentColor
|
||||
width: stackedRoot.digitWidth
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,71 +378,58 @@ Item {
|
||||
spacing: 0
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0').charAt(0)
|
||||
font.pixelSize: stackedRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: root.accentColor
|
||||
width: stackedRoot.digitWidth
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
Repeater {
|
||||
model: root.minutesText.split("")
|
||||
|
||||
StyledText {
|
||||
text: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0').charAt(1)
|
||||
font.pixelSize: stackedRoot.baseSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: root.accentColor
|
||||
width: stackedRoot.digitWidth
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
DigitText {
|
||||
required property string modelData
|
||||
width: stackedRoot.digitWidth
|
||||
text: modelData
|
||||
font.pixelSize: stackedRoot.baseSize
|
||||
color: root.minutesColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
visible: stackedRoot.hasSeconds
|
||||
visible: root.showDigitalSeconds
|
||||
spacing: 0
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0').charAt(0)
|
||||
font.pixelSize: stackedRoot.smallSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.withAlpha(root.accentColor, 0.7)
|
||||
width: stackedRoot.smallSize * 0.58
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
Repeater {
|
||||
model: root.showDigitalSeconds ? root.secondsText.split("") : []
|
||||
|
||||
StyledText {
|
||||
text: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0').charAt(1)
|
||||
font.pixelSize: stackedRoot.smallSize
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.withAlpha(root.accentColor, 0.7)
|
||||
width: stackedRoot.smallSize * 0.58
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
DigitText {
|
||||
required property string modelData
|
||||
width: stackedRoot.smallSize * 0.58
|
||||
text: modelData
|
||||
font.pixelSize: stackedRoot.smallSize
|
||||
color: root.dimColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 1
|
||||
height: stackedRoot.baseSize * 0.1
|
||||
visible: stackedRoot.hasDate
|
||||
visible: root.showDate
|
||||
}
|
||||
|
||||
StyledText {
|
||||
visible: stackedRoot.hasDate
|
||||
DigitText {
|
||||
visible: root.showDate
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: systemClock.date?.toLocaleDateString(I18n.locale(), "MMM dd") ?? ""
|
||||
font.pixelSize: stackedRoot.smallSize * 0.7
|
||||
color: Theme.withAlpha(root.accentColor, 0.7)
|
||||
color: root.dimColor
|
||||
}
|
||||
|
||||
StyledText {
|
||||
DigitText {
|
||||
visible: stackedRoot.hasAmPm
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM"
|
||||
text: root.meridiem
|
||||
font.pixelSize: stackedRoot.smallSize * 0.7
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.withAlpha(root.accentColor, 0.7)
|
||||
color: root.dimColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Modules.Plugins
|
||||
|
||||
Scope {
|
||||
Variants {
|
||||
model: DesktopWidgetRegistry.editing ? Quickshell.screens : []
|
||||
|
||||
PanelWindow {
|
||||
id: editorWindow
|
||||
|
||||
required property var modelData
|
||||
|
||||
screen: modelData
|
||||
visible: true
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
|
||||
WlrLayershell.namespace: "dms:desktop-widget-editor"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||
|
||||
color: "transparent"
|
||||
|
||||
FocusScope {
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (widgetLayer.handleKey(event))
|
||||
event.accepted = true;
|
||||
}
|
||||
Keys.onEscapePressed: overlay.dismiss()
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Theme.scrimColor
|
||||
opacity: Theme.scrimAlpha
|
||||
}
|
||||
|
||||
WidgetEditLayer {
|
||||
id: widgetLayer
|
||||
anchors.fill: parent
|
||||
screenName: editorWindow.screen?.name ?? ""
|
||||
editMode: true
|
||||
bottomInset: overlay.fabReserved
|
||||
onOptionsRequested: instanceData => overlay.showOptions(instanceData)
|
||||
}
|
||||
|
||||
WidgetEditorOverlay {
|
||||
id: overlay
|
||||
anchors.fill: parent
|
||||
editLayer: widgetLayer
|
||||
onFinished: DesktopWidgetRegistry.editing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ Variants {
|
||||
}
|
||||
|
||||
readonly property bool shouldBeVisible: {
|
||||
if (!liveInstanceData.enabled)
|
||||
if (!liveInstanceData.enabled || DesktopWidgetRegistry.editing)
|
||||
return false;
|
||||
const prefs = liveInstanceData.config?.displayPreferences ?? ["all"];
|
||||
return DesktopWidgetRegistry.showsOnScreen(prefs, screenDelegate.screen);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import QtQuick
|
||||
import QtQuick.Window
|
||||
import "LockPlacement.js" as Placement
|
||||
import "../../Common/WidgetPlacement.js" as Placement
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
@@ -4,11 +4,7 @@ import QtQuick
|
||||
import QtQuick.Window
|
||||
import qs.Common
|
||||
import qs.Modals
|
||||
import qs.Modules.ControlCenter.Widgets
|
||||
import qs.Modules.DankDash.Overview
|
||||
import qs.Modules.Plugins
|
||||
import qs.Modules.Settings.DesktopWidgetSettings
|
||||
import qs.Modules.Settings.Widgets
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.DankCommon.Session
|
||||
@@ -75,12 +71,6 @@ FocusScope {
|
||||
return Theme.lockScreenContentColor;
|
||||
}
|
||||
|
||||
function addLockWidget(widgetType) {
|
||||
const def = DesktopWidgetRegistry.getWidget(widgetType);
|
||||
const instance = SettingsData.createDesktopWidgetInstance(widgetType, def?.name ?? widgetType, DesktopWidgetRegistry.getDefaultConfig(widgetType), "lockScreenWidgetInstances");
|
||||
widgetLayer.pendingIds = widgetLayer.pendingIds.concat([instance.id]);
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
WeatherService.addRef();
|
||||
UserInfoService.getUserInfo();
|
||||
@@ -154,31 +144,17 @@ FocusScope {
|
||||
screenName: root.screenName
|
||||
}
|
||||
|
||||
// Grid keys live here because a selected widget holds active focus inside the layer, not the editor.
|
||||
Keys.onPressed: event => {
|
||||
if (!demoMode)
|
||||
return;
|
||||
switch (event.key) {
|
||||
case Qt.Key_G:
|
||||
widgetLayer.toggleGrid();
|
||||
break;
|
||||
case Qt.Key_Z:
|
||||
widgetLayer.stepGrid(-10);
|
||||
break;
|
||||
case Qt.Key_X:
|
||||
widgetLayer.stepGrid(10);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
event.accepted = true;
|
||||
if (widgetLayer.handleKey(event))
|
||||
event.accepted = true;
|
||||
}
|
||||
|
||||
LockWidgetLayer {
|
||||
WidgetEditLayer {
|
||||
id: widgetLayer
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
screenName: root.screenName
|
||||
lockScreen: true
|
||||
lockHost: root
|
||||
editMode: root.demoMode
|
||||
bottomInset: editorLoader.item?.fabReserved ?? 0
|
||||
@@ -229,112 +205,9 @@ FocusScope {
|
||||
anchors.fill: parent
|
||||
active: root.demoMode
|
||||
|
||||
sourceComponent: FocusScope {
|
||||
id: editor
|
||||
|
||||
property bool libraryOpen: false
|
||||
readonly property real fabReserved: fabBar.reservedHeight
|
||||
|
||||
function closeLibrary() {
|
||||
libraryOpen = false;
|
||||
forceActiveFocus();
|
||||
}
|
||||
|
||||
function showOptions(instanceData) {
|
||||
optionsSheet.instanceId = instanceData?.id ?? "";
|
||||
optionsSheet.opened = true;
|
||||
}
|
||||
|
||||
focus: true
|
||||
Component.onCompleted: forceActiveFocus()
|
||||
|
||||
Keys.onEscapePressed: {
|
||||
if (editControls.pendingAction !== "") {
|
||||
editControls.cancelConfirmation();
|
||||
return;
|
||||
}
|
||||
if (libraryOpen) {
|
||||
closeLibrary();
|
||||
return;
|
||||
}
|
||||
root.unlockRequested();
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
visible: editor.libraryOpen
|
||||
acceptedButtons: Qt.AllButtons
|
||||
onClicked: editor.closeLibrary()
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: editor.libraryOpen
|
||||
|
||||
sourceComponent: CcWidgetLibrary {
|
||||
width: Math.min(implicitWidth, editor.width - Theme.spacingL * 2)
|
||||
height: Math.min(implicitHeight, editor.height - Theme.spacingL * 2)
|
||||
widgets: DesktopWidgetRegistry.registeredWidgetsList.filter(widget => widget.id !== "lockAuth" || !SettingsData.lockWidgetInstance("lockAuth")).map(widget => ({
|
||||
id: widget.id,
|
||||
text: widget.name,
|
||||
icon: widget.icon,
|
||||
description: widget.description
|
||||
}))
|
||||
Component.onCompleted: reset()
|
||||
onChosen: widgetId => {
|
||||
root.addLockWidget(widgetId);
|
||||
editor.closeLibrary();
|
||||
}
|
||||
onDismissed: editor.closeLibrary()
|
||||
}
|
||||
}
|
||||
|
||||
DankBottomSheet {
|
||||
id: optionsSheet
|
||||
|
||||
property string instanceId: ""
|
||||
readonly property var instanceData: SettingsData.getDesktopWidgetInstance(instanceId)
|
||||
readonly property var widgetDef: DesktopWidgetRegistry.getWidget(instanceData?.widgetType ?? "")
|
||||
|
||||
maximumWidth: Math.min(Theme.mediumBreakpoint, editor.width - Theme.spacingXL * 2)
|
||||
topMargin: editor.height * 0.3
|
||||
returnFocusItem: editor
|
||||
title: instanceData?.name || widgetDef?.name || ""
|
||||
onDismissRequested: opened = false
|
||||
onActiveChanged: {
|
||||
if (!active)
|
||||
instanceId = "";
|
||||
}
|
||||
|
||||
DesktopWidgetTypeSettings {
|
||||
width: parent.width
|
||||
instanceId: optionsSheet.instanceId
|
||||
instanceData: optionsSheet.instanceData
|
||||
widgetDef: optionsSheet.widgetDef
|
||||
}
|
||||
}
|
||||
|
||||
DesktopWidgetGridHint {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: fabBar.reservedHeight + Theme.spacingL
|
||||
visible: fabBar.shown && (widgetLayer.selectedInstanceId !== "" || widgetLayer.interactingItem !== null)
|
||||
gridEnabled: widgetLayer.gridEnabled
|
||||
gridSize: widgetLayer.gridSize
|
||||
}
|
||||
|
||||
SettingsFabBar {
|
||||
id: fabBar
|
||||
shown: !editor.libraryOpen && !optionsSheet.active
|
||||
|
||||
DashEditControls {
|
||||
id: editControls
|
||||
canClear: false
|
||||
onAddRequested: editor.libraryOpen = true
|
||||
onResetRequested: SettingsData.resetLockScreenWidgets()
|
||||
onFinished: root.unlockRequested()
|
||||
}
|
||||
}
|
||||
sourceComponent: WidgetEditorOverlay {
|
||||
editLayer: widgetLayer
|
||||
onFinished: root.unlockRequested()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,267 +0,0 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
import qs.DankCommon.Session
|
||||
import "../../../DankCommon/Common/Hct.js" as Hct
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var instanceData: null
|
||||
property var lockHost: null
|
||||
readonly property var cfg: instanceData?.config ?? ({})
|
||||
readonly property string style: cfg.style ?? "expressive"
|
||||
readonly property bool textStyle: style === "horizontal" || style === "vertical"
|
||||
readonly property string colorMode: cfg.colorMode ?? "default"
|
||||
readonly property var primaryHct: Hct.toHct(Theme.primary)
|
||||
readonly property color shadowFaceColor: {
|
||||
if (colorMode !== "default")
|
||||
return contentColor;
|
||||
return Theme.isLightMode ? Hct.fromHct(primaryHct.hue, primaryHct.chroma, 65) : Theme.accentOnPrimaryContainer;
|
||||
}
|
||||
readonly property color shadowColor: {
|
||||
if (colorMode === "default")
|
||||
return Theme.isLightMode ? Hct.fromHct(primaryHct.hue, primaryHct.chroma, 30) : Theme.primaryContainer;
|
||||
const source = Hct.toHct(shadowFaceColor);
|
||||
return Hct.fromHct(source.hue, source.chroma, source.tone > 50 ? 30 : 80);
|
||||
}
|
||||
readonly property int weightOverride: cfg.weight ?? 0
|
||||
readonly property int digitWeight: weightOverride > 0 ? weightOverride : Theme.fontWeight
|
||||
readonly property color contentColor: lockHost?.contentColor(cfg.colorMode ?? "default", cfg.customColor ?? "#ffffff") ?? Theme.lockScreenContentColor
|
||||
readonly property string fontFamily: cfg.fontFamily || SettingsData.lockScreenFontFamily
|
||||
readonly property color minutesColor: (cfg.twoTone ?? true) ? Theme.primary : contentColor
|
||||
readonly property var contrastColors: style === "vertical" ? [shadowFaceColor, shadowColor] : style === "horizontal" || style === "expressive" ? [contentColor, minutesColor] : [contentColor]
|
||||
readonly property real clockSize: LockMetrics.clockSize * (style === "horizontal" ? 1.5 : 1)
|
||||
readonly property real clockDigitWidth: clockSize * 0.625
|
||||
|
||||
readonly property bool resizable: true
|
||||
readonly property bool forceSquare: style === "analog"
|
||||
readonly property real boxWidth: style === "analog" ? LockMetrics.clockSize * 2 : LockMetrics.clockSize * 4
|
||||
readonly property real boxHeight: style === "analog" ? LockMetrics.clockSize * 2 : LockMetrics.clockSize * 1.4
|
||||
readonly property real naturalWidth: face.item?.implicitWidth ?? 0
|
||||
readonly property real naturalHeight: face.item?.implicitHeight ?? 0
|
||||
readonly property real defaultWidth: textStyle ? naturalWidth : boxWidth
|
||||
readonly property real defaultHeight: textStyle ? naturalHeight : boxHeight
|
||||
readonly property real minWidth: textStyle ? naturalWidth / 2 : LockMetrics.fieldHeight * 2
|
||||
readonly property real minHeight: textStyle ? naturalHeight / 2 : LockMetrics.fieldHeight
|
||||
readonly property real fitScale: textStyle && naturalWidth > 0 && naturalHeight > 0 ? Math.min(width / naturalWidth, height / naturalHeight) : 1
|
||||
|
||||
implicitWidth: textStyle ? naturalWidth : boxWidth
|
||||
implicitHeight: textStyle ? naturalHeight : boxHeight
|
||||
|
||||
component ClockDigitText: StyledText {
|
||||
font.pixelSize: root.clockSize
|
||||
font.weight: root.digitWeight
|
||||
font.italic: root.cfg.italic ?? false
|
||||
font.features: ({
|
||||
"tnum": 1
|
||||
})
|
||||
color: root.contentColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.family: root.fontFamily !== "" ? root.fontFamily : resolvedFontFamily
|
||||
}
|
||||
|
||||
SystemClock {
|
||||
id: systemClock
|
||||
precision: (root.style === "analog" ? (root.cfg.showAnalogSeconds ?? true) : SettingsData.getEffectiveTimeFormat().includes("s")) ? SystemClock.Seconds : SystemClock.Minutes
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: time
|
||||
|
||||
readonly property string ampm: SettingsData.use24HourClock ? "" : systemClock.date.toLocaleTimeString(I18n.locale(), "AP")
|
||||
readonly property string hours: {
|
||||
const format = SettingsData.use24HourClock || SettingsData.padHours12Hour ? "hh" : "h";
|
||||
const text = systemClock.date.toLocaleTimeString(I18n.locale(), ampm ? format + " AP" : format);
|
||||
return ampm ? text.replace(ampm, "").trim() : text;
|
||||
}
|
||||
readonly property string minutes: systemClock.date.toLocaleTimeString(I18n.locale(), "mm")
|
||||
readonly property string seconds: systemClock.date.toLocaleTimeString(I18n.locale(), "ss")
|
||||
readonly property bool hasSeconds: SettingsData.showSeconds
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: face
|
||||
anchors.fill: root.textStyle ? undefined : parent
|
||||
anchors.centerIn: root.textStyle ? parent : undefined
|
||||
width: root.textStyle ? root.naturalWidth : undefined
|
||||
height: root.textStyle ? root.naturalHeight : undefined
|
||||
scale: root.fitScale
|
||||
sourceComponent: {
|
||||
switch (root.style) {
|
||||
case "vertical":
|
||||
return shadowFace;
|
||||
case "expressive":
|
||||
return expressiveFace;
|
||||
case "analog":
|
||||
return analogFace;
|
||||
}
|
||||
return horizontalFace;
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: horizontalFace
|
||||
|
||||
Item {
|
||||
implicitWidth: row.implicitWidth
|
||||
implicitHeight: row.implicitHeight
|
||||
|
||||
Row {
|
||||
id: row
|
||||
anchors.centerIn: parent
|
||||
layoutDirection: Qt.LeftToRight
|
||||
spacing: 0
|
||||
|
||||
ClockDigitText {
|
||||
id: hourText
|
||||
text: time.hours + ":"
|
||||
}
|
||||
|
||||
ClockDigitText {
|
||||
text: time.minutes
|
||||
color: root.minutesColor
|
||||
}
|
||||
|
||||
ClockDigitText {
|
||||
text: ":" + time.seconds
|
||||
color: root.minutesColor
|
||||
visible: time.hasSeconds
|
||||
}
|
||||
|
||||
ClockDigitText {
|
||||
text: " " + time.ampm
|
||||
font.pixelSize: root.clockSize / 3
|
||||
anchors.baseline: hourText.baseline
|
||||
visible: time.ampm !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: shadowFace
|
||||
|
||||
Item {
|
||||
id: shadowItem
|
||||
|
||||
readonly property real digitSize: root.clockSize * 1.25
|
||||
readonly property real tracking: -digitSize * 0.1
|
||||
readonly property real rowAdvance: digitSize * 0.7
|
||||
readonly property int weight: root.weightOverride > 0 ? root.weightOverride : 1000
|
||||
readonly property bool variableFont: root.fontFamily === "" || root.fontFamily === Theme.defaultFontFamily
|
||||
// One cell width for all four glyphs keeps the columns aligned in fonts without tabular figures.
|
||||
readonly property real cellWidth: Math.max(hoursRow.firstAdvance, hoursRow.secondAdvance, minutesRow.firstAdvance, minutesRow.secondAdvance)
|
||||
implicitWidth: Math.max(hoursRow.width, minutesRow.width)
|
||||
implicitHeight: Math.max(hoursRow.height, minutesRow.y + minutesRow.height)
|
||||
|
||||
ShadowRow {
|
||||
id: hoursRow
|
||||
x: (shadowItem.width - shadowItem.implicitWidth) / 2
|
||||
text: time.hours.padStart(2, "0")
|
||||
}
|
||||
|
||||
ShadowRow {
|
||||
id: minutesRow
|
||||
x: hoursRow.x
|
||||
y: hoursRow.baselineOffset + shadowItem.rowAdvance - baselineOffset
|
||||
text: time.minutes
|
||||
lightFirst: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component ClockDigit: StyledText {
|
||||
id: digit
|
||||
|
||||
readonly property rect inkBounds: metrics.tightBoundingRect
|
||||
readonly property real advanceWidth: metrics.advanceWidth
|
||||
|
||||
font.pixelSize: shadowItem.digitSize
|
||||
font.family: root.fontFamily !== "" ? root.fontFamily : Theme.defaultFontFamily
|
||||
font.weight: shadowItem.variableFont ? Font.Normal : Math.min(Font.Black, shadowItem.weight)
|
||||
font.variableAxes: shadowItem.variableFont ? {
|
||||
"wght": shadowItem.weight,
|
||||
"ROND": 0,
|
||||
"opsz": 18
|
||||
} : ({})
|
||||
font.features: ({
|
||||
"tnum": 1
|
||||
})
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.NoWrap
|
||||
elide: Text.ElideNone
|
||||
verticalAlignment: Text.AlignTop
|
||||
|
||||
TextMetrics {
|
||||
id: metrics
|
||||
font: digit.font
|
||||
text: digit.text
|
||||
renderType: digit.renderType
|
||||
}
|
||||
}
|
||||
|
||||
component ShadowRow: Item {
|
||||
id: shadowRow
|
||||
|
||||
property string text: ""
|
||||
property bool lightFirst: false
|
||||
readonly property real firstAdvance: firstDigit.advanceWidth
|
||||
readonly property real secondAdvance: secondDigit.advanceWidth
|
||||
readonly property real cell: shadowItem.cellWidth
|
||||
readonly property real topBearing: Math.min(firstDigit.inkBounds.y, secondDigit.inkBounds.y)
|
||||
readonly property real bottomBearing: Math.max(firstDigit.inkBounds.y + firstDigit.inkBounds.height, secondDigit.inkBounds.y + secondDigit.inkBounds.height)
|
||||
|
||||
implicitWidth: cell * 2 + shadowItem.tracking
|
||||
implicitHeight: bottomBearing - topBearing
|
||||
baselineOffset: -topBearing
|
||||
|
||||
ClockDigit {
|
||||
id: firstDigit
|
||||
x: (shadowRow.cell - advanceWidth) / 2
|
||||
y: shadowRow.baselineOffset - baselineOffset
|
||||
text: shadowRow.text[0] ?? ""
|
||||
color: shadowRow.lightFirst ? root.shadowFaceColor : root.shadowColor
|
||||
}
|
||||
|
||||
ClockDigit {
|
||||
id: secondDigit
|
||||
x: shadowRow.cell + shadowItem.tracking + (shadowRow.cell - advanceWidth) / 2
|
||||
y: shadowRow.baselineOffset - baselineOffset
|
||||
text: shadowRow.text[1] ?? ""
|
||||
color: shadowRow.lightFirst ? root.shadowColor : root.shadowFaceColor
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: expressiveFace
|
||||
|
||||
DankClockFace {
|
||||
readonly property bool tallBox: height > width * 0.6
|
||||
|
||||
hours: time.hours
|
||||
minutes: time.minutes
|
||||
seconds: time.hasSeconds && !tallBox ? time.seconds : ""
|
||||
stacked: tallBox
|
||||
color: root.contentColor
|
||||
minutesColor: root.minutesColor
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: analogFace
|
||||
|
||||
DankAnalogClock {
|
||||
hours: systemClock.date?.getHours() ?? 0
|
||||
minutes: systemClock.date?.getMinutes() ?? 0
|
||||
seconds: systemClock.date?.getSeconds() ?? 0
|
||||
showSeconds: root.cfg.showAnalogSeconds ?? true
|
||||
showNumbers: root.cfg.showAnalogNumbers ?? false
|
||||
color: root.contentColor
|
||||
backgroundColor: "transparent"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@@ -55,15 +52,6 @@ Item {
|
||||
forceSquare: content.contentForceSquare
|
||||
}
|
||||
|
||||
readonly property bool useGhostPreview: !CompositorService.isNiri
|
||||
|
||||
property real previewX: geometry.widgetX
|
||||
property real previewY: geometry.widgetY
|
||||
property real previewWidth: geometry.widgetWidth
|
||||
property real previewHeight: geometry.widgetHeight
|
||||
|
||||
property bool isInteracting: dragArea.pressed || resizeArea.pressed
|
||||
|
||||
PanelWindow {
|
||||
id: widgetWindow
|
||||
screen: root.screen
|
||||
@@ -78,8 +66,6 @@ Item {
|
||||
|
||||
WlrLayershell.namespace: "dms:desktop-widget:" + root.pluginId + (root.instanceId ? ":" + root.instanceId : "")
|
||||
WlrLayershell.layer: {
|
||||
if (root.isInteracting && !CompositorService.useHyprlandFocusGrab)
|
||||
return WlrLayer.Overlay;
|
||||
if (root.showOnOverlay)
|
||||
return WlrLayer.Overlay;
|
||||
if (root.overviewActive && (root.showOnOverview || root.showOnOverviewOnly))
|
||||
@@ -90,45 +76,11 @@ Item {
|
||||
WlrLayershell.keyboardFocus: {
|
||||
if (PopoutManager.screenshotActive)
|
||||
return WlrKeyboardFocus.None;
|
||||
if (root.isInteracting) {
|
||||
if (CompositorService.useHyprlandFocusGrab)
|
||||
return WlrKeyboardFocus.OnDemand;
|
||||
return WlrKeyboardFocus.Exclusive;
|
||||
}
|
||||
if (content.acceptsKeyboardFocus)
|
||||
return WlrKeyboardFocus.OnDemand;
|
||||
return WlrKeyboardFocus.None;
|
||||
}
|
||||
|
||||
HyprlandFocusGrab {
|
||||
active: CompositorService.isHyprland && root.isInteracting
|
||||
windows: [widgetWindow]
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
focus: root.isInteracting
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (!root.isInteracting)
|
||||
return;
|
||||
switch (event.key) {
|
||||
case Qt.Key_G:
|
||||
SessionData.setWidgetGridSetting(false, geometry.screenKey, "enabled", !geometry.gridEnabled);
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Z:
|
||||
SessionData.setWidgetGridSetting(false, geometry.screenKey, "size", Math.max(10, geometry.gridSize - 10));
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_X:
|
||||
SessionData.setWidgetGridSetting(false, geometry.screenKey, "size", Math.min(200, geometry.gridSize + 10));
|
||||
event.accepted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anchors {
|
||||
left: true
|
||||
top: true
|
||||
@@ -153,234 +105,5 @@ Item {
|
||||
screen: root.screen
|
||||
geometry: geometry
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: interactionBorder
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.color: Theme.primary
|
||||
border.width: 2
|
||||
radius: Theme.cornerRadius
|
||||
visible: root.isInteracting && !root.useGhostPreview
|
||||
opacity: 0.8
|
||||
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 48
|
||||
height: 48
|
||||
topLeftRadius: Theme.cornerRadius
|
||||
bottomRightRadius: Theme.cornerRadius
|
||||
color: Theme.primary
|
||||
opacity: resizeArea.pressed ? 1 : 0.6
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: dragArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
enabled: !root.clickThrough
|
||||
cursorShape: pressed ? Qt.ClosedHandCursor : Qt.ArrowCursor
|
||||
|
||||
property point startPos
|
||||
property real startX
|
||||
property real startY
|
||||
|
||||
onPressed: mouse => {
|
||||
startPos = root.useGhostPreview ? Qt.point(mouse.x, mouse.y) : mapToGlobal(mouse.x, mouse.y);
|
||||
startX = geometry.widgetX;
|
||||
startY = geometry.widgetY;
|
||||
root.previewX = geometry.widgetX;
|
||||
root.previewY = geometry.widgetY;
|
||||
geometry.dragOverrideX = geometry.widgetX;
|
||||
geometry.dragOverrideY = geometry.widgetY;
|
||||
}
|
||||
|
||||
onPositionChanged: mouse => {
|
||||
if (!pressed)
|
||||
return;
|
||||
const currentPos = root.useGhostPreview ? Qt.point(mouse.x, mouse.y) : mapToGlobal(mouse.x, mouse.y);
|
||||
const next = geometry.dragMoveTo(startX, startY, currentPos.x - startPos.x, currentPos.y - startPos.y);
|
||||
if (root.useGhostPreview) {
|
||||
root.previewX = next.x;
|
||||
root.previewY = next.y;
|
||||
return;
|
||||
}
|
||||
geometry.dragOverrideX = next.x;
|
||||
geometry.dragOverrideY = next.y;
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
const finalX = root.useGhostPreview ? root.previewX : geometry.dragOverrideX;
|
||||
const finalY = root.useGhostPreview ? root.previewY : geometry.dragOverrideY;
|
||||
geometry.savePosition(finalX, finalY);
|
||||
geometry.clearDragOverrides();
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: resizeArea
|
||||
width: 48
|
||||
height: 48
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
acceptedButtons: Qt.RightButton
|
||||
enabled: !root.clickThrough
|
||||
cursorShape: pressed ? Qt.SizeFDiagCursor : Qt.ArrowCursor
|
||||
|
||||
property point startPos
|
||||
property real startWidth
|
||||
property real startHeight
|
||||
|
||||
onPressed: mouse => {
|
||||
startPos = root.useGhostPreview ? Qt.point(mouse.x, mouse.y) : mapToGlobal(mouse.x, mouse.y);
|
||||
startWidth = geometry.widgetWidth;
|
||||
startHeight = geometry.widgetHeight;
|
||||
root.previewWidth = geometry.widgetWidth;
|
||||
root.previewHeight = geometry.widgetHeight;
|
||||
geometry.dragOverrideW = geometry.widgetWidth;
|
||||
geometry.dragOverrideH = geometry.widgetHeight;
|
||||
}
|
||||
|
||||
onPositionChanged: mouse => {
|
||||
if (!pressed)
|
||||
return;
|
||||
const currentPos = root.useGhostPreview ? Qt.point(mouse.x, mouse.y) : mapToGlobal(mouse.x, mouse.y);
|
||||
const next = geometry.dragResizeTo(startWidth, startHeight, currentPos.x - startPos.x, currentPos.y - startPos.y);
|
||||
if (root.useGhostPreview) {
|
||||
root.previewWidth = next.width;
|
||||
root.previewHeight = next.height;
|
||||
return;
|
||||
}
|
||||
geometry.dragOverrideW = next.width;
|
||||
geometry.dragOverrideH = next.height;
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
const finalW = root.useGhostPreview ? root.previewWidth : geometry.dragOverrideW;
|
||||
const finalH = root.useGhostPreview ? root.previewHeight : geometry.dragOverrideH;
|
||||
geometry.saveSize(finalW, finalH);
|
||||
geometry.clearDragOverrides();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: root.isInteracting && root.useGhostPreview
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
id: ghostPreviewWindow
|
||||
screen: root.screen
|
||||
color: "transparent"
|
||||
|
||||
anchors {
|
||||
left: true
|
||||
right: true
|
||||
top: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
mask: Region {}
|
||||
|
||||
WlrLayershell.namespace: "dms:desktop-widget-preview"
|
||||
WlrLayershell.layer: WlrLayer.Bottom
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
DesktopWidgetGridLines {
|
||||
id: gridOverlay
|
||||
anchors.fill: parent
|
||||
visible: geometry.gridEnabled
|
||||
gridSize: geometry.gridSize
|
||||
extentWidth: geometry.screenWidth
|
||||
extentHeight: geometry.screenHeight
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
x: root.previewX
|
||||
y: root.previewY
|
||||
width: root.previewWidth
|
||||
height: root.previewHeight
|
||||
color: "transparent"
|
||||
border.color: Theme.primary
|
||||
border.width: 2
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
Rectangle {
|
||||
width: 48
|
||||
height: 48
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
topLeftRadius: Theme.cornerRadius
|
||||
bottomRightRadius: Theme.cornerRadius
|
||||
color: Theme.primary
|
||||
opacity: resizeArea.pressed ? 1 : 0.6
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: root.isInteracting && geometry.gridEnabled && !root.useGhostPreview
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
screen: root.screen
|
||||
color: "transparent"
|
||||
|
||||
anchors {
|
||||
left: true
|
||||
right: true
|
||||
top: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
mask: Region {}
|
||||
|
||||
WlrLayershell.namespace: "dms:desktop-widget-grid"
|
||||
WlrLayershell.layer: root.overviewActive && (root.showOnOverview || root.showOnOverviewOnly) ? WlrLayer.Overlay : WlrLayer.Background
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
DesktopWidgetGridLines {
|
||||
anchors.fill: parent
|
||||
gridSize: geometry.gridSize
|
||||
extentWidth: geometry.screenWidth
|
||||
extentHeight: geometry.screenHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: root.isInteracting
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
id: helperWindow
|
||||
screen: root.screen
|
||||
color: "transparent"
|
||||
|
||||
WlrLayershell.namespace: "dms:desktop-widget-helper"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
anchors {
|
||||
bottom: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
|
||||
implicitHeight: 60
|
||||
|
||||
DesktopWidgetGridHint {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Theme.spacingL
|
||||
gridEnabled: geometry.gridEnabled
|
||||
gridSize: geometry.gridSize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ Loader {
|
||||
return clockComponent;
|
||||
case "systemMonitor":
|
||||
return systemMonitorComponent;
|
||||
case "lockClock":
|
||||
return lockClockComponent;
|
||||
case "lockDate":
|
||||
return lockDateComponent;
|
||||
case "lockAuth":
|
||||
@@ -54,10 +52,6 @@ Loader {
|
||||
SystemMonitorWidget {}
|
||||
}
|
||||
|
||||
property Component lockClockComponent: Component {
|
||||
LockClockWidget {}
|
||||
}
|
||||
|
||||
property Component lockDateComponent: Component {
|
||||
LockDateWidget {}
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,7 +1,6 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
import qs.Modules.Plugins
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@@ -14,13 +13,14 @@ Item {
|
||||
|
||||
readonly property string instanceId: instanceData?.id ?? ""
|
||||
readonly property string widgetType: instanceData?.widgetType ?? ""
|
||||
readonly property bool lockScreen: hostLayer.lockScreen
|
||||
readonly property bool removable: widgetType !== "lockAuth"
|
||||
readonly property bool selected: hostLayer.selectedInstanceId === instanceId
|
||||
readonly property bool interacting: editChrome.item?.interacting ?? false
|
||||
readonly property var contrastColors: content.item?.contrastColors ?? []
|
||||
readonly property real bottomOverflow: content.item?.bottomOverflow ?? 0
|
||||
readonly property bool hasSavedPosition: geometry.hasSavedPosition
|
||||
readonly property bool automaticPlacement: widgetType === "lockClock" && (instanceData?.config?.autoPosition ?? true) && !hasSavedPosition
|
||||
readonly property bool automaticPlacement: lockScreen && widgetType === "desktopClock" && (instanceData?.config?.autoPosition ?? true) && !hasSavedPosition
|
||||
readonly property bool dragging: editChrome.item?.dragging ?? false
|
||||
readonly property var stock: hostLayer.stockRect(widgetType, root)
|
||||
property bool snappedCenterX: false
|
||||
@@ -101,7 +101,7 @@ Item {
|
||||
return;
|
||||
}
|
||||
geometry.savePosition(finalX, finalY);
|
||||
if (widgetType === "lockClock" && (instanceData?.config?.autoPosition ?? true))
|
||||
if (lockScreen && widgetType === "desktopClock" && (instanceData?.config?.autoPosition ?? true))
|
||||
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
||||
autoPosition: false
|
||||
});
|
||||
@@ -112,7 +112,7 @@ Item {
|
||||
instanceId: root.instanceId
|
||||
instanceData: root.instanceData
|
||||
screen: root.screen
|
||||
lockScreen: true
|
||||
lockScreen: root.lockScreen
|
||||
minWidth: content.contentMinWidth
|
||||
minHeight: content.contentMinHeight
|
||||
forceSquare: content.contentForceSquare
|
||||
@@ -132,7 +132,7 @@ Item {
|
||||
instanceData: root.instanceData
|
||||
screen: root.screen
|
||||
geometry: geometry
|
||||
lockScreen: true
|
||||
lockScreen: root.lockScreen
|
||||
lockHost: root.lockHost
|
||||
persistDefaults: false
|
||||
}
|
||||
+37
-16
@@ -4,29 +4,30 @@ import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Modules.Plugins
|
||||
import "LockPlacement.js" as Placement
|
||||
import "../../Common/WidgetPlacement.js" as Placement
|
||||
import qs.DankCommon.Session
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
|
||||
required property string screenName
|
||||
property bool lockScreen: false
|
||||
property var lockHost: null
|
||||
property bool editMode: false
|
||||
property string selectedInstanceId: ""
|
||||
|
||||
readonly property var screen: Quickshell.screens.find(s => s.name === screenName) ?? null
|
||||
readonly property var instances: SettingsData.lockScreenWidgetInstances || []
|
||||
readonly property string listKey: lockScreen ? "lockScreenWidgetInstances" : "desktopWidgetInstances"
|
||||
readonly property var instances: (lockScreen ? SettingsData.lockScreenWidgetInstances : SettingsData.desktopWidgetInstances) || []
|
||||
readonly property string screenKey: SettingsData.getScreenDisplayName(screen)
|
||||
property var _gridSettingsTrigger: SessionData.lockScreenWidgetGridSettings
|
||||
property var _gridSettingsTrigger: lockScreen ? SessionData.lockScreenWidgetGridSettings : SessionData.desktopWidgetGridSettings
|
||||
readonly property int gridSize: {
|
||||
void _gridSettingsTrigger;
|
||||
return SessionData.getWidgetGridSetting(true, screenKey, "size", 40);
|
||||
return SessionData.getWidgetGridSetting(lockScreen, screenKey, "size", 40);
|
||||
}
|
||||
readonly property bool gridEnabled: {
|
||||
void _gridSettingsTrigger;
|
||||
return SessionData.getWidgetGridSetting(true, screenKey, "enabled", false);
|
||||
return SessionData.getWidgetGridSetting(lockScreen, screenKey, "enabled", false);
|
||||
}
|
||||
|
||||
signal focusStolen
|
||||
@@ -70,11 +71,29 @@ FocusScope {
|
||||
}
|
||||
|
||||
function toggleGrid() {
|
||||
SessionData.setWidgetGridSetting(true, screenKey, "enabled", !gridEnabled);
|
||||
SessionData.setWidgetGridSetting(lockScreen, screenKey, "enabled", !gridEnabled);
|
||||
}
|
||||
|
||||
function stepGrid(delta) {
|
||||
SessionData.setWidgetGridSetting(true, screenKey, "size", Math.max(10, Math.min(200, gridSize + delta)));
|
||||
SessionData.setWidgetGridSetting(lockScreen, screenKey, "size", Math.max(10, Math.min(200, gridSize + delta)));
|
||||
}
|
||||
|
||||
// Called by the common ancestor of this layer and the editor bar, since either side can hold focus.
|
||||
function handleKey(event) {
|
||||
if (!editMode)
|
||||
return false;
|
||||
switch (event.key) {
|
||||
case Qt.Key_G:
|
||||
toggleGrid();
|
||||
return true;
|
||||
case Qt.Key_Z:
|
||||
stepGrid(-10);
|
||||
return true;
|
||||
case Qt.Key_X:
|
||||
stepGrid(10);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
activeFocusOnTab: false
|
||||
@@ -97,16 +116,16 @@ FocusScope {
|
||||
property var lockedPositions: ({})
|
||||
// Snapshot taken when a drag or resize starts so the auto-placed clock cannot jump under the pointer.
|
||||
property var heldPlacement: ({})
|
||||
readonly property string backgroundKey: LockPlacementService.backgroundKey(screenName, width, height)
|
||||
readonly property string backgroundKey: lockScreen ? LockPlacementService.backgroundKey(screenName, width, height) : ""
|
||||
readonly property var autoPositions: {
|
||||
if (!editMode || !completed)
|
||||
if (!lockScreen || !editMode || !completed)
|
||||
return lockedPositions;
|
||||
if (interactingItem)
|
||||
return heldPlacement;
|
||||
return currentPlacement();
|
||||
}
|
||||
onInteractingItemChanged: {
|
||||
if (interactingItem)
|
||||
if (lockScreen && interactingItem)
|
||||
heldPlacement = currentPlacement();
|
||||
}
|
||||
|
||||
@@ -115,7 +134,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
function refreshPlacement() {
|
||||
if (!completed || editMode || width <= 0 || height <= 0)
|
||||
if (!lockScreen || !completed || editMode || width <= 0 || height <= 0)
|
||||
return;
|
||||
lockedPositions = currentPlacement();
|
||||
SessionData.setLockScreenAutoPositions(screenKey, {
|
||||
@@ -133,10 +152,10 @@ FocusScope {
|
||||
onHeightChanged: refreshPlacement()
|
||||
onEditModeChanged: refreshPlacement()
|
||||
|
||||
readonly property string placementKey: JSON.stringify(instances.map(instance => {
|
||||
readonly property string placementKey: lockScreen ? JSON.stringify(instances.map(instance => {
|
||||
const item = itemById(instance.id);
|
||||
return [instance.id, instance.enabled, instance.config, item?.width, item?.height, item?.automaticPlacement ? null : item?.x, item?.automaticPlacement ? null : item?.y, item?.hasSavedPosition, item?.contrastColors];
|
||||
}).concat([width, height, Theme.primary.toString(), Theme.secondary.toString(), Theme.lockScreenContentColor.toString(), SessionData.desktopWidgetInstancePositions]))
|
||||
}).concat([width, height, Theme.primary.toString(), Theme.secondary.toString(), Theme.lockScreenContentColor.toString(), SessionData.desktopWidgetInstancePositions])) : ""
|
||||
|
||||
function itemById(id) {
|
||||
for (let i = 0; i < repeater.count; i++) {
|
||||
@@ -148,9 +167,11 @@ FocusScope {
|
||||
}
|
||||
|
||||
function stockRect(widgetType, item) {
|
||||
if (!lockScreen)
|
||||
return null;
|
||||
const centerX = (width - item.width) / 2;
|
||||
switch (widgetType) {
|
||||
case "lockClock":
|
||||
case "desktopClock":
|
||||
return item.automaticPlacement && autoPositions[item.instanceId] ? autoPositions[item.instanceId] : {
|
||||
x: Math.max(0, centerX),
|
||||
y: edgeInset
|
||||
@@ -273,7 +294,7 @@ FocusScope {
|
||||
values: root.instances
|
||||
}
|
||||
|
||||
LockWidgetItem {
|
||||
WidgetEditItem {
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.ControlCenter.Widgets
|
||||
import qs.Modules.DankDash.Overview
|
||||
import qs.Modules.Settings.DesktopWidgetSettings
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
|
||||
required property WidgetEditLayer editLayer
|
||||
readonly property bool lockScreen: editLayer.lockScreen
|
||||
property bool libraryOpen: false
|
||||
readonly property real fabReserved: fabBar.reservedHeight
|
||||
readonly property var libraryWidgets: DesktopWidgetRegistry.registeredWidgetsList.filter(widget => {
|
||||
if (!lockScreen)
|
||||
return !widget.lockOnly;
|
||||
return widget.id !== "lockAuth" || !SettingsData.lockWidgetInstance("lockAuth");
|
||||
}).map(widget => ({
|
||||
id: widget.id,
|
||||
text: widget.name,
|
||||
icon: widget.icon,
|
||||
description: widget.description
|
||||
}))
|
||||
|
||||
signal finished
|
||||
|
||||
function closeLibrary() {
|
||||
libraryOpen = false;
|
||||
forceActiveFocus();
|
||||
}
|
||||
|
||||
function showOptions(instanceData) {
|
||||
optionsSheet.instanceId = instanceData?.id ?? "";
|
||||
optionsSheet.opened = true;
|
||||
}
|
||||
|
||||
function addWidget(widgetType) {
|
||||
const def = DesktopWidgetRegistry.getWidget(widgetType);
|
||||
const instance = SettingsData.createDesktopWidgetInstance(widgetType, def?.name ?? widgetType, DesktopWidgetRegistry.getDefaultConfig(widgetType), editLayer.listKey);
|
||||
editLayer.pendingIds = editLayer.pendingIds.concat([instance.id]);
|
||||
}
|
||||
|
||||
function resetLayout() {
|
||||
if (lockScreen) {
|
||||
SettingsData.resetLockScreenWidgets();
|
||||
return;
|
||||
}
|
||||
for (const instance of SettingsData.desktopWidgetInstances || [])
|
||||
SessionData.resetDesktopWidgetInstanceGeometry(instance.id, ["x", "y", "width", "height"]);
|
||||
}
|
||||
|
||||
function dismiss() {
|
||||
if (editControls.pendingAction !== "") {
|
||||
editControls.cancelConfirmation();
|
||||
return;
|
||||
}
|
||||
if (libraryOpen) {
|
||||
closeLibrary();
|
||||
return;
|
||||
}
|
||||
finished();
|
||||
}
|
||||
|
||||
focus: true
|
||||
Component.onCompleted: forceActiveFocus()
|
||||
Keys.onEscapePressed: dismiss()
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
visible: root.libraryOpen
|
||||
acceptedButtons: Qt.AllButtons
|
||||
onClicked: root.closeLibrary()
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: root.libraryOpen
|
||||
|
||||
sourceComponent: CcWidgetLibrary {
|
||||
width: Math.min(implicitWidth, root.width - Theme.spacingL * 2)
|
||||
height: Math.min(implicitHeight, root.height - Theme.spacingL * 2)
|
||||
widgets: root.libraryWidgets
|
||||
Component.onCompleted: reset()
|
||||
onChosen: widgetId => {
|
||||
root.addWidget(widgetId);
|
||||
root.closeLibrary();
|
||||
}
|
||||
onDismissed: root.closeLibrary()
|
||||
}
|
||||
}
|
||||
|
||||
DankBottomSheet {
|
||||
id: optionsSheet
|
||||
|
||||
property string instanceId: ""
|
||||
readonly property var instanceData: SettingsData.getDesktopWidgetInstance(instanceId)
|
||||
readonly property var widgetDef: DesktopWidgetRegistry.getWidget(instanceData?.widgetType ?? "")
|
||||
|
||||
maximumWidth: Math.min(Theme.mediumBreakpoint, root.width - Theme.spacingXL * 2)
|
||||
topMargin: root.height * 0.3
|
||||
returnFocusItem: root
|
||||
title: instanceData?.name || widgetDef?.name || ""
|
||||
onDismissRequested: opened = false
|
||||
onActiveChanged: {
|
||||
if (!active)
|
||||
instanceId = "";
|
||||
}
|
||||
|
||||
DesktopWidgetTypeSettings {
|
||||
width: parent.width
|
||||
instanceId: optionsSheet.instanceId
|
||||
instanceData: optionsSheet.instanceData
|
||||
widgetDef: optionsSheet.widgetDef
|
||||
}
|
||||
}
|
||||
|
||||
DesktopWidgetGridHint {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: fabBar.reservedHeight + Theme.spacingL
|
||||
visible: fabBar.shown && (root.editLayer.selectedInstanceId !== "" || root.editLayer.interactingItem !== null)
|
||||
gridEnabled: root.editLayer.gridEnabled
|
||||
gridSize: root.editLayer.gridSize
|
||||
}
|
||||
|
||||
SettingsFabBar {
|
||||
id: fabBar
|
||||
shown: !root.libraryOpen && !optionsSheet.active
|
||||
|
||||
DashEditControls {
|
||||
id: editControls
|
||||
canClear: false
|
||||
onAddRequested: root.libraryOpen = true
|
||||
onResetRequested: root.resetLayout()
|
||||
onFinished: root.finished()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,35 +5,56 @@ import qs.Modules.Settings.Widgets
|
||||
DesktopWidgetInstanceSettings {
|
||||
id: root
|
||||
|
||||
readonly property bool analog: cfg.style === "analog"
|
||||
readonly property var styles: ["digital", "analog", "stacked", "expressive", "overlap"]
|
||||
readonly property var styleLabels: [I18n.tr("Digital"), I18n.tr("Analog"), I18n.tr("Stacked", "desktop clock style option"), I18n.tr("Expressive"), I18n.tr("Overlapping", "clock style with overlapping digit rows")]
|
||||
readonly property string style: cfg.style ?? "analog"
|
||||
readonly property bool analog: style === "analog"
|
||||
readonly property bool overlap: style === "overlap"
|
||||
|
||||
SettingsDropdownRow {
|
||||
text: I18n.tr("Clock style")
|
||||
options: [I18n.tr("Digital"), I18n.tr("Analog"), I18n.tr("Stacked", "desktop clock style option")]
|
||||
currentValue: {
|
||||
switch (root.cfg.style) {
|
||||
case "analog":
|
||||
return I18n.tr("Analog");
|
||||
case "stacked":
|
||||
return I18n.tr("Stacked");
|
||||
default:
|
||||
return I18n.tr("Digital");
|
||||
}
|
||||
}
|
||||
options: root.styleLabels
|
||||
currentValue: root.styleLabels[Math.max(0, root.styles.indexOf(root.style))]
|
||||
onValueChanged: value => {
|
||||
switch (value) {
|
||||
case I18n.tr("Analog"):
|
||||
root.updateConfig("style", "analog");
|
||||
return;
|
||||
case I18n.tr("Stacked"):
|
||||
root.updateConfig("style", "stacked");
|
||||
return;
|
||||
default:
|
||||
root.updateConfig("style", "digital");
|
||||
}
|
||||
const index = root.styleLabels.indexOf(value);
|
||||
if (index >= 0)
|
||||
root.updateConfig("style", root.styles[index]);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsFontDropdownRow {
|
||||
visible: !root.analog
|
||||
text: I18n.tr("Font")
|
||||
currentFont: root.cfg.fontFamily ?? ""
|
||||
defaultFamily: (root.lockScreenInstance ? SettingsData.lockScreenFontFamily : SettingsData.fontFamily) || Theme.defaultFontFamily
|
||||
onFontSelected: family => root.updateConfig("fontFamily", family)
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
visible: !root.analog
|
||||
text: I18n.tr("Weight")
|
||||
minimum: 0
|
||||
maximum: 900
|
||||
step: 100
|
||||
minimumLabel: I18n.tr("Default")
|
||||
value: root.cfg.weight ?? 0
|
||||
onSliderValueChanged: newValue => root.updateConfig("weight", newValue)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: root.style === "digital"
|
||||
text: I18n.tr("Italic")
|
||||
checked: root.cfg.italic ?? false
|
||||
onToggled: checked => root.updateConfig("italic", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: !root.analog && !root.overlap
|
||||
text: I18n.tr("Accent minutes", "lock screen clock colors")
|
||||
checked: root.cfg.twoTone ?? root.lockScreenInstance
|
||||
onToggled: checked => root.updateConfig("twoTone", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: root.analog
|
||||
text: I18n.tr("Show hour numbers")
|
||||
@@ -49,15 +70,28 @@ DesktopWidgetInstanceSettings {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: !root.analog
|
||||
visible: !root.analog && !root.overlap
|
||||
text: I18n.tr("Show seconds")
|
||||
checked: root.cfg.showDigitalSeconds ?? false
|
||||
onToggled: checked => root.updateConfig("showDigitalSeconds", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: !root.overlap
|
||||
text: I18n.tr("Show date")
|
||||
checked: root.cfg.showDate ?? true
|
||||
checked: root.cfg.showDate ?? !root.lockScreenInstance
|
||||
onToggled: checked => root.updateConfig("showDate", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: root.lockScreenInstance
|
||||
text: I18n.tr("Automatic placement", "lock screen clock placement")
|
||||
description: I18n.tr("Choose a clear area of the background. Drag the clock to place it yourself.", "lock screen automatic clock placement")
|
||||
checked: root.cfg.autoPosition ?? true
|
||||
onToggled: checked => {
|
||||
if (checked)
|
||||
SessionData.resetDesktopWidgetInstanceGeometry(root.instanceId, ["x", "y"]);
|
||||
root.updateConfig("autoPosition", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ Column {
|
||||
property bool showAppearance: true
|
||||
property bool showPlacement: true
|
||||
readonly property var cfg: instanceData?.config ?? {}
|
||||
readonly property bool lockScreenInstance: SettingsData.widgetInstanceListKey(instanceId) === "lockScreenWidgetInstances"
|
||||
default property alias rows: optionsCard.content
|
||||
|
||||
function updateConfig(key, value) {
|
||||
@@ -33,12 +34,13 @@ Column {
|
||||
text: I18n.tr("Opacity")
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
value: Math.round((root.cfg.transparency ?? 0.8) * 100)
|
||||
value: Math.round((root.cfg.transparency ?? (root.lockScreenInstance ? 0 : 0.8)) * 100)
|
||||
onSliderValueChanged: newValue => root.updateConfig("transparency", newValue / 100)
|
||||
}
|
||||
|
||||
SettingsColorPicker {
|
||||
colorMode: root.cfg.colorMode ?? "primary"
|
||||
showDefault: root.lockScreenInstance
|
||||
colorMode: root.cfg.colorMode ?? (root.lockScreenInstance ? "default" : "primary")
|
||||
customColor: root.cfg.customColor ?? "#ffffff"
|
||||
onColorModeSelected: mode => root.updateConfig("colorMode", mode)
|
||||
onCustomColorSelected: selectedColor => root.updateConfig("customColor", selectedColor.toString())
|
||||
|
||||
@@ -17,8 +17,6 @@ Loader {
|
||||
return clockSettings;
|
||||
case "systemMonitor":
|
||||
return systemMonitorSettings;
|
||||
case "lockClock":
|
||||
return lockClockSettings;
|
||||
case "lockAuth":
|
||||
return lockAuthSettings;
|
||||
case "lockNotifications":
|
||||
@@ -52,15 +50,6 @@ Loader {
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: lockClockSettings
|
||||
|
||||
LWS.LockClockSettings {
|
||||
instanceId: root.instanceId
|
||||
instanceData: root.instanceData
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: lockAuthSettings
|
||||
|
||||
|
||||
@@ -244,20 +244,6 @@ Item {
|
||||
iconName: "info"
|
||||
title: I18n.tr("Help", "noun, card title for desktop widget usage tips")
|
||||
|
||||
SettingsRow {
|
||||
iconName: "drag_pan"
|
||||
iconBox: true
|
||||
title: I18n.tr("Move", "verb, help item title for moving a desktop widget")
|
||||
subtitle: I18n.tr("Right-click and drag anywhere on the widget")
|
||||
}
|
||||
|
||||
SettingsRow {
|
||||
iconName: "open_in_full"
|
||||
iconBox: true
|
||||
title: I18n.tr("Resize", "verb, help item title for resizing a desktop widget")
|
||||
subtitle: I18n.tr("Right-click and drag the bottom-right corner")
|
||||
}
|
||||
|
||||
SettingsRow {
|
||||
iconName: "drag_indicator"
|
||||
iconBox: true
|
||||
@@ -274,6 +260,13 @@ Item {
|
||||
onClicked: root.showDesktopPluginBrowser()
|
||||
}
|
||||
|
||||
DankFab {
|
||||
text: I18n.tr("Edit widgets")
|
||||
iconName: "edit"
|
||||
colorRole: "secondaryContainer"
|
||||
onClicked: DesktopWidgetRegistry.editing = true
|
||||
}
|
||||
|
||||
DankFab {
|
||||
text: I18n.tr("Add widget")
|
||||
iconName: "add"
|
||||
|
||||
@@ -268,6 +268,16 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
function showWidgetBrowser() {
|
||||
lockWidgetBrowserLoader.active = true;
|
||||
lockWidgetBrowserLoader.item?.show();
|
||||
}
|
||||
|
||||
function showPluginBrowser() {
|
||||
lockPluginBrowserLoader.active = true;
|
||||
lockPluginBrowserLoader.item?.show();
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: lockWidgetBrowserLoader
|
||||
active: false
|
||||
@@ -280,6 +290,16 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: lockPluginBrowserLoader
|
||||
active: false
|
||||
|
||||
PluginBrowser {
|
||||
parentModal: root.parentModal
|
||||
typeFilter: "desktop-widget"
|
||||
}
|
||||
}
|
||||
|
||||
SettingsPage {
|
||||
id: mainColumn
|
||||
|
||||
@@ -316,23 +336,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
SettingsRow {
|
||||
iconName: "add"
|
||||
title: I18n.tr("Add widget")
|
||||
clickable: true
|
||||
onClicked: {
|
||||
lockWidgetBrowserLoader.active = true;
|
||||
lockWidgetBrowserLoader.item?.show();
|
||||
}
|
||||
}
|
||||
|
||||
SettingsRow {
|
||||
iconName: "edit"
|
||||
title: I18n.tr("Edit widgets")
|
||||
clickable: true
|
||||
onClicked: SessionService.lockEditorRequested()
|
||||
}
|
||||
|
||||
SettingsRow {
|
||||
iconName: "restart_alt"
|
||||
title: I18n.tr("Reset to default")
|
||||
@@ -859,5 +862,27 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsFabBar {
|
||||
DankFab {
|
||||
text: I18n.tr("Browse plugins")
|
||||
iconName: "store"
|
||||
colorRole: "secondaryContainer"
|
||||
onClicked: root.showPluginBrowser()
|
||||
}
|
||||
|
||||
DankFab {
|
||||
text: I18n.tr("Edit widgets")
|
||||
iconName: "edit"
|
||||
colorRole: "secondaryContainer"
|
||||
onClicked: SessionService.lockEditorRequested()
|
||||
}
|
||||
|
||||
DankFab {
|
||||
text: I18n.tr("Add widget")
|
||||
iconName: "add"
|
||||
onClicked: root.showWidgetBrowser()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Modules.Settings.Widgets
|
||||
import qs.Modules.Settings.DesktopWidgetSettings
|
||||
|
||||
DesktopWidgetInstanceSettings {
|
||||
id: root
|
||||
|
||||
readonly property var styles: ["horizontal", "vertical", "expressive", "analog"]
|
||||
readonly property var styleLabels: [I18n.tr("Horizontal", "lock screen clock style option"), I18n.tr("Vertical", "lock screen clock style option"), I18n.tr("Expressive"), I18n.tr("Analog")]
|
||||
readonly property string style: cfg.style ?? "expressive"
|
||||
readonly property bool textStyle: style === "horizontal" || style === "vertical"
|
||||
|
||||
showAppearance: false
|
||||
|
||||
SettingsDropdownRow {
|
||||
text: I18n.tr("Clock style")
|
||||
options: root.styleLabels
|
||||
currentValue: root.styleLabels[Math.max(0, root.styles.indexOf(root.style))]
|
||||
onValueChanged: value => {
|
||||
const idx = root.styleLabels.indexOf(value);
|
||||
if (idx >= 0)
|
||||
root.updateConfig("style", root.styles[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
visible: root.textStyle
|
||||
text: I18n.tr("Weight")
|
||||
minimum: 0
|
||||
maximum: 900
|
||||
step: 100
|
||||
minimumLabel: I18n.tr("Default")
|
||||
value: root.cfg.weight ?? 0
|
||||
onSliderValueChanged: newValue => root.updateConfig("weight", newValue)
|
||||
}
|
||||
|
||||
SettingsFontDropdownRow {
|
||||
visible: root.textStyle
|
||||
text: I18n.tr("Font")
|
||||
currentFont: root.cfg.fontFamily ?? ""
|
||||
defaultFamily: SettingsData.lockScreenFontFamily || Theme.defaultFontFamily
|
||||
onFontSelected: family => root.updateConfig("fontFamily", family)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: root.style === "horizontal"
|
||||
text: I18n.tr("Italic")
|
||||
checked: root.cfg.italic ?? false
|
||||
onToggled: checked => root.updateConfig("italic", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: root.style === "horizontal" || root.style === "expressive"
|
||||
text: I18n.tr("Accent minutes", "lock screen clock colors")
|
||||
checked: root.cfg.twoTone ?? true
|
||||
onToggled: checked => root.updateConfig("twoTone", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Automatic placement", "lock screen clock placement")
|
||||
description: I18n.tr("Choose a clear area of the background. Drag the clock to place it yourself.", "lock screen automatic clock placement")
|
||||
checked: root.cfg.autoPosition ?? true
|
||||
onToggled: checked => {
|
||||
if (checked)
|
||||
SessionData.resetDesktopWidgetInstanceGeometry(root.instanceId, ["x", "y"]);
|
||||
root.updateConfig("autoPosition", checked);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: root.style === "analog"
|
||||
text: I18n.tr("Show hour numbers")
|
||||
checked: root.cfg.showAnalogNumbers ?? false
|
||||
onToggled: checked => root.updateConfig("showAnalogNumbers", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
visible: root.style === "analog"
|
||||
text: I18n.tr("Show seconds")
|
||||
checked: root.cfg.showAnalogSeconds ?? true
|
||||
onToggled: checked => root.updateConfig("showAnalogSeconds", checked)
|
||||
}
|
||||
|
||||
SettingsColorPicker {
|
||||
showDefault: true
|
||||
colorMode: root.cfg.colorMode ?? "default"
|
||||
customColor: root.cfg.customColor ?? "#ffffff"
|
||||
onColorModeSelected: mode => root.updateConfig("colorMode", mode)
|
||||
onCustomColorSelected: selectedColor => root.updateConfig("customColor", selectedColor.toString())
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ Singleton {
|
||||
|
||||
property var registeredWidgets: ({})
|
||||
property var registeredWidgetsList: []
|
||||
property bool editing: false
|
||||
|
||||
signal registryChanged
|
||||
|
||||
@@ -37,9 +38,9 @@ Singleton {
|
||||
function registerBuiltins() {
|
||||
registerWidget({
|
||||
id: "desktopClock",
|
||||
name: I18n.tr("Desktop Clock", "Desktop clock widget name"),
|
||||
name: I18n.tr("Clock"),
|
||||
icon: "schedule",
|
||||
description: I18n.tr("Analog, digital, or stacked clock display", "Desktop clock widget description"),
|
||||
description: I18n.tr("Analog, digital, stacked, expressive, or overlapping clock", "Desktop clock widget description"),
|
||||
type: "builtin",
|
||||
component: "qs.Modules.BuiltinDesktopPlugins.DesktopClockWidget",
|
||||
settingsComponent: "qs.Modules.Settings.DesktopWidgetSettings.ClockSettings",
|
||||
@@ -80,7 +81,6 @@ Singleton {
|
||||
height: 200
|
||||
}
|
||||
});
|
||||
lockWidget("lockClock", I18n.tr("Clock"), "schedule");
|
||||
lockWidget("lockDate", I18n.tr("Date"), "event");
|
||||
lockWidget("lockAuth", I18n.tr("Password"), "lock");
|
||||
lockWidget("lockNotifications", I18n.tr("Notifications"), "notifications");
|
||||
|
||||
@@ -12,7 +12,7 @@ Singleton {
|
||||
|
||||
function neededFor(screen) {
|
||||
return SettingsData.lockScreenWidgetInstances.some(instance => {
|
||||
if (instance.widgetType !== "lockClock" || instance.enabled === false || instance.config?.autoPosition === false || !DesktopWidgetRegistry.showsOnScreen(instance.config?.displayPreferences, screen))
|
||||
if (instance.widgetType !== "desktopClock" || instance.enabled === false || instance.config?.autoPosition === false || !DesktopWidgetRegistry.showsOnScreen(instance.config?.displayPreferences, screen))
|
||||
return false;
|
||||
const positionKey = instance.config?.syncPositionAcrossScreens ? "_synced" : SettingsData.getScreenDisplayName(screen);
|
||||
return SessionData.desktopWidgetInstancePositions[instance.id]?.[positionKey]?.x === undefined;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import qs.DankCommon.Widgets as DankCommon
|
||||
|
||||
DankCommon.DankOverlapClockFace {}
|
||||
Reference in New Issue
Block a user