Changed the glass animations to a more bubble-like animation
This commit is contained in:
@@ -51,31 +51,47 @@ ModuleChip {
|
||||
|
||||
property real progressVal: 1.0
|
||||
property bool slideFromRight: false
|
||||
|
||||
property real slideX: slideFromRight ? (width + 20) : -(width + 20)
|
||||
|
||||
transform: Translate { id: slideTranslate; x: toastRoot.slideX }
|
||||
transform: [
|
||||
Translate { id: slideTranslate; x: toastRoot.slideX },
|
||||
Scale { id: bubbleScale; yScale: 0; origin.y: toastLayer.atBottom ? toastRoot.height : 0 }
|
||||
]
|
||||
|
||||
Component.onCompleted: entranceSlide.start()
|
||||
Component.onCompleted: entranceAnim.start()
|
||||
|
||||
ParallelAnimation {
|
||||
id: entranceAnim
|
||||
NumberAnimation {
|
||||
id: entranceSlide
|
||||
target: slideTranslate; property: "x"
|
||||
from: toastRoot.slideX; to: 0
|
||||
duration: 300; easing.type: Easing.OutCubic
|
||||
duration: 320; easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
target: bubbleScale; property: "yScale"
|
||||
from: 0; to: 1
|
||||
duration: 280; easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
|
||||
function triggerDismiss() {
|
||||
if (exitSlide.running) return
|
||||
if (exitAnim.running) return
|
||||
autoTimer.stop()
|
||||
exitSlide.start()
|
||||
exitAnim.start()
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: exitAnim
|
||||
NumberAnimation {
|
||||
id: exitSlide
|
||||
target: slideTranslate; property: "x"
|
||||
to: toastRoot.slideX
|
||||
duration: 220; easing.type: Easing.InCubic
|
||||
duration: 250; easing.type: Easing.InCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
target: bubbleScale; property: "yScale"
|
||||
from: 1; to: 0
|
||||
duration: 200; easing.type: Easing.InBack
|
||||
}
|
||||
onStopped: toastRoot.dismissed(toastRoot.toastId)
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ ModuleChip {
|
||||
|| (submenuCard.visible
|
||||
&& trayMenuPopup._submenuParentRef === menuItem)
|
||||
color: active ? root.tmHover : "transparent"
|
||||
Behavior on color { ColorAnimation { duration: 120 } }
|
||||
Behavior on color { ColorAnimation { duration: 60 } }
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -14,8 +14,16 @@ ModuleChip {
|
||||
property int outputMaxVolume: Cfg.Config.volumeOutputMax
|
||||
property int inputMaxVolume: Cfg.Config.volumeInputMax
|
||||
|
||||
ConfigWriter {
|
||||
id: configWriter
|
||||
readonly property string configPath:
|
||||
Quickshell.env("HOME") + "/.config/quickshell/config/config.qml"
|
||||
|
||||
Process {
|
||||
id: volConfigWriter
|
||||
running: false
|
||||
onExited: (code) => {
|
||||
if (code !== 0)
|
||||
console.warn("[Volume] Failed to patch config.qml (exit " + code + ")")
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
@@ -23,15 +31,21 @@ ModuleChip {
|
||||
interval: 800
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
configWriter.writeInts([
|
||||
{ key: "volumeOutputMax", value: root.outputMaxVolume },
|
||||
{ key: "volumeInputMax", value: root.inputMaxVolume }
|
||||
])
|
||||
const outMax = Math.round(root.outputMaxVolume).toString()
|
||||
const inMax = Math.round(root.inputMaxVolume).toString()
|
||||
const cfgPath = root.configPath
|
||||
const sh =
|
||||
"sed -i" +
|
||||
" -e 's/\\(property int[ ]\\+volumeOutputMax:[ ]\\+\\)[0-9.]\\+/\\1" + outMax + "/'" +
|
||||
" -e 's/\\(property int[ ]\\+volumeInputMax:[ ]\\+\\)[0-9.]\\+/\\1" + inMax + "/'" +
|
||||
" " + JSON.stringify(cfgPath)
|
||||
volConfigWriter.command = ["/bin/sh", "-c", sh]
|
||||
volConfigWriter.running = true
|
||||
}
|
||||
}
|
||||
|
||||
onOutputMaxVolumeChanged: saveDebounce.restart()
|
||||
onInputMaxVolumeChanged: saveDebounce.restart()
|
||||
onOutputMaxVolumeChanged: { if (root.outputMaxVolume >= 10) saveDebounce.restart() }
|
||||
onInputMaxVolumeChanged: { if (root.inputMaxVolume >= 10) saveDebounce.restart() }
|
||||
|
||||
readonly property var sink: Pipewire.defaultAudioSink
|
||||
readonly property var source: Pipewire.defaultAudioSource
|
||||
@@ -98,22 +112,24 @@ ModuleChip {
|
||||
}
|
||||
|
||||
width: chipLayout.implicitWidth + 15
|
||||
height: Cfg.Config.moduleHeight
|
||||
radius: panelRadius
|
||||
|
||||
chipColor: t.volBg
|
||||
chipColorHovered: t.volBgHover
|
||||
chipBorderColor: t.volBorder
|
||||
chipBorderColorHovered: t.volBorderHover
|
||||
chipHoverEnabled: true
|
||||
chipTapAction: () => volumePopup.toggle()
|
||||
popupOpen: volumePopup.popupOpen
|
||||
color: hoverHandler.hovered ? t.volBgHover : t.volBg
|
||||
border.color: (hoverHandler.hovered || volumePopup.popupOpen) ? t.volBorderHover : t.volBorder
|
||||
border.width: borderWidth
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 150 } }
|
||||
Behavior on border.color { ColorAnimation { duration: 150 } }
|
||||
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onHoveredChanged: {
|
||||
if (hovered && Cfg.Config.volumeShakeEnabled) shakeAnim.restart()
|
||||
}
|
||||
}
|
||||
TapHandler { onTapped: volumePopup.toggle() }
|
||||
|
||||
SequentialAnimation {
|
||||
id: shakeAnim
|
||||
@@ -140,28 +156,47 @@ ModuleChip {
|
||||
}
|
||||
}
|
||||
|
||||
StandardPopup {
|
||||
PopupPanel {
|
||||
id: volumePopup
|
||||
ns: "volume"
|
||||
chipRoot: root
|
||||
cardWidth: Cfg.Config.volumePopupWidth
|
||||
cardColor: t.volPopupBg
|
||||
cardBorderColor: t.volPopupBorder
|
||||
cardHeight: popupCol.implicitHeight + 34
|
||||
hasKeyboardFocus: true
|
||||
|
||||
Item {
|
||||
Rectangle {
|
||||
id: volCard
|
||||
width: parent.width
|
||||
height: popupCol.implicitHeight + 32
|
||||
|
||||
anchors.top: root.isTop ? parent.top : undefined
|
||||
anchors.bottom: root.isTop ? undefined : parent.bottom
|
||||
|
||||
transform: Scale {
|
||||
yScale: volumePopup.popupOpen ? 1 : 0
|
||||
origin.y: root.isTop ? 0 : volCard.height
|
||||
Behavior on yScale {
|
||||
NumberAnimation {
|
||||
duration: Cfg.Config.popupAnimDuration
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
enabled: volumePopup.visible
|
||||
}
|
||||
}
|
||||
|
||||
opacity: volumePopup.popupOpen ? 1.0 : 0.0
|
||||
Behavior on opacity { NumberAnimation { duration: 200 } }
|
||||
|
||||
radius: Cfg.Config.popupRadius
|
||||
color: root.t.volPopupBg
|
||||
border.color: root.t.volPopupBorder
|
||||
border.width: Cfg.Config.popupBorderWidth
|
||||
|
||||
MouseArea { anchors.fill: parent; propagateComposedEvents: false }
|
||||
|
||||
ColumnLayout {
|
||||
id: popupCol
|
||||
anchors { left: parent.left; right: parent.right; top: parent.top }
|
||||
anchors.margins: 16
|
||||
anchors.topMargin: 18
|
||||
implicitWidth: popupContent.implicitWidth
|
||||
implicitHeight: popupContent.implicitHeight
|
||||
focus: true
|
||||
|
||||
ColumnLayout {
|
||||
id: popupContent
|
||||
anchors.fill: parent
|
||||
spacing: 14
|
||||
|
||||
VolumeSection {
|
||||
@@ -235,7 +270,6 @@ ModuleChip {
|
||||
borderColor: root.t.volPopupBorder
|
||||
onDecrement: root.outputMaxVolume = Math.max(10, root.outputMaxVolume - 10)
|
||||
onIncrement: root.outputMaxVolume = Math.min(300, root.outputMaxVolume + 10)
|
||||
onValueSet: root.outputMaxVolume = Math.max(10, Math.min(300, val))
|
||||
}
|
||||
LimitRow {
|
||||
Layout.fillWidth: true
|
||||
@@ -250,17 +284,10 @@ ModuleChip {
|
||||
borderColor: root.t.volPopupBorder
|
||||
onDecrement: root.inputMaxVolume = Math.max(10, root.inputMaxVolume - 10)
|
||||
onIncrement: root.inputMaxVolume = Math.min(300, root.inputMaxVolume + 10)
|
||||
onValueSet: root.inputMaxVolume = Math.max(10, Math.min(300, val))
|
||||
}
|
||||
}
|
||||
Item { height: 2 }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
onClicked: popupCol.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,36 +335,14 @@ ModuleChip {
|
||||
Layout.fillWidth: true
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
TextInput {
|
||||
Text {
|
||||
text: vs.muted ? "muted" : vs.volume + "%"
|
||||
color: vs.muted ? vs.dimColor : vs.textColor
|
||||
font.pixelSize: 12
|
||||
font.bold: !vs.muted
|
||||
horizontalAlignment: TextInput.AlignHCenter
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.preferredWidth: 44
|
||||
renderType: Text.NativeRendering
|
||||
readOnly: vs.muted
|
||||
selectByMouse: true
|
||||
activeFocusOnPress: true
|
||||
onAccepted: {
|
||||
if (!vs.muted) {
|
||||
let val = parseInt(text.replace("%", "").trim(), 10)
|
||||
if (!isNaN(val)) vs.sliderMoved(Math.max(0, Math.min(vs.maxVolume, val)))
|
||||
text = Qt.binding(function() { return vs.muted ? "muted" : vs.volume + "%" })
|
||||
}
|
||||
popupCol.forceActiveFocus()
|
||||
}
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus && !vs.muted) {
|
||||
text = vs.volume.toString()
|
||||
selectAll()
|
||||
} else if (!activeFocus && !vs.muted) {
|
||||
let val = parseInt(text.replace("%", "").trim(), 10)
|
||||
if (!isNaN(val)) vs.sliderMoved(Math.max(0, Math.min(vs.maxVolume, val)))
|
||||
text = Qt.binding(function() { return vs.muted ? "muted" : vs.volume + "%" })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -504,7 +509,6 @@ ModuleChip {
|
||||
|
||||
signal decrement()
|
||||
signal increment()
|
||||
signal valueSet(int val)
|
||||
|
||||
Text { text: lr.icon; color: lr.iconColor; font.pixelSize: 13; font.bold: true; renderType: Text.NativeRendering }
|
||||
Text {
|
||||
@@ -531,32 +535,13 @@ ModuleChip {
|
||||
HoverHandler { id: decHover; cursorShape: Qt.PointingHandCursor }
|
||||
TapHandler { onTapped: { if (lr.value > lr.minValue) lr.decrement() } }
|
||||
}
|
||||
TextInput {
|
||||
Text {
|
||||
text: lr.value + "%"
|
||||
color: lr.textColor
|
||||
font.pixelSize: 12; font.bold: true
|
||||
horizontalAlignment: TextInput.AlignHCenter
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.preferredWidth: 44
|
||||
renderType: Text.NativeRendering
|
||||
selectByMouse: true
|
||||
activeFocusOnPress: true
|
||||
onAccepted: {
|
||||
let val = parseInt(text.replace("%", "").trim(), 10)
|
||||
if (!isNaN(val)) lr.valueSet(Math.max(lr.minValue, Math.min(lr.maxValue, val)))
|
||||
text = Qt.binding(function() { return lr.value + "%" })
|
||||
popupCol.forceActiveFocus()
|
||||
}
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
text = lr.value.toString()
|
||||
selectAll()
|
||||
} else {
|
||||
let val = parseInt(text.replace("%", "").trim(), 10)
|
||||
if (!isNaN(val)) lr.valueSet(Math.max(lr.minValue, Math.min(lr.maxValue, val)))
|
||||
text = Qt.binding(function() { return lr.value + "%" })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -576,3 +561,5 @@ ModuleChip {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,12 +14,13 @@ Rectangle {
|
||||
anchors.top: isTop ? parent.top : undefined
|
||||
anchors.bottom: isTop ? undefined : parent.bottom
|
||||
|
||||
transform: Translate {
|
||||
y: popupOpen ? 0 : (isTop ? -card.height : card.height)
|
||||
Behavior on y {
|
||||
transform: Scale {
|
||||
yScale: popupOpen ? 1 : 0
|
||||
origin.y: isTop ? 0 : card.height
|
||||
Behavior on yScale {
|
||||
NumberAnimation {
|
||||
duration: Cfg.Config.popupAnimDuration
|
||||
easing.type: Easing.OutExpo
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
enabled: animEnabled
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ QtObject {
|
||||
// ── Position & Dimensions ─────────────────────────────────────────────────
|
||||
property string barPosition: "bottom"
|
||||
property int barHeight: 35
|
||||
property int margin: 20
|
||||
property int radius: 26
|
||||
property int margin: 15
|
||||
property int radius: 20
|
||||
|
||||
// ── Module Lists ──────────────────────────────────────────────────────────
|
||||
property var leftModules: ["Logo", "Stats", "Crypto"]
|
||||
@@ -43,7 +43,7 @@ QtObject {
|
||||
// ── Popup Styling ─────────────────────────────────────────────────────────
|
||||
property int popupRadius: 18
|
||||
property int popupBorderWidth: 1
|
||||
property int popupAnimDuration: 500
|
||||
property int popupAnimDuration: 250
|
||||
|
||||
// ── Clock Module ─────────────────────────────────────────────────────────
|
||||
property bool clockExtendEnabled: true // seconds extension on hover for clock
|
||||
@@ -90,7 +90,7 @@ QtObject {
|
||||
// NOTIFICATIONS
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
property bool notificationShakeEnabled: true // bell ringing shake for notifications
|
||||
property string notificationPosition: "topright"
|
||||
property string notificationPosition: "bottomright"
|
||||
property int notificationHistorySize: 50
|
||||
|
||||
// ── Toast timeouts (milliseconds) ─────────────────────────────────────────
|
||||
|
||||
@@ -28,7 +28,6 @@ PanelWindow {
|
||||
|
||||
property bool _isOpen: false
|
||||
readonly property bool isOpen: _isOpen
|
||||
property string mode: "drun"
|
||||
property bool _keyboardNav: false
|
||||
property var allItems: []
|
||||
property bool loading: false
|
||||
@@ -82,7 +81,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
function readCache() {
|
||||
const path = Cfg.Config.launcherCacheDir + "/" + (mode === "drun" ? "drun.txt" : "run.txt")
|
||||
const path = Cfg.Config.launcherCacheDir + "/drun.txt"
|
||||
dataProc.rawOutput = ""
|
||||
dataProc.command = ["cat", path]
|
||||
dataProc.running = true
|
||||
@@ -140,8 +139,6 @@ PanelWindow {
|
||||
close()
|
||||
}
|
||||
|
||||
onModeChanged: if (_isOpen) loadItems()
|
||||
|
||||
visible: false
|
||||
color: "transparent"
|
||||
|
||||
@@ -159,7 +156,6 @@ PanelWindow {
|
||||
id: closeTimer
|
||||
onTriggered: {
|
||||
root.visible = false
|
||||
root.mode = "drun"
|
||||
root.allItems = []
|
||||
}
|
||||
}
|
||||
@@ -288,44 +284,6 @@ PanelWindow {
|
||||
}
|
||||
resultsList.positionViewAtIndex(resultsList.currentIndex, ListView.Contain)
|
||||
}
|
||||
|
||||
Keys.onTabPressed: root.mode = root.mode === "drun" ? "run" : "drun"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: 28
|
||||
width: modeRow.implicitWidth + 10
|
||||
radius: 8
|
||||
color: t.launcherPill
|
||||
border.color: t.launcherBorder
|
||||
border.width: Cfg.Config.popupBorderWidth
|
||||
|
||||
RowLayout {
|
||||
id: modeRow
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
Repeater {
|
||||
model: ["drun", "run"]
|
||||
delegate: Rectangle {
|
||||
height: 22
|
||||
width: label.implicitWidth + 14
|
||||
radius: 6
|
||||
color: root.mode === modelData ? t.launcherModeActiveBg : "transparent"
|
||||
Text {
|
||||
id: label
|
||||
anchors.centerIn: parent
|
||||
text: modelData
|
||||
font.pixelSize: 10
|
||||
font.bold: root.mode === modelData
|
||||
color: root.mode === modelData ? t.launcherModeActiveText : t.launcherDim
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.mode = modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -386,7 +344,7 @@ PanelWindow {
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: !appIcon.visible
|
||||
text: root.mode === "drun" ? "" : ""
|
||||
text: ""
|
||||
color: resultsList.currentIndex === index && index !== -1 ? t.launcherAccent : t.launcherDim
|
||||
font.pixelSize: 16
|
||||
}
|
||||
|
||||
@@ -158,6 +158,11 @@ Item {
|
||||
opacity: 0
|
||||
scale: 0.86
|
||||
|
||||
transform: Scale {
|
||||
yScale: 1
|
||||
origin.y: card.height / 2
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
overlay.displayFlow = agent.flow
|
||||
enterAnim.start()
|
||||
@@ -175,6 +180,11 @@ Item {
|
||||
from: 0.86; to: 1.0
|
||||
duration: 360; easing.type: Easing.OutBack; easing.overshoot: 0.6
|
||||
}
|
||||
NumberAnimation {
|
||||
target: card.transform; property: "yScale"
|
||||
from: 0; to: 1
|
||||
duration: 360; easing.type: Easing.OutBack; easing.overshoot: 0.6
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
@@ -189,6 +199,11 @@ Item {
|
||||
from: 1.0; to: 0.88
|
||||
duration: 260; easing.type: Easing.InBack
|
||||
}
|
||||
NumberAnimation {
|
||||
target: card.transform; property: "yScale"
|
||||
from: 1; to: 0
|
||||
duration: 260; easing.type: Easing.InBack
|
||||
}
|
||||
onFinished: {
|
||||
overlay.exiting = false
|
||||
root.windowShouldExist = false
|
||||
@@ -208,6 +223,7 @@ Item {
|
||||
}
|
||||
card.opacity = 0
|
||||
card.scale = 0.86
|
||||
card.transform.yScale = 0
|
||||
enterAnim.restart()
|
||||
} else {
|
||||
if (overlay.displayFlow)
|
||||
|
||||
Reference in New Issue
Block a user