Sort applauncher entries alphabetical Use global fontFamily and font size (Theme.qml) Tons of other small fixes
169 lines
No EOL
4.5 KiB
QML
169 lines
No EOL
4.5 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import qs.Settings
|
|
|
|
Item {
|
|
id: revealPill
|
|
|
|
// External properties
|
|
property string icon: ""
|
|
property string text: ""
|
|
property color pillColor: Theme.surfaceVariant
|
|
property color textColor: Theme.textPrimary
|
|
property color iconCircleColor: Theme.accentPrimary
|
|
property color iconTextColor: Theme.backgroundPrimary
|
|
property int pillHeight: 22
|
|
property int iconSize: 22
|
|
property int pillPaddingHorizontal: 14
|
|
|
|
// Internal state
|
|
property bool showPill: false
|
|
property bool shouldAnimateHide: false
|
|
|
|
// Exposed width logic
|
|
readonly property int pillOverlap: iconSize / 2
|
|
readonly property int maxPillWidth: Math.max(1, textItem.implicitWidth + pillPaddingHorizontal * 2 + pillOverlap)
|
|
|
|
signal shown()
|
|
signal hidden()
|
|
|
|
width: iconSize + (showPill ? maxPillWidth - pillOverlap : 0)
|
|
height: pillHeight
|
|
|
|
Rectangle {
|
|
id: pill
|
|
width: showPill ? maxPillWidth : 1 // Never 0 width
|
|
height: pillHeight
|
|
x: (iconCircle.x + iconCircle.width / 2) - width
|
|
opacity: showPill ? 1 : 0
|
|
color: pillColor
|
|
topLeftRadius: pillHeight / 2
|
|
bottomLeftRadius: pillHeight / 2
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
Text {
|
|
id: textItem
|
|
anchors.centerIn: parent
|
|
text: revealPill.text
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.family: Theme.fontFamily
|
|
font.weight: Font.Bold
|
|
color: textColor
|
|
visible: showPill // Hide text when pill is collapsed
|
|
}
|
|
|
|
Behavior on width {
|
|
enabled: showAnim.running || hideAnim.running
|
|
NumberAnimation { duration: 250; easing.type: Easing.OutCubic }
|
|
}
|
|
Behavior on opacity {
|
|
enabled: showAnim.running || hideAnim.running
|
|
NumberAnimation { duration: 250; easing.type: Easing.OutCubic }
|
|
}
|
|
}
|
|
|
|
// Icon circle
|
|
Rectangle {
|
|
id: iconCircle
|
|
width: iconSize
|
|
height: iconSize
|
|
radius: width / 2
|
|
color: showPill ? iconCircleColor : "transparent"
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.right: parent.right
|
|
|
|
Behavior on color {
|
|
ColorAnimation { duration: 200; easing.type: Easing.InOutQuad }
|
|
}
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
font.family: showPill ? "Material Symbols Rounded" : "Material Symbols Outlined"
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
text: revealPill.icon
|
|
color: showPill ? iconTextColor : textColor
|
|
}
|
|
}
|
|
|
|
// Show animation
|
|
ParallelAnimation {
|
|
id: showAnim
|
|
running: false
|
|
NumberAnimation {
|
|
target: pill
|
|
property: "width"
|
|
from: 1 // Start from 1 instead of 0
|
|
to: maxPillWidth
|
|
duration: 250
|
|
easing.type: Easing.OutCubic
|
|
}
|
|
NumberAnimation {
|
|
target: pill
|
|
property: "opacity"
|
|
from: 0
|
|
to: 1
|
|
duration: 250
|
|
easing.type: Easing.OutCubic
|
|
}
|
|
onStarted: {
|
|
showPill = true
|
|
}
|
|
onStopped: {
|
|
delayedHideAnim.start()
|
|
shown()
|
|
}
|
|
}
|
|
|
|
// Delayed auto-hide
|
|
SequentialAnimation {
|
|
id: delayedHideAnim
|
|
running: false
|
|
PauseAnimation { duration: 2500 }
|
|
ScriptAction { script: if (shouldAnimateHide) hideAnim.start() }
|
|
}
|
|
|
|
// Hide animation
|
|
ParallelAnimation {
|
|
id: hideAnim
|
|
running: false
|
|
NumberAnimation {
|
|
target: pill
|
|
property: "width"
|
|
from: maxPillWidth
|
|
to: 1 // End at 1 instead of 0
|
|
duration: 250
|
|
easing.type: Easing.InCubic
|
|
}
|
|
NumberAnimation {
|
|
target: pill
|
|
property: "opacity"
|
|
from: 1
|
|
to: 0
|
|
duration: 250
|
|
easing.type: Easing.InCubic
|
|
}
|
|
onStopped: {
|
|
showPill = false
|
|
shouldAnimateHide = false
|
|
hidden()
|
|
}
|
|
}
|
|
|
|
// Exposed functions
|
|
function show() {
|
|
if (!showPill) {
|
|
shouldAnimateHide = true
|
|
showAnim.start()
|
|
} else {
|
|
// Reset hide timer if already shown
|
|
hideAnim.stop()
|
|
delayedHideAnim.restart()
|
|
}
|
|
}
|
|
|
|
function hide() {
|
|
if (showPill) {
|
|
hideAnim.start()
|
|
}
|
|
}
|
|
} |