launcher, dash, settings: density and consistency pass

port 2.0

(cherry picked from commit fc7c92f8b2)
This commit is contained in:
bbedward authored and dux-ci[bot] committed 2026-10-27 04:03:57 +00:00
1 parent 181e624c0d
commit 523ef916b9
19 files changed
+237 -38

No files matched your search

Generated
+3 -3
View File
@@ -3,11 +3,11 @@
"dank-qml-common": {
"flake": false,
"locked": {
"lastModified": 1793044218,
"narHash": "sha256-379gQ6crrGvK6Ha/k5Uv6npGv/j5z3J35jjArhZBXuY=",
"lastModified": 1793073767,
"narHash": "sha256-mT0Kp4m/FP2u+I6GAZJtBH7LGHh6tSibDuRv4M4YBbc=",
"owner": "duxlabs-dev",
"repo": "dux-qml-common",
"rev": "34db4bb8387a73d705cb75702fefb99f6585eac6",
"rev": "08efce90fd4b2aa90c4064b57e48b14720bbe255",
"type": "github"
},
"original": {
@@ -23,6 +23,7 @@ Singleton {
readonly property real previewWidth: Theme.listItemHeight
readonly property real previewHeight: Theme.avatarSize
readonly property real footerHeight: Theme.buttonHeightXS
readonly property real chromeHeight: Theme.spacingM + pillHeight + resultsGap + footerHeight
readonly property real modeChipHeight: Theme.buttonHeightXS - Theme.spacingXS * 2
readonly property int maxVisibleRows: Theme.launcherMaxVisibleRows
readonly property real maxResultsHeight: maxVisibleRows * (rowHeight + rowGap) + sectionBand
@@ -53,19 +54,23 @@ Singleton {
}
}
function sizeHeight(size) {
function sizeRows(size) {
switch (size) {
case "micro":
return Theme.smallBreakpoint;
return 6;
case "medium":
return Theme.launcherWidthWide;
return 10;
case "large":
return Theme.launcherWidthLarge;
return 13;
default:
return Theme.launcherHeightDefault;
return 8;
}
}
function sizeHeight(size) {
return chromeHeight + sectionBand + sizeRows(size) * (rowHeight + rowGap);
}
function spotlightRadius(width) {
return Theme.fullRadius(width, pillHeight);
}
@@ -103,7 +103,8 @@ Item {
readonly property int baseHeight: LauncherMetrics.sizeHeight(_dmenuSizeOverride || SettingsData.dankLauncherV2Size)
readonly property real _contentImplicitH: launcherContentLoader.item?.implicitHeight ?? LauncherMetrics.pillHeight
readonly property int modalWidth: Math.min(spotlight ? (_dmenuSizeOverride ? LauncherMetrics.sizeWidth(_dmenuSizeOverride) : LauncherMetrics.spotlightWidth) : baseWidth, screenWidth - LauncherMetrics.screenMargin)
readonly property int modalHeight: spotlight ? _contentImplicitH : Math.min(baseHeight, screenHeight - LauncherMetrics.screenMargin)
readonly property int clampedBaseHeight: Math.min(baseHeight, screenHeight - LauncherMetrics.screenMargin)
readonly property int modalHeight: spotlight ? _contentImplicitH : clampedBaseHeight - (launcherContentLoader.item?.surplusHeight ?? 0)
readonly property string preferredConnectedBarSide: SettingsData.frameLauncherEmergeSide
@@ -896,6 +897,7 @@ Item {
focus: true
parentModal: root
transientSurfaceTracker: transientSurfaces
baseHeight: root.clampedBaseHeight
}
}
@@ -18,6 +18,14 @@ FocusScope {
property var parentModal: null
property string viewModeContext: "spotlight"
property alias searchField: searchField
property real baseHeight: height
readonly property real baseChromeHeight: Theme.spacingM + searchRow.height + mesgRow.height + contentStack.anchors.topMargin + contentStack.anchors.bottomMargin + (categoryRow.visible ? categoryRow.height + contentStack.gap : 0) + (fileFilterRow.visible ? fileFilterRow.height + contentStack.gap : 0) + footerBar.height + (footerBar.showFooter || contentHolder.inverted ? 0 : Theme.spacingM) + (contentHolder.inverted || footerBar._connectedBottomEmerge ? 0 : (root.parentModal?.borderWidth ?? 1))
readonly property real surplusHeight: {
const pitch = LauncherMetrics.rowHeight + LauncherMetrics.rowGap;
const available = baseHeight - baseChromeHeight - LauncherMetrics.sectionBand;
const rows = Math.max(0, Math.floor((available + 1) / pitch));
return Math.max(0, Math.round(available - rows * pitch));
}
property alias controller: controller
property alias resultsList: resultsList
property alias actionPanel: actionPanel
@@ -674,7 +682,12 @@ FocusScope {
id: resultsList
focusReturnTarget: searchField
keyForwardTargets: [root]
anchors.fill: parent
anchors.left: parent.left
anchors.right: parent.right
anchors.top: contentHolder.inverted ? undefined : parent.top
anchors.bottom: contentHolder.inverted ? parent.bottom : undefined
availableHeight: parent.height + (actionPanel.height > 0 ? actionPanel.height + contentStack.gap : 0)
height: Math.min(fittedHeight, parent.height)
controller: root.controller
leadingSectionHeaderAtBottom: contentHolder.inverted
transientSurfaceTracker: root.transientSurfaceTracker
@@ -32,6 +32,23 @@ Item {
readonly property real contentHeight: _visualModel.height
readonly property int pageRows: Math.max(1, Math.floor(height / (LauncherMetrics.rowHeight + LauncherMetrics.rowGap)))
property real availableHeight: 0
readonly property real fittedHeight: {
const rows = _visualModel.rows;
const starts = _visualModel.heights;
const inset = bottomSectionHeader.visible ? bottomSectionHeader.height + LauncherMetrics.resultsGap : 0;
const viewport = availableHeight - inset;
if (rows.length === 0 || _visualModel.height <= viewport + 1)
return availableHeight;
let fitted = 0;
for (let i = 0; i < rows.length; i++) {
const bottom = starts[i] + rows[i].height;
if (bottom > viewport + 1)
break;
fitted = bottom;
}
return fitted > 0 ? fitted + inset : availableHeight;
}
signal itemRightClicked(int index, var item, real mouseX, real mouseY)
@@ -39,10 +39,10 @@ FocusScope {
readonly property real _statusH: Theme.listItemTwoLineHeight + Theme.spacingXL
readonly property bool _firstSectionShowsHeader: !!(root.controller.sections?.[0]?.title?.length > 0)
readonly property real _resultsTopGap: _firstSectionShowsHeader ? LauncherMetrics.resultsGap : root.resultsInset
readonly property real _rowsHeightBudget: (root.controller.searchMode === "dmenu" && root.controller.dmenuLines > 0) ? (root.controller.dmenuLines * (LauncherMetrics.rowHeight + LauncherMetrics.rowGap) + (_firstSectionShowsHeader ? LauncherMetrics.sectionBand : _resultsTopGap)) : LauncherMetrics.maxResultsHeight
readonly property real _rowsHeightBudget: (root.controller.searchMode === "dmenu" && root.controller.dmenuLines > 0) ? (root.controller.dmenuLines * (LauncherMetrics.rowHeight + LauncherMetrics.rowGap) + (_firstSectionShowsHeader ? LauncherMetrics.sectionBand : _resultsTopGap)) : LauncherMetrics.maxResultsHeight + _resultsTopGap
readonly property real _maxResultsH: root.maxResultsHeight > 0 ? root.maxResultsHeight : Math.max(0, Math.min(_rowsHeightBudget + resultsList.bottomInset, (parentModal?.screenHeight ?? Theme.mediumBreakpoint) - (parentModal?.modalY ?? 0) - LauncherMetrics.pillHeight - actionPanel.height - Theme.spacingL))
readonly property real _resultsContentH: resultsList.contentHeight > 0 ? _resultsTopGap + resultsList.contentHeight + resultsList.bottomInset : _statusH
readonly property real _resultsH: _hasQuery ? Math.min(_resultsContentH, _maxResultsH) : 0
readonly property real _resultsH: _hasQuery ? Math.min(_resultsContentH, _resultsTopGap + resultsList.fittedHeight + resultsList.bottomInset) : 0
readonly property int _resizeDuration: Theme.expressiveDurations.expressiveFastSpatial
readonly property real _frameClipRadius: Math.max(0, (parentModal?.frameBottomRadius ?? 0) - resultsInset)
readonly property real _editAvailableH: maxResultsHeight > 0 ? maxResultsHeight + _searchAreaH : Math.max(LauncherMetrics.maxResultsHeight, (parentModal?.screenHeight ?? Theme.mediumBreakpoint) - (parentModal?.modalY ?? 0) - Theme.spacingL)
@@ -439,6 +439,7 @@ FocusScope {
focusReturnTarget: searchInput
keyForwardTargets: [searchKeyHandler]
readonly property real bottomInset: Theme.spacingS
availableHeight: Math.max(0, root._maxResultsH - root._resultsTopGap - bottomInset)
anchors.fill: parent
anchors.topMargin: root._resultsTopGap
controller: root.controller
@@ -232,7 +232,6 @@ Item {
anchors.top: parent.top
anchors.leftMargin: sideInset
anchors.rightMargin: sideInset
height: SettingsMetrics.searchBarHeight
placeholderText: I18n.tr("Search settings", "settings search field placeholder")
rightAccessoryWidth: avatarButton.visible ? avatarButton.width + Theme.spacingXS : 0
onFocusStateChanged: hasFocus => {
@@ -317,7 +316,7 @@ Item {
id: avatarButton
anchors.right: parent.right
anchors.rightMargin: (SettingsMetrics.searchBarHeight - buttonSize) / 2
anchors.rightMargin: (searchField.height - buttonSize) / 2
anchors.verticalCenter: parent.verticalCenter
visible: !root.searchActive
buttonSize: Theme.avatarSize
@@ -289,7 +289,7 @@ MediaChromeBase {
width: parent.width
text: [root.artist, root.album].filter(Boolean).join(" \u00b7 ") || "\u00a0"
color: Theme.onSurfaceVariant
font.pixelSize: Theme.fontSizeSmall
font.pixelSize: Theme.fontSizeMedium
horizontalAlignment: Text.AlignHCenter
active: root.scrolling
loop: true
@@ -122,7 +122,7 @@ MediaChromeBase {
reserveText: (durationText + " / " + durationText).replace(/\d/g, "8")
isMonospace: false
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeLarge
font.pixelSize: Theme.fontSizeSmall
font.weight: Theme.fontWeightMedium
}
}
@@ -122,6 +122,7 @@ Card {
id: titleLabel
width: parent.width
text: root.inlineMetadata ? root.titleText + " · " + root.artistText : root.titleText
fontToken: root.options.titleFont ?? MediaOptions.defaultTitleFont
font.pixelSize: root.compact ? Theme.fontSizeMedium : Theme.fontSizeLarge
font.weight: Theme.fontWeightMedium
color: root.contentColor
@@ -0,0 +1,131 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs.Common
import qs.Services
import qs.DCommon.Widgets
import qs.Modules.DDash
Rectangle {
id: root
property var widgetOptions: ({})
readonly property var weather: WeatherService.weather
readonly property var readings: {
SettingsData.useFahrenheit;
SettingsData.windSpeedUnit;
return [
{
icon: "humidity_low",
label: I18n.tr("Humidity", "weather metric label"),
value: WeatherService.formatPercent(weather.humidity)
},
{
icon: "air",
label: I18n.tr("Wind", "noun, weather wind speed metric label"),
value: WeatherService.formatSpeed(weather.wind)
},
{
icon: "speed",
label: I18n.tr("Pressure", "weather atmospheric pressure metric label"),
value: WeatherService.formatPressure(weather.pressure)
},
{
icon: "rainy",
label: I18n.tr("Precipitation", "weather precipitation probability metric label"),
value: WeatherService.formatPercent(weather.precipitationProbability)
},
{
nerdIcon: "sunrise",
label: I18n.tr("Sunrise", "sunrise time label, also time of day period name"),
value: weather.rawSunrise ? WeatherService.formatTime(weather.rawSunrise) : weather.sunrise
},
{
nerdIcon: "sunset",
label: I18n.tr("Sunset", "sunset time label, also time of day period name"),
value: weather.rawSunset ? WeatherService.formatTime(weather.rawSunset) : weather.sunset
}
];
}
readonly property real cellHeight: Theme.fontSizeSmall * 1.4 + Theme.fontSizeMedium * 1.4 + Theme.spacingXS
readonly property int rows: Math.max(1, Math.min(2, Math.floor((height - Theme.spacingL * 2) / cellHeight)))
readonly property int columns: Math.ceil(readings.length / rows)
radius: Theme.cornerRadiusXL
color: toneColors.surfaceColor
border.width: Theme.layerOutlineWidth
border.color: Theme.outlineMedium
Accessible.role: Accessible.StaticText
Accessible.name: readings.map(reading => reading.label + " " + (reading.value ?? I18n.tr("Not available"))).join(", ")
DTone {
id: toneColors
tone: root.widgetOptions.tone ?? ""
}
Grid {
anchors.fill: parent
anchors.margins: Theme.spacingL
columns: root.columns
rows: root.rows
columnSpacing: Theme.spacingS
rowSpacing: Theme.spacingS
Repeater {
model: root.readings
Column {
id: cell
required property var modelData
width: (parent.width - (root.columns - 1) * parent.columnSpacing) / root.columns
height: (parent.height - (root.rows - 1) * parent.rowSpacing) / root.rows
spacing: Theme.spacingXS
topPadding: Math.max(0, (height - implicitHeight) / 2)
Row {
width: parent.width
spacing: Theme.spacingXS
DIcon {
anchors.verticalCenter: parent.verticalCenter
visible: !!cell.modelData.icon
name: cell.modelData.icon ?? ""
size: Theme.iconSizeSmall
color: toneColors.contentColor
}
DNFIcon {
anchors.verticalCenter: parent.verticalCenter
visible: !!cell.modelData.nerdIcon
name: cell.modelData.nerdIcon ?? ""
size: Theme.iconSizeSmall
color: toneColors.contentColor
}
StyledText {
anchors.verticalCenter: parent.verticalCenter
width: parent.width - Theme.iconSizeSmall - parent.spacing
text: cell.modelData.label
font.pixelSize: Theme.fontSizeSmall
color: toneColors.contentColor
elide: Text.ElideRight
}
}
StyledText {
width: parent.width
text: root.weather.available && cell.modelData.value != null ? cell.modelData.value : "--"
font.pixelSize: Theme.fontSizeMedium
font.weight: Theme.fontWeightMedium
color: toneColors.contentColor
elide: Text.ElideRight
font.features: ({
"tnum": 1
})
}
}
}
}
}
+28 -7
View File
@@ -107,12 +107,25 @@ Item {
maxH: 3,
options: [DashRegistry.toneOption("primary"), DashRegistry.toggle("city", I18n.tr("Show city"), false)]
},
{
id: "readings",
text: I18n.tr("Readings", "weather widget title, grid of current measurements"),
icon: "grid_view",
component: readings,
w: 2,
h: 2,
minW: 2,
minH: 1,
maxW: 4,
maxH: 2,
options: [DashRegistry.toneOption()]
},
{
id: "hourly",
text: I18n.tr("Hourly", "adjective, hourly weather forecast widget title"),
icon: "schedule",
component: hourly,
w: 2,
w: 4,
h: 2,
minW: 2,
minH: 2,
@@ -130,7 +143,8 @@ Item {
minH: 2,
maxW: 4,
maxH: 3,
options: [DashRegistry.toneOption()]
options: [DashRegistry.toneOption()],
enabled: false
},
{
id: "moon",
@@ -142,7 +156,8 @@ Item {
minH: 2,
maxW: 4,
maxH: 3,
options: [DashRegistry.toneOption()]
options: [DashRegistry.toneOption()],
enabled: false
},
{
id: "humidity",
@@ -154,7 +169,8 @@ Item {
minH: 2,
maxW: 2,
maxH: 3,
options: root.metricOptions
options: root.metricOptions,
enabled: false
},
{
id: "wind",
@@ -166,7 +182,8 @@ Item {
minH: 2,
maxW: 2,
maxH: 3,
options: root.metricOptions
options: root.metricOptions,
enabled: false
},
{
id: "daily",
@@ -179,8 +196,7 @@ Item {
minH: 2,
maxW: 4,
maxH: 4,
options: root.forecastOptions,
enabled: false
options: root.forecastOptions
},
{
id: "pressure",
@@ -250,6 +266,11 @@ Item {
WeatherMetricCard {}
}
Component {
id: readings
WeatherReadingsCard {}
}
Component {
id: hourly
WeatherForecastWidget {
@@ -135,7 +135,6 @@ DPopout {
id: searchField
Layout.fillWidth: true
Layout.minimumWidth: Theme.fontSizeMedium * 8
Layout.preferredHeight: Theme.buttonHeightS
placeholderText: I18n.tr("Search", "search field placeholder") + "…"
text: processListPopout.searchText
onTextChanged: processListPopout.searchText = text
+2 -1
View File
@@ -526,8 +526,9 @@ Item {
SettingsToggleRow {
text: I18n.tr("Follow mouse")
description: I18n.tr("Anchored popouts open at the cursor instead of their widget")
description: I18n.tr("The Control Center opens at the cursor instead of its widget", "bar click action follow mouse description")
settingKey: "barClickActionFollowMouse"
visible: bar.selectedBarConfig?.middleClickAction === "control-center" || bar.selectedBarConfig?.rightClickAction === "control-center"
tags: ["bar", "click", "mouse", "cursor", "position", "anchor", "popout"]
checked: bar.selectedBarConfig?.clickActionFollowMouse ?? false
onToggled: checked => SettingsData.updateBarConfig(bar.selectedBarId, {
@@ -195,7 +195,6 @@ DFloatingWindow {
DSearchField {
id: searchField
width: parent.width
height: Theme.fieldHeightLarge
textColor: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium
placeholderText: I18n.tr("Search widgets...")
@@ -30,7 +30,7 @@ SettingsCard {
resetStore: root.store
resetKeys: ["islandSharedRouting"]
text: I18n.tr("Shared shortcuts", "island settings dropdown label, which island handles global shortcuts")
description: I18n.tr("Routes launcher, dash, control center and notification shortcuts", "shared shortcuts dropdown description")
description: I18n.tr("Routes launcher, dash, control center and notification shortcuts. Bar widget clicks always open their own popout", "shared shortcuts dropdown description")
options: [I18n.tr("Normal routing", "shared shortcuts option, shortcuts open where they normally would"), I18n.tr("Always here", "shared shortcuts option, shortcuts always open on this island"), I18n.tr("Last used on this screen", "shared shortcuts option, shortcuts open on the island last used on this display")]
dropdownWidth: Theme.smallBreakpoint / 2
currentValue: options[Math.max(0, root.routingValues.indexOf(root.sharedRouting))]
@@ -33,7 +33,6 @@ Singleton {
readonly property real navIconSize: Theme.avatarSize
readonly property real navItemMinHeight: Theme.listItemHeight
readonly property real sidebarGroupGap: Theme.spacingS
readonly property real searchBarHeight: 56
readonly property real searchBarGap: Theme.spacingM
readonly property real avatarSize: 64
readonly property real splitDividerHeight: Theme.iconSize
@@ -3500,26 +3500,25 @@
"category": "General",
"keywords": [
"anchor",
"anchored",
"bar",
"center",
"click",
"control",
"cursor",
"follow",
"general",
"mouse",
"open",
"opens",
"panel",
"popout",
"popouts",
"position",
"statusbar",
"taskbar",
"their",
"topbar",
"widget"
],
"parentLabel": "Bar",
"description": "Anchored popouts open at the cursor instead of their widget"
"description": "The Control Center opens at the cursor instead of its widget"
},
{
"section": "frameEnabled",
@@ -4123,11 +4122,13 @@
"category": "General",
"keywords": [
"alert",
"always",
"app drawer",
"app menu",
"applications",
"bar",
"center",
"clicks",
"control",
"control center",
"dash",
@@ -4138,7 +4139,9 @@
"launcher",
"notif",
"notification",
"open",
"panel",
"popout",
"routes",
"routing",
"shared",
@@ -4146,10 +4149,12 @@
"start menu",
"statusbar",
"taskbar",
"topbar"
"their",
"topbar",
"widget"
],
"parentLabel": "Bar",
"description": "Routes launcher, dash, control center and notification shortcuts",
"description": "Routes launcher, dash, control center and notification shortcuts. Bar widget clicks always open their own popout",
"conditionKey": "islandEnabled"
},
{
@@ -18023,11 +18028,13 @@
"category": "Dot",
"keywords": [
"alert",
"always",
"app drawer",
"app menu",
"applications",
"bar",
"center",
"clicks",
"control",
"control center",
"dash",
@@ -18038,7 +18045,9 @@
"launcher",
"notif",
"notification",
"open",
"panel",
"popout",
"routes",
"routing",
"shared",
@@ -18046,10 +18055,12 @@
"start menu",
"statusbar",
"taskbar",
"topbar"
"their",
"topbar",
"widget"
],
"parentLabel": "Bar",
"description": "Routes launcher, dash, control center and notification shortcuts",
"description": "Routes launcher, dash, control center and notification shortcuts. Bar widget clicks always open their own popout",
"conditionKey": "dotEnabled"
},
{