splitted the code base into more components and implemented safety measures to Crypto.qml, also added missing themes and removed hardcoded values

This commit is contained in:
SomeElse
2026-05-17 01:17:01 +00:00
parent c8343398f9
commit 262fd8afa0
26 changed files with 344 additions and 295 deletions

View File

@@ -13,7 +13,7 @@ ModuleChip {
readonly property var bat: UPower.displayDevice
readonly property bool batReady: bat && bat.ready && bat.isLaptopBattery
readonly property bool moduleEnabled: false
readonly property bool moduleEnabled: batReady
readonly property real pct: batReady ? bat.percentage * 100 : 72
readonly property int state: batReady ? bat.state : UPowerDeviceState.Unknown
@@ -173,37 +173,19 @@ ModuleChip {
Behavior on opacity { NumberAnimation { duration: 200 } }
}
Rectangle {
PopupCard {
id: card
width: parent.width
popupOpen: batteryPopup.popupOpen
isTop: root.isTop
animEnabled: batteryPopup.visible
height: cardCol.implicitHeight + 28
anchors.top: root.isTop ? parent.top : undefined
anchors.bottom: root.isTop ? undefined : parent.bottom
transform: Translate {
y: batteryPopup.popupOpen ? 0
: (root.isTop ? -card.height : card.height)
Behavior on y {
NumberAnimation {
duration: Cfg.Config.popupAnimDuration
easing.type: Easing.OutExpo
}
enabled: batteryPopup.visible
}
}
opacity: batteryPopup.popupOpen ? 1.0 : 0.0
Behavior on opacity { NumberAnimation { duration: 220 } }
color: root.t.batPopupBg
radius: Cfg.Config.popupRadius
border.color: root.t.batPopupBorder
border.width: Cfg.Config.popupBorderWidth
layer.enabled: true
MouseArea { anchors.fill: parent; propagateComposedEvents: false }
ColumnLayout {
id: cardCol
anchors {

View File

@@ -9,8 +9,6 @@ import "../../components"
ModuleChip {
id: root
TimezoneProvider { id: timezone }
width: clockLayout.implicitWidth + 24
height: Cfg.Config.moduleHeight
radius: panelRadius
@@ -57,7 +55,7 @@ ModuleChip {
}
Text {
text: timezone.toTz(timeManager.now).toLocaleTimeString(Qt.locale(), "HH:mm")
text: TimezoneProvider.toTz(timeManager.now).toLocaleTimeString(Qt.locale(), "HH:mm")
color: root.t.clockTime
font.pixelSize: 13
font.bold: true
@@ -66,7 +64,7 @@ ModuleChip {
Text {
id: secondsText
text: ":" + timezone.toTz(timeManager.now).toLocaleTimeString(Qt.locale(), "ss")
text: ":" + TimezoneProvider.toTz(timeManager.now).toLocaleTimeString(Qt.locale(), "ss")
color: root.t.clockSeconds
font.pixelSize: 13
font.bold: true
@@ -88,37 +86,19 @@ ModuleChip {
chipRoot: root
cardWidth: 284
Rectangle {
PopupCard {
id: card
width: parent.width
popupOpen: calendarPopup.popupOpen
isTop: root.isTop
animEnabled: calendarPopup.visible
height: cardCol.implicitHeight + 24
anchors.top: root.isTop ? parent.top : undefined
anchors.bottom: root.isTop ? undefined : parent.bottom
transform: Translate {
y: calendarPopup.popupOpen ? 0 : (root.isTop ? -card.height : card.height)
Behavior on y {
NumberAnimation {
duration: Cfg.Config.popupAnimDuration;
easing.type: Easing.OutExpo
}
enabled: calendarPopup.visible
}
}
opacity: calendarPopup.popupOpen ? 1.0 : 0.0
Behavior on opacity { NumberAnimation { duration: 200 } }
color: root.t.calCardBg
radius: Cfg.Config.popupRadius
border.color: root.t.calCardBorder
border.width: Cfg.Config.popupBorderWidth
layer.enabled: true
MouseArea { anchors.fill: parent; propagateComposedEvents: false }
component MonthNavButton: Rectangle {
id: navBtn
required property int direction
@@ -180,7 +160,7 @@ ModuleChip {
Layout.fillWidth: true
Text {
text: timezone.toTz(timeManager.now).toLocaleDateString(Qt.locale(), "dddd")
text: TimezoneProvider.toTz(timeManager.now).toLocaleDateString(Qt.locale(), "dddd")
color: root.t.clockPopupDim
font.pixelSize: 12
font.capitalization: Font.AllUppercase
@@ -189,7 +169,7 @@ ModuleChip {
}
Text {
text: timezone.toTz(timeManager.now).toLocaleDateString(Qt.locale(), "d MMMM yyyy")
text: TimezoneProvider.toTz(timeManager.now).toLocaleDateString(Qt.locale(), "d MMMM yyyy")
color: root.t.clockPopupHeader
font.pixelSize: 22
font.bold: true
@@ -219,8 +199,8 @@ ModuleChip {
id: cal
Layout.fillWidth: true
implicitHeight: gridCol.implicitHeight
property int displayYear: timezone.toTz(timeManager.now).getFullYear()
property int displayMonth: timezone.toTz(timeManager.now).getMonth()
property int displayYear: TimezoneProvider.toTz(timeManager.now).getFullYear()
property int displayMonth: TimezoneProvider.toTz(timeManager.now).getMonth()
property int pendingYear: displayYear
property int pendingMonth: displayMonth
property int slideDir: 1
@@ -229,7 +209,7 @@ ModuleChip {
target: calendarPopup
function onPopupOpenChanged() {
if (calendarPopup.popupOpen) {
let tzd = timezone.toTz(timeManager.now)
let tzd = TimezoneProvider.toTz(timeManager.now)
cal.displayYear = tzd.getFullYear()
cal.displayMonth = tzd.getMonth()
}
@@ -291,7 +271,7 @@ ModuleChip {
readonly property int dayNum: (weekRow.weekIndex * 7 + index) - ((new Date(cal.displayYear, cal.displayMonth, 1).getDay() + 6) % 7) + 1
readonly property bool inMonth: dayNum >= 1 && dayNum <= new Date(cal.displayYear, cal.displayMonth + 1, 0).getDate()
readonly property bool isToday: {
let tzd = timezone.toTz(timeManager.now)
let tzd = TimezoneProvider.toTz(timeManager.now)
return inMonth && dayNum === tzd.getDate()
&& cal.displayYear === tzd.getFullYear()
&& cal.displayMonth === tzd.getMonth()
@@ -300,6 +280,8 @@ ModuleChip {
Rectangle {
anchors.centerIn: parent; width: 22; height: 22; radius: 11
color: isToday ? root.t.accent : "transparent"
border.color: isToday ? root.t.borderToday : "transparent"
border.width: isToday ? 2 : 0
visible: inMonth
}
@@ -327,7 +309,7 @@ ModuleChip {
Layout.rightMargin: 6
Text {
text: "UTC " + (timezone.tzOffsetHours() >= 0 ? "+" : "") + timezone.tzOffsetHours()
text: "UTC " + (TimezoneProvider.tzOffsetHours() >= 0 ? "+" : "") + TimezoneProvider.tzOffsetHours()
color: root.t.clockPopupUtc
font.pixelSize: 13
font.bold: true
@@ -338,7 +320,7 @@ ModuleChip {
Text {
text: {
let d = timezone.toTz(timeManager.now)
let d = TimezoneProvider.toTz(timeManager.now)
let month = d.getMonth() + 1
let day = d.getDate()
let year = d.getFullYear()

View File

@@ -151,6 +151,16 @@ ModuleChip {
return val.toFixed(2)
}
function safeNumber(val, fallback) {
const n = Number(val)
return (typeof n === "number" && isFinite(n)) ? n : fallback
}
function safeString(val, maxLen, fallback) {
if (typeof val !== "string") return fallback
return val.slice(0, maxLen).replace(/[\x00-\x1f\x7f-\x9f]/g, "")
}
function fetchPrice() {
if (loading) return
loading = true
@@ -164,26 +174,30 @@ ModuleChip {
"&sparkline=false&price_change_percentage=24h"
const xhr = new XMLHttpRequest()
xhr.timeout = 15000
xhr.onreadystatechange = function () {
if (xhr.readyState !== XMLHttpRequest.DONE) return
loading = false
if (xhr.status !== 200) { hasError = true; return }
try {
const data = JSON.parse(xhr.responseText)
if (!data || data.length === 0) { hasError = true; return }
const coin = data[0]
price = coin.current_price ?? -1
change24h = coin.price_change_percentage_24h ?? 0
high24h = coin.high_24h ?? 0
low24h = coin.low_24h ?? 0
marketCap = coin.market_cap ?? 0
volume24h = coin.total_volume ?? 0
rank = coin.market_cap_rank ?? 0
circulatingSupply = coin.circulating_supply ?? 0
ath = coin.ath ?? 0
athChange = coin.ath_change_percentage ?? 0
coinSymbol = (coin.symbol ?? localCoinId).toUpperCase()
coinName = coin.name ?? ""
const text = xhr.responseText
if (text.length > 65536) { hasError = true; return }
const data = JSON.parse(text)
if (!Array.isArray(data) || data.length === 0) { hasError = true; return }
const coin = data[0]
if (typeof coin !== "object" || coin === null) { hasError = true; return }
price = safeNumber(coin.current_price, -1)
change24h = safeNumber(coin.price_change_percentage_24h, 0)
high24h = safeNumber(coin.high_24h, 0)
low24h = safeNumber(coin.low_24h, 0)
marketCap = safeNumber(coin.market_cap, 0)
volume24h = safeNumber(coin.total_volume, 0)
rank = Math.trunc(safeNumber(coin.market_cap_rank, 0))
circulatingSupply = safeNumber(coin.circulating_supply, 0)
ath = safeNumber(coin.ath, 0)
athChange = safeNumber(coin.ath_change_percentage, 0)
coinSymbol = safeString(coin.symbol, 8, localCoinId).toUpperCase()
coinName = safeString(coin.name, 50, "")
lastUpdated = new Date().toLocaleTimeString(Qt.locale(), "HH:mm:ss")
root.displayCurrency = root.localActiveCurrency
root.activeCoinIndex = (root.activeCoinIndex + 1) % Math.max(1, root.localPairs.length)
@@ -282,24 +296,13 @@ ModuleChip {
_doOpen()
}
Rectangle {
PopupCard {
id: card
width: parent.width
popupOpen: cryptoPopup.popupOpen
isTop: root.isTop
animEnabled: cryptoPopup.visible
height: cardCol.implicitHeight + 24
anchors.top: root.isTop ? parent.top : undefined
anchors.bottom: root.isTop ? undefined : parent.bottom
transform: Translate {
y: cryptoPopup.popupOpen ? 0 : (root.isTop ? -card.height : card.height)
Behavior on y {
NumberAnimation { duration: Cfg.Config.popupAnimDuration; easing.type: Easing.OutExpo }
enabled: cryptoPopup.visible
}
}
opacity: cryptoPopup.popupOpen ? 1.0 : 0.0
Behavior on opacity { NumberAnimation { duration: 200 } }
Behavior on height { NumberAnimation { duration: 220; easing.type: Easing.OutCubic } }
color: t.cryptoPopupBg ?? t.calCardBg ?? "#cc0c0e12"
@@ -308,8 +311,6 @@ ModuleChip {
border.width: Cfg.Config.popupBorderWidth
layer.enabled: true
MouseArea { anchors.fill: parent; propagateComposedEvents: false }
property int activeTab: 0
ColumnLayout {
@@ -319,11 +320,11 @@ ModuleChip {
anchors.topMargin: 16
spacing: 10
Rectangle {
Layout.fillWidth: true
height: 30
radius: 10
color: "#15ffffff"
Rectangle {
Layout.fillWidth: true
height: 30
radius: 10
color: t.cryptoFieldBg ?? "#15ffffff"
RowLayout {
anchors.fill: parent
@@ -340,13 +341,13 @@ ModuleChip {
readonly property bool active: card.activeTab === tabIndex
color: active
? (t.accent ?? "#ffc19375")
: (tm.containsMouse ? "#22ffffff" : "transparent")
: (tm.containsMouse ? (t.cryptoFieldBgFocus ?? "#22ffffff") : "transparent")
Behavior on color { ColorAnimation { duration: 130 } }
Text {
anchors.centerIn: parent
text: parent.label
color: parent.active ? "#ff0c0e12" : (t.cryptoPopupDim ?? t.textDim ?? "#997a8996")
color: parent.active ? (t.cryptoTextOnAccent ?? "#ff0c0e12") : (t.cryptoPopupDim ?? t.textDim ?? "#997a8996")
font.pixelSize: 11
font.bold: parent.active
Behavior on color { ColorAnimation { duration: 130 } }
@@ -412,7 +413,7 @@ ModuleChip {
Rectangle {
width: badge.implicitWidth + 12
height: 22; radius: 11
color: root.change24h >= 0 ? "#22b4c9a1" : "#22f38ba8"
color: root.change24h >= 0 ? (t.cryptoUpBg ?? "#22b4c9a1") : (t.cryptoDownBg ?? "#22f38ba8")
Text {
id: badge
@@ -495,7 +496,7 @@ ModuleChip {
Rectangle {
anchors.fill: parent
radius: 3
color: "#1affffff"
color: t.cryptoRangeTrack ?? "#1affffff"
}
Rectangle {
@@ -548,7 +549,7 @@ ModuleChip {
id: refreshBtn
width: 26; height: 26; radius: 8
color: rMouse.containsMouse
? (rMouse.pressed ? (t.accent ?? "#ffc19375") : "#22ffffff")
? (rMouse.pressed ? (t.accent ?? "#ffc19375") : (t.cryptoFieldBgFocus ?? "#22ffffff"))
: "transparent"
Behavior on color { ColorAnimation { duration: 120 } }
@@ -608,7 +609,7 @@ ModuleChip {
Layout.fillWidth: true
height: 30
radius: 8
color: fi.activeFocus ? "#22ffffff" : "#15ffffff"
color: fi.activeFocus ? (t.cryptoFieldBgFocus ?? "#22ffffff") : (t.cryptoFieldBg ?? "#15ffffff")
border.color: fi.activeFocus ? (t.accent ?? "#ffc19375") : "transparent"
border.width: 1
Behavior on color { ColorAnimation { duration: 120 } }
@@ -626,7 +627,7 @@ ModuleChip {
Text {
anchors.fill: parent
text: parent.parent.parent.placeholder
color: "#55" + (t.textDim ?? "#7a8996").slice(1)
color: t.cryptoPlaceholder ?? "#557a8996"
font.pixelSize: 12
font.family: "monospace"
visible: fi.text === "" && !fi.activeFocus
@@ -648,20 +649,20 @@ ModuleChip {
Rectangle {
width: 24; height: 24; radius: 7
color: mm.containsMouse ? (mm.pressed ? (t.accent ?? "#ffc19375") : "#22ffffff") : "#15ffffff"
color: mm.containsMouse ? (mm.pressed ? (t.accent ?? "#ffc19375") : (t.cryptoFieldBgFocus ?? "#22ffffff")) : (t.cryptoFieldBg ?? "#15ffffff")
Behavior on color { ColorAnimation { duration: 100 } }
Text { anchors.centerIn: parent; text: ""; font.pixelSize: 14; font.bold: true; color: t.cryptoPopupText ?? t.textMain ?? "#ffe8eef2" }
MouseArea { id: mm; anchors.fill: parent; hoverEnabled: true; cursorShape: Qt.PointingHandCursor; onClicked: if (value > minVal) stepped(value - 1) }
}
Rectangle {
width: 54; height: 24; radius: 6; color: "#15ffffff"
width: 54; height: 24; radius: 6; color: t.cryptoFieldBg ?? "#15ffffff"
Text { anchors.centerIn: parent; text: value; color: t.cryptoPopupText ?? t.textMain ?? "#ffe8eef2"; font.pixelSize: 12; font.bold: true; font.family: "monospace" }
}
Rectangle {
width: 24; height: 24; radius: 7
color: pm.containsMouse ? (pm.pressed ? (t.accent ?? "#ffc19375") : "#22ffffff") : "#15ffffff"
color: pm.containsMouse ? (pm.pressed ? (t.accent ?? "#ffc19375") : (t.cryptoFieldBgFocus ?? "#22ffffff")) : (t.cryptoFieldBg ?? "#15ffffff")
Behavior on color { ColorAnimation { duration: 100 } }
Text { anchors.centerIn: parent; text: "+"; font.pixelSize: 14; font.bold: true; color: t.cryptoPopupText ?? t.textMain ?? "#ffe8eef2" }
MouseArea { id: pm; anchors.fill: parent; hoverEnabled: true; cursorShape: Qt.PointingHandCursor; onClicked: if (value < maxVal) stepped(value + 1) }
@@ -678,7 +679,7 @@ ModuleChip {
Rectangle {
width: 36; height: 20; radius: 10
color: checked ? (t.accent ?? "#ffc19375") : "#22ffffff"
color: checked ? (t.accent ?? "#ffc19375") : (t.cryptoFieldBgFocus ?? "#22ffffff")
Behavior on color { ColorAnimation { duration: 150 } }
Rectangle {
@@ -783,7 +784,7 @@ ModuleChip {
anchors { right: parent.right
verticalCenter: parent.verticalCenter }
width: 14; height: 14; radius: 4
color: rmChipMouse.containsMouse ? "#44f38ba8" : "transparent"
color: rmChipMouse.containsMouse ? (t.cryptoChipRemoveBg ?? "#44f38ba8") : "transparent"
Behavior on color { ColorAnimation { duration: 100 } }
Text {
anchors.centerIn: parent
@@ -817,7 +818,7 @@ ModuleChip {
Rectangle {
anchors.fill: parent
radius: 2
color: "#15ffffff"
color: t.cryptoFieldBg ?? "#15ffffff"
}
Rectangle {
@@ -853,7 +854,7 @@ ModuleChip {
Rectangle {
Layout.fillWidth: true
height: 30; radius: 8
color: addCoinInput.activeFocus ? "#22ffffff" : "#15ffffff"
color: addCoinInput.activeFocus ? (t.cryptoFieldBgFocus ?? "#22ffffff") : (t.cryptoFieldBg ?? "#15ffffff")
border.color: addCoinInput.activeFocus ? (t.accent ?? "#ffc19375") : "transparent"
border.width: 1
Behavior on color { ColorAnimation { duration: 120 } }
@@ -870,7 +871,7 @@ ModuleChip {
Text {
anchors.fill: parent
text: "e.g. bitcoin, monero, solana"
color: "#55" + (t.textDim ?? "#7a8996").slice(1)
color: t.cryptoPlaceholder ?? "#557a8996"
font.pixelSize: 12; font.family: "monospace"
visible: parent.text === "" && !parent.activeFocus
verticalAlignment: Text.AlignVCenter
@@ -899,7 +900,7 @@ ModuleChip {
Rectangle {
Layout.fillWidth: true
height: 30; radius: 8
color: addCurrencyInput.activeFocus ? "#22ffffff" : "#15ffffff"
color: addCurrencyInput.activeFocus ? (t.cryptoFieldBgFocus ?? "#22ffffff") : (t.cryptoFieldBg ?? "#15ffffff")
border.color: addCurrencyInput.activeFocus ? (t.accent ?? "#ffc19375") : "transparent"
border.width: 1
Behavior on color { ColorAnimation { duration: 120 } }
@@ -916,7 +917,7 @@ ModuleChip {
Text {
anchors.fill: parent
text: "e.g. usd, eur, brl"
color: "#55" + (t.textDim ?? "#7a8996").slice(1)
color: t.cryptoPlaceholder ?? "#557a8996"
font.pixelSize: 12; font.family: "monospace"
visible: parent.text === "" && !parent.activeFocus
verticalAlignment: Text.AlignVCenter
@@ -937,8 +938,8 @@ ModuleChip {
Rectangle {
width: 30; height: 30; radius: 8
color: addPairMouse.containsMouse
? (addPairMouse.pressed ? (t.accent ?? "#ffc19375") : "#22ffffff")
: "#15ffffff"
? (addPairMouse.pressed ? (t.accent ?? "#ffc19375") : (t.cryptoFieldBgFocus ?? "#22ffffff"))
: (t.cryptoFieldBg ?? "#15ffffff")
Behavior on color { ColorAnimation { duration: 100 } }
Text {
anchors.centerIn: parent; text: "+"
@@ -985,8 +986,8 @@ ModuleChip {
Rectangle {
width: 24; height: 24; radius: 7
color: decMouse.containsMouse
? (decMouse.pressed ? (t.accent ?? "#ffc19375") : "#22ffffff")
: "#15ffffff"
? (decMouse.pressed ? (t.accent ?? "#ffc19375") : (t.cryptoFieldBgFocus ?? "#22ffffff"))
: (t.cryptoFieldBg ?? "#15ffffff")
Behavior on color { ColorAnimation { duration: 100 } }
Text { anchors.centerIn: parent; text: ""; font.pixelSize: 14; font.bold: true; color: t.cryptoPopupText ?? t.textMain ?? "#ffe8eef2" }
MouseArea {
@@ -998,7 +999,7 @@ ModuleChip {
Rectangle {
width: 54; height: 24; radius: 6
color: refreshInput.activeFocus ? "#22ffffff" : "#15ffffff"
color: refreshInput.activeFocus ? (t.cryptoFieldBgFocus ?? "#22ffffff") : (t.cryptoFieldBg ?? "#15ffffff")
border.color: refreshInput.activeFocus ? (t.accent ?? "#ffc19375") : "transparent"
border.width: 1
Behavior on color { ColorAnimation { duration: 120 } }
@@ -1047,8 +1048,8 @@ ModuleChip {
Rectangle {
width: 24; height: 24; radius: 7
color: incMouse.containsMouse
? (incMouse.pressed ? (t.accent ?? "#ffc19375") : "#22ffffff")
: "#15ffffff"
? (incMouse.pressed ? (t.accent ?? "#ffc19375") : (t.cryptoFieldBgFocus ?? "#22ffffff"))
: (t.cryptoFieldBg ?? "#15ffffff")
Behavior on color { ColorAnimation { duration: 100 } }
Text { anchors.centerIn: parent; text: "+"; font.pixelSize: 14; font.bold: true; color: t.cryptoPopupText ?? t.textMain ?? "#ffe8eef2" }
MouseArea {
@@ -1081,7 +1082,7 @@ ModuleChip {
Text {
anchors.centerIn: parent
text: "Apply & Refresh"
color: applyMouse.containsMouse ? "#ff0c0e12" : (t.cryptoPopupText ?? t.textMain ?? "#ffe8eef2")
color: applyMouse.containsMouse ? (t.cryptoTextOnAccent ?? "#ff0c0e12") : (t.cryptoPopupText ?? t.textMain ?? "#ffe8eef2")
font.pixelSize: 12
font.bold: true
Behavior on color { ColorAnimation { duration: 130 } }

View File

@@ -163,36 +163,18 @@ ModuleChip {
root.wifiDevice.scannerEnabled = true
}
Rectangle {
id: card
width: parent.width
PopupCard {
popupOpen: netPopup.popupOpen
isTop: root.isTop
animEnabled: netPopup.visible
height: cardBody.implicitHeight + 24
anchors.top: root.isTop ? parent.top : undefined
anchors.bottom: root.isTop ? undefined : parent.bottom
transform: Translate {
y: netPopup.popupOpen ? 0 : (root.isTop ? -card.height : card.height)
Behavior on y {
NumberAnimation {
duration: Cfg.Config.popupAnimDuration
easing.type: Easing.OutExpo
}
enabled: netPopup.visible
}
}
opacity: netPopup.popupOpen ? 1.0 : 0.0
Behavior on opacity { NumberAnimation { duration: 200 } }
color: root.t.netPopupBg
radius: Cfg.Config.popupRadius
border.color: root.t.netPopupBorder
border.width: Cfg.Config.popupBorderWidth
layer.enabled: true
MouseArea { anchors.fill: parent; propagateComposedEvents: false }
ColumnLayout {
id: cardBody
anchors {

View File

@@ -529,9 +529,8 @@ ModuleChip {
function open() { hideTimer.stop(); visible = true; popupOpen = true }
function close() { popupOpen = false; hideTimer.restart() }
Timer {
PopupHideTimer {
id: hideTimer
interval: Cfg.Config.popupAnimDuration + 70
onTriggered: historyPopup.visible = false
}
@@ -566,36 +565,18 @@ ModuleChip {
clip: true
Rectangle {
PopupCard {
id: historyCard
width: parent.width
popupOpen: historyPopup.popupOpen
isTop: root.isTop
animEnabled: historyPopup.visible
height: Math.min(histHeader.implicitHeight + 56 + (notifHistory.count > 0 ? histCol.implicitHeight : 90), 520)
anchors.top: root.isTop ? parent.top : undefined
anchors.bottom: root.isTop ? undefined : parent.bottom
transform: Translate {
y: historyPopup.popupOpen ? 0 : (root.isTop ? -historyCard.height : historyCard.height)
Behavior on y {
NumberAnimation {
duration: Cfg.Config.popupAnimDuration;
easing.type: Easing.OutExpo
}
enabled: historyPopup.visible
}
}
opacity: historyPopup.popupOpen ? 1.0 : 0.0
Behavior on opacity { NumberAnimation { duration: 200 } }
color: t.notifHistoryBg
radius: Cfg.Config.popupRadius
border.color: t.notifHistoryBorder
border.width: Cfg.Config.popupBorderWidth
MouseArea { anchors.fill: parent; propagateComposedEvents: false }
RowLayout {
id: histHeader
anchors { left: parent.left; right: parent.right; top: parent.top }

View File

@@ -6,6 +6,7 @@ import Quickshell.Services.SystemTray
import Quickshell.Widgets
import "../../config" as Cfg
import "../../components"
Item {
id: root
@@ -217,9 +218,8 @@ Item {
}
}
Timer {
PopupHideTimer {
id: hideTimer
interval: Cfg.Config.popupAnimDuration + 70
onTriggered: {
trayMenuPopup.visible = false
rootMenuOpener.menu = null
@@ -389,29 +389,13 @@ Item {
anchors.bottomMargin: root.isTop ? 0 : (Cfg.Config.barHeight + 8)
height: parent.height - Cfg.Config.barHeight - 8
Rectangle {
PopupCard {
id: menuCard
width: parent.width
popupOpen: trayMenuPopup.popupOpen
isTop: root.isTop
animEnabled: true
height: menuCol.height + 12
anchors.top: root.isTop ? parent.top : undefined
anchors.bottom: root.isTop ? undefined : parent.bottom
transform: Translate {
y: trayMenuPopup.popupOpen ? 0
: (root.isTop ? -menuCard.height : menuCard.height)
Behavior on y {
NumberAnimation {
duration: Cfg.Config.popupAnimDuration
easing.type: Easing.OutExpo
}
}
}
opacity: trayMenuPopup.popupOpen ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 200 } }
color: root.tmBg
radius: Cfg.Config.popupRadius
border.color: root.tmBorder

View File

@@ -165,36 +165,17 @@ ModuleChip {
chipRoot: root
cardWidth: Cfg.Config.volumePopupWidth
Rectangle {
id: volCard
width: parent.width
PopupCard {
popupOpen: volumePopup.popupOpen
isTop: root.isTop
animEnabled: volumePopup.visible
height: popupCol.implicitHeight + 32
anchors.top: root.isTop ? parent.top : undefined
anchors.bottom: root.isTop ? undefined : parent.bottom
transform: Translate {
y: volumePopup.popupOpen ? 0 : (root.isTop ? -volCard.height : volCard.height)
Behavior on y {
NumberAnimation {
duration: Cfg.Config.popupAnimDuration;
easing.type: Easing.OutExpo
}
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 }