MediaMini: add scrolling support (as requested in #293)

This commit is contained in:
Ly-sec
2025-09-25 01:02:01 +02:00
parent 35a7ed165f
commit 96c2817e06
9 changed files with 134 additions and 9 deletions
+70 -8
View File
@@ -36,6 +36,8 @@ Item {
readonly property bool showAlbumArt: (widgetSettings.showAlbumArt !== undefined) ? widgetSettings.showAlbumArt : widgetMetadata.showAlbumArt
readonly property bool showVisualizer: (widgetSettings.showVisualizer !== undefined) ? widgetSettings.showVisualizer : widgetMetadata.showVisualizer
readonly property string visualizerType: (widgetSettings.visualizerType !== undefined && widgetSettings.visualizerType !== "") ? widgetSettings.visualizerType : widgetMetadata.visualizerType
readonly property bool scrollingTitle: Settings.data.audio.scrollingTitle
readonly property int scrollingSpeed: Settings.data.audio.scrollingSpeed
// 6% of total width
readonly property real minWidth: Math.max(1, screen.width * 0.06)
@@ -180,8 +182,8 @@ Item {
}
}
NText {
id: titleText
Item {
id: titleContainer
Layout.preferredWidth: {
if (mouseArea.containsMouse) {
@@ -191,13 +193,73 @@ Item {
}
}
Layout.alignment: Qt.AlignVCenter
Layout.preferredHeight: titleText.height
text: getTitle()
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
color: Color.mSecondary
clip: true
property bool shouldScroll: scrollingTitle && fullTitleMetrics.contentWidth > titleContainer.width
property bool isScrolling: false
// Start scrolling when text is too long and not hovering
Timer {
id: scrollStartTimer
interval: 2000 // Wait 2 seconds before starting scroll
repeat: false
onTriggered: {
if (titleContainer.shouldScroll && !mouseArea.containsMouse) {
titleContainer.isScrolling = true
}
}
}
// Reset scroll position when text changes or on hover
onShouldScrollChanged: {
if (shouldScroll && !mouseArea.containsMouse) {
scrollStartTimer.restart()
} else {
scrollStartTimer.stop()
isScrolling = false
}
}
Connections {
target: mouseArea
function onContainsMouseChanged() {
if (mouseArea.containsMouse) {
scrollStartTimer.stop()
titleContainer.isScrolling = false
} else if (titleContainer.shouldScroll) {
scrollStartTimer.restart()
}
}
}
NText {
id: titleText
text: getTitle()
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
verticalAlignment: Text.AlignVCenter
color: Color.mSecondary
property real scrollPosition: 0
x: scrollPosition
// Continuous scrolling animation
SequentialAnimation on scrollPosition {
running: titleContainer.isScrolling
loops: Animation.Infinite
NumberAnimation {
from: 0
to: -(fullTitleMetrics.contentWidth - titleContainer.width)
duration: scrollingSpeed * 1000 // Convert seconds to milliseconds
easing.type: Easing.Linear
}
}
}
Behavior on Layout.preferredWidth {
NumberAnimation {
+21
View File
@@ -385,6 +385,27 @@ ColumnLayout {
currentKey: Settings.data.audio.cavaFrameRate
onSelected: key => Settings.data.audio.cavaFrameRate = key
}
// Scrolling Title Settings
NToggle {
label: I18n.tr("settings.audio.media.scrolling-title.label")
description: I18n.tr("settings.audio.media.scrolling-title.description")
checked: Settings.data.audio.scrollingTitle
onToggled: checked => Settings.data.audio.scrollingTitle = checked
}
NSpinBox {
Layout.fillWidth: true
label: I18n.tr("settings.audio.media.scrolling-speed.label")
description: I18n.tr("settings.audio.media.scrolling-speed.description")
minimum: 5
maximum: 60
value: Settings.data.audio.scrollingSpeed
stepSize: 1
suffix: "s"
enabled: Settings.data.audio.scrollingTitle
onValueChanged: Settings.data.audio.scrollingSpeed = value
}
}
NDivider {