mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-07 22:15:38 -05:00
meta: large-scale refactor progress
This commit is contained in:
@@ -2,7 +2,8 @@ pragma Singleton
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Qt.labs.platform // ← gives us StandardPaths
|
||||
import Qt.labs.platform
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
@@ -53,7 +54,8 @@ Singleton {
|
||||
|
||||
if (!matugenAvailable) {
|
||||
console.warn("Matugen missing → dynamic theme disabled")
|
||||
Theme.rootObj.wallpaperErrorStatus = "matugen_missing"
|
||||
ToastService.wallpaperErrorStatus = "matugen_missing"
|
||||
ToastService.showWarning("matugen not found - dynamic theming disabled")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -74,7 +76,8 @@ Singleton {
|
||||
} else {
|
||||
console.error("code", code)
|
||||
console.error("Wallpaper not found:", wallpaperPath)
|
||||
Theme.rootObj.showWallpaperError()
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Wallpaper processing failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,17 +94,20 @@ Singleton {
|
||||
const out = matugenCollector.text
|
||||
if (!out.length) {
|
||||
console.error("matugen produced zero bytes\nstderr:", matugenProcess.stderr)
|
||||
Theme.rootObj.showWallpaperError()
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Wallpaper processing failed")
|
||||
return
|
||||
}
|
||||
try {
|
||||
root.matugenJson = out
|
||||
root.matugenColors = JSON.parse(out)
|
||||
root.colorsUpdated()
|
||||
Theme.rootObj.wallpaperErrorStatus = ""
|
||||
ToastService.clearWallpaperError()
|
||||
ToastService.showInfo("Dynamic theme colors updated")
|
||||
} catch (e) {
|
||||
console.error("JSON parse failed:", e)
|
||||
Theme.rootObj.showWallpaperError()
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Wallpaper processing failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,6 @@ import Quickshell.Io
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
// Reference to the main shell root for calling functions
|
||||
property var rootObj: null
|
||||
|
||||
// Initialize theme system
|
||||
Component.onCompleted: {
|
||||
console.log("Theme Component.onCompleted")
|
||||
@@ -609,4 +606,19 @@ Singleton {
|
||||
default: return "Custom power profile"
|
||||
}
|
||||
}
|
||||
|
||||
// Wallpaper IPC handler
|
||||
IpcHandler {
|
||||
target: "wallpaper"
|
||||
|
||||
function refresh() {
|
||||
console.log("Wallpaper IPC: refresh() called")
|
||||
// Trigger color extraction if using dynamic theme
|
||||
if (typeof Theme !== "undefined" && Theme.isDynamicTheme) {
|
||||
console.log("Triggering color extraction due to wallpaper IPC")
|
||||
Colors.extractColors()
|
||||
}
|
||||
return "WALLPAPER_REFRESH_SUCCESS"
|
||||
}
|
||||
}
|
||||
}
|
||||
83
Services/ToastService.qml
Normal file
83
Services/ToastService.qml
Normal file
@@ -0,0 +1,83 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property int levelInfo: 0
|
||||
readonly property int levelWarn: 1
|
||||
readonly property int levelError: 2
|
||||
|
||||
property string currentMessage: ""
|
||||
property int currentLevel: levelInfo
|
||||
property bool toastVisible: false
|
||||
property var toastQueue: []
|
||||
|
||||
property string wallpaperErrorStatus: ""
|
||||
|
||||
Timer {
|
||||
id: toastTimer
|
||||
interval: 5000
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: hideToast()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: queueTimer
|
||||
interval: 500
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: processQueue()
|
||||
}
|
||||
|
||||
function showToast(message, level = levelInfo) {
|
||||
toastQueue.push({ message, level })
|
||||
if (!toastVisible) {
|
||||
processQueue()
|
||||
}
|
||||
}
|
||||
|
||||
function showInfo(message) {
|
||||
showToast(message, levelInfo)
|
||||
}
|
||||
|
||||
function showWarning(message) {
|
||||
showToast(message, levelWarn)
|
||||
}
|
||||
|
||||
function showError(message) {
|
||||
showToast(message, levelError)
|
||||
}
|
||||
|
||||
function hideToast() {
|
||||
toastVisible = false
|
||||
currentMessage = ""
|
||||
currentLevel = levelInfo
|
||||
toastTimer.stop()
|
||||
if (toastQueue.length > 0) {
|
||||
queueTimer.start()
|
||||
}
|
||||
}
|
||||
|
||||
function processQueue() {
|
||||
if (toastQueue.length === 0) return
|
||||
|
||||
const toast = toastQueue.shift()
|
||||
currentMessage = toast.message
|
||||
currentLevel = toast.level
|
||||
toastVisible = true
|
||||
|
||||
toastTimer.interval =
|
||||
toast.level === levelError ? 8000 :
|
||||
toast.level === levelWarn ? 6000 : 5000
|
||||
toastTimer.start()
|
||||
}
|
||||
|
||||
function clearWallpaperError() {
|
||||
wallpaperErrorStatus = ""
|
||||
}
|
||||
}
|
||||
@@ -263,6 +263,21 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-refresh timer for when control center is open
|
||||
property bool autoRefreshEnabled: false
|
||||
|
||||
Timer {
|
||||
id: autoRefreshTimer
|
||||
interval: 20000
|
||||
running: root.autoRefreshEnabled
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if (root.autoRefreshEnabled) {
|
||||
root.scanWifi()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateCurrentWifiInfo() {
|
||||
console.log("Updating current WiFi info...")
|
||||
currentWifiInfo.running = true
|
||||
|
||||
@@ -8,9 +8,11 @@ import qs.Services
|
||||
import Quickshell.Services.UPower
|
||||
|
||||
PanelWindow {
|
||||
id: batteryControlPopup
|
||||
id: root
|
||||
|
||||
visible: root.batteryPopupVisible
|
||||
property bool batteryPopupVisible: false
|
||||
|
||||
visible: batteryPopupVisible
|
||||
|
||||
implicitWidth: 400
|
||||
implicitHeight: 300
|
||||
@@ -32,7 +34,7 @@ PanelWindow {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
root.batteryPopupVisible = false
|
||||
batteryPopupVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +48,8 @@ PanelWindow {
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
|
||||
opacity: root.batteryPopupVisible ? 1.0 : 0.0
|
||||
scale: root.batteryPopupVisible ? 1.0 : 0.85
|
||||
opacity: batteryPopupVisible ? 1.0 : 0.0
|
||||
scale: batteryPopupVisible ? 1.0 : 0.85
|
||||
|
||||
// Prevent click-through to background
|
||||
MouseArea {
|
||||
@@ -114,7 +116,7 @@ PanelWindow {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.batteryPopupVisible = false
|
||||
batteryPopupVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,10 @@ import qs.Services
|
||||
Column {
|
||||
id: calendarWidget
|
||||
|
||||
property var theme: Theme
|
||||
property date displayDate: new Date()
|
||||
property date selectedDate: new Date()
|
||||
|
||||
spacing: theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
// Load events when display date changes
|
||||
onDisplayDateChanged: {
|
||||
@@ -61,16 +60,16 @@ Column {
|
||||
Rectangle {
|
||||
width: 40
|
||||
height: 40
|
||||
radius: theme.cornerRadius
|
||||
color: prevMonthArea.containsMouse ? Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.12) : "transparent"
|
||||
radius: Theme.cornerRadius
|
||||
color: prevMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "chevron_left"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.iconSize
|
||||
color: theme.primary
|
||||
font.weight: theme.iconFontWeight
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize
|
||||
color: Theme.primary
|
||||
font.weight: Theme.iconFontWeight
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -91,8 +90,8 @@ Column {
|
||||
width: parent.width - 80
|
||||
height: 40
|
||||
text: Qt.formatDate(displayDate, "MMMM yyyy")
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
color: theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
@@ -101,16 +100,16 @@ Column {
|
||||
Rectangle {
|
||||
width: 40
|
||||
height: 40
|
||||
radius: theme.cornerRadius
|
||||
color: nextMonthArea.containsMouse ? Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.12) : "transparent"
|
||||
radius: Theme.cornerRadius
|
||||
color: nextMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "chevron_right"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.iconSize
|
||||
color: theme.primary
|
||||
font.weight: theme.iconFontWeight
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize
|
||||
color: Theme.primary
|
||||
font.weight: Theme.iconFontWeight
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -144,8 +143,8 @@ Column {
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: modelData
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.6)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
}
|
||||
@@ -183,20 +182,20 @@ Column {
|
||||
property bool isToday: dayDate.toDateString() === new Date().toDateString()
|
||||
property bool isSelected: dayDate.toDateString() === selectedDate.toDateString()
|
||||
|
||||
color: isSelected ? theme.primary :
|
||||
isToday ? Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.12) :
|
||||
dayArea.containsMouse ? Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.08) : "transparent"
|
||||
color: isSelected ? Theme.primary :
|
||||
isToday ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) :
|
||||
dayArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
||||
|
||||
radius: theme.cornerRadiusSmall
|
||||
radius: Theme.cornerRadiusSmall
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: dayDate.getDate()
|
||||
font.pixelSize: theme.fontSizeMedium
|
||||
color: isSelected ? theme.surface :
|
||||
isToday ? theme.primary :
|
||||
isCurrentMonth ? theme.surfaceText :
|
||||
Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.4)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: isSelected ? Theme.surface :
|
||||
isToday ? Theme.primary :
|
||||
isCurrentMonth ? Theme.surfaceText :
|
||||
Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4)
|
||||
font.weight: isToday || isSelected ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
@@ -215,11 +214,11 @@ Column {
|
||||
color: {
|
||||
if (isSelected) {
|
||||
// Use a lighter tint of primary for selected state
|
||||
return Qt.lighter(theme.primary, 1.3)
|
||||
return Qt.lighter(Theme.primary, 1.3)
|
||||
} else if (isToday) {
|
||||
return theme.primary
|
||||
return Theme.primary
|
||||
} else {
|
||||
return theme.primary
|
||||
return Theme.primary
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,22 +237,22 @@ Column {
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: theme.shortDuration
|
||||
easing.type: theme.standardEasing
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: theme.shortDuration
|
||||
easing.type: theme.standardEasing
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: theme.shortDuration
|
||||
easing.type: theme.standardEasing
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ import qs.Common
|
||||
import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: centerCommandCenter
|
||||
id: root
|
||||
|
||||
property var theme: Theme
|
||||
readonly property bool hasActiveMedia: MprisController.activePlayer !== null
|
||||
property bool calendarVisible: false
|
||||
|
||||
visible: root.calendarVisible
|
||||
visible: calendarVisible
|
||||
|
||||
implicitWidth: 480
|
||||
implicitHeight: 600
|
||||
@@ -48,15 +48,15 @@ PanelWindow {
|
||||
}
|
||||
|
||||
function calculateHeight() {
|
||||
let contentHeight = theme.spacingM * 2 // margins
|
||||
let contentHeight = Theme.spacingM * 2 // margins
|
||||
|
||||
// Main row with widgets and calendar
|
||||
let widgetHeight = 160 // Media widget always present
|
||||
widgetHeight += 140 + theme.spacingM // Weather widget always present
|
||||
widgetHeight += 140 + Theme.spacingM // Weather widget always present
|
||||
let calendarHeight = 300
|
||||
let mainRowHeight = Math.max(widgetHeight, calendarHeight)
|
||||
|
||||
contentHeight += mainRowHeight + theme.spacingM // Add spacing between main row and events
|
||||
contentHeight += mainRowHeight + Theme.spacingM
|
||||
|
||||
// Add events widget height - use calculated height instead of actual
|
||||
if (CalendarService && CalendarService.khalAvailable) {
|
||||
@@ -68,9 +68,9 @@ PanelWindow {
|
||||
return Math.min(contentHeight, parent.height * 0.9)
|
||||
}
|
||||
|
||||
color: theme.surfaceContainer
|
||||
radius: theme.cornerRadiusLarge
|
||||
border.color: Qt.rgba(theme.outline.r, theme.outline.g, theme.outline.b, 0.08)
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadiusLarge
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
|
||||
layer.enabled: true
|
||||
@@ -85,27 +85,27 @@ PanelWindow {
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(theme.surfaceTint.r, theme.surfaceTint.g, theme.surfaceTint.b, 0.04)
|
||||
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
|
||||
radius: parent.radius
|
||||
|
||||
SequentialAnimation on opacity {
|
||||
running: root.calendarVisible
|
||||
running: calendarVisible
|
||||
loops: Animation.Infinite
|
||||
NumberAnimation {
|
||||
to: 0.08
|
||||
duration: theme.extraLongDuration
|
||||
easing.type: theme.standardEasing
|
||||
duration: Theme.extraLongDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
NumberAnimation {
|
||||
to: 0.02
|
||||
duration: theme.extraLongDuration
|
||||
easing.type: theme.standardEasing
|
||||
duration: Theme.extraLongDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
opacity: root.calendarVisible ? 1.0 : 0.0
|
||||
scale: root.calendarVisible ? 1.0 : 0.92
|
||||
opacity: calendarVisible ? 1.0 : 0.0
|
||||
scale: calendarVisible ? 1.0 : 0.92
|
||||
|
||||
// Update height when calendar service events change
|
||||
Connections {
|
||||
@@ -130,47 +130,47 @@ PanelWindow {
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: theme.longDuration
|
||||
easing.type: theme.emphasizedEasing
|
||||
duration: Theme.longDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: theme.longDuration
|
||||
easing.type: theme.emphasizedEasing
|
||||
duration: Theme.longDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: theme.mediumDuration
|
||||
easing.type: theme.standardEasing
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: theme.spacingM
|
||||
spacing: theme.spacingM
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
// Main row with widgets and calendar
|
||||
Row {
|
||||
width: parent.width
|
||||
height: {
|
||||
let widgetHeight = 160 // Media widget always present
|
||||
widgetHeight += 140 + theme.spacingM // Weather widget always present
|
||||
widgetHeight += 140 + Theme.spacingM // Weather widget always present
|
||||
let calendarHeight = 300
|
||||
return Math.max(widgetHeight, calendarHeight)
|
||||
}
|
||||
spacing: theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
// Left section for widgets
|
||||
Column {
|
||||
id: leftWidgets
|
||||
width: hasAnyWidgets ? parent.width * 0.45 : 0
|
||||
height: childrenRect.height
|
||||
spacing: theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
visible: hasAnyWidgets
|
||||
anchors.top: parent.top
|
||||
|
||||
@@ -180,23 +180,20 @@ PanelWindow {
|
||||
visible: true // Always visible - shows placeholder when no media
|
||||
width: parent.width
|
||||
height: 160
|
||||
theme: centerCommandCenter.theme
|
||||
}
|
||||
|
||||
WeatherWidget {
|
||||
visible: true // Always visible - shows placeholder when no weather
|
||||
width: parent.width
|
||||
height: 140
|
||||
theme: centerCommandCenter.theme
|
||||
}
|
||||
}
|
||||
|
||||
// Right section for calendar
|
||||
CalendarWidget {
|
||||
id: calendarWidget
|
||||
width: leftWidgets.hasAnyWidgets ? parent.width * 0.55 - theme.spacingL : parent.width
|
||||
width: leftWidgets.hasAnyWidgets ? parent.width * 0.55 - Theme.spacingL : parent.width
|
||||
height: parent.height
|
||||
theme: centerCommandCenter.theme
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +201,6 @@ PanelWindow {
|
||||
EventsWidget {
|
||||
id: eventsWidget
|
||||
width: parent.width
|
||||
theme: centerCommandCenter.theme
|
||||
selectedDate: calendarWidget.selectedDate
|
||||
|
||||
}
|
||||
@@ -215,7 +211,7 @@ PanelWindow {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
onClicked: {
|
||||
root.calendarVisible = false
|
||||
calendarVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import qs.Services
|
||||
Rectangle {
|
||||
id: eventsWidget
|
||||
|
||||
property var theme: Theme
|
||||
property date selectedDate: new Date()
|
||||
property var selectedDateEvents: []
|
||||
property bool hasEvents: selectedDateEvents && selectedDateEvents.length > 0
|
||||
@@ -21,9 +20,9 @@ Rectangle {
|
||||
|
||||
width: parent.width
|
||||
height: shouldShow ? (hasEvents ? Math.min(300, 80 + selectedDateEvents.length * 60) : 120) : 0
|
||||
radius: theme.cornerRadiusLarge
|
||||
color: Qt.rgba(theme.surfaceVariant.r, theme.surfaceVariant.g, theme.surfaceVariant.b, 0.12)
|
||||
border.color: Qt.rgba(theme.outline.r, theme.outline.g, theme.outline.b, 0.08)
|
||||
radius: Theme.cornerRadiusLarge
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
visible: shouldShow
|
||||
|
||||
@@ -40,8 +39,8 @@ Rectangle {
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: theme.mediumDuration
|
||||
easing.type: theme.emphasizedEasing
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,14 +80,14 @@ Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: theme.spacingL
|
||||
spacing: theme.spacingS
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Text {
|
||||
text: "event"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.iconSize - 2
|
||||
color: theme.primary
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize - 2
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
@@ -97,8 +96,8 @@ Rectangle {
|
||||
(Qt.formatDate(selectedDate, "MMM d") + " • " +
|
||||
(selectedDateEvents.length === 1 ? "1 event" : selectedDateEvents.length + " events")) :
|
||||
Qt.formatDate(selectedDate, "MMM d")
|
||||
font.pixelSize: theme.fontSizeMedium
|
||||
color: theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
@@ -107,21 +106,21 @@ Rectangle {
|
||||
// No events placeholder - centered in entire widget (not just content area)
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: theme.spacingXS
|
||||
spacing: Theme.spacingXS
|
||||
visible: !hasEvents
|
||||
|
||||
Text {
|
||||
text: "event_busy"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.iconSize + 8
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.3)
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize + 8
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "No events"
|
||||
font.pixelSize: theme.fontSizeMedium
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.5)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||
font.weight: Font.Normal
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
@@ -134,12 +133,12 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: theme.spacingL
|
||||
anchors.topMargin: theme.spacingM
|
||||
anchors.margins: Theme.spacingL
|
||||
anchors.topMargin: Theme.spacingM
|
||||
visible: opacity > 0
|
||||
opacity: hasEvents ? 1.0 : 0.0
|
||||
clip: true
|
||||
spacing: theme.spacingS
|
||||
spacing: Theme.spacingS
|
||||
boundsMovement: Flickable.StopAtBounds
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
@@ -149,28 +148,28 @@ Rectangle {
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: theme.mediumDuration
|
||||
easing.type: theme.emphasizedEasing
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
width: eventsList.width
|
||||
height: eventContent.implicitHeight + theme.spacingM
|
||||
radius: theme.cornerRadius
|
||||
height: eventContent.implicitHeight + Theme.spacingM
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (modelData.url && eventMouseArea.containsMouse) {
|
||||
return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.12)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
} else if (eventMouseArea.containsMouse) {
|
||||
return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.06)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06)
|
||||
}
|
||||
return Qt.rgba(theme.surfaceVariant.r, theme.surfaceVariant.g, theme.surfaceVariant.b, 0.06)
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.06)
|
||||
}
|
||||
border.color: {
|
||||
if (modelData.url && eventMouseArea.containsMouse) {
|
||||
return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.3)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3)
|
||||
} else if (eventMouseArea.containsMouse) {
|
||||
return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.15)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15)
|
||||
}
|
||||
return "transparent"
|
||||
}
|
||||
@@ -184,7 +183,7 @@ Rectangle {
|
||||
anchors.leftMargin: 4
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
radius: 2
|
||||
color: theme.primary
|
||||
color: Theme.primary
|
||||
opacity: 0.8
|
||||
}
|
||||
|
||||
@@ -193,15 +192,15 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: theme.spacingL + 4
|
||||
anchors.rightMargin: theme.spacingM
|
||||
anchors.leftMargin: Theme.spacingL + 4
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: 6
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: modelData.title
|
||||
font.pixelSize: theme.fontSizeMedium
|
||||
color: theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
@@ -220,9 +219,9 @@ Rectangle {
|
||||
|
||||
Text {
|
||||
text: "schedule"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.7)
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
@@ -240,8 +239,8 @@ Rectangle {
|
||||
return startTime
|
||||
}
|
||||
}
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.7)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
@@ -256,16 +255,16 @@ Rectangle {
|
||||
|
||||
Text {
|
||||
text: "location_on"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.7)
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: modelData.location
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.7)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
maximumLineCount: 1
|
||||
@@ -293,15 +292,15 @@ Rectangle {
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: theme.shortDuration
|
||||
easing.type: theme.standardEasing
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
duration: theme.shortDuration
|
||||
easing.type: theme.standardEasing
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ Rectangle {
|
||||
id: mediaPlayerWidget
|
||||
|
||||
property MprisPlayer activePlayer: MprisController.activePlayer
|
||||
property var theme: Theme
|
||||
|
||||
property string lastValidTitle: ""
|
||||
property string lastValidArtist: ""
|
||||
@@ -40,9 +39,9 @@ Rectangle {
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
radius: theme.cornerRadiusLarge
|
||||
color: Qt.rgba(theme.surfaceContainer.r, theme.surfaceContainer.g, theme.surfaceContainer.b, 0.4)
|
||||
border.color: Qt.rgba(theme.outline.r, theme.outline.g, theme.outline.b, 0.08)
|
||||
radius: Theme.cornerRadiusLarge
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.4)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
|
||||
layer.enabled: true
|
||||
@@ -96,26 +95,26 @@ Rectangle {
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.margins: theme.spacingS
|
||||
anchors.margins: Theme.spacingS
|
||||
|
||||
// Placeholder when no media - centered in entire widget
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: theme.spacingS
|
||||
spacing: Theme.spacingS
|
||||
visible: (!activePlayer && !lastValidTitle) || (activePlayer && activePlayer.trackTitle === "" && lastValidTitle === "")
|
||||
|
||||
Text {
|
||||
text: "music_note"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.iconSize + 8
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.5)
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize + 8
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "No Media Playing"
|
||||
font.pixelSize: theme.fontSizeMedium
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.7)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
@@ -123,21 +122,21 @@ Rectangle {
|
||||
// Active content in a column
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: theme.spacingS
|
||||
spacing: Theme.spacingS
|
||||
visible: activePlayer && activePlayer.trackTitle !== "" || lastValidTitle !== ""
|
||||
|
||||
// Normal media info when playing
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 60
|
||||
spacing: theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
// Album Art
|
||||
Rectangle {
|
||||
width: 60
|
||||
height: 60
|
||||
radius: theme.cornerRadius
|
||||
color: Qt.rgba(theme.surfaceVariant.r, theme.surfaceVariant.g, theme.surfaceVariant.b, 0.3)
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
@@ -164,9 +163,9 @@ Rectangle {
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "album"
|
||||
font.family: theme.iconFont
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: 28
|
||||
color: theme.surfaceVariantText
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,9 +173,9 @@ Rectangle {
|
||||
|
||||
// Track Info
|
||||
Column {
|
||||
width: parent.width - 60 - theme.spacingM
|
||||
width: parent.width - 60 - Theme.spacingM
|
||||
height: parent.height
|
||||
spacing: theme.spacingXS
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
Text {
|
||||
text: activePlayer?.trackTitle || lastValidTitle || "Unknown Track"
|
||||
@@ -185,9 +184,9 @@ Rectangle {
|
||||
lastValidTitle = activePlayer.trackTitle;
|
||||
}
|
||||
}
|
||||
font.pixelSize: theme.fontSizeMedium
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Bold
|
||||
color: theme.surfaceText
|
||||
color: Theme.surfaceText
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
@@ -199,8 +198,8 @@ Rectangle {
|
||||
lastValidArtist = activePlayer.trackArtist;
|
||||
}
|
||||
}
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.8)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8)
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
@@ -212,8 +211,8 @@ Rectangle {
|
||||
lastValidAlbum = activePlayer.trackAlbum;
|
||||
}
|
||||
}
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.6)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
visible: text.length > 0
|
||||
@@ -232,7 +231,7 @@ Rectangle {
|
||||
width: parent.width
|
||||
height: 6
|
||||
radius: 3
|
||||
color: Qt.rgba(theme.surfaceVariant.r, theme.surfaceVariant.g, theme.surfaceVariant.b, 0.3)
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
visible: activePlayer !== null
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -240,7 +239,7 @@ Rectangle {
|
||||
id: progressFill
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
color: theme.primary
|
||||
color: Theme.primary
|
||||
|
||||
width: parent.width * ratio()
|
||||
|
||||
@@ -255,8 +254,8 @@ Rectangle {
|
||||
width: 12
|
||||
height: 12
|
||||
radius: 6
|
||||
color: theme.primary
|
||||
border.color: Qt.lighter(theme.primary, 1.3)
|
||||
color: Theme.primary
|
||||
border.color: Qt.lighter(Theme.primary, 1.3)
|
||||
border.width: 1
|
||||
|
||||
x: Math.max(0, Math.min(parent.width - width, progressFill.width - width/2))
|
||||
@@ -346,7 +345,7 @@ Rectangle {
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
height: parent.height
|
||||
|
||||
// Previous button
|
||||
@@ -354,14 +353,14 @@ Rectangle {
|
||||
width: 28
|
||||
height: 28
|
||||
radius: 14
|
||||
color: prevBtnArea.containsMouse ? Qt.rgba(theme.surfaceVariant.r, theme.surfaceVariant.g, theme.surfaceVariant.b, 0.12) : "transparent"
|
||||
color: prevBtnArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12) : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "skip_previous"
|
||||
font.family: theme.iconFont
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: 16
|
||||
color: theme.surfaceText
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -388,14 +387,14 @@ Rectangle {
|
||||
width: 32
|
||||
height: 32
|
||||
radius: 16
|
||||
color: theme.primary
|
||||
color: Theme.primary
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: activePlayer?.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow"
|
||||
font.family: theme.iconFont
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: 20
|
||||
color: theme.background
|
||||
color: Theme.background
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -411,14 +410,14 @@ Rectangle {
|
||||
width: 28
|
||||
height: 28
|
||||
radius: 14
|
||||
color: nextBtnArea.containsMouse ? Qt.rgba(theme.surfaceVariant.r, theme.surfaceVariant.g, theme.surfaceVariant.b, 0.12) : "transparent"
|
||||
color: nextBtnArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12) : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "skip_next"
|
||||
font.family: theme.iconFont
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: 16
|
||||
color: theme.surfaceText
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
||||
@@ -7,13 +7,12 @@ import qs.Services
|
||||
Rectangle {
|
||||
id: weatherWidget
|
||||
|
||||
property var theme: Theme
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
radius: theme.cornerRadiusLarge
|
||||
color: Qt.rgba(theme.surfaceContainer.r, theme.surfaceContainer.g, theme.surfaceContainer.b, 0.4)
|
||||
border.color: Qt.rgba(theme.outline.r, theme.outline.g, theme.outline.b, 0.08)
|
||||
radius: Theme.cornerRadiusLarge
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.4)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
|
||||
layer.enabled: true
|
||||
@@ -29,21 +28,21 @@ Rectangle {
|
||||
// Placeholder when no weather - centered in entire widget
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: theme.spacingS
|
||||
spacing: Theme.spacingS
|
||||
visible: !WeatherService.weather.available || WeatherService.weather.temp === 0
|
||||
|
||||
Text {
|
||||
text: "cloud_off"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.iconSize + 8
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.5)
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize + 8
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "No Weather Data"
|
||||
font.pixelSize: theme.fontSizeMedium
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.7)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
@@ -51,8 +50,8 @@ Rectangle {
|
||||
// Weather content when available - original Column structure
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: theme.spacingL
|
||||
spacing: theme.spacingS
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingS
|
||||
visible: WeatherService.weather.available && WeatherService.weather.temp !== 0
|
||||
|
||||
// Weather header info
|
||||
@@ -62,25 +61,25 @@ Rectangle {
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: theme.spacingL
|
||||
spacing: Theme.spacingL
|
||||
|
||||
// Weather icon
|
||||
Text {
|
||||
text: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.iconSize + 8
|
||||
color: theme.primary
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize + 8
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: theme.spacingXS
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Text {
|
||||
text: (Prefs.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" + (Prefs.useFahrenheit ? "F" : "C")
|
||||
font.pixelSize: theme.fontSizeXLarge
|
||||
color: theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeXLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Light
|
||||
|
||||
MouseArea {
|
||||
@@ -94,8 +93,8 @@ Rectangle {
|
||||
|
||||
Text {
|
||||
text: WeatherService.weather.city || ""
|
||||
font.pixelSize: theme.fontSizeMedium
|
||||
color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.7)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
visible: text.length > 0
|
||||
}
|
||||
}
|
||||
@@ -105,73 +104,73 @@ Rectangle {
|
||||
// Weather details grid
|
||||
Grid {
|
||||
columns: 2
|
||||
spacing: theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Row {
|
||||
spacing: theme.spacingXS
|
||||
spacing: Theme.spacingXS
|
||||
Text {
|
||||
text: "humidity_low"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: theme.surfaceText
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
Text {
|
||||
text: WeatherService.weather.humidity ? WeatherService.weather.humidity + "%" : "--"
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: theme.spacingXS
|
||||
spacing: Theme.spacingXS
|
||||
Text {
|
||||
text: "air"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: theme.surfaceText
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
Text {
|
||||
text: WeatherService.weather.wind || "--"
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: theme.spacingXS
|
||||
spacing: Theme.spacingXS
|
||||
Text {
|
||||
text: "wb_twilight"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: theme.surfaceText
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
Text {
|
||||
text: WeatherService.weather.sunrise || "--"
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: theme.spacingXS
|
||||
spacing: Theme.spacingXS
|
||||
Text {
|
||||
text: "bedtime"
|
||||
font.family: theme.iconFont
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: theme.surfaceText
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
Text {
|
||||
text: WeatherService.weather.sunset || "--"
|
||||
font.pixelSize: theme.fontSizeSmall
|
||||
color: theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,16 @@ import qs.Common
|
||||
import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: controlCenterPopup
|
||||
id: root
|
||||
|
||||
visible: root.controlCenterVisible
|
||||
property bool controlCenterVisible: false
|
||||
|
||||
visible: controlCenterVisible
|
||||
|
||||
onVisibleChanged: {
|
||||
// Enable/disable WiFi auto-refresh based on control center visibility
|
||||
WifiService.autoRefreshEnabled = visible && NetworkService.wifiEnabled
|
||||
}
|
||||
|
||||
implicitWidth: 600
|
||||
implicitHeight: 500
|
||||
@@ -34,7 +41,7 @@ PanelWindow {
|
||||
|
||||
Rectangle {
|
||||
width: Math.min(600, Screen.width - Theme.spacingL * 2)
|
||||
height: controlCenterPopup.powerOptionsExpanded ? 570 : 500
|
||||
height: root.powerOptionsExpanded ? 570 : 500
|
||||
x: Math.max(Theme.spacingL, Screen.width - width - Theme.spacingL)
|
||||
y: Theme.barHeight + Theme.spacingXS
|
||||
color: Theme.popupBackground()
|
||||
@@ -46,15 +53,15 @@ PanelWindow {
|
||||
transform: [
|
||||
Scale {
|
||||
id: scaleTransform
|
||||
origin.x: parent.width // Scale from top-right corner
|
||||
origin.x: 600 // Use fixed width since popup is max 600px wide
|
||||
origin.y: 0
|
||||
xScale: root.controlCenterVisible ? 1.0 : 0.95
|
||||
yScale: root.controlCenterVisible ? 1.0 : 0.8
|
||||
xScale: controlCenterVisible ? 1.0 : 0.95
|
||||
yScale: controlCenterVisible ? 1.0 : 0.8
|
||||
},
|
||||
Translate {
|
||||
id: translateTransform
|
||||
x: root.controlCenterVisible ? 0 : 15 // Slide slightly left when hidden
|
||||
y: root.controlCenterVisible ? 0 : -30
|
||||
x: controlCenterVisible ? 0 : 15 // Slide slightly left when hidden
|
||||
y: controlCenterVisible ? 0 : -30
|
||||
}
|
||||
]
|
||||
|
||||
@@ -62,13 +69,13 @@ PanelWindow {
|
||||
states: [
|
||||
State {
|
||||
name: "visible"
|
||||
when: root.controlCenterVisible
|
||||
when: controlCenterVisible
|
||||
PropertyChanges { target: scaleTransform; xScale: 1.0; yScale: 1.0 }
|
||||
PropertyChanges { target: translateTransform; x: 0; y: 0 }
|
||||
},
|
||||
State {
|
||||
name: "hidden"
|
||||
when: !root.controlCenterVisible
|
||||
when: !controlCenterVisible
|
||||
PropertyChanges { target: scaleTransform; xScale: 0.95; yScale: 0.8 }
|
||||
PropertyChanges { target: translateTransform; x: 15; y: -30 }
|
||||
}
|
||||
@@ -96,7 +103,7 @@ PanelWindow {
|
||||
}
|
||||
]
|
||||
|
||||
opacity: root.controlCenterVisible ? 1.0 : 0.0
|
||||
opacity: controlCenterVisible ? 1.0 : 0.0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
@@ -253,7 +260,7 @@ PanelWindow {
|
||||
width: 40
|
||||
height: 40
|
||||
radius: 20
|
||||
color: powerButton.containsMouse || controlCenterPopup.powerOptionsExpanded ?
|
||||
color: powerButton.containsMouse || root.powerOptionsExpanded ?
|
||||
Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) :
|
||||
Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5)
|
||||
|
||||
@@ -267,10 +274,10 @@ PanelWindow {
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: controlCenterPopup.powerOptionsExpanded ? "expand_less" : "power_settings_new"
|
||||
text: root.powerOptionsExpanded ? "expand_less" : "power_settings_new"
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize - 2
|
||||
color: powerButton.containsMouse || controlCenterPopup.powerOptionsExpanded ? Theme.error : Theme.surfaceText
|
||||
color: powerButton.containsMouse || root.powerOptionsExpanded ? Theme.error : Theme.surfaceText
|
||||
|
||||
Behavior on text {
|
||||
// Smooth icon transition
|
||||
@@ -302,7 +309,7 @@ PanelWindow {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
controlCenterPopup.powerOptionsExpanded = !controlCenterPopup.powerOptionsExpanded
|
||||
root.powerOptionsExpanded = !root.powerOptionsExpanded
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,8 +345,8 @@ PanelWindow {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
root.controlCenterVisible = false
|
||||
root.settingsVisible = true
|
||||
controlCenterVisible = false
|
||||
settingsPopup.settingsVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,12 +363,12 @@ PanelWindow {
|
||||
// Animated Collapsible Power Options (optimized)
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: controlCenterPopup.powerOptionsExpanded ? 60 : 0
|
||||
height: root.powerOptionsExpanded ? 60 : 0
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.4)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: controlCenterPopup.powerOptionsExpanded ? 1 : 0
|
||||
opacity: controlCenterPopup.powerOptionsExpanded ? 1.0 : 0.0
|
||||
border.width: root.powerOptionsExpanded ? 1 : 0
|
||||
opacity: root.powerOptionsExpanded ? 1.0 : 0.0
|
||||
clip: true
|
||||
|
||||
// Single coordinated animation for power options
|
||||
@@ -382,7 +389,7 @@ PanelWindow {
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingL
|
||||
visible: controlCenterPopup.powerOptionsExpanded
|
||||
visible: root.powerOptionsExpanded
|
||||
|
||||
// Logout
|
||||
Rectangle {
|
||||
@@ -421,11 +428,13 @@ PanelWindow {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
controlCenterPopup.powerOptionsExpanded = false
|
||||
root.powerConfirmAction = "logout"
|
||||
root.powerConfirmTitle = "Logout"
|
||||
root.powerConfirmMessage = "Are you sure you want to logout?"
|
||||
root.powerConfirmVisible = true
|
||||
root.powerOptionsExpanded = false
|
||||
if (typeof root !== "undefined" && root.powerConfirmDialog) {
|
||||
root.powerConfirmDialog.powerConfirmAction = "logout"
|
||||
root.powerConfirmDialog.powerConfirmTitle = "Logout"
|
||||
root.powerConfirmDialog.powerConfirmMessage = "Are you sure you want to logout?"
|
||||
root.powerConfirmDialog.powerConfirmVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,11 +483,13 @@ PanelWindow {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
controlCenterPopup.powerOptionsExpanded = false
|
||||
root.powerConfirmAction = "reboot"
|
||||
root.powerConfirmTitle = "Restart"
|
||||
root.powerConfirmMessage = "Are you sure you want to restart?"
|
||||
root.powerConfirmVisible = true
|
||||
root.powerOptionsExpanded = false
|
||||
if (typeof root !== "undefined" && root.powerConfirmDialog) {
|
||||
root.powerConfirmDialog.powerConfirmAction = "reboot"
|
||||
root.powerConfirmDialog.powerConfirmTitle = "Restart"
|
||||
root.powerConfirmDialog.powerConfirmMessage = "Are you sure you want to restart?"
|
||||
root.powerConfirmDialog.powerConfirmVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,11 +538,13 @@ PanelWindow {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
controlCenterPopup.powerOptionsExpanded = false
|
||||
root.powerConfirmAction = "poweroff"
|
||||
root.powerConfirmTitle = "Shutdown"
|
||||
root.powerConfirmMessage = "Are you sure you want to shutdown?"
|
||||
root.powerConfirmVisible = true
|
||||
root.powerOptionsExpanded = false
|
||||
if (typeof root !== "undefined" && root.powerConfirmDialog) {
|
||||
root.powerConfirmDialog.powerConfirmAction = "poweroff"
|
||||
root.powerConfirmDialog.powerConfirmTitle = "Shutdown"
|
||||
root.powerConfirmDialog.powerConfirmMessage = "Are you sure you want to shutdown?"
|
||||
root.powerConfirmDialog.powerConfirmVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,7 +592,7 @@ PanelWindow {
|
||||
width: (parent.width - Theme.spacingXS * (tabCount - 1)) / tabCount
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: controlCenterPopup.currentTab === modelData.id ?
|
||||
color: root.currentTab === modelData.id ?
|
||||
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) :
|
||||
tabArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
||||
|
||||
@@ -591,15 +604,15 @@ PanelWindow {
|
||||
text: modelData.icon
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize - 4
|
||||
color: controlCenterPopup.currentTab === modelData.id ? Theme.primary : Theme.surfaceText
|
||||
color: root.currentTab === modelData.id ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: modelData.name
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: controlCenterPopup.currentTab === modelData.id ? Theme.primary : Theme.surfaceText
|
||||
font.weight: controlCenterPopup.currentTab === modelData.id ? Font.Medium : Font.Normal
|
||||
color: root.currentTab === modelData.id ? Theme.primary : Theme.surfaceText
|
||||
font.weight: root.currentTab === modelData.id ? Font.Medium : Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
@@ -611,7 +624,7 @@ PanelWindow {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
controlCenterPopup.currentTab = modelData.id
|
||||
root.currentTab = modelData.id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,7 +642,7 @@ PanelWindow {
|
||||
// Tab content area
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: controlCenterPopup.powerOptionsExpanded ? 240 : 300
|
||||
height: root.powerOptionsExpanded ? 240 : 300
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.1)
|
||||
|
||||
@@ -644,36 +657,29 @@ PanelWindow {
|
||||
NetworkTab {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
visible: controlCenterPopup.currentTab === "network"
|
||||
visible: root.currentTab === "network"
|
||||
|
||||
wifiPasswordSSID: root.wifiPasswordSSID
|
||||
wifiPasswordInput: root.wifiPasswordInput
|
||||
wifiPasswordDialogVisible: root.wifiPasswordDialogVisible
|
||||
|
||||
onWifiAutoRefreshEnabledChanged: {
|
||||
root.wifiAutoRefreshEnabled = wifiAutoRefreshEnabled
|
||||
}
|
||||
}
|
||||
|
||||
// Audio Tab
|
||||
AudioTab {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
visible: controlCenterPopup.currentTab === "audio"
|
||||
visible: root.currentTab === "audio"
|
||||
}
|
||||
|
||||
// Bluetooth Tab
|
||||
BluetoothTab {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
visible: BluetoothService.available && controlCenterPopup.currentTab === "bluetooth"
|
||||
visible: BluetoothService.available && root.currentTab === "bluetooth"
|
||||
}
|
||||
|
||||
// Display Tab
|
||||
DisplayTab {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
visible: controlCenterPopup.currentTab === "display"
|
||||
visible: root.currentTab === "display"
|
||||
|
||||
}
|
||||
}
|
||||
@@ -685,7 +691,7 @@ PanelWindow {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
onClicked: {
|
||||
root.controlCenterVisible = false
|
||||
controlCenterVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,6 @@ Item {
|
||||
else return 1 // Default to WiFi when nothing is connected
|
||||
}
|
||||
|
||||
// Expose properties that the parent needs to bind to
|
||||
property bool wifiAutoRefreshEnabled: false
|
||||
property string wifiPasswordSSID: ""
|
||||
property string wifiPasswordInput: ""
|
||||
property bool wifiPasswordDialogVisible: false
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
@@ -67,7 +62,7 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
networkTab.networkSubTab = 0
|
||||
networkTab.wifiAutoRefreshEnabled = false
|
||||
WifiService.autoRefreshEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,7 +103,7 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
networkTab.networkSubTab = 1
|
||||
networkTab.wifiAutoRefreshEnabled = true
|
||||
WifiService.autoRefreshEnabled = true
|
||||
if (NetworkService.wifiEnabled) {
|
||||
WifiService.scanWifi()
|
||||
}
|
||||
@@ -795,9 +790,9 @@ Item {
|
||||
WifiService.connectToWifi(modelData.ssid)
|
||||
} else if (modelData.secured) {
|
||||
// Secured network, need password - use root dialog
|
||||
root.wifiPasswordSSID = modelData.ssid
|
||||
root.wifiPasswordInput = ""
|
||||
root.wifiPasswordDialogVisible = true
|
||||
wifiPasswordDialog.wifiPasswordSSID = modelData.ssid
|
||||
wifiPasswordDialog.wifiPasswordInput = ""
|
||||
wifiPasswordDialog.wifiPasswordDialogVisible = true
|
||||
} else {
|
||||
// Open network, connect directly
|
||||
WifiService.connectToWifi(modelData.ssid)
|
||||
|
||||
@@ -9,7 +9,6 @@ Rectangle {
|
||||
|
||||
property bool showPercentage: true
|
||||
property bool showIcon: true
|
||||
property var processDropdown: null
|
||||
|
||||
width: 55
|
||||
height: 30
|
||||
@@ -18,10 +17,6 @@ Rectangle {
|
||||
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) :
|
||||
Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
|
||||
|
||||
Component.onCompleted: {
|
||||
// CPU widget initialized
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: cpuArea
|
||||
anchors.fill: parent
|
||||
@@ -29,10 +24,8 @@ Rectangle {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
if (processDropdown) {
|
||||
ProcessMonitorService.setSortBy("cpu")
|
||||
processDropdown.toggle()
|
||||
}
|
||||
processListDropdown.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,9 @@ import qs.Common
|
||||
import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: notificationHistoryPopup
|
||||
id: root
|
||||
|
||||
property bool notificationHistoryVisible: false
|
||||
signal closeRequested()
|
||||
|
||||
visible: notificationHistoryVisible
|
||||
|
||||
@@ -35,7 +34,7 @@ PanelWindow {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
closeRequested()
|
||||
notificationHistoryVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +52,7 @@ PanelWindow {
|
||||
transform: [
|
||||
Scale {
|
||||
id: scaleTransform
|
||||
origin.x: parent.width
|
||||
origin.x: 400 // Use fixed width since popup is 400px wide
|
||||
origin.y: 0
|
||||
xScale: notificationHistoryVisible ? 1.0 : 0.95
|
||||
yScale: notificationHistoryVisible ? 1.0 : 0.8
|
||||
|
||||
@@ -7,9 +7,14 @@ import Quickshell.Io
|
||||
import qs.Common
|
||||
|
||||
PanelWindow {
|
||||
id: powerConfirmDialog
|
||||
id: root
|
||||
|
||||
visible: root.powerConfirmVisible
|
||||
property bool powerConfirmVisible: false
|
||||
property string powerConfirmAction: ""
|
||||
property string powerConfirmTitle: ""
|
||||
property string powerConfirmMessage: ""
|
||||
|
||||
visible: powerConfirmVisible
|
||||
|
||||
implicitWidth: 400
|
||||
implicitHeight: 300
|
||||
@@ -43,8 +48,8 @@ PanelWindow {
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: 1
|
||||
|
||||
opacity: root.powerConfirmVisible ? 1.0 : 0.0
|
||||
scale: root.powerConfirmVisible ? 1.0 : 0.9
|
||||
opacity: powerConfirmVisible ? 1.0 : 0.0
|
||||
scale: powerConfirmVisible ? 1.0 : 0.9
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
@@ -67,10 +72,10 @@ PanelWindow {
|
||||
|
||||
// Title
|
||||
Text {
|
||||
text: root.powerConfirmTitle
|
||||
text: powerConfirmTitle
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: {
|
||||
switch(root.powerConfirmAction) {
|
||||
switch(powerConfirmAction) {
|
||||
case "poweroff": return Theme.error
|
||||
case "reboot": return Theme.warning
|
||||
default: return Theme.surfaceText
|
||||
@@ -83,7 +88,7 @@ PanelWindow {
|
||||
|
||||
// Message
|
||||
Text {
|
||||
text: root.powerConfirmMessage
|
||||
text: powerConfirmMessage
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
width: parent.width
|
||||
@@ -119,7 +124,7 @@ PanelWindow {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.powerConfirmVisible = false
|
||||
powerConfirmVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,7 +136,7 @@ PanelWindow {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
let baseColor
|
||||
switch(root.powerConfirmAction) {
|
||||
switch(powerConfirmAction) {
|
||||
case "poweroff": baseColor = Theme.error; break
|
||||
case "reboot": baseColor = Theme.warning; break
|
||||
default: baseColor = Theme.primary; break
|
||||
@@ -155,8 +160,8 @@ PanelWindow {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.powerConfirmVisible = false
|
||||
executePowerAction(root.powerConfirmAction)
|
||||
powerConfirmVisible = false
|
||||
executePowerAction(powerConfirmAction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@ import Quickshell.Io
|
||||
import qs.Common
|
||||
|
||||
PanelWindow {
|
||||
id: powerMenuPopup
|
||||
id: root
|
||||
|
||||
visible: root.powerMenuVisible
|
||||
property bool powerMenuVisible: false
|
||||
|
||||
visible: powerMenuVisible
|
||||
|
||||
implicitWidth: 400
|
||||
implicitHeight: 320
|
||||
@@ -31,7 +33,7 @@ PanelWindow {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
root.powerMenuVisible = false
|
||||
powerMenuVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +47,8 @@ PanelWindow {
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
|
||||
opacity: root.powerMenuVisible ? 1.0 : 0.0
|
||||
scale: root.powerMenuVisible ? 1.0 : 0.85
|
||||
opacity: powerMenuVisible ? 1.0 : 0.0
|
||||
scale: powerMenuVisible ? 1.0 : 0.85
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
@@ -109,7 +111,7 @@ PanelWindow {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.powerMenuVisible = false
|
||||
powerMenuVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,7 +158,7 @@ PanelWindow {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.powerMenuVisible = false
|
||||
powerMenuVisible = false
|
||||
root.powerConfirmAction = "logout"
|
||||
root.powerConfirmTitle = "Log Out"
|
||||
root.powerConfirmMessage = "Are you sure you want to log out?"
|
||||
@@ -201,7 +203,7 @@ PanelWindow {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.powerMenuVisible = false
|
||||
powerMenuVisible = false
|
||||
root.powerConfirmAction = "suspend"
|
||||
root.powerConfirmTitle = "Suspend"
|
||||
root.powerConfirmMessage = "Are you sure you want to suspend the system?"
|
||||
@@ -246,7 +248,7 @@ PanelWindow {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.powerMenuVisible = false
|
||||
powerMenuVisible = false
|
||||
root.powerConfirmAction = "reboot"
|
||||
root.powerConfirmTitle = "Reboot"
|
||||
root.powerConfirmMessage = "Are you sure you want to reboot the system?"
|
||||
@@ -291,7 +293,7 @@ PanelWindow {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.powerMenuVisible = false
|
||||
powerMenuVisible = false
|
||||
root.powerConfirmAction = "poweroff"
|
||||
root.powerConfirmTitle = "Power Off"
|
||||
root.powerConfirmMessage = "Are you sure you want to power off the system?"
|
||||
|
||||
@@ -10,7 +10,7 @@ import qs.Common
|
||||
import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: processDropdown
|
||||
id: processListDropdown
|
||||
|
||||
property bool isVisible: false
|
||||
property var parentWidget: null
|
||||
@@ -41,7 +41,7 @@ PanelWindow {
|
||||
// Click outside to close
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: processDropdown.hide()
|
||||
onClicked: processListDropdown.hide()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -63,8 +63,8 @@ PanelWindow {
|
||||
id: scaleTransform
|
||||
origin.x: parent.width * 0.85 // Scale from top-right
|
||||
origin.y: 0
|
||||
xScale: processDropdown.isVisible ? 1.0 : 0.95
|
||||
yScale: processDropdown.isVisible ? 1.0 : 0.8
|
||||
xScale: processListDropdown.isVisible ? 1.0 : 0.95
|
||||
yScale: processListDropdown.isVisible ? 1.0 : 0.8
|
||||
|
||||
Behavior on xScale {
|
||||
NumberAnimation {
|
||||
@@ -82,8 +82,8 @@ PanelWindow {
|
||||
},
|
||||
Translate {
|
||||
id: translateTransform
|
||||
x: processDropdown.isVisible ? 0 : 20
|
||||
y: processDropdown.isVisible ? 0 : -30
|
||||
x: processListDropdown.isVisible ? 0 : 20
|
||||
y: processListDropdown.isVisible ? 0 : -30
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
@@ -101,7 +101,7 @@ PanelWindow {
|
||||
}
|
||||
]
|
||||
|
||||
opacity: processDropdown.isVisible ? 1.0 : 0.0
|
||||
opacity: processListDropdown.isVisible ? 1.0 : 0.0
|
||||
|
||||
// Add shadow effect
|
||||
layer.enabled: true
|
||||
@@ -111,7 +111,7 @@ PanelWindow {
|
||||
shadowVerticalOffset: 8
|
||||
shadowBlur: 1.0
|
||||
shadowColor: Qt.rgba(0, 0, 0, 0.15)
|
||||
shadowOpacity: processDropdown.isVisible ? 0.15 : 0
|
||||
shadowOpacity: processListDropdown.isVisible ? 0.15 : 0
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
|
||||
@@ -9,7 +9,6 @@ Rectangle {
|
||||
|
||||
property bool showPercentage: true
|
||||
property bool showIcon: true
|
||||
property var processDropdown: null
|
||||
|
||||
width: 55
|
||||
height: 30
|
||||
@@ -18,10 +17,6 @@ Rectangle {
|
||||
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) :
|
||||
Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
|
||||
|
||||
Component.onCompleted: {
|
||||
// RAM widget initialized
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: ramArea
|
||||
anchors.fill: parent
|
||||
@@ -29,10 +24,8 @@ Rectangle {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
if (processDropdown) {
|
||||
ProcessMonitorService.setSortBy("memory")
|
||||
processDropdown.toggle()
|
||||
}
|
||||
processListDropdown.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Column {
|
||||
id: themePicker
|
||||
@@ -198,7 +199,7 @@ Column {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
color: {
|
||||
if (root.wallpaperErrorStatus === "error" || root.wallpaperErrorStatus === "matugen_missing") {
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") {
|
||||
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
|
||||
} else {
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
@@ -206,7 +207,7 @@ Column {
|
||||
}
|
||||
|
||||
border.color: {
|
||||
if (root.wallpaperErrorStatus === "error" || root.wallpaperErrorStatus === "matugen_missing") {
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") {
|
||||
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.5)
|
||||
} else if (Theme.isDynamicTheme) {
|
||||
return Theme.primary
|
||||
@@ -223,13 +224,13 @@ Column {
|
||||
|
||||
Text {
|
||||
text: {
|
||||
if (root.wallpaperErrorStatus === "error" || root.wallpaperErrorStatus === "matugen_missing") return "error"
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") return "error"
|
||||
else return "palette"
|
||||
}
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: 16
|
||||
color: {
|
||||
if (root.wallpaperErrorStatus === "error" || root.wallpaperErrorStatus === "matugen_missing") return Theme.error
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") return Theme.error
|
||||
else return Theme.surfaceText
|
||||
}
|
||||
font.weight: Theme.iconFontWeight
|
||||
@@ -238,13 +239,13 @@ Column {
|
||||
|
||||
Text {
|
||||
text: {
|
||||
if (root.wallpaperErrorStatus === "error") return "Error"
|
||||
else if (root.wallpaperErrorStatus === "matugen_missing") return "No matugen"
|
||||
if (ToastService.wallpaperErrorStatus === "error") return "Error"
|
||||
else if (ToastService.wallpaperErrorStatus === "matugen_missing") return "No matugen"
|
||||
else return "Auto"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: {
|
||||
if (root.wallpaperErrorStatus === "error" || root.wallpaperErrorStatus === "matugen_missing") return Theme.error
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") return Theme.error
|
||||
else return Theme.surfaceText
|
||||
}
|
||||
font.weight: Font.Medium
|
||||
@@ -297,21 +298,21 @@ Column {
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: autoMouseArea.containsMouse && (!Theme.isDynamicTheme || root.wallpaperErrorStatus === "error" || root.wallpaperErrorStatus === "matugen_missing")
|
||||
visible: autoMouseArea.containsMouse && (!Theme.isDynamicTheme || ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
|
||||
Text {
|
||||
id: autoTooltipText
|
||||
text: {
|
||||
if (root.wallpaperErrorStatus === "error") {
|
||||
if (ToastService.wallpaperErrorStatus === "error") {
|
||||
return "Wallpaper symlink missing at ~/quickshell/current_wallpaper"
|
||||
} else if (root.wallpaperErrorStatus === "matugen_missing") {
|
||||
} else if (ToastService.wallpaperErrorStatus === "matugen_missing") {
|
||||
return "Install matugen package for dynamic themes"
|
||||
} else {
|
||||
return "Dynamic wallpaper-based colors"
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: (root.wallpaperErrorStatus === "error" || root.wallpaperErrorStatus === "matugen_missing") ? Theme.error : Theme.surfaceText
|
||||
color: (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") ? Theme.error : Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
wrapMode: Text.WordWrap
|
||||
width: Math.min(implicitWidth, 250)
|
||||
|
||||
125
Widgets/ToastWidget.qml
Normal file
125
Widgets/ToastWidget.qml
Normal file
@@ -0,0 +1,125 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
visible: ToastService.toastVisible
|
||||
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
color: "transparent"
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
// Makes the background transparent to mouse events
|
||||
mask: Region {
|
||||
item: toast
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: toast
|
||||
width: Math.min(400, Screen.width - Theme.spacingL * 2)
|
||||
height: toastContent.height + Theme.spacingL * 2
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: Theme.barHeight + Theme.spacingL
|
||||
|
||||
color: {
|
||||
switch (ToastService.currentLevel) {
|
||||
case ToastService.levelError: return Theme.error
|
||||
case ToastService.levelWarn: return Theme.warning
|
||||
case ToastService.levelInfo: return Theme.primary
|
||||
default: return Theme.primary
|
||||
}
|
||||
}
|
||||
|
||||
radius: Theme.cornerRadiusLarge
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: MultiEffect {
|
||||
shadowEnabled: true
|
||||
shadowHorizontalOffset: 0
|
||||
shadowVerticalOffset: 4
|
||||
shadowBlur: 0.8
|
||||
shadowColor: Qt.rgba(0, 0, 0, 0.3)
|
||||
shadowOpacity: 0.3
|
||||
}
|
||||
|
||||
opacity: ToastService.toastVisible ? 0.9 : 0.0
|
||||
scale: ToastService.toastVisible ? 1.0 : 0.9
|
||||
|
||||
transform: Translate {
|
||||
y: ToastService.toastVisible ? 0 : -20
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: toastContent
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Text {
|
||||
text: {
|
||||
switch (ToastService.currentLevel) {
|
||||
case ToastService.levelError: return "error"
|
||||
case ToastService.levelWarn: return "warning"
|
||||
case ToastService.levelInfo: return "info"
|
||||
default: return "info"
|
||||
}
|
||||
}
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize
|
||||
color: Theme.background
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: ToastService.currentMessage
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.background
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: Math.min(implicitWidth, 300)
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: ToastService.hideToast()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import qs.Widgets
|
||||
import "../../Common/Utilities.js" as Utils
|
||||
|
||||
PanelWindow {
|
||||
id: topBar
|
||||
id: root
|
||||
|
||||
property var modelData
|
||||
screen: modelData
|
||||
@@ -26,31 +26,16 @@ PanelWindow {
|
||||
Connections {
|
||||
target: Prefs
|
||||
function onTopBarTransparencyChanged() {
|
||||
topBar.backgroundTransparency = Prefs.topBarTransparency
|
||||
root.backgroundTransparency = Prefs.topBarTransparency
|
||||
}
|
||||
}
|
||||
|
||||
// Properties exposed to shell
|
||||
|
||||
// Shell reference to access root properties directly
|
||||
property var shellRoot: null
|
||||
|
||||
// Notification properties
|
||||
property int notificationCount: 0
|
||||
|
||||
// Process dropdown reference
|
||||
property var processDropdown: null
|
||||
readonly property int notificationCount: NotificationService.notifications.length
|
||||
|
||||
|
||||
// Clipboard properties
|
||||
signal clipboardRequested()
|
||||
|
||||
// Tray menu properties
|
||||
property bool showTrayMenu: false
|
||||
property var currentTrayMenu: null
|
||||
property var currentTrayItem: null
|
||||
property real trayMenuX: 0
|
||||
property real trayMenuY: 0
|
||||
|
||||
|
||||
|
||||
@@ -83,7 +68,7 @@ PanelWindow {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadiusXLarge
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, topBar.backgroundTransparency)
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, root.backgroundTransparency)
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: MultiEffect {
|
||||
@@ -146,7 +131,7 @@ PanelWindow {
|
||||
|
||||
WorkspaceSwitcher {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
screenName: topBar.screenName
|
||||
screenName: root.screenName
|
||||
}
|
||||
|
||||
FocusedAppWidget {
|
||||
@@ -160,9 +145,7 @@ PanelWindow {
|
||||
anchors.centerIn: parent
|
||||
|
||||
onClockClicked: {
|
||||
if (topBar.shellRoot) {
|
||||
topBar.shellRoot.calendarVisible = !topBar.shellRoot.calendarVisible
|
||||
}
|
||||
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,9 +156,7 @@ PanelWindow {
|
||||
visible: Prefs.showMusic && MprisController.activePlayer
|
||||
|
||||
onClicked: {
|
||||
if (topBar.shellRoot) {
|
||||
topBar.shellRoot.calendarVisible = !topBar.shellRoot.calendarVisible
|
||||
}
|
||||
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,9 +169,7 @@ PanelWindow {
|
||||
visible: Prefs.showWeather && WeatherService.weather.available && WeatherService.weather.temp > 0 && WeatherService.weather.tempF > 0
|
||||
|
||||
onClicked: {
|
||||
if (topBar.shellRoot) {
|
||||
topBar.shellRoot.calendarVisible = !topBar.shellRoot.calendarVisible
|
||||
}
|
||||
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,13 +184,11 @@ PanelWindow {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: Prefs.showSystemTray
|
||||
onMenuRequested: (menu, item, x, y) => {
|
||||
if (topBar.shellRoot) {
|
||||
topBar.shellRoot.currentTrayMenu = menu
|
||||
topBar.shellRoot.currentTrayItem = item
|
||||
topBar.shellRoot.trayMenuX = rightSection.x + rightSection.width - 400 - Theme.spacingL
|
||||
topBar.shellRoot.trayMenuY = Theme.barHeight - Theme.spacingXS
|
||||
topBar.shellRoot.showTrayMenu = true
|
||||
}
|
||||
trayMenuPopup.currentTrayMenu = menu
|
||||
trayMenuPopup.currentTrayItem = item
|
||||
trayMenuPopup.trayMenuX = rightSection.x + rightSection.width - 400 - Theme.spacingL
|
||||
trayMenuPopup.trayMenuY = Theme.barHeight - Theme.spacingXS
|
||||
trayMenuPopup.showTrayMenu = true
|
||||
menu.menuVisible = true
|
||||
}
|
||||
}
|
||||
@@ -240,7 +217,7 @@ PanelWindow {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
topBar.clipboardRequested()
|
||||
clipboardHistoryPopup.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,43 +233,38 @@ PanelWindow {
|
||||
CpuMonitorWidget {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: Prefs.showSystemResources
|
||||
processDropdown: topBar.processDropdown
|
||||
}
|
||||
|
||||
RamMonitorWidget {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: Prefs.showSystemResources
|
||||
processDropdown: topBar.processDropdown
|
||||
}
|
||||
|
||||
NotificationCenterButton {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
hasUnread: topBar.notificationCount > 0
|
||||
isActive: topBar.shellRoot ? topBar.shellRoot.notificationHistoryVisible : false
|
||||
hasUnread: root.notificationCount > 0
|
||||
isActive: notificationCenter.notificationHistoryVisible
|
||||
onClicked: {
|
||||
if (topBar.shellRoot) {
|
||||
topBar.shellRoot.notificationHistoryVisible = !topBar.shellRoot.notificationHistoryVisible
|
||||
}
|
||||
notificationCenter.notificationHistoryVisible = !notificationCenter.notificationHistoryVisible
|
||||
}
|
||||
}
|
||||
|
||||
// Battery Widget
|
||||
BatteryWidget {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
batteryPopupVisible: topBar.shellRoot.batteryPopupVisible
|
||||
batteryPopupVisible: batteryControlPopup.batteryPopupVisible
|
||||
onToggleBatteryPopup: {
|
||||
topBar.shellRoot.batteryPopupVisible = !topBar.shellRoot.batteryPopupVisible
|
||||
batteryControlPopup.batteryPopupVisible = !batteryControlPopup.batteryPopupVisible
|
||||
}
|
||||
}
|
||||
|
||||
ControlCenterButton {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
isActive: topBar.shellRoot ? topBar.shellRoot.controlCenterVisible : false
|
||||
isActive: controlCenterPopup.controlCenterVisible
|
||||
|
||||
onClicked: {
|
||||
if (topBar.shellRoot) {
|
||||
topBar.shellRoot.controlCenterVisible = !topBar.shellRoot.controlCenterVisible
|
||||
if (topBar.shellRoot.controlCenterVisible) {
|
||||
controlCenterPopup.controlCenterVisible = !controlCenterPopup.controlCenterVisible
|
||||
if (controlCenterPopup.controlCenterVisible) {
|
||||
if (NetworkService.wifiEnabled) {
|
||||
WifiService.scanWifi()
|
||||
}
|
||||
@@ -303,5 +275,4 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,15 @@ import Quickshell.Wayland
|
||||
import qs.Common
|
||||
|
||||
PanelWindow {
|
||||
id: trayMenuPopup
|
||||
id: root
|
||||
|
||||
visible: root.showTrayMenu
|
||||
property bool showTrayMenu: false
|
||||
property real trayMenuX: 0
|
||||
property real trayMenuY: 0
|
||||
property var currentTrayMenu: null
|
||||
property var currentTrayItem: null
|
||||
|
||||
visible: showTrayMenu
|
||||
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
@@ -25,8 +31,8 @@ PanelWindow {
|
||||
|
||||
Rectangle {
|
||||
id: menuContainer
|
||||
x: root.trayMenuX
|
||||
y: root.trayMenuY
|
||||
x: trayMenuX
|
||||
y: trayMenuY
|
||||
width: Math.max(180, Math.min(300, menuList.maxTextWidth + Theme.spacingL * 2))
|
||||
height: Math.max(60, menuList.contentHeight + Theme.spacingS * 2)
|
||||
color: Theme.popupBackground()
|
||||
@@ -47,8 +53,8 @@ PanelWindow {
|
||||
}
|
||||
|
||||
// Material 3 animations
|
||||
opacity: root.showTrayMenu ? 1.0 : 0.0
|
||||
scale: root.showTrayMenu ? 1.0 : 0.85
|
||||
opacity: showTrayMenu ? 1.0 : 0.0
|
||||
scale: showTrayMenu ? 1.0 : 0.85
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
@@ -70,7 +76,7 @@ PanelWindow {
|
||||
|
||||
QsMenuOpener {
|
||||
id: menuOpener
|
||||
menu: root.currentTrayItem ? root.currentTrayItem.menu : null
|
||||
menu: currentTrayItem ? currentTrayItem.menu : null
|
||||
}
|
||||
|
||||
// Custom menu styling using ListView
|
||||
@@ -151,7 +157,7 @@ PanelWindow {
|
||||
if (modelData.triggered) {
|
||||
modelData.triggered()
|
||||
}
|
||||
root.showTrayMenu = false
|
||||
showTrayMenu = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +177,7 @@ PanelWindow {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
onClicked: {
|
||||
root.showTrayMenu = false
|
||||
showTrayMenu = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,13 @@ import qs.Common
|
||||
import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: wifiPasswordDialog
|
||||
id: root
|
||||
|
||||
visible: root.wifiPasswordDialogVisible
|
||||
property bool wifiPasswordDialogVisible: false
|
||||
property string wifiPasswordSSID: ""
|
||||
property string wifiPasswordInput: ""
|
||||
|
||||
visible: wifiPasswordDialogVisible
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
@@ -19,7 +23,7 @@ PanelWindow {
|
||||
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: root.wifiPasswordDialogVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
WlrLayershell.keyboardFocus: wifiPasswordDialogVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
|
||||
color: "transparent"
|
||||
|
||||
@@ -32,7 +36,7 @@ PanelWindow {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(0, 0, 0, 0.5)
|
||||
opacity: root.wifiPasswordDialogVisible ? 1.0 : 0.0
|
||||
opacity: wifiPasswordDialogVisible ? 1.0 : 0.0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
@@ -44,8 +48,8 @@ PanelWindow {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
root.wifiPasswordDialogVisible = false
|
||||
root.wifiPasswordInput = ""
|
||||
wifiPasswordDialogVisible = false
|
||||
wifiPasswordInput = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,8 +63,8 @@ PanelWindow {
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: 1
|
||||
|
||||
opacity: root.wifiPasswordDialogVisible ? 1.0 : 0.0
|
||||
scale: root.wifiPasswordDialogVisible ? 1.0 : 0.9
|
||||
opacity: wifiPasswordDialogVisible ? 1.0 : 0.0
|
||||
scale: wifiPasswordDialogVisible ? 1.0 : 0.9
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
@@ -97,7 +101,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Enter password for \"" + root.wifiPasswordSSID + "\""
|
||||
text: "Enter password for \"" + wifiPasswordSSID + "\""
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
width: parent.width
|
||||
@@ -125,8 +129,8 @@ PanelWindow {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.wifiPasswordDialogVisible = false
|
||||
root.wifiPasswordInput = ""
|
||||
wifiPasswordDialogVisible = false
|
||||
wifiPasswordInput = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,15 +166,15 @@ PanelWindow {
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
root.wifiPasswordInput = text
|
||||
wifiPasswordInput = text
|
||||
}
|
||||
|
||||
onAccepted: {
|
||||
WifiService.connectToWifiWithPassword(root.wifiPasswordSSID, root.wifiPasswordInput)
|
||||
WifiService.connectToWifiWithPassword(wifiPasswordSSID, wifiPasswordInput)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (root.wifiPasswordDialogVisible) {
|
||||
if (wifiPasswordDialogVisible) {
|
||||
forceActiveFocus()
|
||||
}
|
||||
}
|
||||
@@ -260,8 +264,8 @@ PanelWindow {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.wifiPasswordDialogVisible = false
|
||||
root.wifiPasswordInput = ""
|
||||
wifiPasswordDialogVisible = false
|
||||
wifiPasswordInput = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,7 +275,7 @@ PanelWindow {
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
color: connectArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
|
||||
enabled: root.wifiPasswordInput.length > 0
|
||||
enabled: wifiPasswordInput.length > 0
|
||||
opacity: enabled ? 1.0 : 0.5
|
||||
|
||||
Text {
|
||||
@@ -290,7 +294,7 @@ PanelWindow {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: parent.enabled
|
||||
onClicked: {
|
||||
WifiService.connectToWifiWithPassword(root.wifiPasswordSSID, root.wifiPasswordInput)
|
||||
WifiService.connectToWifiWithPassword(wifiPasswordSSID, wifiPasswordInput)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
185
shell.qml
185
shell.qml
@@ -1,161 +1,51 @@
|
||||
//@ pragma UseQApplication
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.SystemTray
|
||||
import Quickshell.Services.Notifications
|
||||
import Quickshell.Services.Mpris
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Widgets.CenterCommandCenter
|
||||
import qs.Widgets.ControlCenter
|
||||
import qs.Widgets.TopBar
|
||||
import qs.Common
|
||||
import "./Common/Utilities.js" as Utils
|
||||
|
||||
ShellRoot {
|
||||
id: root
|
||||
|
||||
Component.onCompleted: {
|
||||
// Make root accessible to Theme singleton for error handling
|
||||
Theme.rootObj = root
|
||||
|
||||
// Initialize service monitoring states based on preferences
|
||||
SystemMonitorService.enableTopBarMonitoring(Prefs.showSystemResources)
|
||||
ProcessMonitorService.enableMonitoring(false) // Start disabled, enable when process dropdown is opened
|
||||
// Audio service auto-updates devices, no manual scanning needed
|
||||
}
|
||||
|
||||
property bool calendarVisible: false
|
||||
property bool showTrayMenu: false
|
||||
property real trayMenuX: 0
|
||||
property real trayMenuY: 0
|
||||
property var currentTrayMenu: null
|
||||
property var currentTrayItem: null
|
||||
property bool notificationHistoryVisible: false
|
||||
property bool mediaPlayerVisible: false
|
||||
property bool hasActiveMedia: MprisController.active && (MprisController.active.trackTitle || MprisController.active.trackArtist)
|
||||
property bool controlCenterVisible: false
|
||||
|
||||
property bool batteryPopupVisible: false
|
||||
property bool powerMenuVisible: false
|
||||
property bool powerConfirmVisible: false
|
||||
property string powerConfirmAction: ""
|
||||
property string powerConfirmTitle: ""
|
||||
property string powerConfirmMessage: ""
|
||||
property bool settingsVisible: false
|
||||
|
||||
|
||||
// WiFi password dialog
|
||||
property bool wifiPasswordDialogVisible: false
|
||||
property string wifiPasswordSSID: ""
|
||||
property string wifiPasswordInput: ""
|
||||
property bool wifiAutoRefreshEnabled: false
|
||||
|
||||
// Wallpaper error status
|
||||
property string wallpaperErrorStatus: ""
|
||||
|
||||
|
||||
// Screen size breakpoints for responsive design
|
||||
property real screenWidth: Screen.width
|
||||
property bool isSmallScreen: screenWidth < 1200
|
||||
property bool isMediumScreen: screenWidth >= 1200 && screenWidth < 1600
|
||||
property bool isLargeScreen: screenWidth >= 1600
|
||||
|
||||
|
||||
// Weather configuration
|
||||
|
||||
|
||||
Timer {
|
||||
id: wifiAutoRefreshTimer
|
||||
interval: 20000
|
||||
running: root.wifiAutoRefreshEnabled && root.controlCenterVisible
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if (root.wifiAutoRefreshEnabled && root.controlCenterVisible && NetworkService.wifiEnabled) {
|
||||
WifiService.scanWifi()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WiFi Connection Status Timer
|
||||
Timer {
|
||||
id: wifiConnectionStatusTimer
|
||||
interval: 3000 // 3 seconds
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
root.wifiConnectionStatus = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Wallpaper Error Status Timer
|
||||
Timer {
|
||||
id: wallpaperErrorTimer
|
||||
interval: 5000 // 5 seconds
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
root.wallpaperErrorStatus = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Function to show wallpaper error
|
||||
function showWallpaperError() {
|
||||
console.log("showWallpaperError called - setting error status")
|
||||
root.wallpaperErrorStatus = "error"
|
||||
wallpaperErrorTimer.restart()
|
||||
}
|
||||
|
||||
|
||||
// Multi-monitor support using Variants
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
delegate: TopBar {
|
||||
modelData: item
|
||||
|
||||
// Connect shell properties
|
||||
shellRoot: root
|
||||
notificationCount: NotificationService.notifications.length
|
||||
processDropdown: processListDropdown
|
||||
|
||||
// Connect tray menu properties
|
||||
showTrayMenu: root.showTrayMenu
|
||||
currentTrayMenu: root.currentTrayMenu
|
||||
currentTrayItem: root.currentTrayItem
|
||||
trayMenuX: root.trayMenuX
|
||||
trayMenuY: root.trayMenuY
|
||||
|
||||
// Connect clipboard
|
||||
onClipboardRequested: {
|
||||
clipboardHistoryPopup.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Global popup windows
|
||||
CenterCommandCenter {}
|
||||
TrayMenuPopup {}
|
||||
CenterCommandCenter {
|
||||
id: centerCommandCenter
|
||||
}
|
||||
TrayMenuPopup {
|
||||
id: trayMenuPopup
|
||||
}
|
||||
NotificationInit {}
|
||||
NotificationCenter {
|
||||
notificationHistoryVisible: root.notificationHistoryVisible
|
||||
onCloseRequested: {
|
||||
root.notificationHistoryVisible = false
|
||||
id: notificationCenter
|
||||
}
|
||||
ControlCenterPopup {
|
||||
id: controlCenterPopup
|
||||
}
|
||||
WifiPasswordDialog {
|
||||
id: wifiPasswordDialog
|
||||
}
|
||||
ControlCenterPopup {}
|
||||
WifiPasswordDialog {}
|
||||
InputDialog {
|
||||
id: globalInputDialog
|
||||
}
|
||||
BatteryControlPopup {}
|
||||
PowerMenuPopup {}
|
||||
PowerConfirmDialog {}
|
||||
BatteryControlPopup {
|
||||
id: batteryControlPopup
|
||||
}
|
||||
PowerMenuPopup {
|
||||
id: powerMenuPopup
|
||||
}
|
||||
PowerConfirmDialog {
|
||||
id: powerConfirmDialog
|
||||
}
|
||||
|
||||
ProcessListDropdown {
|
||||
id: processListDropdown
|
||||
@@ -163,24 +53,6 @@ ShellRoot {
|
||||
|
||||
SettingsPopup {
|
||||
id: settingsPopup
|
||||
settingsVisible: root.settingsVisible
|
||||
|
||||
// Use a more direct approach for two-way binding
|
||||
onSettingsVisibleChanged: {
|
||||
if (settingsVisible !== root.settingsVisible) {
|
||||
root.settingsVisible = settingsVisible
|
||||
}
|
||||
}
|
||||
|
||||
// Also listen to root changes
|
||||
Connections {
|
||||
target: root
|
||||
function onSettingsVisibleChanged() {
|
||||
if (settingsPopup.settingsVisible !== root.settingsVisible) {
|
||||
settingsPopup.settingsVisible = root.settingsVisible
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Application and clipboard components
|
||||
@@ -200,17 +72,8 @@ ShellRoot {
|
||||
id: clipboardHistoryPopup
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "wallpaper"
|
||||
ToastWidget {
|
||||
id: toastWidget
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
console.log("Wallpaper IPC: refresh() called")
|
||||
// Trigger color extraction if using dynamic theme
|
||||
if (typeof Theme !== "undefined" && Theme.isDynamicTheme) {
|
||||
console.log("Triggering color extraction due to wallpaper IPC")
|
||||
Colors.extractColors()
|
||||
}
|
||||
return "WALLPAPER_REFRESH_SUCCESS"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user