island: simplify volume and brightness home slots

This commit is contained in:
bbedward
2026-09-02 14:59:43 -04:00
parent 6df71083ec
commit 13fafa1dff
7 changed files with 208 additions and 170 deletions
-2
View File
@@ -1021,8 +1021,6 @@ Singleton {
property string dankIslandHomeVolumeDisplay: "both"
property string dankIslandHomeBrightnessSlot: "hidden"
property string dankIslandHomeBrightnessDisplay: "both"
property var dankIslandHomeLeftOrder: ["media", "weather", "status", "volume", "brightness", "notifications"]
property var dankIslandHomeRightOrder: ["weather", "status", "notifications", "media", "volume", "brightness"]
property string dankIslandBatteryStyle: "solid"
property bool dankIslandSatellitesEnabled: true
property string dankIslandSatellitePosition: "edges"
@@ -557,8 +557,6 @@ var SPEC = {
dankIslandHomeVolumeDisplay: { def: "both" },
dankIslandHomeBrightnessSlot: { def: "hidden" },
dankIslandHomeBrightnessDisplay: { def: "both" },
dankIslandHomeLeftOrder: { def: ["media", "weather", "status", "volume", "brightness", "notifications"] },
dankIslandHomeRightOrder: { def: ["weather", "status", "notifications", "media", "volume", "brightness"] },
dankIslandBatteryStyle: { def: "solid" },
dankIslandSatellitesEnabled: { def: true },
dankIslandSatellitePosition: { def: "edges" },
@@ -27,43 +27,74 @@ Item {
readonly property real brightnessMaximum: DisplayService.brightnessMaximum(root.brightnessDevice)
readonly property int brightnessPercent: root.brightnessMaximum > 0 ? Math.round(DisplayService.brightnessLevel / root.brightnessMaximum * 100) : 0
readonly property int volumePercent: Math.min(AudioService.sinkMaxVolume, Math.round((AudioService.sink?.audio?.volume ?? 0) * 100))
readonly property var leftGroupOrder: ["media", "weather", "status", "volume", "brightness"]
readonly property var rightGroupOrder: ["weather", "status", "volume", "brightness", "notifications", "media"]
readonly property var groupIds: root.groupsForSide("left").concat(["clock"]).concat(root.groupsForSide("right"))
readonly property real touchpadThreshold: 100
property real wheelAccumulator: 0
property bool weatherRefHeld: false
function groupsForSide(side) {
const ids = [];
const order = side === "left" ? root.controller.homeLeftOrder : root.controller.homeRightOrder;
for (const id of order) {
if (id === "media" && root.controller.homeMediaSlot === side)
ids.push(id);
else if (id === "weather" && root.controller.homeWeatherSlot === side && WeatherService.weather.available)
ids.push(id);
else if (id === "status" && root.controller.homeStatusSlot === side)
ids.push(id);
else if (id === "notifications" && side === "right" && root.controller.homeNotificationBadge)
ids.push(id);
else if (id === "volume" && root.controller.homeVolumeSlot === side && AudioService.sink?.audio)
ids.push(id);
else if (id === "brightness" && root.controller.homeBrightnessSlot === side && DisplayService.brightnessAvailable && root.brightnessDevice)
ids.push(id);
const order = side === "left" ? root.leftGroupOrder : root.rightGroupOrder;
return order.filter(id => root.groupShown(id, side));
}
function groupShown(id, side) {
switch (id) {
case "media":
return root.controller.homeMediaSlot === side;
case "weather":
return root.controller.homeWeatherSlot === side && WeatherService.weather.available;
case "status":
return root.controller.homeStatusSlot === side;
case "notifications":
return side === "right" && root.controller.homeNotificationBadge;
case "volume":
return root.controller.homeVolumeSlot === side && !!AudioService.sink?.audio;
case "brightness":
return root.controller.homeBrightnessSlot === side && DisplayService.brightnessAvailable && !!root.brightnessDevice;
}
return ids;
return false;
}
function wheelDirection(delta) {
const isMouseWheel = Math.abs(delta) >= 120 && Math.abs(delta) % 120 === 0;
if (isMouseWheel)
return delta > 0 ? 1 : -1;
root.wheelAccumulator += delta;
if (Math.abs(root.wheelAccumulator) < root.touchpadThreshold)
return 0;
const direction = root.wheelAccumulator > 0 ? 1 : -1;
root.wheelAccumulator = 0;
return direction;
}
function adjustSystemLevel(activityId, delta) {
if (delta === 0)
const direction = root.wheelDirection(delta);
if (direction === 0)
return;
const direction = delta > 0 ? 1 : -1;
if (activityId === "volume") {
if (!AudioService.sink?.audio)
return;
SessionData.suppressOSDTemporarily();
AudioService.adjustDefaultSinkVolume(5, direction);
AudioService.playVolumeChangeSoundIfEnabled();
switch (activityId) {
case "volume":
root.adjustVolume(direction);
return;
case "brightness":
root.adjustBrightness(direction);
return;
}
if (activityId !== "brightness" || !root.brightnessDevice)
}
function adjustVolume(direction) {
if (!AudioService.sink?.audio)
return;
SessionData.suppressOSDTemporarily();
AudioService.adjustDefaultSinkVolume(AudioService.wheelVolumeStep, direction);
AudioService.playVolumeChangeSoundIfEnabled();
}
function adjustBrightness(direction) {
if (!root.brightnessDevice)
return;
SessionData.suppressOSDTemporarily();
const next = Math.max(DisplayService.brightnessMinimum(root.brightnessDevice), Math.min(root.brightnessMaximum, DisplayService.brightnessLevel + direction * 5));
DisplayService.setBrightness(next, root.brightnessDevice.id, true);
}
@@ -255,14 +286,14 @@ Item {
visible: systemLevelRow.displayMode !== "percentage"
name: item.isVolume ? AudioService.sinkVolumeIconName : DisplayService.brightnessIconName(root.brightnessDevice, DisplayService.brightnessLevel)
size: root.statusIconSize
color: item.isBrightness ? Theme.primary : Theme.surfaceTextSecondary
color: Theme.surfaceTextSecondary
}
NumericText {
anchors.verticalCenter: parent.verticalCenter
visible: systemLevelRow.displayMode !== "icon"
text: (item.isVolume ? root.volumePercent : root.brightnessPercent) + "%"
reserveText: item.isVolume ? Math.round(AudioService.sinkMaxVolume) + "%" : "100%"
reserveText: item.isVolume ? AudioService.sinkMaxVolume + "%" : "100%"
color: Theme.surfaceTextSecondary
font.pixelSize: root.textSize
}
@@ -314,7 +345,7 @@ Item {
return;
}
if (item.isVolume || item.isBrightness) {
root.systemModel.show(item.groupId);
root.systemModel.open(item.groupId);
return;
}
root.controller.requestControlCenter("", false);
@@ -279,21 +279,6 @@ QtObject {
return "both";
}
function resolvedHomeOrder(value, fallback) {
const known = ["media", "weather", "status", "notifications", "volume", "brightness"];
const order = [];
const configured = Array.isArray(value) ? value : [];
for (const id of configured) {
if (known.indexOf(id) !== -1 && order.indexOf(id) === -1)
order.push(id);
}
for (const id of fallback) {
if (order.indexOf(id) === -1)
order.push(id);
}
return order;
}
readonly property string homeMediaSlot: resolvedHomeSlot(SettingsData.dankIslandHomeMediaSlot, "left")
readonly property string homeStatusSlot: resolvedHomeSlot(SettingsData.dankIslandHomeStatusSlot, "hidden")
readonly property string homeWeatherSlot: SettingsData.weatherEnabled ? resolvedHomeSlot(SettingsData.dankIslandHomeWeatherSlot, "hidden") : "hidden"
@@ -301,8 +286,6 @@ QtObject {
readonly property string homeVolumeDisplay: resolvedSystemLevelDisplay(SettingsData.dankIslandHomeVolumeDisplay)
readonly property string homeBrightnessSlot: resolvedHomeSlot(SettingsData.dankIslandHomeBrightnessSlot, "hidden")
readonly property string homeBrightnessDisplay: resolvedSystemLevelDisplay(SettingsData.dankIslandHomeBrightnessDisplay)
readonly property var homeLeftOrder: resolvedHomeOrder(SettingsData.dankIslandHomeLeftOrder, ["media", "weather", "status", "volume", "brightness", "notifications"])
readonly property var homeRightOrder: resolvedHomeOrder(SettingsData.dankIslandHomeRightOrder, ["weather", "status", "notifications", "media", "volume", "brightness"])
readonly property real homeCompactWidth: Math.ceil(homeSlotMargin * 2 + Math.max(homeContentWidth, 1))
readonly property real mediaCompactWidth: Math.ceil(Math.max(1, mediaContentWidth))
@@ -27,6 +27,10 @@ QtObject {
function show(activityKind) {
if (SessionData.suppressOSD)
return;
open(activityKind);
}
function open(activityKind) {
if (controller.requestSystemActivity(activityKind))
kind = activityKind;
}
+54 -121
View File
@@ -5,7 +5,6 @@ import qs.Common
import qs.Modules.Settings.Widgets
import qs.Services
import qs.Widgets
import "../../Common/QmlUtils.js" as QmlUtils
Item {
id: root
@@ -42,113 +41,6 @@ Item {
return index >= 0 ? index : Math.max(0, values.indexOf(fallback));
}
function setHomeActivitySlot(activityId, settingKey, index, selected) {
if (!selected)
return;
const slot = root.homeSlotValues[index] ?? "hidden";
const leftOrder = Array.isArray(SettingsData.dankIslandHomeLeftOrder) ? SettingsData.dankIslandHomeLeftOrder.filter(id => id !== activityId) : [];
const rightOrder = Array.isArray(SettingsData.dankIslandHomeRightOrder) ? SettingsData.dankIslandHomeRightOrder.filter(id => id !== activityId) : [];
if (slot === "left")
leftOrder.unshift(activityId);
else if (slot === "right")
rightOrder.push(activityId);
SettingsData.set("dankIslandHomeLeftOrder", leftOrder);
SettingsData.set("dankIslandHomeRightOrder", rightOrder);
SettingsData.set(settingKey, slot);
}
component SystemLevelActivityRow: Item {
id: activityRow
required property string activityId
required property string settingKey
required property string text
required property string description
required property string slot
required property string displayMode
property var tags: []
readonly property bool compact: width - controls.implicitWidth - Theme.spacingM * 3 < 200
readonly property bool isHighlighted: SettingsSearchService.highlightSection === settingKey
width: parent?.width ?? 0
height: compact ? textColumn.implicitHeight + Theme.spacingS + controls.implicitHeight + Theme.spacingM * 2 : Math.max(60, Math.max(textColumn.implicitHeight, controls.implicitHeight) + Theme.spacingM * 2)
Component.onCompleted: {
const flickable = QmlUtils.findParentFlickable(activityRow.parent);
if (flickable)
SettingsSearchService.registerCard(settingKey, activityRow, flickable);
}
Component.onDestruction: SettingsSearchService.unregisterCard(settingKey)
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.primary, activityRow.isHighlighted ? 0.2 : 0)
visible: activityRow.isHighlighted
}
Column {
id: textColumn
x: Theme.spacingM
y: activityRow.compact ? Theme.spacingM : (activityRow.height - height) / 2
width: activityRow.compact ? activityRow.width - Theme.spacingM * 2 : activityRow.width - controls.implicitWidth - Theme.spacingM * 3
spacing: Theme.spacingXXS
StyledText {
width: parent.width
text: activityRow.text
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
elide: Text.ElideRight
}
StyledText {
width: parent.width
text: activityRow.description
color: Theme.surfaceVariantText
font.pixelSize: Theme.fontSizeSmall
wrapMode: Text.WordWrap
}
}
Column {
id: controls
x: activityRow.compact ? (activityRow.width - width) / 2 : activityRow.width - width - Theme.spacingM
y: activityRow.compact ? textColumn.y + textColumn.implicitHeight + Theme.spacingS : (activityRow.height - height) / 2
spacing: Theme.spacingXS
DankButtonGroup {
model: [I18n.tr("Left", "island settings: activity left of clock"), I18n.tr("Right", "island settings: activity right of clock"), I18n.tr("Hidden", "island settings: activity hidden")]
currentIndex: root.valueIndex(root.homeSlotValues, activityRow.slot, "hidden")
selectionMode: "single"
onSelectionChanged: (index, selected) => root.setHomeActivitySlot(activityRow.activityId, activityRow.settingKey, index, selected)
}
DankButtonGroup {
anchors.horizontalCenter: parent.horizontalCenter
visible: activityRow.slot !== "hidden"
model: [I18n.tr("Icon", "island settings: system level icon only"), "%", I18n.tr("Both", "island settings: system level icon and percentage")]
currentIndex: root.valueIndex(root.systemLevelDisplayValues, activityRow.displayMode, "both")
buttonHeight: 32
minButtonWidth: 52
buttonPadding: Theme.spacingS
textSize: Theme.fontSizeSmall
checkEnabled: false
selectionMode: "single"
onSelectionChanged: (index, selected) => {
if (!selected)
return;
const value = root.systemLevelDisplayValues[index] ?? "both";
SettingsData.set(activityRow.activityId === "volume" ? "dankIslandHomeVolumeDisplay" : "dankIslandHomeBrightnessDisplay", value);
}
}
}
}
DankFlickable {
anchors.fill: parent
clip: true
@@ -287,7 +179,10 @@ Item {
description: I18n.tr("Search when idle, visualizer when media is playing", "island settings: media slot description")
model: [I18n.tr("Left", "island settings: media or launcher slot left of the clock"), I18n.tr("Right", "island settings: media or launcher slot right of the clock"), I18n.tr("Hidden", "island settings: media or launcher slot hidden")]
currentIndex: root.valueIndex(root.homeSlotValues, SettingsData.dankIslandHomeMediaSlot, "left")
onSelectionChanged: (index, selected) => root.setHomeActivitySlot("media", "dankIslandHomeMediaSlot", index, selected)
onSelectionChanged: (index, selected) => {
if (selected)
SettingsData.set("dankIslandHomeMediaSlot", root.homeSlotValues[index] ?? "left");
}
}
SettingsButtonGroupRow {
@@ -297,7 +192,10 @@ Item {
description: BatteryService.batteryAvailable ? I18n.tr("Battery gauge opens Control Center", "island settings: status slot description with battery") : I18n.tr("Tools icon opens Control Center", "island settings: status slot description without battery")
model: [I18n.tr("Left", "island settings: battery or control center slot left of the clock"), I18n.tr("Right", "island settings: battery or control center slot right of the clock"), I18n.tr("Hidden", "island settings: battery or control center slot hidden")]
currentIndex: root.valueIndex(root.homeSlotValues, SettingsData.dankIslandHomeStatusSlot, "hidden")
onSelectionChanged: (index, selected) => root.setHomeActivitySlot("status", "dankIslandHomeStatusSlot", index, selected)
onSelectionChanged: (index, selected) => {
if (selected)
SettingsData.set("dankIslandHomeStatusSlot", root.homeSlotValues[index] ?? "hidden");
}
}
SettingsButtonGroupRow {
@@ -307,27 +205,62 @@ Item {
description: SettingsData.weatherEnabled ? I18n.tr("Weather icon and temperature open the weather activity", "island settings: weather slot description") : I18n.tr("Enable weather in Time & Weather to show this shortcut", "island settings: weather slot disabled hint")
model: [I18n.tr("Left", "island settings: weather slot left of the clock"), I18n.tr("Right", "island settings: weather slot right of the clock"), I18n.tr("Hidden", "island settings: weather slot hidden")]
currentIndex: root.valueIndex(root.homeSlotValues, SettingsData.dankIslandHomeWeatherSlot, "hidden")
onSelectionChanged: (index, selected) => root.setHomeActivitySlot("weather", "dankIslandHomeWeatherSlot", index, selected)
onSelectionChanged: (index, selected) => {
if (selected)
SettingsData.set("dankIslandHomeWeatherSlot", root.homeSlotValues[index] ?? "hidden");
}
}
SystemLevelActivityRow {
activityId: "volume"
SettingsButtonGroupRow {
settingKey: "dankIslandHomeVolumeSlot"
tags: ["island", "home", "compact", "volume", "audio", "percentage"]
tags: ["island", "home", "compact", "volume", "audio"]
text: I18n.tr("Volume", "island settings: volume slot row")
description: I18n.tr("Current output volume on the home face", "island settings: volume slot description")
slot: SettingsData.dankIslandHomeVolumeSlot
displayMode: SettingsData.dankIslandHomeVolumeDisplay
model: [I18n.tr("Left", "island settings: volume slot left of the clock"), I18n.tr("Right", "island settings: volume slot right of the clock"), I18n.tr("Hidden", "island settings: volume slot hidden")]
currentIndex: root.valueIndex(root.homeSlotValues, SettingsData.dankIslandHomeVolumeSlot, "hidden")
onSelectionChanged: (index, selected) => {
if (selected)
SettingsData.set("dankIslandHomeVolumeSlot", root.homeSlotValues[index] ?? "hidden");
}
}
SystemLevelActivityRow {
activityId: "brightness"
SettingsButtonGroupRow {
settingKey: "dankIslandHomeVolumeDisplay"
tags: ["island", "home", "compact", "volume", "icon", "percentage"]
text: I18n.tr("Volume Style", "island settings: volume display mode row")
visible: SettingsData.dankIslandHomeVolumeSlot !== "hidden"
model: [I18n.tr("Icon", "island settings: level shown as icon only"), I18n.tr("Percentage", "island settings: level shown as percentage only"), I18n.tr("Both", "island settings: level shown as icon and percentage")]
currentIndex: root.valueIndex(root.systemLevelDisplayValues, SettingsData.dankIslandHomeVolumeDisplay, "both")
onSelectionChanged: (index, selected) => {
if (selected)
SettingsData.set("dankIslandHomeVolumeDisplay", root.systemLevelDisplayValues[index] ?? "both");
}
}
SettingsButtonGroupRow {
settingKey: "dankIslandHomeBrightnessSlot"
tags: ["island", "home", "compact", "brightness", "display", "percentage"]
tags: ["island", "home", "compact", "brightness", "display"]
text: I18n.tr("Brightness", "island settings: brightness slot row")
description: I18n.tr("Current display brightness on the home face", "island settings: brightness slot description")
slot: SettingsData.dankIslandHomeBrightnessSlot
displayMode: SettingsData.dankIslandHomeBrightnessDisplay
model: [I18n.tr("Left", "island settings: brightness slot left of the clock"), I18n.tr("Right", "island settings: brightness slot right of the clock"), I18n.tr("Hidden", "island settings: brightness slot hidden")]
currentIndex: root.valueIndex(root.homeSlotValues, SettingsData.dankIslandHomeBrightnessSlot, "hidden")
onSelectionChanged: (index, selected) => {
if (selected)
SettingsData.set("dankIslandHomeBrightnessSlot", root.homeSlotValues[index] ?? "hidden");
}
}
SettingsButtonGroupRow {
settingKey: "dankIslandHomeBrightnessDisplay"
tags: ["island", "home", "compact", "brightness", "icon", "percentage"]
text: I18n.tr("Brightness Style", "island settings: brightness display mode row")
visible: SettingsData.dankIslandHomeBrightnessSlot !== "hidden"
model: [I18n.tr("Icon", "island settings: level shown as icon only"), I18n.tr("Percentage", "island settings: level shown as percentage only"), I18n.tr("Both", "island settings: level shown as icon and percentage")]
currentIndex: root.valueIndex(root.systemLevelDisplayValues, SettingsData.dankIslandHomeBrightnessDisplay, "both")
onSelectionChanged: (index, selected) => {
if (selected)
SettingsData.set("dankIslandHomeBrightnessDisplay", root.systemLevelDisplayValues[index] ?? "both");
}
}
SettingsToggleRow {
@@ -12381,6 +12381,52 @@
"icon": "touch_app",
"description": "Click expands only on an intentional press. Hybrid peeks the current compact face on hover"
},
{
"section": "dankIslandHomeBrightnessSlot",
"label": "Brightness",
"tabIndex": 46,
"category": "Dank Island",
"keywords": [
"activities",
"backlight",
"bright",
"brightness",
"compact",
"current",
"dank",
"dim",
"display",
"dynamic island",
"face",
"home",
"island",
"monitor",
"output",
"screen"
],
"description": "Current display brightness on the home face"
},
{
"section": "dankIslandHomeBrightnessDisplay",
"label": "Brightness Style",
"tabIndex": 46,
"category": "Dank Island",
"keywords": [
"activities",
"backlight",
"bright",
"brightness",
"compact",
"dank",
"dim",
"dynamic island",
"home",
"icon",
"island",
"percentage",
"style"
]
},
{
"section": "dankIslandNotificationBadgeClearOnOpen",
"label": "Clear Badge on Open",
@@ -13208,6 +13254,51 @@
],
"description": "Stage the Wayland overlay layer to remain visible over fullscreen apps"
},
{
"section": "dankIslandHomeVolumeSlot",
"label": "Volume",
"tabIndex": 46,
"category": "Dank Island",
"keywords": [
"activities",
"audio",
"compact",
"current",
"dank",
"dynamic island",
"face",
"home",
"island",
"loudness",
"output",
"sound",
"speaker",
"volume"
],
"description": "Current output volume on the home face"
},
{
"section": "dankIslandHomeVolumeDisplay",
"label": "Volume Style",
"tabIndex": 46,
"category": "Dank Island",
"keywords": [
"activities",
"audio",
"compact",
"dank",
"dynamic island",
"home",
"icon",
"island",
"loudness",
"percentage",
"sound",
"speaker",
"style",
"volume"
]
},
{
"section": "dankIslandHomeWeatherSlot",
"label": "Weather",