mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-28 05:57:47 -04:00
- Hyprland & Mango users will benefit most while niri gains solid QOL updates
- New icon picker in dot settings
- Dragging, flinging and opening the dot now run on one static surface so they stay smooth on every compositor
Port 2.0
(cherry picked from commit 0cd03e0180)
319 lines
13 KiB
QML
319 lines
13 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import qs.Common
|
|
import qs.DCommon.Widgets
|
|
import qs.Modals.FileBrowser
|
|
import qs.Modules.DIsland
|
|
import qs.Services
|
|
import qs.Modules.Settings.Widgets
|
|
|
|
Item {
|
|
id: root
|
|
|
|
LayoutMirroring.enabled: I18n.isRtl
|
|
LayoutMirroring.childrenInherit: true
|
|
|
|
readonly property var paletteValues: ["default", "bright", "dim"]
|
|
|
|
readonly property IslandSettingsStore dot: IslandSettingsStore {
|
|
barId: SettingsData.dotBarConfig?.id ?? ""
|
|
}
|
|
|
|
readonly property bool highContrast: dot.setting("islandHighContrast")
|
|
readonly property bool paletteTinted: ["bright", "dim"].includes(dot.setting("islandPalette"))
|
|
readonly property var iconModes: ["icon", "os", "dank", "compositor", "custom"]
|
|
readonly property string iconMode: dot.setting("islandFreeIconMode")
|
|
readonly property string iconColor: dot.setting("islandFreeIconColor")
|
|
readonly property bool iconColorCustom: iconColor !== "" && iconColor !== "primary" && iconColor !== "surface"
|
|
readonly property string compositorLabel: CompositorService.displayName || I18n.tr("Compositor")
|
|
|
|
// A screen with no stored entry already sits at the default centre.
|
|
function resetDotPosition() {
|
|
for (const screen of Quickshell.screens) {
|
|
const key = IslandHostRegistry.key(screen.name, root.dot.barId);
|
|
if (SessionData.islandFreePositions[key])
|
|
SessionData.setIslandFreePosition(key, 0.5, 0.5);
|
|
}
|
|
}
|
|
|
|
FileBrowserModal {
|
|
id: iconFileBrowser
|
|
|
|
browserTitle: I18n.tr("Select Dot Icon")
|
|
bucket: "logo"
|
|
filters: ["*.svg", "*.png", "*.jpg", "*.jpeg", "*.webp"]
|
|
onAccepted: paths => root.dot.apply("islandFreeIconPath", paths[0])
|
|
}
|
|
|
|
SettingsPage {
|
|
SettingsCard {
|
|
settingKey: "dotSize"
|
|
tags: ["dot", "dankdot", "size", "diameter", "idle", "fade"]
|
|
iconName: "blur_on"
|
|
title: I18n.tr("General")
|
|
|
|
SettingsSliderRow {
|
|
settingKey: "islandFreeSize"
|
|
tags: ["dot", "size", "diameter"]
|
|
resetStore: dot
|
|
resetKeys: ["islandFreeSize"]
|
|
text: I18n.tr("Size")
|
|
unit: "px"
|
|
minimum: 24
|
|
maximum: 160
|
|
step: 1
|
|
value: dot.setting("islandFreeSize")
|
|
onSliderDragFinished: finalValue => dot.apply("islandFreeSize", finalValue)
|
|
}
|
|
|
|
SettingsButtonGroupRow {
|
|
settingKey: "dotIcon"
|
|
tags: ["dot", "icon", "symbol", "logo", "face"]
|
|
resetStore: root.dot
|
|
resetKeys: ["islandFreeIconMode"]
|
|
text: I18n.tr("Icon")
|
|
buttonPadding: Theme.spacingS
|
|
minButtonWidth: 44
|
|
textSize: Theme.fontSizeSmall
|
|
model: [I18n.tr("Symbol"), I18n.tr("OS Logo"), "Dux", root.compositorLabel, I18n.tr("Custom")]
|
|
values: root.iconModes
|
|
value: root.iconMode
|
|
fallbackValue: "icon"
|
|
onValueSelected: value => root.dot.apply("islandFreeIconMode", value)
|
|
}
|
|
|
|
SettingsRow {
|
|
settingKey: "dotIconSymbol"
|
|
tags: ["dot", "icon", "symbol", "glyph"]
|
|
resetStore: root.dot
|
|
resetKeys: ["islandFreeIcon"]
|
|
title: I18n.tr("Symbol")
|
|
visible: root.iconMode === "icon"
|
|
|
|
DIconPicker {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
currentIcon: root.dot.setting("islandFreeIcon")
|
|
onIconSelected: iconName => root.dot.apply("islandFreeIcon", iconName)
|
|
}
|
|
}
|
|
|
|
SettingsTextFieldRow {
|
|
settingKey: "dotIconImage"
|
|
tags: ["dot", "icon", "image", "custom", "file", "logo"]
|
|
resetStore: root.dot
|
|
resetKeys: ["islandFreeIconPath"]
|
|
text: I18n.tr("Custom")
|
|
visible: root.iconMode === "custom"
|
|
placeholderText: I18n.tr("Select an image file...")
|
|
value: root.dot.setting("islandFreeIconPath")
|
|
onEditingFinished: value => root.dot.apply("islandFreeIconPath", value.trim())
|
|
|
|
actions: DActionButton {
|
|
iconName: "folder_open"
|
|
Accessible.name: I18n.tr("Select Dot Icon")
|
|
onClicked: iconFileBrowser.open()
|
|
}
|
|
}
|
|
|
|
ColorDropdownRow {
|
|
settingKey: "dotIconColor"
|
|
tags: ["dot", "icon", "color", "tint", "logo"]
|
|
resetStore: root.dot
|
|
resetKeys: ["islandFreeIconColor"]
|
|
text: I18n.tr("Color override")
|
|
options: [({
|
|
"value": "",
|
|
"label": I18n.tr("Default")
|
|
}), ({
|
|
"value": "primary",
|
|
"label": I18n.tr("Primary")
|
|
}), ({
|
|
"value": "surface",
|
|
"label": I18n.tr("Surface", "color option")
|
|
}), ({
|
|
"value": "custom",
|
|
"label": I18n.tr("Custom")
|
|
})]
|
|
currentMode: root.iconColorCustom ? "custom" : root.iconColor
|
|
customColor: root.iconColorCustom ? root.iconColor : Theme.primary
|
|
pickerTitle: I18n.tr("Color override")
|
|
onModeSelected: mode => {
|
|
if (mode !== "custom") {
|
|
root.dot.apply("islandFreeIconColor", mode);
|
|
return;
|
|
}
|
|
if (!root.iconColorCustom)
|
|
root.dot.apply("islandFreeIconColor", Theme.primary.toString());
|
|
}
|
|
onCustomColorSelected: selectedColor => root.dot.apply("islandFreeIconColor", selectedColor.toString())
|
|
}
|
|
|
|
SettingsSliderRow {
|
|
settingKey: "dotEdgeMargin"
|
|
tags: ["dot", "edge", "margin", "gap"]
|
|
resetStore: dot
|
|
resetKeys: ["islandFreeEdgeMargin"]
|
|
text: I18n.tr("Edge margin", "island settings: gap kept from the display edge")
|
|
unit: "px"
|
|
minimum: 0
|
|
maximum: 64
|
|
step: 1
|
|
value: dot.setting("islandFreeEdgeMargin")
|
|
onSliderDragFinished: finalValue => dot.apply("islandFreeEdgeMargin", finalValue)
|
|
}
|
|
|
|
SettingsSliderRow {
|
|
settingKey: "islandFreeIdleDelay"
|
|
tags: ["dot", "idle", "delay", "fade", "timeout"]
|
|
resetStore: dot
|
|
resetKeys: ["islandFreeIdleDelay"]
|
|
text: I18n.tr("Idle delay", "island settings: time before the dot fades, 0 disables idling")
|
|
unit: "ms"
|
|
minimumLabel: I18n.tr("Off")
|
|
minimum: 0
|
|
maximum: 30000
|
|
step: 500
|
|
value: dot.setting("islandFreeIdleDelay")
|
|
onSliderDragFinished: finalValue => dot.apply("islandFreeIdleDelay", finalValue)
|
|
}
|
|
|
|
SettingsSliderRow {
|
|
settingKey: "islandFreeIdleScale"
|
|
tags: ["dot", "idle", "shrink", "scale"]
|
|
resetStore: dot
|
|
resetKeys: ["islandFreeIdleScale"]
|
|
text: I18n.tr("Idle size", "island settings: how far the dot shrinks while idle")
|
|
unit: "%"
|
|
minimum: 20
|
|
maximum: 100
|
|
step: 1
|
|
value: Math.round(dot.setting("islandFreeIdleScale") * 100)
|
|
enabled: dot.setting("islandFreeIdleDelay") > 0
|
|
onSliderDragFinished: finalValue => dot.apply("islandFreeIdleScale", finalValue / 100)
|
|
}
|
|
|
|
SettingsSliderRow {
|
|
settingKey: "islandFreeIdleOpacity"
|
|
tags: ["dot", "idle", "opacity", "fade"]
|
|
resetStore: dot
|
|
resetKeys: ["islandFreeIdleOpacity"]
|
|
text: I18n.tr("Idle opacity", "island settings: dot opacity while idle")
|
|
unit: "%"
|
|
minimum: 5
|
|
maximum: 100
|
|
step: 1
|
|
value: Math.round(dot.setting("islandFreeIdleOpacity") * 100)
|
|
enabled: dot.setting("islandFreeIdleDelay") > 0
|
|
onSliderDragFinished: finalValue => dot.apply("islandFreeIdleOpacity", finalValue / 100)
|
|
}
|
|
|
|
SettingsRow {
|
|
settingKey: "dotResetPosition"
|
|
tags: ["dot", "position", "center", "reset", "move"]
|
|
iconName: "drag_pan"
|
|
title: I18n.tr("Reset Position")
|
|
clickable: true
|
|
onClicked: root.resetDotPosition()
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
iconName: "palette"
|
|
title: I18n.tr("Surface")
|
|
settingKey: "dotSurface"
|
|
tags: ["dot", "background", "color", "opacity", "palette", "contrast"]
|
|
|
|
SurfaceColorRow {
|
|
settingKey: "dotSurfaceColor"
|
|
tags: ["dot", "background", "color", "surface"]
|
|
resetStore: dot
|
|
resetKeys: ["surfaceColor", "surfaceCustomColor"]
|
|
text: I18n.tr("Background")
|
|
enabled: !root.highContrast && !root.paletteTinted
|
|
defaultColor: Theme.hostSurface
|
|
currentMode: dot.config?.surfaceColor ?? "default"
|
|
customColor: dot.config?.surfaceCustomColor ?? SettingsData.barConfigDefault("surfaceCustomColor")
|
|
pickerTitle: I18n.tr("Background")
|
|
onModeSelected: mode => dot.apply("surfaceColor", mode)
|
|
onCustomColorSelected: selectedColor => dot.apply("surfaceCustomColor", selectedColor.toString())
|
|
}
|
|
|
|
SettingsSliderRow {
|
|
settingKey: "dotOpacity"
|
|
tags: ["dot", "opacity", "transparency", "background"]
|
|
resetStore: dot
|
|
resetKeys: ["transparency"]
|
|
text: I18n.tr("Opacity")
|
|
enabled: !root.highContrast
|
|
minimum: 0
|
|
maximum: 100
|
|
step: 1
|
|
value: Math.round(SettingsData.barTransparency(dot.config) * 100)
|
|
onSliderDragFinished: finalValue => SettingsData.updateBarConfig(dot.config.id, {
|
|
followInterfaceStyle: false,
|
|
transparency: finalValue / 100
|
|
})
|
|
}
|
|
|
|
SettingsButtonGroupRow {
|
|
settingKey: "dotPalette"
|
|
tags: ["dot", "palette", "surface", "bright", "dim"]
|
|
resetStore: dot
|
|
resetKeys: ["islandPalette"]
|
|
text: I18n.tr("Palette", "island settings: surface tone choice")
|
|
model: [I18n.tr("Default", "island settings: default surface tone"), I18n.tr("Bright", "island settings: bright surface tone"), I18n.tr("Dim", "island settings: dim surface tone")]
|
|
values: root.paletteValues
|
|
enabled: !root.highContrast
|
|
value: dot.setting("islandPalette")
|
|
fallbackValue: "default"
|
|
onValueSelected: value => dot.apply("islandPalette", value)
|
|
}
|
|
|
|
SettingsToggleRow {
|
|
settingKey: "dotHighContrast"
|
|
tags: ["dot", "contrast", "accessibility", "outline"]
|
|
resetStore: root.dot
|
|
resetKeys: ["islandHighContrast"]
|
|
text: I18n.tr("High contrast", "island settings: high contrast toggle")
|
|
checked: dot.setting("islandHighContrast")
|
|
onToggled: checked => dot.apply("islandHighContrast", checked)
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
iconName: "display_settings"
|
|
title: I18n.tr("Displays")
|
|
settingKey: "dotDisplays"
|
|
tags: ["dot", "display", "monitor", "screen"]
|
|
|
|
SettingsDisplayPicker {
|
|
displayPreferences: dot.config?.screenPreferences || ["all"]
|
|
emptyMeansAll: false
|
|
allowEmpty: true
|
|
showLastDisplay: true
|
|
showOnLastDisplay: dot.config?.showOnLastDisplay ?? true
|
|
preferencesHandler: prefs => dot.apply("screenPreferences", prefs)
|
|
onLastDisplayToggled: checked => dot.apply("showOnLastDisplay", checked)
|
|
}
|
|
}
|
|
|
|
IslandBehaviorCard {
|
|
store: dot
|
|
keyPrefix: "dot"
|
|
docked: false
|
|
isDot: true
|
|
}
|
|
|
|
IslandNotificationsCard {
|
|
store: dot
|
|
keyPrefix: "dot"
|
|
badgeGated: false
|
|
}
|
|
|
|
IslandMotionCard {
|
|
store: dot
|
|
keyPrefix: "dot"
|
|
}
|
|
}
|
|
}
|