mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-16 16:24:00 -04:00
media: rebrand to Bento
popouts: instantly set empty input region on exit
This commit is contained in:
@@ -88,7 +88,7 @@ jobs:
|
||||
## Claude review
|
||||
<one line verdict>
|
||||
- <finding, file:line> per inline comment posted this run
|
||||
Checked: <one line>. Model: claude-opus-5.
|
||||
Checked: <one line>. Model: claude-opus-5-5.
|
||||
|
||||
No findings: "No issues found." plus what was checked.
|
||||
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
|
||||
Review only. Never edit files, commit, push, approve or request changes. Do not build, vet, format or run tests; CI already does that and the tools are not available here. Post each finding once. Keep comments short.
|
||||
claude_args: |
|
||||
--model claude-opus-5
|
||||
--model claude-opus-5-5
|
||||
--max-turns 120
|
||||
--allowedTools "Read,Grep,Glob,LS,Task,mcp__github_inline_comment__create_inline_comment,Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr comment:*),Bash(gh api repos/${{ github.repository }}/pulls/${{ github.event.issue.number }}/comments:*),Bash(git diff:*),Bash(git log:*),Bash(git show:*),Bash(git blame:*)"
|
||||
--disallowedTools "Edit,Write,MultiEdit,NotebookEdit,WebFetch,WebSearch"
|
||||
|
||||
@@ -12,14 +12,15 @@ Singleton {
|
||||
albumArtBackdrop: true,
|
||||
albumArtAccent: true,
|
||||
animatedArt: false,
|
||||
lyrics: true
|
||||
lyrics: true,
|
||||
deviceName: true
|
||||
})
|
||||
|
||||
readonly property string defaultPlayerStyle: "zurvan"
|
||||
readonly property string defaultPlayerStyle: "bento"
|
||||
readonly property var playerStyles: [
|
||||
{
|
||||
"value": "zurvan",
|
||||
"text": "Zurvan"
|
||||
"value": "bento",
|
||||
"text": "Bento"
|
||||
},
|
||||
{
|
||||
"value": "material",
|
||||
@@ -28,7 +29,7 @@ Singleton {
|
||||
]
|
||||
|
||||
readonly property var titleFontDefaults: ({
|
||||
zurvan: "Notable",
|
||||
bento: "Notable",
|
||||
material: "ui"
|
||||
})
|
||||
|
||||
|
||||
@@ -194,8 +194,6 @@ Singleton {
|
||||
readonly property real mediaCardMargin: Theme.spacingL
|
||||
readonly property real mediaArtSize: 150
|
||||
readonly property real mediaArtSizeDash: 336
|
||||
readonly property real mediaArtLowResRatio: 0.5
|
||||
readonly property real mediaArtLowResScale: 0.85
|
||||
readonly property real mediaArtSizeMaterial: 200
|
||||
readonly property real mediaArtRadius: Theme.cornerRadiusXL
|
||||
readonly property real mediaArtSoftRadiusRatio: 0.3
|
||||
@@ -204,12 +202,15 @@ Singleton {
|
||||
readonly property real mediaPlayWidthRatio: 1.5
|
||||
readonly property real mediaPlayWidthStep: 0.75
|
||||
readonly property real mediaTransportPressScale: 1.2
|
||||
readonly property real mediaDeviceNameWidthRatio: 0.42
|
||||
readonly property real accentSelectedAlpha: 0.2
|
||||
readonly property real groupIdleAlpha: 0.1
|
||||
readonly property int mediaPositionPollInterval: 1000
|
||||
readonly property int mediaVolumeEchoTimeout: 1500
|
||||
readonly property int mediaTransitionGraceInterval: 3000
|
||||
readonly property int mediaPlayerLossGraceInterval: 1500
|
||||
readonly property real mediaTextScrollSpeed: 40
|
||||
readonly property int mediaTextScrollStep: 30
|
||||
readonly property int mediaLyricsRequestTimeout: 16000
|
||||
readonly property int mediaLyricsLoadingDelay: 300
|
||||
readonly property real mediaLyricsPositionTolerance: 0.05
|
||||
|
||||
@@ -122,7 +122,7 @@ Singleton {
|
||||
"value": "slanted",
|
||||
"text": I18n.tr("Slanted", "Album artwork shape")
|
||||
}
|
||||
]), choice("titleFont", I18n.tr("Title font"), MediaOptions.defaultTitleFont, Theme.fontChoices), toggle("seekbar", I18n.tr("Show seekbar"), MediaOptions.defaults.seekbar), toggle("waveProgress", I18n.tr("Wave progress bars"), MediaOptions.defaults.waveProgress), toggle("albumArtBackdrop", I18n.tr("Album art backdrop"), MediaOptions.defaults.albumArtBackdrop), toggle("albumArtAccent", I18n.tr("Use album art accent"), MediaOptions.defaults.albumArtAccent), toggle("animatedArt", I18n.tr("Apple Music animated covers"), MediaOptions.defaults.animatedArt, I18n.tr("Sends the playing artist and album name to Apple")), toggle("lyrics", I18n.tr("Lyrics", "Media player lyrics button"), MediaOptions.defaults.lyrics, I18n.tr("Sends the playing track, artist and album name to enabled lyrics providers"))]
|
||||
]), choice("titleFont", I18n.tr("Title font"), MediaOptions.defaultTitleFont, Theme.fontChoices), toggle("deviceName", I18n.tr("Show device name", "Media player option that puts the audio output device name on its button"), MediaOptions.defaults.deviceName), toggle("seekbar", I18n.tr("Show seekbar"), MediaOptions.defaults.seekbar), toggle("waveProgress", I18n.tr("Wave progress bars"), MediaOptions.defaults.waveProgress), toggle("albumArtBackdrop", I18n.tr("Album art backdrop"), MediaOptions.defaults.albumArtBackdrop), toggle("albumArtAccent", I18n.tr("Use album art accent"), MediaOptions.defaults.albumArtAccent), toggle("animatedArt", I18n.tr("Apple Music animated covers"), MediaOptions.defaults.animatedArt, I18n.tr("Sends the playing artist and album name to Apple")), toggle("lyrics", I18n.tr("Lyrics", "Media player lyrics button"), MediaOptions.defaults.lyrics, I18n.tr("Sends the playing track, artist and album name to enabled lyrics providers"))]
|
||||
},
|
||||
{
|
||||
"id": "wallpaper",
|
||||
|
||||
+14
-11
@@ -12,27 +12,25 @@ MediaChromeBase {
|
||||
|
||||
readonly property bool compact: width < Theme.smallBreakpoint || halfWidth < headerHeight + controls.implicitHeight
|
||||
readonly property real halfWidth: Math.max(0, (width - padding * 2 - Theme.spacingXL) / 2)
|
||||
readonly property real bodyHeight: Math.max(0, height - padding * 2)
|
||||
// !TODO: expose this variant? playerPaneOpen false gives art beside lyrics, or art alone with hover transport
|
||||
readonly property bool playerPane: root.player.playerPaneOpen
|
||||
readonly property bool controlsColumn: playerPane
|
||||
readonly property bool lyricsColumn: root.player.lyricsOpen && !playerPane
|
||||
readonly property bool splitPanes: controlsColumn || lyricsColumn
|
||||
readonly property bool artTransport: !playerPane && !!root.presentation
|
||||
readonly property real naturalArtSize: Math.max(0, Math.min(artSize, compact ? width / 2 : halfWidth))
|
||||
readonly property real artworkSize: compact ? naturalArtSize : Math.max(naturalArtSize, Math.min(halfWidth, bodyHeight))
|
||||
readonly property real naturalArtSize: Math.round(Math.max(0, Math.min(artSize, compact ? width / 2 : halfWidth)))
|
||||
// Sized from the controls column, never from this item's own height: reading back the height
|
||||
// the artwork itself sets makes the split settle wherever the current track happened to put it.
|
||||
readonly property real artworkSize: Math.round(compact ? naturalArtSize : Math.min(halfWidth, Math.max(naturalArtSize, headerHeight + controls.implicitHeight)))
|
||||
readonly property real columnHeight: compact ? artworkSize : Math.max(artworkSize, paneHeight)
|
||||
readonly property real paneHeight: Math.max(artworkSize, headerHeight + controls.implicitHeight)
|
||||
readonly property real paneMinHeight: Math.max(naturalArtSize, headerHeight + controls.implicitHeight)
|
||||
readonly property real headerHeight: sourceRow.height + Theme.spacingS
|
||||
readonly property real renderScale: Window.window?.devicePixelRatio ?? Screen.devicePixelRatio
|
||||
readonly property int artSide: TrackArtService.resolvedArtSide
|
||||
readonly property bool lowResArt: artSide > 0 && artSide < artworkSize * renderScale * DashMetrics.mediaArtLowResRatio
|
||||
|
||||
artSize: DashMetrics.mediaArtSizeDash
|
||||
surfaceColor: Theme.foregroundColor(Theme.hostSurface)
|
||||
baseHeight: Math.max(DashMetrics.tabMinHeight, padding * 2 + (compact ? naturalArtSize + Theme.spacingXL + paneMinHeight : Math.max(naturalArtSize, paneMinHeight)))
|
||||
focusTargets: (viewToggle.visible ? [viewToggle] : []).concat(artTransportLoader.item?.focusTargets ?? [], [playerButton], sourceGroup.focusTargets, transport.focusTargets, seekbar.canSeek && seekBlock.visible ? [seekbar] : [])
|
||||
focusTargets: (viewToggle.visible ? [viewToggle] : []).concat(artTransportLoader.item?.focusTargets ?? [], [playerButton], sourceGroup.focusTargets, transport.focusTargets, seekbar.canSeek && root.hasSeekbar ? [seekbar] : [])
|
||||
panelButtons: [playerButton].concat(sourceGroup.panelButtons)
|
||||
inlineVolume: true
|
||||
|
||||
@@ -56,10 +54,8 @@ MediaChromeBase {
|
||||
Item {
|
||||
id: art
|
||||
|
||||
readonly property real scaledSize: root.artworkSize * (root.lowResArt ? DashMetrics.mediaArtLowResScale : 1)
|
||||
|
||||
anchors.centerIn: parent
|
||||
width: root.compact ? scaledSize : Math.min(root.artworkSize, Math.max(scaledSize, root.headerHeight + controls.implicitHeight))
|
||||
width: root.artworkSize
|
||||
height: width
|
||||
|
||||
HoverHandler {
|
||||
@@ -282,6 +278,7 @@ MediaChromeBase {
|
||||
loop: true
|
||||
fadeEdges: true
|
||||
pxPerMs: DashMetrics.mediaTextScrollSpeed / 1000
|
||||
stepInterval: DashMetrics.mediaTextScrollStep
|
||||
}
|
||||
|
||||
ScrollingText {
|
||||
@@ -294,6 +291,7 @@ MediaChromeBase {
|
||||
loop: true
|
||||
fadeEdges: true
|
||||
pxPerMs: DashMetrics.mediaTextScrollSpeed / 1000
|
||||
stepInterval: DashMetrics.mediaTextScrollStep
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,11 +325,13 @@ MediaChromeBase {
|
||||
visible: hasControls
|
||||
}
|
||||
|
||||
// Kept in the column for a length-less stream so the pane, and with it the
|
||||
// artwork it sizes, does not resize when one comes up in the queue.
|
||||
Item {
|
||||
id: seekBlock
|
||||
width: parent.width
|
||||
height: Theme.buttonHeightXS
|
||||
visible: root.hasSeekbar
|
||||
visible: root.seekbarEnabled && !!root.presentation
|
||||
LayoutMirroring.enabled: false
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
@@ -339,6 +339,7 @@ MediaChromeBase {
|
||||
id: elapsed
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.hasSeekbar
|
||||
text: Format.formatDuration(seekbar.value * (root.presentation?.length ?? 0))
|
||||
reserveText: duration.text.replace(/\d/g, "8")
|
||||
}
|
||||
@@ -349,6 +350,7 @@ MediaChromeBase {
|
||||
anchors.right: duration.left
|
||||
anchors.margins: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.hasSeekbar
|
||||
player: root.player
|
||||
}
|
||||
|
||||
@@ -356,6 +358,7 @@ MediaChromeBase {
|
||||
id: duration
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.hasSeekbar
|
||||
text: Format.formatDuration(root.presentation?.length ?? 0)
|
||||
reserveText: text.replace(/\d/g, "8")
|
||||
}
|
||||
@@ -39,7 +39,7 @@ Row {
|
||||
panelId: "volume"
|
||||
iconName: root.player.getVolumeIcon()
|
||||
enabled: root.player.volumeAvailable
|
||||
tooltipText: I18n.tr("Volume") + ": " + Math.round(root.player.currentVolume * 100) + "%"
|
||||
tooltipText: (root.player.usePlayerVolume ? I18n.tr("Media volume") : I18n.tr("Volume")) + ": " + Math.round(root.player.currentVolume * 100) + "%"
|
||||
|
||||
MediaVolumeWheel {
|
||||
player: root.player
|
||||
@@ -50,7 +50,7 @@ Row {
|
||||
GroupButton {
|
||||
id: devicesButton
|
||||
panelId: "devices"
|
||||
tooltipText: I18n.tr("Devices", "Media player output device picker")
|
||||
tooltipText: I18n.tr("Devices", "Media player output device picker") + ": " + AudioService.displayName(AudioService.sink)
|
||||
iconName: AudioService.sinkIcon(AudioService.sink)
|
||||
|
||||
MediaSinkWheel {}
|
||||
|
||||
@@ -151,7 +151,7 @@ DankBottomSheet {
|
||||
subtitle: [modelData?.trackTitle, modelData?.trackArtist].filter(Boolean).join(" · ")
|
||||
selected: modelData === root.player.activePlayer
|
||||
onActivated: {
|
||||
MprisController.switchActivePlayer(modelData);
|
||||
MprisController.setActivePlayer(modelData);
|
||||
root.player.panel = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.DankDash
|
||||
import "../../../DankCommon/Common/FocusNavigation.js" as FocusNavigation
|
||||
|
||||
Item {
|
||||
@@ -11,26 +12,13 @@ Item {
|
||||
|
||||
required property var player
|
||||
|
||||
readonly property var focusTargets: [volumeButton, devicesButton]
|
||||
readonly property var panelButtons: [volumeButton, devicesButton]
|
||||
readonly property var focusTargets: [volumeButton, deviceChip, deviceIcon]
|
||||
readonly property var panelButtons: [volumeButton, deviceChip, deviceIcon]
|
||||
readonly property string devicesLabel: I18n.tr("Devices", "Media player output device picker")
|
||||
readonly property string sinkName: AudioService.displayName(AudioService.sink)
|
||||
readonly property string fittedSinkName: {
|
||||
const room = devicesButton.maximumLabelWidth;
|
||||
// advanceWidth() is not reactive, this read re-evaluates once the font resolves
|
||||
if (labelMetrics.averageCharacterWidth <= 0)
|
||||
return "";
|
||||
if (Math.ceil(labelMetrics.advanceWidth(sinkName)) <= room)
|
||||
return sinkName;
|
||||
const words = sinkName.split(/\s+/);
|
||||
while (words.length > 1) {
|
||||
words.pop();
|
||||
const shortened = words.join(" ");
|
||||
if (Math.ceil(labelMetrics.advanceWidth(shortened)) <= room)
|
||||
return shortened;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
readonly property string deviceTooltip: devicesLabel + ": " + sinkName
|
||||
readonly property bool showSinkName: root.player.options?.deviceName ?? MediaOptions.defaults.deviceName
|
||||
readonly property string volumeLabel: root.player.usePlayerVolume ? I18n.tr("Media volume") : I18n.tr("Volume")
|
||||
readonly property bool muted: player.usePlayerVolume ? player.currentVolume === 0 : AudioService.sinkSilent
|
||||
readonly property real volumeRatio: player.maxVolumePercent > 0 ? player.currentVolume * 100 / player.maxVolumePercent : 0
|
||||
|
||||
@@ -38,13 +26,6 @@ Item {
|
||||
|
||||
Keys.onPressed: event => event.accepted = FocusNavigation.handleHorizontalKey(event, focusTargets, I18n.isRtl)
|
||||
|
||||
FontMetrics {
|
||||
id: labelMetrics
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Theme.fontWeightMedium
|
||||
}
|
||||
|
||||
DankRingGauge {
|
||||
id: volumeRing
|
||||
|
||||
@@ -72,7 +53,7 @@ Item {
|
||||
iconName: root.player.getVolumeIcon()
|
||||
iconColor: root.muted ? Theme.onSurfaceVariant : Theme.onSurface
|
||||
enabled: root.player.volumeAvailable
|
||||
tooltipText: I18n.tr("Volume") + ": " + Math.round(root.player.currentVolume * 100) + "%"
|
||||
tooltipText: root.volumeLabel + ": " + Math.round(root.player.currentVolume * 100) + "%"
|
||||
onClicked: root.player.togglePanel(panelId)
|
||||
|
||||
MediaVolumeWheel {
|
||||
@@ -83,22 +64,41 @@ Item {
|
||||
}
|
||||
|
||||
DankButton {
|
||||
id: devicesButton
|
||||
id: deviceChip
|
||||
|
||||
readonly property string panelId: "devices"
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
maximumWidth: Math.max(0, root.width - volumeRing.width - Theme.spacingXS)
|
||||
text: root.fittedSinkName || root.devicesLabel
|
||||
visible: root.showSinkName
|
||||
maximumWidth: Math.round(root.width * DashMetrics.mediaDeviceNameWidthRatio)
|
||||
text: root.sinkName
|
||||
iconName: AudioService.sinkIcon(AudioService.sink)
|
||||
tooltipText: root.fittedSinkName === root.sinkName ? root.devicesLabel : root.sinkName
|
||||
Accessible.name: root.devicesLabel + ": " + root.sinkName
|
||||
tooltipText: root.deviceTooltip
|
||||
Accessible.name: root.deviceTooltip
|
||||
buttonHeight: Theme.buttonHeightXS
|
||||
backgroundColor: MediaAccentService.accentSecondaryContainer
|
||||
textColor: MediaAccentService.onAccentSecondaryContainer
|
||||
horizontalPadding: Theme.spacingM
|
||||
onClicked: root.player.togglePanel("devices")
|
||||
onClicked: root.player.togglePanel(panelId)
|
||||
|
||||
MediaSinkWheel {}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: deviceIcon
|
||||
|
||||
readonly property string panelId: "devices"
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !root.showSinkName
|
||||
buttonSize: volumeRing.width
|
||||
iconName: AudioService.sinkIcon(AudioService.sink)
|
||||
iconColor: MediaAccentService.onAccentSecondaryContainer
|
||||
backgroundColor: MediaAccentService.accentSecondaryContainer
|
||||
tooltipText: root.deviceTooltip
|
||||
onClicked: root.player.togglePanel(panelId)
|
||||
|
||||
MediaSinkWheel {}
|
||||
}
|
||||
|
||||
@@ -45,9 +45,22 @@ Item {
|
||||
}
|
||||
readonly property bool volumeAvailable: !!((activePlayer && activePlayer.volumeSupported && !__isChromeBrowser) || (AudioService.sink && AudioService.sink.audio))
|
||||
readonly property bool usePlayerVolume: activePlayer && activePlayer.volumeSupported && !__isChromeBrowser
|
||||
readonly property real currentVolume: usePlayerVolume ? activePlayer.volume : (AudioService.sink?.audio?.volume ?? 0)
|
||||
readonly property real reportedVolume: usePlayerVolume ? activePlayer.volume : (AudioService.sink?.audio?.volume ?? 0)
|
||||
readonly property real currentVolume: pendingVolume >= 0 ? pendingVolume : reportedVolume
|
||||
readonly property real maxVolumePercent: usePlayerVolume ? 100 : AudioService.sinkMaxVolume
|
||||
|
||||
// MPRIS volume round-trips through the player, so successive steps would each read a stale
|
||||
// activePlayer.volume and collapse into one. Drive them from the value we last asked for.
|
||||
property real pendingVolume: -1
|
||||
|
||||
onReportedVolumeChanged: {
|
||||
if (pendingVolume >= 0 && Math.abs(reportedVolume - pendingVolume) < 0.005)
|
||||
clearPendingVolume();
|
||||
}
|
||||
|
||||
onUsePlayerVolumeChanged: clearPendingVolume()
|
||||
onActivePlayerChanged: clearPendingVolume()
|
||||
|
||||
implicitWidth: DashMetrics.contentWidthFor(SettingsData.showWeekNumber, DashMetrics.panelColumnsFor(entryId))
|
||||
implicitHeight: mediaChrome.item?.implicitHeight ?? DashMetrics.tabMinHeight
|
||||
|
||||
@@ -93,6 +106,12 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: pendingVolumeTimer
|
||||
interval: DashMetrics.mediaVolumeEchoTimeout
|
||||
onTriggered: root.pendingVolume = -1
|
||||
}
|
||||
|
||||
MediaPresentation {
|
||||
id: mediaPresentation
|
||||
player: root
|
||||
@@ -155,12 +174,19 @@ Item {
|
||||
return AudioService.sinkVolumeIconName;
|
||||
}
|
||||
|
||||
function clearPendingVolume() {
|
||||
pendingVolume = -1;
|
||||
pendingVolumeTimer.stop();
|
||||
}
|
||||
|
||||
function setVolume(ratio) {
|
||||
if (!volumeAvailable)
|
||||
return;
|
||||
const clamped = Math.min(maxVolumePercent / 100, Math.max(0, ratio));
|
||||
SessionData.suppressOSDTemporarily();
|
||||
if (usePlayerVolume) {
|
||||
pendingVolume = clamped;
|
||||
pendingVolumeTimer.restart();
|
||||
activePlayer.volume = clamped;
|
||||
return;
|
||||
}
|
||||
@@ -281,12 +307,12 @@ Item {
|
||||
Loader {
|
||||
id: mediaChrome
|
||||
anchors.fill: parent
|
||||
sourceComponent: root.playerStyle === "material" ? materialChrome : zurvanChrome
|
||||
sourceComponent: root.playerStyle === "material" ? materialChrome : bentoChrome
|
||||
}
|
||||
|
||||
Component {
|
||||
id: zurvanChrome
|
||||
ZurvanChrome {
|
||||
id: bentoChrome
|
||||
BentoChrome {
|
||||
player: root
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ CcSheetDialog {
|
||||
iconName: "settings"
|
||||
onClicked: {
|
||||
root.dismiss();
|
||||
PopoutService.closeDankDash();
|
||||
PopoutService.openSettingsWithTab(root.entryId === "media" ? "media_player" : "weather");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ Card {
|
||||
readonly property string artUrl: TrackArtService.resolvedArtUrl
|
||||
readonly property color accent: MediaAccentService.accent
|
||||
readonly property bool showSeekbar: options.seekbar !== false && !tiny
|
||||
readonly property bool zurvan: options.playerStyle === "zurvan"
|
||||
readonly property bool bento: options.playerStyle === "bento"
|
||||
readonly property bool inlineMetadata: compact && titleLabel.implicitHeight + artistLabel.implicitHeight + trackText.spacing > transport.y - Theme.spacingXS
|
||||
readonly property var playbackFocusTargets: [playButton, previousButton, nextButton].concat(seekbar.canSeek ? [seekbar] : [])
|
||||
|
||||
@@ -167,7 +167,7 @@ Card {
|
||||
id: transport
|
||||
|
||||
readonly property bool stacked: root.narrow && !root.tiny
|
||||
readonly property bool centered: root.zurvan && !stacked && !root.tiny
|
||||
readonly property bool centered: root.bento && !stacked && !root.tiny
|
||||
readonly property bool medium: !root.compact && width >= Theme.buttonHeightM * 4
|
||||
readonly property real buttonHeight: medium ? Theme.buttonHeightM : Theme.buttonHeightS
|
||||
readonly property real spacing: root.compact || stacked ? Theme.spacingXS : Theme.spacingS
|
||||
@@ -194,7 +194,7 @@ Card {
|
||||
checkable: true
|
||||
checked: root.playing
|
||||
iconFilled: false
|
||||
radius: Theme.buttonRadius(width, height, buttonSize, pressed, !root.zurvan && checked)
|
||||
radius: Theme.buttonRadius(width, height, buttonSize, pressed, !root.bento && checked)
|
||||
iconName: root.playing ? "pause" : "play_arrow"
|
||||
Accessible.name: root.playing ? I18n.tr("Pause") : I18n.tr("Play")
|
||||
enabled: !!root.activePlayer?.canTogglePlaying
|
||||
@@ -209,11 +209,11 @@ Card {
|
||||
anchors.bottom: parent.bottom
|
||||
size: transport.medium ? "m" : "s"
|
||||
width: transport.stacked ? (parent.width - transport.spacing) / 2 : (parent.width - playButton.width - transport.spacing * 2) / 2
|
||||
variant: root.zurvan ? "tonal" : "standard"
|
||||
round: !root.zurvan
|
||||
variant: root.bento ? "tonal" : "standard"
|
||||
round: !root.bento
|
||||
radius: Theme.buttonRadius(width, height, buttonSize, pressed, round)
|
||||
containerColor: MediaAccentService.accentSecondaryContainer
|
||||
contentColor: root.zurvan ? MediaAccentService.onAccentSecondaryContainer : Theme.onSecondaryContainer
|
||||
contentColor: root.bento ? MediaAccentService.onAccentSecondaryContainer : Theme.onSecondaryContainer
|
||||
iconName: "skip_previous"
|
||||
Accessible.name: I18n.tr("Previous")
|
||||
enabled: !!root.activePlayer?.canGoPrevious || (!!root.activePlayer?.canSeek && root.activePlayer.position > 8)
|
||||
|
||||
@@ -279,7 +279,10 @@ Item {
|
||||
DankButton {
|
||||
text: I18n.tr("Settings")
|
||||
iconName: "settings"
|
||||
onClicked: PopoutService.openSettingsWithTab("weather")
|
||||
onClicked: {
|
||||
PopoutService.closeDankDash();
|
||||
PopoutService.openSettingsWithTab("weather");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,13 +367,6 @@ Singleton {
|
||||
_persistIdentity(activePlayer.identity);
|
||||
}
|
||||
|
||||
function switchActivePlayer(player) {
|
||||
const current = root.activePlayer;
|
||||
if (current && current !== player && current.canPause)
|
||||
current.pause();
|
||||
setActivePlayer(player);
|
||||
}
|
||||
|
||||
function setActivePlayer(player: MprisPlayer): void {
|
||||
activePlayer = player;
|
||||
if (player)
|
||||
|
||||
@@ -1424,8 +1424,6 @@ Item {
|
||||
screen: root.surfaceScreen
|
||||
visible: false
|
||||
color: "transparent"
|
||||
readonly property bool closeVisualActive: root.shouldBeVisible || root.isClosing
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
root._surfaceFrameReady = false;
|
||||
@@ -1506,13 +1504,14 @@ Item {
|
||||
height: root.maskHeight
|
||||
}
|
||||
|
||||
// Empty input region to avoid the animating surface taking pointer events
|
||||
Item {
|
||||
id: contentMaskRect
|
||||
visible: false
|
||||
x: contentContainer.x - contentContainer.horizontalConnectorExtent - root.inputMargin
|
||||
y: contentContainer.y - contentContainer.verticalConnectorExtent - root.inputMargin
|
||||
width: root.connected || contentWindow.closeVisualActive ? root.renderedAlignedWidth + contentContainer.horizontalConnectorExtent * 2 + root.inputMargin * 2 : 0
|
||||
height: root.connected || contentWindow.closeVisualActive ? root.renderedAlignedHeight + contentContainer.verticalConnectorExtent * 2 + root.inputMargin * 2 : 0
|
||||
width: root.shouldBeVisible ? root.renderedAlignedWidth + contentContainer.horizontalConnectorExtent * 2 + root.inputMargin * 2 : 0
|
||||
height: root.shouldBeVisible ? root.renderedAlignedHeight + contentContainer.verticalConnectorExtent * 2 + root.inputMargin * 2 : 0
|
||||
}
|
||||
|
||||
Loader {
|
||||
|
||||
@@ -16,6 +16,7 @@ Item {
|
||||
property real holdStartMs: 2000
|
||||
property real holdEndMs: 2000
|
||||
property real pxPerMs: 1 / 60
|
||||
property int stepInterval: 60
|
||||
property real overscroll: 5
|
||||
property bool animateTextChange: false
|
||||
property bool loop: false
|
||||
@@ -34,6 +35,7 @@ Item {
|
||||
property int scrollDirection: 1
|
||||
property real scrollHoldMs: holdStartMs
|
||||
property real textShift: 0
|
||||
property real lastStepMs: 0
|
||||
|
||||
function resetScroll() {
|
||||
scrollOffset = 0;
|
||||
@@ -67,8 +69,11 @@ Item {
|
||||
}
|
||||
|
||||
onScrollActiveChanged: {
|
||||
if (!scrollActive)
|
||||
if (!scrollActive) {
|
||||
resetScroll();
|
||||
return;
|
||||
}
|
||||
lastStepMs = Date.now();
|
||||
}
|
||||
|
||||
clip: true
|
||||
@@ -86,10 +91,13 @@ Item {
|
||||
wrapMode: Text.NoWrap
|
||||
width: root.needsScrolling ? implicitWidth : Math.min(implicitWidth, root.width)
|
||||
elide: SettingsData.scrollTitleEnabled ? Text.ElideNone : Text.ElideRight
|
||||
// Whole-pixel x plus NativeRendering's glyph snapping quantises the offset twice, which
|
||||
// turns even motion into a 1px/2px stutter. Both go while the text is actually scrolling.
|
||||
renderType: root.needsScrolling ? Text.QtRendering : resolvedRenderType
|
||||
x: {
|
||||
if (root.needsScrolling) {
|
||||
const offset = Math.min(root.scrollOffset, root.maxScrollOffset);
|
||||
return Math.round((root.rightToLeft ? root.width - width + offset : -offset) + root.textShift);
|
||||
return (root.rightToLeft ? root.width - width + offset : -offset) + root.textShift;
|
||||
}
|
||||
switch (root.horizontalAlignment) {
|
||||
case Text.AlignHCenter:
|
||||
@@ -120,6 +128,7 @@ Item {
|
||||
font: label.font
|
||||
color: label.color
|
||||
wrapMode: Text.NoWrap
|
||||
renderType: Text.QtRendering
|
||||
Accessible.ignored: true
|
||||
}
|
||||
}
|
||||
@@ -157,13 +166,16 @@ Item {
|
||||
// Timer stepping, not NumberAnimation: a running animation commits frames every vsync (#2863).
|
||||
// When cava frames are already driving renders, scroll steps ride those ticks instead (#2863).
|
||||
Timer {
|
||||
interval: 60
|
||||
interval: root.stepInterval
|
||||
repeat: true
|
||||
running: root.scrollActive
|
||||
onTriggered: {
|
||||
const now = Date.now();
|
||||
const elapsed = Math.min(now - root.lastStepMs, root.stepInterval * 4);
|
||||
root.lastStepMs = now;
|
||||
if (cavaTickWatch.running)
|
||||
return;
|
||||
root.stepScroll(60);
|
||||
root.stepScroll(elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ ShellRoot {
|
||||
DC.Log.backend = Log;
|
||||
DC.Host.session = SessionService;
|
||||
DC.Host.cache = CacheData;
|
||||
void IconThemeService.ready;
|
||||
if (entrypoint.runGreeter)
|
||||
return;
|
||||
// Build the polkit agent here, outside incubation: first-touching it from a Connections target during DMSShell's async load crashed QQmlConnections::connectSignalsToMethods.
|
||||
@@ -58,7 +59,7 @@ ShellRoot {
|
||||
|
||||
Loader {
|
||||
id: shellCoreLoader
|
||||
active: !entrypoint.runGreeter && IconThemeService.ready
|
||||
active: !entrypoint.runGreeter
|
||||
asynchronous: true
|
||||
source: "ShellCore.qml"
|
||||
onLoaded: dmsShellLoader.setSource("DMSShell.qml", {
|
||||
@@ -73,7 +74,7 @@ ShellRoot {
|
||||
|
||||
Loader {
|
||||
id: dmsGreeterLoader
|
||||
active: entrypoint.runGreeter && IconThemeService.ready
|
||||
active: entrypoint.runGreeter
|
||||
asynchronous: false
|
||||
source: "DMSGreeter.qml"
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ ShellRoot {
|
||||
SettingsData.reduceMotion = true;
|
||||
SettingsData.dashOptions = {
|
||||
media: {
|
||||
playerStyle: "zurvan",
|
||||
playerStyle: "bento",
|
||||
lyrics: true
|
||||
}
|
||||
};
|
||||
@@ -237,7 +237,7 @@ ShellRoot {
|
||||
check(media.lyrics.lines.length === 5 && media.lyrics.lines[2].x.includes("backing vocal"), "same-time lyrics stay together");
|
||||
let overlay = media.lyricsFocusTarget;
|
||||
check(overlay && overlay.activeFocus, "lyrics receives keyboard focus");
|
||||
check(overlay.width === artwork.width && overlay.height === artwork.height, "Zurvan lyrics stay within the artwork shape");
|
||||
check(overlay.width === artwork.width && overlay.height === artwork.height, "Bento lyrics stay within the artwork shape");
|
||||
const openCorners = artCorners(artwork);
|
||||
check(openCorners === corners, "opening lyrics leaves pixels outside the artwork untouched: " + corners + " -> " + openCorners);
|
||||
const line = find(overlay, item => item.text === root.longLine && item.truncated !== undefined);
|
||||
@@ -248,7 +248,7 @@ ShellRoot {
|
||||
check(line.lineCount === wrappedLineCount, "lyric highlighting preserves line breaks");
|
||||
source.position = 10;
|
||||
input.wait(30);
|
||||
capture("zurvan");
|
||||
capture("bento");
|
||||
input.keyClick(Qt.Key_PageDown);
|
||||
input.wait(30);
|
||||
check(!overlay.following && input.findChild(overlay, "followPlayback")?.visible, "browsing pauses automatic following");
|
||||
@@ -413,7 +413,7 @@ ShellRoot {
|
||||
check(media.lyrics.state === "ready" && !media.lyrics.synced, "embedded lyrics remain available with all providers off");
|
||||
SettingsData.dashOptions = {
|
||||
media: {
|
||||
playerStyle: "zurvan",
|
||||
playerStyle: "bento",
|
||||
lyrics: true,
|
||||
artStyle: "circle"
|
||||
}
|
||||
@@ -438,7 +438,7 @@ ShellRoot {
|
||||
SettingsData.reduceMotion = false;
|
||||
SettingsData.dashOptions = {
|
||||
media: {
|
||||
playerStyle: "zurvan",
|
||||
playerStyle: "bento",
|
||||
lyrics: true
|
||||
}
|
||||
};
|
||||
|
||||
@@ -199,11 +199,11 @@ ShellRoot {
|
||||
viewport.width = 780;
|
||||
SettingsData.dashOptions = {
|
||||
media: {
|
||||
playerStyle: "zurvan"
|
||||
playerStyle: "bento"
|
||||
}
|
||||
};
|
||||
input.wait(30);
|
||||
check(!!find(media, item => item.loop === true), "switching back restores Zurvan");
|
||||
check(!!find(media, item => item.loop === true), "switching back restores Bento");
|
||||
media.lyricsOpen = false;
|
||||
media.playerPaneOpen = false;
|
||||
input.wait(30);
|
||||
@@ -215,7 +215,7 @@ ShellRoot {
|
||||
input.wait(30);
|
||||
SettingsData.dashOptions = {
|
||||
media: {
|
||||
playerStyle: "zurvan",
|
||||
playerStyle: "bento",
|
||||
lyrics: false
|
||||
}
|
||||
};
|
||||
@@ -225,7 +225,7 @@ ShellRoot {
|
||||
check(!!lyricsToggle && !lyricsToggle.visible, "lyrics option gates the button");
|
||||
SettingsData.dashOptions = {
|
||||
media: {
|
||||
playerStyle: "zurvan",
|
||||
playerStyle: "bento",
|
||||
lyrics: true
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user