diff options
Diffstat (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash')
14 files changed, 0 insertions, 4987 deletions
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml deleted file mode 100644 index 34b324c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml +++ /dev/null @@ -1,425 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:dash" - - property bool dashVisible: false - property var triggerScreen: null - property int currentTabIndex: 0 - - popupWidth: SettingsData.showWeekNumber ? 736 : 700 - popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 500 - triggerWidth: 80 - screen: triggerScreen - shouldBeVisible: dashVisible - - property bool __focusArmed: false - property bool __contentReady: false - - property var __mediaTabRef: null - - property int __dropdownType: 0 - property point __dropdownAnchor: Qt.point(0, 0) - property bool __dropdownRightEdge: false - property var __dropdownPlayer: null - property var __dropdownPlayers: [] - - function __showVolumeDropdown(pos, rightEdge, player, players) { - __dropdownAnchor = pos; - __dropdownRightEdge = rightEdge; - __dropdownPlayer = player; - __dropdownPlayers = players; - __dropdownType = 1; - } - - function __showAudioDevicesDropdown(pos, rightEdge) { - __dropdownAnchor = pos; - __dropdownRightEdge = rightEdge; - __dropdownType = 2; - } - - function __showPlayersDropdown(pos, rightEdge, player, players) { - __dropdownAnchor = pos; - __dropdownRightEdge = rightEdge; - __dropdownPlayer = player; - __dropdownPlayers = players; - __dropdownType = 3; - } - - function __hideDropdowns() { - __volumeCloseTimer.stop(); - __dropdownType = 0; - __mediaTabRef?.resetDropdownStates(); - } - - function __startCloseTimer() { - __volumeCloseTimer.restart(); - } - - function __stopCloseTimer() { - __volumeCloseTimer.stop(); - } - - Timer { - id: __volumeCloseTimer - interval: 400 - onTriggered: { - if (__dropdownType === 1) { - __hideDropdowns(); - } - } - } - - overlayContent: Component { - MediaDropdownOverlay { - dropdownType: root.__dropdownType - anchorPos: root.__dropdownAnchor - isRightEdge: root.__dropdownRightEdge - activePlayer: root.__dropdownPlayer - allPlayers: root.__dropdownPlayers - onCloseRequested: root.__hideDropdowns() - onPanelEntered: root.__stopCloseTimer() - onPanelExited: root.__startCloseTimer() - onVolumeChanged: volume => { - const player = root.__dropdownPlayer; - const isChrome = player?.identity?.toLowerCase().includes("chrome") || player?.identity?.toLowerCase().includes("chromium"); - const usePlayerVolume = player && player.volumeSupported && !isChrome; - if (usePlayerVolume) { - player.volume = volume; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = volume; - } - } - onPlayerSelected: player => { - const currentPlayer = MprisController.activePlayer; - if (currentPlayer && currentPlayer !== player && currentPlayer.canPause) { - currentPlayer.pause(); - } - MprisController.setActivePlayer(player); - root.__hideDropdowns(); - } - onDeviceSelected: device => { - root.__hideDropdowns(); - } - } - } - - function __tryFocusOnce() { - if (!__focusArmed) - return; - const win = root.window; - if (!win || !win.visible) - return; - if (!contentLoader.item) - return; - if (win.requestActivate) - win.requestActivate(); - contentLoader.item.forceActiveFocus(Qt.TabFocusReason); - - if (contentLoader.item.activeFocus) - __focusArmed = false; - } - - onDashVisibleChanged: { - if (dashVisible) { - __focusArmed = true; - __contentReady = !!contentLoader.item; - open(); - __tryFocusOnce(); - } else { - __focusArmed = false; - __contentReady = false; - __hideDropdowns(); - close(); - } - } - - Connections { - target: contentLoader - function onLoaded() { - __contentReady = true; - if (__focusArmed) - __tryFocusOnce(); - } - } - - Connections { - target: root.window ? root.window : null - enabled: !!root.window - function onVisibleChanged() { - if (__focusArmed) - __tryFocusOnce(); - } - } - - onBackgroundClicked: { - dashVisible = false; - } - - content: Component { - Rectangle { - id: mainContainer - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: Math.max(700, pages.implicitWidth + (Theme.spacingM * 2)) - implicitHeight: contentColumn.height + Theme.spacingM * 2 - color: "transparent" - focus: true - - Component.onCompleted: { - if (root.shouldBeVisible) { - mainContainer.forceActiveFocus(); - } - } - - Connections { - target: root - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(function () { - mainContainer.forceActiveFocus(); - }); - } - } - } - - Keys.onPressed: function (event) { - if (event.key === Qt.Key_Escape) { - root.dashVisible = false; - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Tab && !(event.modifiers & Qt.ShiftModifier)) { - let nextIndex = root.currentTabIndex + 1; - while (nextIndex < tabBar.model.length && tabBar.model[nextIndex] && tabBar.model[nextIndex].isAction) { - nextIndex++; - } - if (nextIndex >= tabBar.model.length) { - nextIndex = 0; - } - root.currentTabIndex = nextIndex; - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier))) { - let prevIndex = root.currentTabIndex - 1; - while (prevIndex >= 0 && tabBar.model[prevIndex] && tabBar.model[prevIndex].isAction) { - prevIndex--; - } - if (prevIndex < 0) { - prevIndex = tabBar.model.length - 1; - while (prevIndex >= 0 && tabBar.model[prevIndex] && tabBar.model[prevIndex].isAction) { - prevIndex--; - } - } - if (prevIndex >= 0) { - root.currentTabIndex = prevIndex; - } - event.accepted = true; - return; - } - - if (root.currentTabIndex === 2 && wallpaperLoader.item?.handleKeyEvent) { - if (wallpaperLoader.item.handleKeyEvent(event)) { - event.accepted = true; - return; - } - } - } - - Column { - id: contentColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - DankTabBar { - id: tabBar - - width: parent.width - height: 48 - currentIndex: root.currentTabIndex - spacing: Theme.spacingS - equalWidthTabs: true - enableArrowNavigation: false - focus: false - activeFocusOnTab: false - nextFocusTarget: { - const item = pages.currentItem; - if (!item) - return null; - if (item.focusTarget) - return item.focusTarget; - return item; - } - - model: { - let tabs = [ - { - "icon": "dashboard", - "text": I18n.tr("Overview") - }, - { - "icon": "music_note", - "text": I18n.tr("Media") - }, - { - "icon": "wallpaper", - "text": I18n.tr("Wallpapers") - } - ]; - - if (SettingsData.weatherEnabled) { - tabs.push({ - "icon": "wb_sunny", - "text": I18n.tr("Weather") - }); - } - - tabs.push({ - "icon": "settings", - "text": I18n.tr("Settings"), - "isAction": true - }); - return tabs; - } - - onTabClicked: function (index) { - root.currentTabIndex = index; - } - - onActionTriggered: function (index) { - let settingsIndex = SettingsData.weatherEnabled ? 4 : 3; - if (index === settingsIndex) { - dashVisible = false; - PopoutService.focusOrToggleSettings(); - } - } - } - - Item { - width: parent.width - height: Theme.spacingXS - } - - Item { - id: pages - width: parent.width - height: implicitHeight - implicitWidth: currentItem && currentItem.implicitWidth > 0 ? currentItem.implicitWidth : (700 - Theme.spacingM * 2) - implicitHeight: { - if (root.currentTabIndex === 0) - return overviewLoader.item?.implicitHeight ?? 410; - if (root.currentTabIndex === 1) - return mediaLoader.item?.implicitHeight ?? 410; - if (root.currentTabIndex === 2) - return wallpaperLoader.item?.implicitHeight ?? 410; - if (SettingsData.weatherEnabled && root.currentTabIndex === 3) - return weatherLoader.item?.implicitHeight ?? 410; - return 410; - } - - readonly property var currentItem: { - if (root.currentTabIndex === 0) - return overviewLoader.item; - if (root.currentTabIndex === 1) - return mediaLoader.item; - if (root.currentTabIndex === 2) - return wallpaperLoader.item; - if (root.currentTabIndex === 3) - return weatherLoader.item; - return null; - } - - Loader { - id: overviewLoader - anchors.fill: parent - active: root.currentTabIndex === 0 - visible: active - sourceComponent: Component { - OverviewTab { - onCloseDash: root.dashVisible = false - onSwitchToWeatherTab: { - if (SettingsData.weatherEnabled) { - root.currentTabIndex = 3; - } - } - onSwitchToMediaTab: { - root.currentTabIndex = 1; - } - } - } - } - - Loader { - id: mediaLoader - anchors.fill: parent - active: root.currentTabIndex === 1 - visible: active - sourceComponent: Component { - MediaPlayerTab { - targetScreen: root.screen - popoutX: root.alignedX - popoutY: root.alignedY - popoutWidth: root.alignedWidth - popoutHeight: root.alignedHeight - contentOffsetY: Theme.spacingM + 48 + Theme.spacingS + Theme.spacingXS - section: root.triggerSection - barPosition: root.effectiveBarPosition - Component.onCompleted: root.__mediaTabRef = this - onShowVolumeDropdown: (pos, screen, rightEdge, player, players) => { - root.__showVolumeDropdown(pos, rightEdge, player, players); - } - onShowAudioDevicesDropdown: (pos, screen, rightEdge) => { - root.__showAudioDevicesDropdown(pos, rightEdge); - } - onShowPlayersDropdown: (pos, screen, rightEdge, player, players) => { - root.__showPlayersDropdown(pos, rightEdge, player, players); - } - onHideDropdowns: root.__hideDropdowns() - onVolumeButtonExited: root.__startCloseTimer() - } - } - } - - Loader { - id: wallpaperLoader - anchors.fill: parent - active: root.currentTabIndex === 2 - visible: active - sourceComponent: Component { - WallpaperTab { - active: true - tabBarItem: tabBar - keyForwardTarget: mainContainer - targetScreen: root.screen - parentPopout: root - } - } - } - - Loader { - id: weatherLoader - anchors.fill: parent - active: SettingsData.weatherEnabled && root.currentTabIndex === 3 - visible: active - sourceComponent: Component { - WeatherTab {} - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml deleted file mode 100644 index 35dfe97..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml +++ /dev/null @@ -1,513 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell.Services.Pipewire -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property int dropdownType: 0 - property var activePlayer: null - property var allPlayers: [] - property point anchorPos: Qt.point(0, 0) - property bool isRightEdge: false - - property bool __isChromeBrowser: { - if (!activePlayer?.identity) - return false; - const id = activePlayer.identity.toLowerCase(); - return id.includes("chrome") || id.includes("chromium"); - } - property bool usePlayerVolume: activePlayer && activePlayer.volumeSupported && !__isChromeBrowser - property real currentVolume: usePlayerVolume ? activePlayer.volume : (AudioService.sink?.audio?.volume ?? 0) - property bool volumeAvailable: (activePlayer && activePlayer.volumeSupported && !__isChromeBrowser) || (AudioService.sink && AudioService.sink.audio) - property var availableDevices: { - const hidden = SessionData.hiddenOutputDeviceNames ?? []; - return Pipewire.nodes.values.filter(node => { - if (!node.audio || !node.isSink || node.isStream) - return false; - return !hidden.includes(node.name); - }); - } - - signal closeRequested - signal deviceSelected(var device) - signal playerSelected(var player) - signal volumeChanged(real volume) - signal panelEntered - signal panelExited - - property int __volumeHoverCount: 0 - - function volumeAreaEntered() { - __volumeHoverCount++; - panelEntered(); - } - - function volumeAreaExited() { - __volumeHoverCount--; - Qt.callLater(() => { - if (__volumeHoverCount <= 0) - panelExited(); - }); - } - - Rectangle { - id: volumePanel - visible: dropdownType === 1 && volumeAvailable - width: 60 - height: 180 - x: isRightEdge ? anchorPos.x : anchorPos.x - width - y: anchorPos.y - height / 2 - radius: Theme.cornerRadius * 2 - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 1 - - opacity: dropdownType === 1 ? 1 : 0 - scale: dropdownType === 1 ? 1 : 0.96 - transformOrigin: isRightEdge ? Item.Left : Item.Right - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - ElevationShadow { - id: volumeShadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: volumePanel.radius - targetColor: volumePanel.color - borderColor: volumePanel.border.color - borderWidth: volumePanel.border.width - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - MouseArea { - anchors.fill: parent - anchors.margins: -12 - hoverEnabled: true - onEntered: volumeAreaEntered() - onExited: volumeAreaExited() - } - - Item { - anchors.fill: parent - anchors.margins: Theme.spacingS - - Item { - id: volumeSlider - width: parent.width * 0.5 - height: parent.height - Theme.spacingXL * 2 - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - Rectangle { - width: parent.width - height: parent.height - anchors.centerIn: parent - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - radius: Theme.cornerRadius - } - - Rectangle { - width: parent.width - height: volumeAvailable ? (Math.min(1.0, currentVolume) * parent.height) : 0 - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - bottomLeftRadius: Theme.cornerRadius - bottomRightRadius: Theme.cornerRadius - } - - Rectangle { - width: parent.width + 8 - height: 8 - radius: Theme.cornerRadius - y: { - const ratio = volumeAvailable ? Math.min(1.0, currentVolume) : 0; - const travel = parent.height - height; - return Math.max(0, Math.min(travel, travel * (1 - ratio))); - } - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - border.width: 3 - border.color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1.0) - } - - MouseArea { - anchors.fill: parent - anchors.margins: -12 - enabled: volumeAvailable - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - preventStealing: true - - onEntered: volumeAreaEntered() - onExited: volumeAreaExited() - onPressed: mouse => updateVolume(mouse) - onPositionChanged: mouse => { - if (pressed) - updateVolume(mouse); - } - onClicked: mouse => updateVolume(mouse) - - function updateVolume(mouse) { - if (!volumeAvailable) - return; - const ratio = 1.0 - (mouse.y / height); - const volume = Math.max(0, Math.min(1, ratio)); - root.volumeChanged(volume); - } - } - } - - StyledText { - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: Theme.spacingL - text: volumeAvailable ? Math.round(currentVolume * 100) + "%" : "0%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - } - - Rectangle { - id: audioDevicesPanel - visible: dropdownType === 2 - width: 280 - height: Math.max(200, Math.min(280, availableDevices.length * 50 + 100)) - x: isRightEdge ? anchorPos.x : anchorPos.x - width - y: anchorPos.y - height / 2 - radius: Theme.cornerRadius * 2 - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.98) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6) - border.width: 2 - - opacity: dropdownType === 2 ? 1 : 0 - scale: dropdownType === 2 ? 1 : 0.96 - transformOrigin: isRightEdge ? Item.Left : Item.Right - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - ElevationShadow { - id: audioDevicesShadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: audioDevicesPanel.radius - targetColor: audioDevicesPanel.color - borderColor: audioDevicesPanel.border.color - borderWidth: audioDevicesPanel.border.width - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - - StyledText { - text: I18n.tr("Audio Output Devices (") + availableDevices.length + ")" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - bottomPadding: Theme.spacingM - } - - DankFlickable { - width: parent.width - height: parent.height - 40 - contentHeight: deviceColumn.height - clip: true - - Column { - id: deviceColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: availableDevices - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: modelData === AudioService.sink ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: modelData === AudioService.sink ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - - DankIcon { - name: getAudioDeviceIcon(modelData) - size: 20 - color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - - function getAudioDeviceIcon(device) { - if (!device?.name) - return "speaker"; - const name = device.name.toLowerCase(); - if (name.includes("bluez") || name.includes("bluetooth")) - return "headset"; - if (name.includes("hdmi")) - return "tv"; - if (name.includes("usb")) - return "headset"; - return "speaker"; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 20 - Theme.spacingM * 2 - - StyledText { - text: AudioService.displayName(modelData) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === AudioService.sink ? Font.Medium : Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - - StyledText { - text: modelData === AudioService.sink ? "Active" : "Available" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - } - } - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData) { - Pipewire.preferredDefaultAudioSink = modelData; - root.deviceSelected(modelData); - } - } - } - } - } - } - } - } - } - - Rectangle { - id: playersPanel - visible: dropdownType === 3 - width: 240 - height: Math.max(180, Math.min(240, (allPlayers?.length || 0) * 50 + 80)) - x: isRightEdge ? anchorPos.x : anchorPos.x - width - y: anchorPos.y - height / 2 - radius: Theme.cornerRadius * 2 - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.98) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6) - border.width: 2 - - opacity: dropdownType === 3 ? 1 : 0 - scale: dropdownType === 3 ? 1 : 0.96 - transformOrigin: isRightEdge ? Item.Left : Item.Right - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - ElevationShadow { - id: playersShadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: playersPanel.radius - targetColor: playersPanel.color - borderColor: playersPanel.border.color - borderWidth: playersPanel.border.width - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - - StyledText { - text: I18n.tr("Media Players (") + (allPlayers?.length || 0) + ")" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - bottomPadding: Theme.spacingM - } - - DankFlickable { - width: parent.width - height: parent.height - 40 - contentHeight: playerColumn.height - clip: true - - Column { - id: playerColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: allPlayers || [] - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: playerMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: modelData === activePlayer ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: modelData === activePlayer ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - - DankIcon { - name: "music_note" - size: 20 - color: modelData === activePlayer ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 20 - Theme.spacingM * 2 - - StyledText { - text: { - if (!modelData) - return "Unknown Player"; - const identity = modelData.identity || "Unknown Player"; - const trackTitle = modelData.trackTitle || ""; - return trackTitle.length > 0 ? identity + " - " + trackTitle : identity; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === activePlayer ? Font.Medium : Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - - StyledText { - text: { - if (!modelData) - return ""; - const artist = modelData.trackArtist || ""; - const isActive = modelData === activePlayer; - if (artist.length > 0) - return artist + (isActive ? " (Active)" : ""); - return isActive ? "Active" : "Available"; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - } - } - - MouseArea { - id: playerMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData?.identity) { - root.playerSelected(modelData); - } - } - } - } - } - } - } - } - } - - MouseArea { - anchors.fill: parent - z: -1 - enabled: dropdownType !== 0 - onClicked: closeRequested() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml deleted file mode 100644 index c6d7bfc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml +++ /dev/null @@ -1,785 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import Quickshell.Services.Mpris -import Quickshell.Io -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property MprisPlayer activePlayer: MprisController.activePlayer - property var allPlayers: MprisController.availablePlayers - property var targetScreen: null - property real popoutX: 0 - property real popoutY: 0 - property real popoutWidth: 0 - property real popoutHeight: 0 - property real contentOffsetY: 0 - property string section: "" - property int barPosition: SettingsData.Position.Top - - signal showVolumeDropdown(point pos, var screen, bool rightEdge, var player, var players) - signal showAudioDevicesDropdown(point pos, var screen, bool rightEdge) - signal showPlayersDropdown(point pos, var screen, bool rightEdge, var player, var players) - signal hideDropdowns - signal volumeButtonExited - - property bool volumeExpanded: false - property bool devicesExpanded: false - property bool playersExpanded: false - - function resetDropdownStates() { - volumeExpanded = false; - devicesExpanded = false; - playersExpanded = false; - } - - DankTooltipV2 { - id: sharedTooltip - } - - readonly property bool isRightEdge: { - if (barPosition === SettingsData.Position.Right) - return true; - if (barPosition === SettingsData.Position.Left) - return false; - return section === "right"; - } - readonly property bool __isChromeBrowser: { - if (!activePlayer?.identity) - return false; - const id = activePlayer.identity.toLowerCase(); - return id.includes("chrome") || id.includes("chromium"); - } - readonly property bool volumeAvailable: (activePlayer && activePlayer.volumeSupported && !__isChromeBrowser) || (AudioService.sink && AudioService.sink.audio) - readonly property bool usePlayerVolume: activePlayer && activePlayer.volumeSupported && !__isChromeBrowser - readonly property real currentVolume: usePlayerVolume ? activePlayer.volume : (AudioService.sink?.audio?.volume ?? 0) - - property bool isSwitching: false - - // Derived "no players" state: always correct, no timers. - readonly property int _playerCount: allPlayers ? allPlayers.length : 0 - readonly property bool _noneAvailable: _playerCount === 0 - readonly property bool _trulyIdle: activePlayer && activePlayer.playbackState === MprisPlaybackState.Stopped && !activePlayer.trackTitle && !activePlayer.trackArtist - readonly property bool showNoPlayerNow: (!_switchHold) && (_noneAvailable || _trulyIdle) - - property bool _switchHold: false - Timer { - id: _switchHoldTimer - interval: 650 - repeat: false - onTriggered: _switchHold = false - } - - onActivePlayerChanged: { - if (!activePlayer) { - isSwitching = false; - _switchHold = false; - return; - } - isSwitching = true; - _switchHold = true; - _switchHoldTimer.restart(); - TrackArtService.loadArtwork(activePlayer.trackArtUrl); - } - - function maybeFinishSwitch() { - if (activePlayer && activePlayer.trackTitle !== "") { - isSwitching = false; - _switchHold = false; - } - } - - readonly property real ratio: { - if (!activePlayer || !activePlayer.length || activePlayer.length <= 0) { - return 0; - } - const pos = (activePlayer.position || 0) % Math.max(1, activePlayer.length); - const calculatedRatio = pos / activePlayer.length; - return Math.max(0, Math.min(1, calculatedRatio)); - } - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: playerContent.height + playerContent.anchors.topMargin * 2 - - Connections { - target: activePlayer - function onTrackTitleChanged() { - _switchHoldTimer.restart(); - maybeFinishSwitch(); - } - function onTrackArtUrlChanged() { - TrackArtService.loadArtwork(activePlayer.trackArtUrl); - } - } - - Connections { - target: MprisController - function onAvailablePlayersChanged() { - const count = (MprisController.availablePlayers?.length || 0); - if (count === 0) { - isSwitching = false; - _switchHold = false; - } else { - _switchHold = true; - _switchHoldTimer.restart(); - } - } - } - - function getAudioDeviceIcon(device) { - if (!device || !device.name) - return "speaker"; - - const name = device.name.toLowerCase(); - - if (name.includes("bluez") || name.includes("bluetooth")) - return "headset"; - if (name.includes("hdmi")) - return "tv"; - if (name.includes("usb")) - return "headset"; - if (name.includes("analog") || name.includes("built-in")) - return "speaker"; - - return "speaker"; - } - - function getVolumeIcon() { - if (!volumeAvailable) - return "volume_off"; - - const volume = currentVolume; - - if (usePlayerVolume) { - if (volume === 0.0) - return "music_off"; - return "music_note"; - } - - if (volume === 0.0) - return "volume_off"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - - function adjustVolume(step) { - if (!volumeAvailable) - return; - const maxVol = usePlayerVolume ? 100 : AudioService.sinkMaxVolume; - const current = Math.round(currentVolume * 100); - const newVolume = Math.min(maxVol, Math.max(0, current + step)); - - SessionData.suppressOSDTemporarily(); - if (usePlayerVolume) { - activePlayer.volume = newVolume / 100; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = newVolume / 100; - } - } - - property bool isSeeking: false - - Timer { - interval: 1000 - running: activePlayer?.playbackState === MprisPlaybackState.Playing && !isSeeking - repeat: true - onTriggered: activePlayer?.positionChanged() - } - - Item { - id: bgContainer - anchors.fill: parent - visible: TrackArtService._bgArtSource !== "" - - Image { - id: bgImage - anchors.centerIn: parent - width: Math.max(parent.width, parent.height) * 1.1 - height: width - source: TrackArtService._bgArtSource - fillMode: Image.PreserveAspectCrop - asynchronous: true - cache: true - visible: false - onStatusChanged: { - if (status === Image.Ready) - maybeFinishSwitch(); - } - } - - Item { - id: blurredBg - anchors.fill: parent - visible: false - - MultiEffect { - anchors.centerIn: parent - width: bgImage.width - height: bgImage.height - source: bgImage - blurEnabled: true - blurMax: 64 - blur: 0.8 - saturation: -0.2 - brightness: -0.25 - } - } - - Rectangle { - id: bgMask - anchors.fill: parent - radius: Theme.cornerRadius - visible: false - layer.enabled: true - } - - MultiEffect { - anchors.fill: parent - source: blurredBg - maskEnabled: true - maskSource: bgMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1.0 - opacity: 0.7 - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.surface - opacity: 0.3 - } - } - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - visible: showNoPlayerNow - - DankIcon { - name: "music_note" - size: Theme.iconSize * 3 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No Active Players") - font.pixelSize: Theme.fontSizeLarge - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Item { - anchors.fill: parent - clip: false - visible: !_noneAvailable && (!showNoPlayerNow) - ColumnLayout { - id: playerContent - width: 484 - height: 370 - spacing: Theme.spacingXS - anchors.top: parent.top - anchors.topMargin: 20 - anchors.horizontalCenter: parent.horizontalCenter - - Item { - width: parent.width - height: 200 - clip: false - - DankAlbumArt { - width: Math.min(parent.width * 0.8, parent.height * 0.9) - height: width - anchors.centerIn: parent - activePlayer: root.activePlayer - } - } - - // Song Info and Controls Section - Item { - width: parent.width - Layout.fillHeight: true - - Column { - id: songInfo - width: parent.width - spacing: Theme.spacingXS - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: activePlayer?.trackTitle || I18n.tr("Unknown Track") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - wrapMode: Text.WordWrap - maximumLineCount: 2 - } - - StyledText { - text: activePlayer?.trackTitle || I18n.tr("Unknown Artist") - font.pixelSize: Theme.fontSizeMedium - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8) - width: parent.width - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - wrapMode: Text.WordWrap - maximumLineCount: 1 - } - - StyledText { - text: activePlayer?.trackAlbum || "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - width: parent.width - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - wrapMode: Text.WordWrap - maximumLineCount: 1 - visible: text.length > 0 - } - } - - Item { - id: seekbarContainer - width: parent.width - anchors.top: songInfo.bottom - anchors.bottom: playbackControls.top - anchors.horizontalCenter: parent.horizontalCenter - - Column { - width: parent.width - spacing: 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: parent.height * 0.2 - - DankSeekbar { - width: parent.width * 0.8 - height: 20 - anchors.horizontalCenter: parent.horizontalCenter - activePlayer: root.activePlayer - isSeeking: root.isSeeking - onIsSeekingChanged: root.isSeeking = isSeeking - } - - Item { - width: parent.width * 0.8 - height: 16 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - text: { - if (!activePlayer) - return "0:00"; - const rawPos = Math.max(0, activePlayer.position || 0); - const pos = activePlayer.length ? rawPos % Math.max(1, activePlayer.length) : rawPos; - const minutes = Math.floor(pos / 60); - const seconds = Math.floor(pos % 60); - const timeStr = minutes + ":" + (seconds < 10 ? "0" : "") + seconds; - return timeStr; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - text: { - if (!activePlayer || !activePlayer.length) - return "0:00"; - const dur = Math.max(0, activePlayer.length || 0); - const minutes = Math.floor(dur / 60); - const seconds = Math.floor(dur % 60); - return minutes + ":" + (seconds < 10 ? "0" : "") + seconds; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - Item { - id: playbackControls - width: parent.width - height: 50 - anchors.bottom: parent.bottom - - Row { - anchors.centerIn: parent - spacing: Theme.spacingM - height: parent.height - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - visible: activePlayer && activePlayer.shuffleSupported - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: shuffleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "shuffle" - size: 20 - color: activePlayer && activePlayer.shuffle ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: shuffleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer && activePlayer.canControl && activePlayer.shuffleSupported) { - activePlayer.shuffle = !activePlayer.shuffle; - } - } - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: prevBtnArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_previous" - size: 24 - color: Theme.surfaceText - } - - MouseArea { - id: prevBtnArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: MprisController.previousOrRewind() - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 50 - height: 50 - radius: 25 - anchors.centerIn: parent - color: Theme.primary - - DankIcon { - anchors.centerIn: parent - name: activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow" - size: 28 - color: Theme.background - weight: 500 - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer && activePlayer.togglePlaying() - } - - ElevationShadow { - anchors.fill: parent - z: -1 - level: Theme.elevationLevel1 - fallbackOffset: 1 - targetRadius: parent.radius - targetColor: parent.color - shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - shadowEnabled: Theme.elevationEnabled - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: nextBtnArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_next" - size: 24 - color: Theme.surfaceText - } - - MouseArea { - id: nextBtnArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer && activePlayer.next() - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - visible: activePlayer && activePlayer.loopSupported - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: repeatArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: { - if (!activePlayer) - return "repeat"; - switch (activePlayer.loopState) { - case MprisLoopState.Track: - return "repeat_one"; - case MprisLoopState.Playlist: - return "repeat"; - default: - return "repeat"; - } - } - size: 20 - color: activePlayer && activePlayer.loopState !== MprisLoopState.None ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: repeatArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer && activePlayer.canControl && activePlayer.loopSupported) { - switch (activePlayer.loopState) { - case MprisLoopState.None: - activePlayer.loopState = MprisLoopState.Playlist; - break; - case MprisLoopState.Playlist: - activePlayer.loopState = MprisLoopState.Track; - break; - case MprisLoopState.Track: - activePlayer.loopState = MprisLoopState.None; - break; - } - } - } - } - } - } - } - } - } - } - } - - Rectangle { - id: playerSelectorButton - width: 40 - height: 40 - radius: 20 - x: isRightEdge ? Theme.spacingM : parent.width - 40 - Theme.spacingM - y: 185 - color: playerSelectorArea.containsMouse || playersExpanded ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 1 - z: 100 - visible: (allPlayers?.length || 0) >= 1 - - DankIcon { - anchors.centerIn: parent - name: "assistant_device" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: playerSelectorArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (playersExpanded) { - hideDropdowns(); - return; - } - hideDropdowns(); - playersExpanded = true; - const buttonsOnRight = !isRightEdge; - const btnY = playerSelectorButton.y + playerSelectorButton.height / 2; - const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX; - const screenY = popoutY + contentOffsetY + btnY; - showPlayersDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight, activePlayer, allPlayers); - } - onEntered: sharedTooltip.show(I18n.tr("Media Players"), playerSelectorButton, 0, 0, isRightEdge ? "right" : "left") - onExited: sharedTooltip.hide() - } - } - - Rectangle { - id: volumeButton - width: 40 - height: 40 - radius: 20 - x: isRightEdge ? Theme.spacingM : parent.width - 40 - Theme.spacingM - y: 130 - color: volumeButtonArea.containsMouse && volumeAvailable || volumeExpanded ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, volumeAvailable ? 0.3 : 0.15) - border.width: 1 - z: 101 - enabled: volumeAvailable - - property real previousVolume: 0.0 - - DankIcon { - anchors.centerIn: parent - name: getVolumeIcon() - size: 18 - color: volumeAvailable && currentVolume > 0 ? Theme.primary : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, volumeAvailable ? 1.0 : 0.5) - } - - MouseArea { - id: volumeButtonArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: { - if (volumeExpanded) - return; - hideDropdowns(); - volumeExpanded = true; - const buttonsOnRight = !isRightEdge; - const btnY = volumeButton.y + volumeButton.height / 2; - const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX; - const screenY = popoutY + contentOffsetY + btnY; - showVolumeDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight, activePlayer, allPlayers); - } - onExited: { - if (volumeExpanded) - volumeButtonExited(); - } - onClicked: { - SessionData.suppressOSDTemporarily(); - if (currentVolume > 0) { - volumeButton.previousVolume = currentVolume; - if (usePlayerVolume) { - activePlayer.volume = 0; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = 0; - } - } else { - const restoreVolume = volumeButton.previousVolume > 0 ? volumeButton.previousVolume : 0.5; - if (usePlayerVolume) { - activePlayer.volume = restoreVolume; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = restoreVolume; - } - } - } - onWheel: wheelEvent => { - SessionData.suppressOSDTemporarily(); - const delta = wheelEvent.angleDelta.y; - const current = (currentVolume * 100) || 0; - const maxVol = usePlayerVolume ? 100 : AudioService.sinkMaxVolume; - const newVolume = delta > 0 ? Math.min(maxVol, current + 5) : Math.max(0, current - 5); - - if (usePlayerVolume) { - activePlayer.volume = newVolume / 100; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = newVolume / 100; - } - wheelEvent.accepted = true; - } - } - } - - Rectangle { - id: audioDevicesButton - width: 40 - height: 40 - radius: 20 - x: isRightEdge ? Theme.spacingM : parent.width - 40 - Theme.spacingM - y: 240 - color: audioDevicesArea.containsMouse || devicesExpanded ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 1 - z: 100 - - DankIcon { - anchors.centerIn: parent - name: devicesExpanded ? "expand_less" : "speaker" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: audioDevicesArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (devicesExpanded) { - hideDropdowns(); - return; - } - hideDropdowns(); - devicesExpanded = true; - const buttonsOnRight = !isRightEdge; - const btnY = audioDevicesButton.y + audioDevicesButton.height / 2; - const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX; - const screenY = popoutY + contentOffsetY + btnY; - showAudioDevicesDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight); - } - onEntered: sharedTooltip.show(I18n.tr("Output Device"), audioDevicesButton, 0, 0, isRightEdge ? "right" : "left") - onExited: sharedTooltip.hide() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml deleted file mode 100644 index 1972f06..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml +++ /dev/null @@ -1,539 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - - property bool showEventDetails: false - property date selectedDate: systemClock.date - property var selectedDateEvents: [] - property bool hasEvents: selectedDateEvents && selectedDateEvents.length > 0 - - signal closeDash - - function weekStartQt() { - if (SettingsData.firstDayOfWeek >= 7 || SettingsData.firstDayOfWeek < 0) { - return Qt.locale().firstDayOfWeek; - } - return SettingsData.firstDayOfWeek; - } - - function weekStartJs() { - return weekStartQt() % 7; - } - - function startOfWeek(dateObj) { - const d = new Date(dateObj); - const jsDow = d.getDay(); - const diff = (jsDow - weekStartJs() + 7) % 7; - d.setDate(d.getDate() - diff); - return d; - } - - function endOfWeek(dateObj) { - const d = new Date(dateObj); - const jsDow = d.getDay(); - const add = (weekStartJs() + 6 - jsDow + 7) % 7; - d.setDate(d.getDate() + add); - return d; - } - - function getWeekNumber(dateObj) { - // Set time to noon to avoid potential Daylight Saving Time related bugs - const weekStartDay = startOfWeek(dateObj); - weekStartDay.setHours(12, 0, 0, 0); - - let week1Start; - - if (weekStartJs() === 1) { - // ISO 8601 Standard, week start on Monday - // A week belongs to the year its Thursday falls in - // So we have to get the yearTarget from weekStartDay instead of dateObj - let yearTarget = weekStartDay; - yearTarget.setDate(yearTarget.getDate() + 3); // Monday + 3 = Thursday - - // Week 1 is the week containing Jan 4th - const jan4 = new Date(yearTarget.getFullYear(), 0, 4); - week1Start = startOfWeek(jan4); - } else { - // Traditional / US Standard, week start on Sunday - // A week belongs to the year its Sunday falls in - let yearTarget = weekStartDay; - yearTarget.setDate(yearTarget.getDate() + 6); // Monday + 6 = Sunday - - // Week 1 is the week containing Jan 1st - const jan1 = new Date(yearTarget.getFullYear(), 0, 1); - week1Start = startOfWeek(jan1); - } - - week1Start.setHours(12, 0, 0, 0); - - const diffDays = Math.round((weekStartDay.getTime() - week1Start.getTime()) / 86400000); // Number of miliseconds in a day - return Math.floor(diffDays / 7) + 1; - } - - function updateSelectedDateEvents() { - if (CalendarService && CalendarService.khalAvailable) { - const events = CalendarService.getEventsForDate(selectedDate); - selectedDateEvents = events; - } else { - selectedDateEvents = []; - } - } - - function loadEventsForMonth() { - if (!CalendarService || !CalendarService.khalAvailable) { - return; - } - - const firstOfMonth = new Date(calendarGrid.displayDate.getFullYear(), calendarGrid.displayDate.getMonth(), 1); - const lastOfMonth = new Date(calendarGrid.displayDate.getFullYear(), calendarGrid.displayDate.getMonth() + 1, 0); - - const startDate = startOfWeek(firstOfMonth); - startDate.setDate(startDate.getDate() - 7); - - const endDate = endOfWeek(lastOfMonth); - endDate.setDate(endDate.getDate() + 7); - - CalendarService.loadEvents(startDate, endDate); - } - - onSelectedDateChanged: updateSelectedDateEvents() - Component.onCompleted: { - loadEventsForMonth(); - updateSelectedDateEvents(); - } - - Connections { - function onEventsByDateChanged() { - updateSelectedDateEvents(); - } - - function onKhalAvailableChanged() { - if (CalendarService && CalendarService.khalAvailable) { - loadEventsForMonth(); - } - updateSelectedDateEvents(); - } - - target: CalendarService - enabled: CalendarService !== null - } - - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) - border.width: 1 - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Item { - width: parent.width - height: 40 - visible: showEventDetails - - Rectangle { - width: 32 - height: 32 - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - radius: Theme.cornerRadius - color: backButtonArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "arrow_back" - size: 14 - color: Theme.primary - } - - MouseArea { - id: backButtonArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.showEventDetails = false - } - } - - StyledText { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 32 + Theme.spacingS * 2 - anchors.rightMargin: Theme.spacingS - height: 40 - anchors.verticalCenter: parent.verticalCenter - text: { - const dateStr = Qt.formatDate(selectedDate, "MMM d"); - if (selectedDateEvents && selectedDateEvents.length > 0) { - const eventCount = selectedDateEvents.length === 1 ? I18n.tr("1 event") : selectedDateEvents.length + " " + I18n.tr("events"); - return dateStr + " • " + eventCount; - } - return dateStr; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - } - } - - Row { - width: parent.width - height: 28 - visible: !showEventDetails - - Rectangle { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: prevMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "chevron_left" - size: 14 - color: Theme.primary - } - - MouseArea { - id: prevMonthArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - let newDate = new Date(calendarGrid.displayDate); - newDate.setMonth(newDate.getMonth() - 1); - calendarGrid.displayDate = newDate; - loadEventsForMonth(); - } - } - } - - StyledText { - width: parent.width - 56 - height: 28 - text: calendarGrid.displayDate.toLocaleDateString(I18n.locale(), "MMMM yyyy") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - - Rectangle { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: nextMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "chevron_right" - size: 14 - color: Theme.primary - } - - MouseArea { - id: nextMonthArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - let newDate = new Date(calendarGrid.displayDate); - newDate.setMonth(newDate.getMonth() + 1); - calendarGrid.displayDate = newDate; - loadEventsForMonth(); - } - } - } - } - - Row { - width: parent.width - height: parent.height - 28 - Theme.spacingS - visible: !showEventDetails - spacing: SettingsData.showWeekNumber ? Theme.spacingS : 0 - - Column { - id: weekNumberColumn - visible: SettingsData.showWeekNumber - width: SettingsData.showWeekNumber ? 28 : 0 - height: parent.height - spacing: Theme.spacingS - - Item { - width: parent.width - height: 18 - } - - Grid { - width: parent.width - height: parent.height - 18 - Theme.spacingS - columns: 1 - rows: 6 - - Repeater { - model: 6 - Rectangle { - width: parent.width - height: parent.height / 6 - color: "transparent" - - StyledText { - anchors.centerIn: parent - text: { - const rowDate = new Date(calendarGrid.firstDay); - rowDate.setDate(rowDate.getDate() + index * 7); - return root.getWeekNumber(rowDate); - } - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - } - } - } - } - } - - Column { - width: SettingsData.showWeekNumber ? (parent.width - weekNumberColumn.width - parent.spacing) : parent.width - height: parent.height - spacing: Theme.spacingS - - Row { - width: parent.width - height: 18 - - Repeater { - model: { - const days = []; - const qtFirst = weekStartQt(); - for (let i = 0; i < 7; ++i) { - const qtDay = ((qtFirst - 1 + i) % 7) + 1; - days.push(I18n.locale().dayName(qtDay, Locale.ShortFormat)); - } - return days; - } - - Rectangle { - width: parent.width / 7 - height: 18 - color: "transparent" - - StyledText { - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - } - } - } - } - - Grid { - id: calendarGrid - width: parent.width - height: parent.height - 18 - Theme.spacingS - columns: 7 - rows: 6 - - property date displayDate: systemClock.date - property date selectedDate: systemClock.date - - readonly property date firstDay: { - const firstOfMonth = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1); - return startOfWeek(firstOfMonth); - } - - Repeater { - model: 42 - - Rectangle { - readonly property date dayDate: { - const date = new Date(parent.firstDay); - date.setDate(date.getDate() + index); - return date; - } - readonly property bool isCurrentMonth: dayDate.getMonth() === calendarGrid.displayDate.getMonth() - readonly property bool isToday: dayDate.toDateString() === new Date().toDateString() - readonly property bool isSelected: dayDate.toDateString() === calendarGrid.selectedDate.toDateString() - - width: parent.width / 7 - height: parent.height / 6 - color: "transparent" - - Rectangle { - anchors.centerIn: parent - width: Math.min(parent.width - 4, parent.height - 4, 32) - height: width - color: 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.cornerRadius - - StyledText { - anchors.centerIn: parent - text: dayDate.getDate() - font.pixelSize: Theme.fontSizeSmall - color: isToday ? Theme.primary : isCurrentMonth ? Theme.surfaceText : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4) - font.weight: isToday ? Font.Medium : Font.Normal - } - - Rectangle { - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: 4 - width: 12 - height: 2 - radius: Theme.cornerRadius - visible: CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate) - color: isToday ? Qt.lighter(Theme.primary, 1.3) : Theme.primary - opacity: isToday ? 0.9 : 0.7 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - MouseArea { - id: dayArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate)) { - root.selectedDate = dayDate; - root.showEventDetails = true; - } - } - } - } - } - } - } - } - - DankListView { - width: parent.width - Theme.spacingS * 2 - height: parent.height - (showEventDetails ? 40 : 28 + 18) - Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - model: selectedDateEvents - visible: showEventDetails - clip: true - spacing: Theme.spacingXS - - delegate: Rectangle { - width: parent ? parent.width : 0 - height: eventContent.implicitHeight + Theme.spacingS - radius: Theme.cornerRadius - color: { - if (modelData.url && eventMouseArea.containsMouse) { - 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 Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency); - } - border.color: { - if (modelData.url && eventMouseArea.containsMouse) { - 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 "transparent"; - } - border.width: 1 - - Rectangle { - width: 3 - height: parent.height - 6 - anchors.left: parent.left - anchors.leftMargin: 3 - anchors.verticalCenter: parent.verticalCenter - radius: Theme.cornerRadius - color: Theme.primary - opacity: 0.8 - } - - Column { - id: eventContent - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingS + 6 - anchors.rightMargin: Theme.spacingXS - spacing: 2 - - StyledText { - width: parent.width - text: modelData.title - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - maximumLineCount: 1 - } - - StyledText { - width: parent.width - text: { - if (!modelData || modelData.allDay) { - return I18n.tr("All day"); - } else if (modelData.start && modelData.end) { - const timeFormat = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - const startTime = Qt.formatTime(modelData.start, timeFormat); - if (modelData.start.toDateString() !== modelData.end.toDateString() || modelData.start.getTime() !== modelData.end.getTime()) { - return startTime + " – " + Qt.formatTime(modelData.end, timeFormat); - } - return startTime; - } - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.weight: Font.Normal - visible: text !== "" - } - } - - MouseArea { - id: eventMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: modelData.url ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: modelData.url !== "" - onClicked: { - if (modelData.url && modelData.url !== "") { - if (Qt.openUrlExternally(modelData.url) === false) { - console.warn("Failed to open URL: " + modelData.url); - } else { - root.closeDash(); - } - } - } - } - } - } - } - - SystemClock { - id: systemClock - precision: SystemClock.Hours - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml deleted file mode 100644 index 8996c81..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml +++ /dev/null @@ -1,24 +0,0 @@ -import QtQuick -import qs.Common - -Rectangle { - id: card - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property int pad: Theme.spacingM - - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 - - default property alias content: contentItem.data - - Item { - id: contentItem - anchors.fill: parent - anchors.margins: card.pad - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml deleted file mode 100644 index 5f597c3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml +++ /dev/null @@ -1,113 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import qs.Common -import qs.Widgets - -Card { - id: root - - Column { - anchors.centerIn: parent - spacing: 0 - - Column { - spacing: -8 - anchors.horizontalCenter: parent.horizontalCenter - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: { - if (SettingsData.use24HourClock) { - return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(0) - } else { - const hours = systemClock?.date?.getHours() - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours - return String(display).padStart(2, '0').charAt(0) - } - } - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: { - if (SettingsData.use24HourClock) { - return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(1) - } else { - const hours = systemClock?.date?.getHours() - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours - return String(display).padStart(2, '0').charAt(1) - } - } - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0) - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1) - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - } - } - - Row { - visible: SettingsData.showSeconds - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock?.date?.getSeconds()).padStart(2, '0') - font.pixelSize: 24 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.7) - font.weight: Font.Medium - horizontalAlignment: Text.AlignHCenter - } - } - - Item { - width: 1 - height: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: systemClock?.date?.toLocaleDateString(I18n.locale(), "MMM dd") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - SystemClock { - id: systemClock - precision: SettingsData.showSeconds ? SystemClock.Seconds : SystemClock.Minutes - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml deleted file mode 100644 index 35f4f47..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml +++ /dev/null @@ -1,211 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Shapes -import Quickshell.Services.Mpris -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - clip: false - - signal clicked() - - property MprisPlayer activePlayer: MprisController.activePlayer - property real currentPosition: activePlayer?.positionSupported ? activePlayer.position : 0 - property real displayPosition: currentPosition - - readonly property real ratio: { - if (!activePlayer || activePlayer.length <= 0) return 0 - const pos = displayPosition % Math.max(1, activePlayer.length) - const calculatedRatio = pos / activePlayer.length - return Math.max(0, Math.min(1, calculatedRatio)) - } - - onActivePlayerChanged: { - if (activePlayer?.positionSupported) { - currentPosition = Qt.binding(() => activePlayer?.position || 0) - } else { - currentPosition = 0 - } - } - - Timer { - interval: 300 - running: activePlayer?.playbackState === MprisPlaybackState.Playing && !isSeeking - repeat: true - onTriggered: activePlayer?.positionSupported && activePlayer.positionChanged() - } - - property bool isSeeking: false - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - visible: !activePlayer - - DankIcon { - name: "music_note" - size: Theme.iconSize - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No Media") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - anchors.centerIn: parent - width: parent.width - Theme.spacingXS * 2 - spacing: Theme.spacingL - visible: activePlayer - - Item { - width: 140 - height: 110 - anchors.horizontalCenter: parent.horizontalCenter - clip: false - - DankAlbumArt { - width: 110 - height: 80 - anchors.centerIn: parent - activePlayer: root.activePlayer - albumSize: 76 - animationScale: 1.05 - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - topPadding: Theme.spacingL - - StyledText { - text: activePlayer?.trackTitle || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - elide: Text.ElideRight - maximumLineCount: 1 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: activePlayer?.trackArtist || I18n.tr("Unknown Artist") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - width: parent.width - elide: Text.ElideRight - maximumLineCount: 1 - horizontalAlignment: Text.AlignHCenter - } - } - - DankSeekbar { - width: parent.width + 4 - height: 20 - x: -2 - activePlayer: root.activePlayer - isSeeking: root.isSeeking - onIsSeekingChanged: root.isSeeking = isSeeking - } - - Item { - width: parent.width - height: 32 - - Row { - spacing: Theme.spacingS - anchors.centerIn: parent - - Rectangle { - width: 28 - height: 28 - radius: 14 - anchors.verticalCenter: playPauseButton.verticalCenter - color: prevArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_previous" - size: 14 - color: Theme.surfaceText - } - - MouseArea { - id: prevArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: MprisController.previousOrRewind() - } - } - - Rectangle { - id: playPauseButton - width: 32 - height: 32 - radius: 16 - color: Theme.primary - - DankIcon { - anchors.centerIn: parent - name: activePlayer?.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow" - size: 16 - color: Theme.background - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer?.togglePlaying() - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - anchors.verticalCenter: playPauseButton.verticalCenter - color: nextArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_next" - size: 14 - color: Theme.surfaceText - } - - MouseArea { - id: nextArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer?.next() - } - } - } - } - } - - MouseArea { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.bottomMargin: 123 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - visible: activePlayer - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml deleted file mode 100644 index cb7089b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml +++ /dev/null @@ -1,178 +0,0 @@ -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - - Component.onCompleted: { - DgopService.addRef(["cpu", "memory", "system"]) - } - Component.onDestruction: { - DgopService.removeRef(["cpu", "memory", "system"]) - } - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingM - - // CPU Bar - Column { - width: (parent.width - 2 * Theme.spacingM) / 3 - height: parent.height - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: parent.height - Theme.iconSizeSmall - Theme.spacingS - radius: 4 - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - - Rectangle { - width: parent.width - height: parent.height * Math.min((DgopService.cpuUsage || 6) / 100, 1) - radius: parent.radius - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: { - if (DgopService.cpuUsage > 80) return Theme.error - if (DgopService.cpuUsage > 60) return Theme.warning - return Theme.primary - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Item { - width: parent.width - height: Theme.iconSizeSmall - - DankIcon { - name: "memory" - size: Theme.iconSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - color: { - if (DgopService.cpuUsage > 80) return Theme.error - if (DgopService.cpuUsage > 60) return Theme.warning - return Theme.primary - } - } - } - } - - // Temperature Bar - Column { - width: (parent.width - 2 * Theme.spacingM) / 3 - height: parent.height - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: parent.height - Theme.iconSizeSmall - Theme.spacingS - radius: 4 - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - - Rectangle { - width: parent.width - height: parent.height * Math.min(Math.max((DgopService.cpuTemperature || 40) / 100, 0), 1) - radius: parent.radius - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: { - if (DgopService.cpuTemperature > 85) return Theme.error - if (DgopService.cpuTemperature > 69) return Theme.warning - return Theme.primary - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Item { - width: parent.width - height: Theme.iconSizeSmall - - DankIcon { - name: "device_thermostat" - size: Theme.iconSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - color: { - if (DgopService.cpuTemperature > 85) return Theme.error - if (DgopService.cpuTemperature > 69) return Theme.warning - return Theme.primary - } - } - } - } - - // RAM Bar - Column { - width: (parent.width - 2 * Theme.spacingM) / 3 - height: parent.height - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: parent.height - Theme.iconSizeSmall - Theme.spacingS - radius: 4 - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - - Rectangle { - width: parent.width - height: parent.height * Math.min((DgopService.memoryUsage || 42) / 100, 1) - radius: parent.radius - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: { - if (DgopService.memoryUsage > 90) return Theme.error - if (DgopService.memoryUsage > 75) return Theme.warning - return Theme.primary - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Item { - width: parent.width - height: Theme.iconSizeSmall - - DankIcon { - name: "developer_board" - size: Theme.iconSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - color: { - if (DgopService.memoryUsage > 90) return Theme.error - if (DgopService.memoryUsage > 75) return Theme.warning - return Theme.primary - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml deleted file mode 100644 index 0d90b44..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml +++ /dev/null @@ -1,110 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - Component.onCompleted: DgopService.addRef("system") - Component.onDestruction: DgopService.removeRef("system") - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankCircularImage { - id: avatarContainer - - width: 77 - height: 77 - anchors.verticalCenter: parent.verticalCenter - imageSource: { - if (PortalService.profileImage === "") - return ""; - - if (PortalService.profileImage.startsWith("/")) - return "file://" + PortalService.profileImage; - - return PortalService.profileImage; - } - fallbackIcon: "person" - } - - Column { - spacing: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: UserInfoService.username || I18n.tr("brandon") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - horizontalAlignment: Text.AlignLeft - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingS - - SystemLogo { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - colorOverride: Theme.primary - } - - StyledText { - text: { - if (CompositorService.isNiri) - return I18n.tr("on Niri"); - if (CompositorService.isHyprland) - return I18n.tr("on Hyprland"); - // technically they might not be on mangowc, but its what we support in the docs - if (CompositorService.isDwl) - return I18n.tr("on MangoWC"); - if (CompositorService.isSway) - return I18n.tr("on Sway"); - if (CompositorService.isScroll) - return I18n.tr("on Scroll"); - if (CompositorService.isMiracle) - return I18n.tr("on Miracle WM"); - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8) - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - width: parent.parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - 16 - Theme.spacingS - horizontalAlignment: Text.AlignLeft - } - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingS - - DankIcon { - name: "schedule" - size: 16 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: DgopService.shortUptime || I18n.tr("up") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.verticalCenter: parent.verticalCenter - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml deleted file mode 100644 index 0bba92e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml +++ /dev/null @@ -1,94 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - signal clicked - - Component.onCompleted: WeatherService.addRef() - Component.onDestruction: WeatherService.removeRef() - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - visible: !WeatherService.weather.available - - DankIcon { - name: "cloud_off" - size: 24 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: WeatherService.weather.loading ? I18n.tr("Loading...") : I18n.tr("No Weather") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - - Button { - text: I18n.tr("Refresh") - flat: true - visible: !WeatherService.weather.loading - anchors.horizontalCenter: parent.horizontalCenter - onClicked: WeatherService.forceRefresh() - } - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingL - visible: WeatherService.weather.available - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: 48 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - anchors.left: parent.left - text: { - const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp; - if (temp === undefined || temp === null) - return "--°" + (SettingsData.useFahrenheit ? "F" : "C"); - return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C"); - } - font.pixelSize: Theme.fontSizeXLarge + 4 - color: Theme.surfaceText - font.weight: Font.Light - } - - StyledText { - text: WeatherService.getWeatherCondition(WeatherService.weather.wCode) - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - elide: Text.ElideRight - width: parent.parent.parent.width - 48 - Theme.spacingL * 2 - horizontalAlignment: Text.AlignLeft - } - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml deleted file mode 100644 index de7ea35..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml +++ /dev/null @@ -1,75 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.DankDash.Overview - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: 410 - - signal switchToWeatherTab - signal switchToMediaTab - signal closeDash - - Item { - anchors.fill: parent - // Clock - top left (narrower and shorter) - ClockCard { - x: 0 - y: 0 - width: parent.width * 0.2 - Theme.spacingM * 2 - height: 180 - } - - // Weather - top middle-left (narrower) - WeatherOverviewCard { - x: SettingsData.weatherEnabled ? parent.width * 0.2 - Theme.spacingM : 0 - y: 0 - width: SettingsData.weatherEnabled ? parent.width * 0.3 : 0 - height: 100 - visible: SettingsData.weatherEnabled - - onClicked: root.switchToWeatherTab() - } - - // UserInfo - top middle-right (extend when weather disabled) - UserInfoCard { - x: SettingsData.weatherEnabled ? parent.width * 0.5 : parent.width * 0.2 - Theme.spacingM - y: 0 - width: SettingsData.weatherEnabled ? parent.width * 0.5 : parent.width * 0.8 - height: 100 - } - - // SystemMonitor - middle left (narrow and shorter) - SystemMonitorCard { - x: 0 - y: 180 + Theme.spacingM - width: parent.width * 0.2 - Theme.spacingM * 2 - height: 220 - } - - // Calendar - bottom middle (wider and taller) - CalendarOverviewCard { - x: parent.width * 0.2 - Theme.spacingM - y: 100 + Theme.spacingM - width: parent.width * 0.6 - height: 300 - - onCloseDash: root.closeDash() - } - - // Media - bottom right (narrow and taller) - MediaOverviewCard { - x: parent.width * 0.8 - y: 100 + Theme.spacingM - width: parent.width * 0.2 - height: 300 - - onClicked: root.switchToMediaTab() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml deleted file mode 100644 index 1f35b00..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml +++ /dev/null @@ -1,590 +0,0 @@ -import Qt.labs.folderlistmodel -import QtCore -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Modals.FileBrowser -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: 410 - - property string wallpaperDir: "" - property int currentPage: 0 - property int itemsPerPage: 16 - property int totalPages: Math.max(1, Math.ceil(wallpaperFolderModel.count / itemsPerPage)) - property bool active: false - property Item focusTarget: wallpaperGrid - property Item tabBarItem: null - property int gridIndex: 0 - property Item keyForwardTarget: null - property var parentPopout: null - property int lastPage: 0 - property bool enableAnimation: false - property string homeDir: StandardPaths.writableLocation(StandardPaths.HomeLocation) - property string selectedFileName: "" - property var targetScreen: null - property string targetScreenName: targetScreen ? targetScreen.name : "" - - signal requestTabChange(int newIndex) - - function getCurrentWallpaper() { - if (SessionData.perMonitorWallpaper && targetScreenName) { - return SessionData.getMonitorWallpaper(targetScreenName); - } - return SessionData.wallpaperPath; - } - - function setCurrentWallpaper(path) { - if (SessionData.perMonitorWallpaper && targetScreenName) { - SessionData.setMonitorWallpaper(targetScreenName, path); - } else { - SessionData.setWallpaper(path); - } - } - - onCurrentPageChanged: { - if (currentPage !== lastPage) { - enableAnimation = false; - lastPage = currentPage; - } - updateSelectedFileName(); - } - - onGridIndexChanged: { - updateSelectedFileName(); - } - - onVisibleChanged: { - if (visible && active) { - setInitialSelection(); - } - } - - Component.onCompleted: { - loadWallpaperDirectory(); - } - - onActiveChanged: { - if (active && visible) { - setInitialSelection(); - } - } - - function handleKeyEvent(event) { - const columns = 4; - const currentCol = gridIndex % columns; - const visibleCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - if (gridIndex >= 0 && gridIndex < visibleCount) { - const absoluteIndex = currentPage * itemsPerPage + gridIndex; - if (absoluteIndex < wallpaperFolderModel.count) { - const filePath = wallpaperFolderModel.get(absoluteIndex, "filePath"); - if (filePath) { - setCurrentWallpaper(filePath.toString().replace(/^file:\/\//, '')); - } - } - } - return true; - } - - if (event.key === Qt.Key_Right || event.key === Qt.Key_L) { - if (I18n.isRtl) { - if (gridIndex > 0) { - gridIndex--; - } else if (currentPage > 0) { - currentPage--; - const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - gridIndex = prevPageCount - 1; - } - } else { - if (gridIndex + 1 < visibleCount) { - gridIndex++; - } else if (currentPage < totalPages - 1) { - gridIndex = 0; - currentPage++; - } - } - return true; - } - - if (event.key === Qt.Key_Left || event.key === Qt.Key_H) { - if (I18n.isRtl) { - if (gridIndex + 1 < visibleCount) { - gridIndex++; - } else if (currentPage < totalPages - 1) { - gridIndex = 0; - currentPage++; - } - } else { - if (gridIndex > 0) { - gridIndex--; - } else if (currentPage > 0) { - currentPage--; - const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - gridIndex = prevPageCount - 1; - } - } - return true; - } - - if (event.key === Qt.Key_Down || event.key === Qt.Key_J) { - if (gridIndex + columns < visibleCount) { - gridIndex += columns; - } else if (currentPage < totalPages - 1) { - gridIndex = currentCol; - currentPage++; - } - return true; - } - - if (event.key === Qt.Key_Up || event.key === Qt.Key_K) { - if (gridIndex >= columns) { - gridIndex -= columns; - } else if (currentPage > 0) { - currentPage--; - const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - const prevPageRows = Math.ceil(prevPageCount / columns); - gridIndex = (prevPageRows - 1) * columns + currentCol; - gridIndex = Math.min(gridIndex, prevPageCount - 1); - } - return true; - } - - if (event.key === Qt.Key_PageUp && currentPage > 0) { - gridIndex = 0; - currentPage--; - return true; - } - - if (event.key === Qt.Key_PageDown && currentPage < totalPages - 1) { - gridIndex = 0; - currentPage++; - return true; - } - - if (event.key === Qt.Key_Home && event.modifiers & Qt.ControlModifier) { - gridIndex = 0; - currentPage = 0; - return true; - } - - if (event.key === Qt.Key_End && event.modifiers & Qt.ControlModifier) { - currentPage = totalPages - 1; - const lastPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - gridIndex = Math.max(0, lastPageCount - 1); - return true; - } - - return false; - } - - function setInitialSelection() { - const currentWallpaper = getCurrentWallpaper(); - if (!currentWallpaper || wallpaperFolderModel.count === 0) { - gridIndex = 0; - updateSelectedFileName(); - Qt.callLater(() => { - enableAnimation = true; - }); - return; - } - - for (var i = 0; i < wallpaperFolderModel.count; i++) { - const filePath = wallpaperFolderModel.get(i, "filePath"); - if (filePath && filePath.toString().replace(/^file:\/\//, '') === currentWallpaper) { - const targetPage = Math.floor(i / itemsPerPage); - const targetIndex = i % itemsPerPage; - currentPage = targetPage; - gridIndex = targetIndex; - updateSelectedFileName(); - Qt.callLater(() => { - enableAnimation = true; - }); - return; - } - } - gridIndex = 0; - updateSelectedFileName(); - Qt.callLater(() => { - enableAnimation = true; - }); - } - - function loadWallpaperDirectory() { - const currentWallpaper = getCurrentWallpaper(); - - if (!currentWallpaper || currentWallpaper.startsWith("#")) { - if (CacheData.wallpaperLastPath && CacheData.wallpaperLastPath !== "") { - wallpaperDir = CacheData.wallpaperLastPath; - } else { - wallpaperDir = ""; - } - return; - } - - wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/')); - } - - function updateSelectedFileName() { - if (wallpaperFolderModel.count === 0) { - selectedFileName = ""; - return; - } - - const absoluteIndex = currentPage * itemsPerPage + gridIndex; - if (absoluteIndex < wallpaperFolderModel.count) { - const filePath = wallpaperFolderModel.get(absoluteIndex, "filePath"); - if (filePath) { - const pathStr = filePath.toString().replace(/^file:\/\//, ''); - selectedFileName = pathStr.substring(pathStr.lastIndexOf('/') + 1); - return; - } - } - selectedFileName = ""; - } - - Connections { - target: SessionData - function onWallpaperPathChanged() { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - function onMonitorWallpapersChanged() { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - function onPerMonitorWallpaperChanged() { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - } - - onTargetScreenNameChanged: { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - - Connections { - target: wallpaperFolderModel - function onCountChanged() { - if (wallpaperFolderModel.status === FolderListModel.Ready) { - if (visible && active) { - setInitialSelection(); - } - updateSelectedFileName(); - } - } - function onStatusChanged() { - if (wallpaperFolderModel.status === FolderListModel.Ready && wallpaperFolderModel.count > 0) { - if (visible && active) { - setInitialSelection(); - } - updateSelectedFileName(); - } - } - } - - FolderListModel { - id: wallpaperFolderModel - - showDirsFirst: false - showDotAndDotDot: false - showHidden: false - caseSensitive: false - nameFilters: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - showFiles: true - showDirs: false - sortField: FolderListModel.Name - folder: wallpaperDir ? "file://" + wallpaperDir.split('/').map(s => encodeURIComponent(s)).join('/') : "" - } - - FileBrowserSurfaceModal { - id: wallpaperBrowser - - browserTitle: I18n.tr("Select Wallpaper Directory", "wallpaper directory file browser title") - browserIcon: "folder_open" - browserType: "wallpaper" - showHiddenFiles: false - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - parentPopout: root.parentPopout - - onFileSelected: path => { - const cleanPath = path.replace(/^file:\/\//, ''); - setCurrentWallpaper(cleanPath); - - const dirPath = cleanPath.substring(0, cleanPath.lastIndexOf('/')); - if (dirPath) { - wallpaperDir = dirPath; - CacheData.wallpaperLastPath = dirPath; - CacheData.saveCache(); - } - close(); - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: parent.height - 50 - - GridView { - id: wallpaperGrid - anchors.centerIn: parent - width: parent.width - Theme.spacingS - height: parent.height - Theme.spacingS - cellWidth: width / 4 - cellHeight: height / 4 - clip: true - enabled: root.active - interactive: root.active - boundsBehavior: Flickable.StopAtBounds - keyNavigationEnabled: false - activeFocusOnTab: false - highlightFollowsCurrentItem: true - highlightMoveDuration: enableAnimation ? Theme.shortDuration : 0 - focus: false - - highlight: Item { - z: 1000 - Rectangle { - anchors.fill: parent - anchors.margins: Theme.spacingXS - color: "transparent" - border.width: 3 - border.color: Theme.primary - radius: Theme.cornerRadius - } - } - - model: { - const startIndex = currentPage * itemsPerPage; - const endIndex = Math.min(startIndex + itemsPerPage, wallpaperFolderModel.count); - const items = []; - for (var i = startIndex; i < endIndex; i++) { - const filePath = wallpaperFolderModel.get(i, "filePath"); - if (filePath) { - items.push(filePath.toString().replace(/^file:\/\//, '')); - } - } - return items; - } - - onModelChanged: { - const clampedIndex = model.length > 0 ? Math.min(Math.max(0, gridIndex), model.length - 1) : 0; - if (gridIndex !== clampedIndex) { - gridIndex = clampedIndex; - } - } - - onCountChanged: { - if (count > 0) { - const clampedIndex = Math.min(gridIndex, count - 1); - currentIndex = clampedIndex; - positionViewAtIndex(clampedIndex, GridView.Contain); - } - Qt.callLater(() => { - enableAnimation = true; - }); - } - - Connections { - target: root - function onGridIndexChanged() { - if (wallpaperGrid.count > 0) { - wallpaperGrid.currentIndex = gridIndex; - if (!enableAnimation) { - wallpaperGrid.positionViewAtIndex(gridIndex, GridView.Contain); - } - } - } - } - - delegate: Item { - width: wallpaperGrid.cellWidth - height: wallpaperGrid.cellHeight - - property string wallpaperPath: modelData || "" - property bool isSelected: getCurrentWallpaper() === modelData - - Rectangle { - id: wallpaperCard - anchors.fill: parent - anchors.margins: Theme.spacingXS - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - radius: Theme.cornerRadius - clip: true - - Rectangle { - anchors.fill: parent - color: isSelected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15) : "transparent" - radius: parent.radius - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - id: maskRect - width: thumbnailImage.width - height: thumbnailImage.height - radius: Theme.cornerRadius - visible: false - layer.enabled: true - } - - CachingImage { - id: thumbnailImage - anchors.fill: parent - imagePath: modelData || "" - maxCacheSize: 256 - - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskThresholdMin: 0.5 - maskSpreadAtMin: 1.0 - maskSource: maskRect - } - } - - StateLayer { - anchors.fill: parent - cornerRadius: parent.radius - stateColor: Theme.primary - } - - MouseArea { - id: wallpaperMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - onClicked: { - gridIndex = index; - if (modelData) { - setCurrentWallpaper(modelData); - } - } - } - } - } - } - - StyledText { - anchors.centerIn: parent - visible: wallpaperFolderModel.count === 0 - text: I18n.tr("No wallpapers found\n\nClick the folder icon below to browse") - font.pixelSize: 14 - color: Theme.outline - horizontalAlignment: Text.AlignHCenter - } - } - - Column { - width: parent.width - height: 50 - - Row { - width: parent.width - height: 32 - spacing: Theme.spacingS - - Item { - width: (parent.width - controlsRow.width - browseButton.width - Theme.spacingS) / 2 - height: parent.height - } - - Row { - id: controlsRow - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankActionButton { - anchors.verticalCenter: parent.verticalCenter - iconName: "skip_previous" - iconSize: 20 - buttonSize: 32 - enabled: currentPage > 0 - opacity: enabled ? 1.0 : 0.3 - onClicked: { - if (currentPage > 0) { - currentPage--; - } - } - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: wallpaperFolderModel.count > 0 - ? (wallpaperFolderModel.count === 1 - ? I18n.tr("%1 wallpaper • %2 / %3").arg(wallpaperFolderModel.count).arg(currentPage + 1).arg(totalPages) - : I18n.tr("%1 wallpapers • %2 / %3").arg(wallpaperFolderModel.count).arg(currentPage + 1).arg(totalPages)) - : I18n.tr("No wallpapers") - font.pixelSize: 14 - color: Theme.surfaceText - opacity: 0.7 - } - - DankActionButton { - anchors.verticalCenter: parent.verticalCenter - iconName: "skip_next" - iconSize: 20 - buttonSize: 32 - enabled: currentPage < totalPages - 1 - opacity: enabled ? 1.0 : 0.3 - onClicked: { - if (currentPage < totalPages - 1) { - currentPage++; - } - } - } - } - - DankActionButton { - id: browseButton - anchors.verticalCenter: parent.verticalCenter - iconName: "folder_open" - iconSize: 20 - buttonSize: 32 - opacity: 0.7 - onClicked: wallpaperBrowser.open() - } - } - - StyledText { - width: parent.width - height: 18 - text: selectedFileName - font.pixelSize: 12 - color: Theme.surfaceText - opacity: 0.5 - visible: selectedFileName !== "" - elide: Text.ElideMiddle - horizontalAlignment: Text.AlignHCenter - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml deleted file mode 100644 index 5c57b65..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml +++ /dev/null @@ -1,206 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - radius: Theme.cornerRadius - - property var date: null - property var daily: true - property var forecastData: null - property var dense: false - - readonly property bool isCurrent: { - if (daily) { - date ? WeatherService.calendarDayDifference(new Date(), date) === 0 : false; - } else { - date ? WeatherService.calendarHourDifference(new Date(), date) === 0 : false; - } - } - - readonly property string dateText: { - if (daily) - return root.forecastData?.day ?? "--"; - if (!root.forecastData?.rawTime) - return root.forecastData?.time ?? "--"; - try { - const date = new Date(root.forecastData.rawTime); - const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - return date.toLocaleTimeString(Qt.locale(), format); - } catch (e) { - return root.forecastData?.time ?? "--"; - } - } - - readonly property var minTemp: WeatherService.formatTemp(root.forecastData?.tempMin) - readonly property var maxTemp: WeatherService.formatTemp(root.forecastData?.tempMax) - readonly property string minMaxTempText: (minTemp ?? "--") + "/" + (maxTemp ?? "--") - - readonly property var temp: WeatherService.formatTemp(root.forecastData?.temp) - readonly property string tempText: temp ?? "--" - - readonly property var feelsLikeTemp: WeatherService.formatTemp(root.forecastData?.feelsLike) - readonly property string feelsLikeText: feelsLikeTemp ?? "--" - - readonly property var humidity: WeatherService.formatPercent(root.forecastData?.humidity) - readonly property string humidityText: humidity ?? "--" - - readonly property var wind: { - SettingsData.windSpeedUnit; - SettingsData.useFahrenheit; - return WeatherService.formatSpeed(root.forecastData?.wind); - } - readonly property string windText: wind ?? "--" - - readonly property var pressure: { - SettingsData.useFahrenheit; - return WeatherService.formatPressure(root.forecastData?.pressure); - } - readonly property string pressureText: pressure ?? "--" - - readonly property var precipitation: root.forecastData?.precipitationProbability - readonly property string precipitationText: precipitation + "%" ?? "--" - - readonly property var visibility: WeatherService.formatVisibility(root.forecastData?.visibility) - readonly property string visibilityText: visibility ?? "--" - - readonly property var values: daily ? [] : [ - { - "name"// 'name': "Temperature", - : - // 'text': root.tempText, - // 'icon': "thermometer" - // }, { - // 'name': "Feels Like", - // 'text': root.feelsLikeText, - // 'icon': "thermostat" - // }, { - I18n.tr("Humidity"), - "text": root.humidityText, - "icon": "humidity_low" - }, - { - "name": I18n.tr("Wind Speed"), - "text": root.windText, - "icon": "air" - }, - { - "name": I18n.tr("Pressure"), - "text": root.pressureText, - "icon": "speed" - }, - { - "name": I18n.tr("Precipitation Chance"), - "text": root.precipitationText, - "icon": "rainy" - }, - { - "name": I18n.tr("Visibility"), - "text": root.visibilityText, - "icon": "wb_sunny" - } - ] - - color: isCurrent ? Theme.withAlpha(Theme.primary, 0.1) : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: isCurrent ? Theme.withAlpha(Theme.primary, 0.3) : "transparent" - border.width: isCurrent ? 1 : 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: root.forecastData != null ? root.dateText : I18n.tr("Forecast Not Available") - font.pixelSize: Theme.fontSizeSmall - color: root.isCurrent ? Theme.primary : (root.forecastData ? Theme.surfaceText : Theme.outline) - font.weight: root.isCurrent ? Font.Medium : Font.Normal - anchors.horizontalCenter: parent.horizontalCenter - } - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - visible: root.forecastData != null - - Column { - spacing: Theme.spacingXS - - DankIcon { - name: root.forecastData ? WeatherService.getWeatherIcon(root.forecastData.wCode || 0, root.forecastData.isDay ?? true) : "cloud" - size: Theme.iconSize - color: root.isCurrent ? Theme.primary : Theme.withAlpha(Theme.primary, 0.8) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.daily ? root.minMaxTempText : root.tempText - font.pixelSize: Theme.fontSizeSmall - color: root.isCurrent ? Theme.primary : Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.feelsLikeText - font.pixelSize: Theme.fontSizeSmall - color: root.isCurrent ? Theme.primary : Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - visible: !root.daily - } - } - - Column { - id: detailsColumn - spacing: 2 - visible: !root.dense - width: implicitWidth - - states: [ - State { - name: "dense" - when: root.dense - PropertyChanges { - target: detailsColumn - opacity: 0 - width: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "opacity,width" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Repeater { - model: root.values.length - Row { - spacing: 2 - - DankIcon { - name: root.values[index].icon - size: 8 - color: Theme.withAlpha(Theme.surfaceText, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.values[index].text - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.withAlpha(Theme.surfaceText, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml deleted file mode 100644 index 21ea656..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml +++ /dev/null @@ -1,1124 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Shapes -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: 410 - property bool syncing: false - property bool showHourly: false - property bool available: WeatherService.weather.available - - function syncFrom(type) { - if (!dailyLoader.item || !hourlyLoader.item) - return; - const hourlyList = hourlyLoader.item; - const dailyList = dailyLoader.item; - syncing = true; - - try { - if (type === "hour") { - const date = new Date(); - date.setHours(hourlyList.currentIndex); - dateStepper.currentDate = date; - - dailyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.forecast?.length ?? 1) - 1, WeatherService.calendarDayDifference((new Date()), date))); - } else if (type === "day") { - const date = new Date(dateStepper.currentDate); - date.setMonth((new Date()).getMonth()); - date.setDate((new Date()).getDate() + dailyList.currentIndex); - dateStepper.currentDate = date; - - const hourIndex = Math.max(0, Math.min((WeatherService.weather.hourlyForecast?.length ?? 1) - 1, WeatherService.calendarHourDifference((new Date()), date) + (new Date).getHours())); - hourlyList.currentIndex = hourIndex; - } else if (type === "date") { - const date = dateStepper.currentDate; - dailyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.forecast?.length ?? 1) - 1, WeatherService.calendarDayDifference((new Date()), date))); - hourlyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.hourlyForecast?.length ?? 1) - 1, WeatherService.calendarHourDifference((new Date()), date) + (new Date()).getHours())); - } - } catch (e) { - console.warn("Weather Date Sync Error:", e); - } - - syncing = false; - } - - readonly property string sunriseTimeText: { - if (!WeatherService.weather.rawSunrise) - return WeatherService.weather.sunrise || ""; - try { - const date = new Date(WeatherService.weather.rawSunrise); - const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - return date.toLocaleTimeString(Qt.locale(), format); - } catch (e) { - return WeatherService.weather.sunrise || ""; - } - } - - readonly property string sunsetTimeText: { - if (!WeatherService.weather.rawSunset) - return WeatherService.weather.sunset || ""; - try { - const date = new Date(WeatherService.weather.rawSunset); - const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - return date.toLocaleTimeString(Qt.locale(), format); - } catch (e) { - return WeatherService.weather.sunset || ""; - } - } - - readonly property var heroMetrics: { - SettingsData.useFahrenheit; - SettingsData.windSpeedUnit; - return [ - { - "icon": "humidity_low", - "label": I18n.tr("Humidity"), - "value": WeatherService.formatPercent(WeatherService.weather.humidity) ?? "--" - }, - { - "icon": "air", - "label": I18n.tr("Wind"), - "value": WeatherService.formatSpeed(WeatherService.weather.wind) ?? "--" - }, - { - "icon": "speed", - "label": I18n.tr("Pressure"), - "value": WeatherService.formatPressure(WeatherService.weather.pressure) ?? "--" - }, - { - "icon": "rainy", - "label": I18n.tr("Precipitation"), - "value": (WeatherService.weather.precipitationProbability ?? 0) + "%" - }, - { - "icon": "wb_twilight", - "label": I18n.tr("Sunrise"), - "value": root.sunriseTimeText || "--" - }, - { - "icon": "bedtime", - "label": I18n.tr("Sunset"), - "value": root.sunsetTimeText || "--" - } - ]; - } - - Column { - id: unavailableColumn - anchors.centerIn: parent - spacing: Theme.spacingL - visible: !root.available - - DankIcon { - name: "cloud_off" - size: Theme.iconSize * 2 - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - Row { - width: refreshButtonTwo.width + refreshText.width - height: refreshButtonTwo.height - spacing: Theme.spacingS - - StyledText { - id: refreshText - text: I18n.tr("No Weather Data Available") - font.pixelSize: Theme.fontSizeLarge - color: Theme.withAlpha(Theme.surfaceText, 0.7) - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - id: refreshButtonTwo - name: "refresh" - size: Theme.iconSize - 4 - color: Theme.withAlpha(Theme.surfaceText, 0.4) - anchors.top: parent.top - anchors.verticalCenter: parent.verticalCenter - - property bool isRefreshing: false - enabled: !isRefreshing - - MouseArea { - id: refreshButtonMouseAreaTwo - anchors.fill: parent - hoverEnabled: true - cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ForbiddenCursor - enabled: parent.enabled - - Timer { - id: hoverDelayTwo - interval: 300 - repeat: false - onTriggered: { - refreshButtonTooltipTwo.show(I18n.tr("Refresh Weather"), refreshButtonTwo, 0, 0, "left"); - } - } - - onEntered: { - hoverDelayTwo.restart(); - } - - onExited: { - hoverDelayTwo.stop(); - refreshButtonTooltipTwo.hide(); - } - - onClicked: { - refreshButtonTwo.isRefreshing = true; - WeatherService.forceRefresh(); - refreshTimerTwo.restart(); - } - } - - DankTooltipV2 { - id: refreshButtonTooltipTwo - } - - Timer { - id: refreshTimerTwo - interval: 2000 - onTriggered: refreshButtonTwo.isRefreshing = false - } - - NumberAnimation on rotation { - running: refreshButtonTwo.isRefreshing - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - } - } - } - } - - Column { - id: mainColumn - anchors.fill: parent - visible: root.available - spacing: Theme.spacingS - - Rectangle { - id: heroCard - width: parent.width - height: heroContent.height + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Theme.withAlpha(Theme.outline, 0.08) - border.width: 1 - - Column { - id: heroContent - x: Theme.spacingL - y: Theme.spacingL - width: parent.width - Theme.spacingL * 2 - spacing: Theme.spacingM - - Item { - width: parent.width - height: Math.max(heroLeft.height, heroMetricsGrid.height) - - Row { - id: heroLeft - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingL - - DankIcon { - id: weatherIcon - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.iconSize * 2 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) - shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - } - } - - Column { - id: tempColumn - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - Item { - anchors.left: parent.left - width: tempText.width + unitText.width + Theme.spacingXS - height: tempText.height - - StyledText { - id: tempText - LayoutMirroring.enabled: false - text: (SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" - font.pixelSize: Theme.fontSizeXLarge + 8 - color: Theme.surfaceText - font.weight: Font.Light - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: unitText - LayoutMirroring.enabled: false - text: SettingsData.useFahrenheit ? "F" : "C" - font.pixelSize: Theme.fontSizeMedium - color: Theme.withAlpha(Theme.surfaceText, 0.7) - anchors.left: tempText.right - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (WeatherService.weather.available) - SettingsData.set("useFahrenheit", !SettingsData.useFahrenheit); - } - enabled: WeatherService.weather.available - } - } - } - - StyledText { - text: WeatherService.getWeatherCondition(WeatherService.weather.wCode) - font.pixelSize: Theme.fontSizeMedium - color: Theme.withAlpha(Theme.surfaceText, 0.7) - anchors.left: parent.left - } - - StyledText { - property var feelsLike: SettingsData.useFahrenheit ? (WeatherService.weather.feelsLikeF || WeatherService.weather.tempF) : (WeatherService.weather.feelsLike || WeatherService.weather.temp) - text: I18n.tr("Feels Like %1°", "weather feels like temperature").arg(feelsLike) - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.left: parent.left - } - - StyledText { - text: WeatherService.weather.city || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.5) - visible: text.length > 0 - anchors.left: parent.left - } - } - } - - Grid { - id: heroMetricsGrid - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - columns: 3 - columnSpacing: Theme.spacingXL - rowSpacing: Theme.spacingS - - Repeater { - model: root.heroMetrics - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: modelData.icon - size: Theme.iconSizeSmall - 2 - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.left: parent.left - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.left: parent.left - } - } - } - } - } - } - } - } - - Item { - id: skyDateRow - width: parent.width - height: dateStepper.height - - Item { - id: dateStepper - height: dateStepperInner.height + Theme.spacingM * 2 - width: dateStepperInner.width - - property var currentDate: new Date() - - readonly property var changeDate: (magnitudeIndex, sign) => { - switch (magnitudeIndex) { - case 0: - break; - case 1: - var newDate = new Date(dateStepper.currentDate); - newDate.setMonth(dateStepper.currentDate.getMonth() + sign * 1); - dateStepper.currentDate = newDate; - break; - case 2: - dateStepper.currentDate = new Date(dateStepper.currentDate.getTime() + sign * 24 * 3600 * 1000); - break; - case 3: - dateStepper.currentDate = new Date(dateStepper.currentDate.getTime() + sign * 3600 * 1000); - break; - case 4: - dateStepper.currentDate = new Date(dateStepper.currentDate.getTime() + sign * 5 * 60 * 1000); - break; - } - } - readonly property var splitDate: Qt.formatDateTime(dateStepper.currentDate, SettingsData.use24HourClock ? "yyyy.MM.dd.HH.mm" : "yyyy.MM.dd.hh.mm.AP").split('.') - - Item { - id: dateStepperInner - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - readonly property var space: Theme.spacingXS - width: yearStepper.width + monthStepper.width + dayStepper.width + hourStepper.width + minuteStepper.width + (suffix.visible ? suffix.width : 0) + 10.5 * space + 2 * dateStepperInnerPadding.width - height: Math.max(yearStepper.height, monthStepper.height, dayStepper.height, hourStepper.height, minuteStepper.height) - - Item { - id: dateStepperInnerPadding - width: dateResetButton.width - } - - DankNumberStepper { - id: yearStepper - anchors.left: dateStepperInnerPadding.right - anchors.leftMargin: parent.space - width: implicitWidth - text: dateStepper.splitDate[0] - } - - DankNumberStepper { - id: monthStepper - width: implicitWidth - anchors.left: yearStepper.right - anchors.leftMargin: parent.space - text: dateStepper.splitDate[1] - onIncrement: () => dateStepper.changeDate(1, +1) - onDecrement: () => dateStepper.changeDate(1, -1) - } - - DankNumberStepper { - id: dayStepper - width: implicitWidth - anchors.left: monthStepper.right - anchors.leftMargin: parent.space - text: dateStepper.splitDate[2] - onIncrement: () => dateStepper.changeDate(2, +1) - onDecrement: () => dateStepper.changeDate(2, -1) - } - - DankNumberStepper { - id: hourStepper - width: implicitWidth - anchors.left: dayStepper.right - anchors.leftMargin: 1.5 * parent.space - text: dateStepper.splitDate[3] - onIncrement: () => dateStepper.changeDate(3, +1) - onDecrement: () => dateStepper.changeDate(3, -1) - } - - DankNumberStepper { - id: minuteStepper - width: implicitWidth - anchors.left: hourStepper.right - anchors.leftMargin: parent.space - text: dateStepper.splitDate[4] - onIncrement: () => dateStepper.changeDate(4, +1) - onDecrement: () => dateStepper.changeDate(4, -1) - } - - Item { - anchors.verticalCenter: parent.verticalCenter - anchors.left: yearStepper.right - anchors.right: monthStepper.left - StyledText { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - text: "-" - } - } - Item { - anchors.verticalCenter: parent.verticalCenter - anchors.left: monthStepper.right - anchors.right: dayStepper.left - StyledText { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - text: "-" - } - } - Item { - anchors.verticalCenter: parent.verticalCenter - anchors.left: hourStepper.right - anchors.right: minuteStepper.left - StyledText { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - text: ":" - } - } - StyledText { - id: suffix - visible: !SettingsData.use24HourClock - anchors.verticalCenter: minuteStepper.verticalCenter - anchors.left: minuteStepper.right - anchors.leftMargin: 2 * parent.space - isMonospace: true - text: dateStepper.splitDate[5] ?? "" - font.pixelSize: Theme.fontSizeSmall - } - DankActionButton { - id: dateResetButton - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - enabled: Math.abs(dateStepper.currentDate - new Date()) > 1000 - iconColor: enabled ? Theme.blendAlpha(Theme.surfaceText, 0.5) : "transparent" - iconSize: 12 - buttonSize: 20 - iconName: "replay" - onClicked: { - dateStepper.currentDate = new Date(); - } - } - } - - onCurrentDateChanged: if (!syncing) - root.syncFrom("date") - } - - Rectangle { - id: skyBox - anchors.left: dateStepper.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - height: parent.height - - LayoutMirroring.enabled: false - LayoutMirroring.childrenInherit: true - - property var backgroundOpacity: 0.3 - property var sunTime: WeatherService.getCurrentSunTime(dateStepper.currentDate) - property var periodIndex: sunTime?.periodIndex - property var periodPercent: sunTime?.periodPercent - property var blackColor: Theme.blend(Theme.surface, Qt.rgba(0, 0, 0, 255), 0.2) - property var redColor: Theme.secondary - property var blueColor: Theme.primary - function blackBlue(r) { - return Theme.blend(blackColor, blueColor, r); - } - property var topColor: { - const colorMap = [blackColor, Theme.withAlpha(blackBlue(0.0), 0.8), Theme.withAlpha(blackBlue(0.2), 0.7), Theme.withAlpha(blackBlue(0.5), 0.6), Theme.withAlpha(blackBlue(0.7), 0.6), Theme.withAlpha(blackBlue(0.9), 0.6), Theme.withAlpha(blackBlue(1.0), 0.6), Theme.withAlpha(blackBlue(0.9), 0.6), Theme.withAlpha(blackBlue(0.7), 0.6), Theme.withAlpha(blackBlue(0.5), 0.6), Theme.withAlpha(blackBlue(0.2), 0.7), Theme.withAlpha(blackBlue(0.0), 0.8), blackColor, blackColor]; - const index = periodIndex ?? 0; - return Theme.blend(colorMap[index], colorMap[index + 1], periodPercent ?? 0); - } - property var sunColor: { - const colorMap = [Theme.withAlpha(redColor, 0.05), Theme.withAlpha(redColor, 0.1), Theme.withAlpha(redColor, 0.3), Theme.withAlpha(redColor, 0.4), Theme.withAlpha(redColor, 0.5), Theme.withAlpha(blueColor, 0.2), Theme.withAlpha(blueColor, 0.0), Theme.withAlpha(blueColor, 0.2), Theme.withAlpha(redColor, 0.5), Theme.withAlpha(redColor, 0.4), Theme.withAlpha(redColor, 0.3), Theme.withAlpha(redColor, 0.1), Theme.withAlpha(redColor, 0.05), Theme.withAlpha(redColor, 0.0)]; - const index = periodIndex ?? 0; - return Theme.blend(colorMap[index], colorMap[index + 1], periodPercent ?? 0); - } - - color: "transparent" - - Rectangle { - anchors.fill: parent - opacity: skyBox.backgroundOpacity - - gradient: Gradient { - GradientStop { - position: 0.0 - color: Theme.withAlpha(skyBox.blackColor, 0.0) - } - GradientStop { - position: 0.05 - color: skyBox.topColor - } - GradientStop { - position: 0.3 - color: skyBox.topColor - } - GradientStop { - position: 0.5 - color: skyBox.topColor - } - GradientStop { - position: 0.501 - color: skyBox.blackColor - } - GradientStop { - position: 0.9 - color: skyBox.blackColor - } - GradientStop { - position: 1.0 - color: Theme.withAlpha(skyBox.blackColor, 0.0) - } - } - } - - property var currentDate: dateStepper.currentDate - property var hMargin: 0 - property var vMargin: Theme.spacingM - property var effectiveHeight: skyBox.height - 2 * vMargin - property var effectiveWidth: skyBox.width - 2 * hMargin - - StyledText { - text: parent.sunTime?.period ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.7) - x: 0 - y: 0 - } - - Shape { - id: skyShape - anchors.left: parent.left - anchors.top: parent.top - anchors.right: parent.right - height: parent.height / 2 - opacity: skyBox.backgroundOpacity - - ShapePath { - strokeColor: "transparent" - fillGradient: RadialGradient { - centerX: skyBox.hMargin + sun.x + sun.width / 2 - centerY: skyBox.vMargin + sun.y + 30 - centerRadius: { - const a = Math.abs((skyBox.sunTime?.dayPercent ?? 0) - 0.5); - const out = 200 * (0.5 - a * a); - return out; - } - focalX: skyBox.hMargin + sun.x + sun.width / 2 - focalY: skyBox.vMargin + sun.y - GradientStop { - position: 0 - color: skyBox.sunColor - } - GradientStop { - position: 0.3 - color: Theme.blendAlpha(skyBox.sunColor, 0.5) - } - GradientStop { - position: 1 - color: "transparent" - } - } - PathLine { - x: 0 - y: 0 - } - PathLine { - x: skyShape.width - y: 0 - } - PathLine { - x: skyShape.width - y: skyShape.height - } - PathLine { - x: 0 - y: skyShape.height - } - } - - ShapePath { - strokeColor: "transparent" - fillGradient: RadialGradient { - centerX: sun.x - centerY: sun.y - centerRadius: 500 - focalX: centerX - focalY: centerY + 0.99 * (centerRadius - focalRadius) - focalRadius: 10 - GradientStop { - position: 0 - color: skyBox.sunColor - } - GradientStop { - position: 0.45 - color: skyBox.sunColor - } - GradientStop { - position: 0.55 - color: "transparent" - } - GradientStop { - position: 1 - color: "transparent" - } - } - PathLine { - x: 0 - y: 0 - } - PathLine { - x: skyShape.width - y: 0 - } - PathLine { - x: skyShape.width - y: skyShape.height - } - PathLine { - x: 0 - y: skyShape.height - } - } - } - - Canvas { - id: ecliptic - anchors.fill: parent - property var points: WeatherService.getEcliptic(dateStepper.currentDate) - - function getX(index) { - return points[index].h * skyBox.effectiveWidth + skyBox.hMargin; - } - function getY(index) { - return points[index].v * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 + skyBox.vMargin; - } - - onPointsChanged: requestPaint() - - onPaint: { - var ctx = getContext("2d"); - ctx.clearRect(0, 0, width, height); - if (!points || points.length === 0) - return; - ctx.beginPath(); - ctx.moveTo(getX(0), getY(0)); - for (var i = 1; i < points.length; i++) { - ctx.lineTo(getX(i), getY(i)); - } - ctx.strokeStyle = Theme.withAlpha(Theme.outline, 0.2); - ctx.stroke(); - } - } - - property real latitude: WeatherService.getLocation()?.latitude ?? 0 - property real sunDeclination: WeatherService.getSunDeclination(dateStepper.currentDate) - - readonly property bool solarNoonIsSouth: latitude > sunDeclination - - StyledText { - id: middle - text: skyBox.solarNoonIsSouth ? "S" : "N" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - x: skyBox.width / 2 - middle.width / 2 - y: skyBox.height / 2 - middle.height / 2 - } - - StyledText { - id: left - text: skyBox.solarNoonIsSouth ? "E" : "W" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - x: skyBox.width / 4 - left.width / 2 - y: skyBox.height / 2 - left.height / 2 - } - - StyledText { - id: right - text: skyBox.solarNoonIsSouth ? "W" : "E" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - x: 3 * skyBox.width / 4 - right.width / 2 - y: skyBox.height / 2 - right.height / 2 - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: right.right - anchors.right: skyBox.right - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: middle.right - anchors.right: right.left - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: left.right - anchors.right: middle.left - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: skyBox.left - anchors.right: left.left - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - DankNFIcon { - id: moonPhase - name: WeatherService.getMoonPhase(skyBox.currentDate) || "" - size: Theme.fontSizeXLarge - color: Theme.withAlpha(Theme.surfaceText, 0.7) - rotation: (WeatherService.getMoonAngle(skyBox.currentDate) || 0) / Math.PI * 180 - visible: !!pos - - property var pos: WeatherService.getSkyArcPosition(skyBox.currentDate, false) - x: (pos?.h ?? 0) * skyBox.effectiveWidth - (moonPhase.width / 2) + skyBox.hMargin - y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (moonPhase.height / 2) + skyBox.vMargin - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) - } - } - - DankIcon { - id: sun - name: "light_mode" - size: Theme.fontSizeXLarge - color: Theme.primary - visible: !!pos - - property var pos: WeatherService.getSkyArcPosition(skyBox.currentDate, true) - x: (pos?.h ?? 0) * skyBox.effectiveWidth - (sun.width / 2) + skyBox.hMargin - y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (sun.height / 2) + skyBox.vMargin - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) - } - } - } - } - - Item { - id: chipsRow - width: parent.width - height: forecastChips.height - - DankFilterChips { - id: forecastChips - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - model: [I18n.tr("Daily"), I18n.tr("Hourly")] - currentIndex: root.showHourly ? 1 : 0 - showCheck: false - showCounts: false - onSelectionChanged: index => { - root.showHourly = index === 1; - } - } - - DankActionButton { - id: denseButton - anchors.right: refreshButton.left - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - visible: root.showHourly && hourlyLoader.item !== null - iconName: SessionData.weatherHourlyDetailed ? "tile_large" : "tile_medium" - onClicked: SessionData.setWeatherHourlyDetailed(!SessionData.weatherHourlyDetailed) - } - - DankIcon { - id: refreshButton - name: "refresh" - size: Theme.iconSize - 4 - color: Theme.withAlpha(Theme.surfaceText, 0.4) - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - property bool isRefreshing: false - enabled: !isRefreshing - - MouseArea { - id: refreshButtonMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ForbiddenCursor - enabled: parent.enabled - - Timer { - id: hoverDelay - interval: 300 - repeat: false - onTriggered: { - refreshButtonTooltip.show(I18n.tr("Refresh Weather"), refreshButton, 0, 0, "left"); - } - } - - onEntered: { - hoverDelay.restart(); - } - - onExited: { - hoverDelay.stop(); - refreshButtonTooltip.hide(); - } - - onClicked: { - refreshButton.isRefreshing = true; - WeatherService.forceRefresh(); - refreshTimer.restart(); - } - } - - DankTooltipV2 { - id: refreshButtonTooltip - } - - Timer { - id: refreshTimer - interval: 2000 - onTriggered: refreshButton.isRefreshing = false - } - - NumberAnimation on rotation { - running: refreshButton.isRefreshing - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - } - } - } - - Item { - width: parent.width - height: root.height - heroCard.height - skyDateRow.height - chipsRow.height - mainColumn.spacing * 3 - - Loader { - id: dailyLoader - anchors.fill: parent - sourceComponent: dailyComponent - active: root.visible && root.available - visible: !root.showHourly - asynchronous: true - opacity: 0 - onLoaded: { - root.syncing = true; - item.currentIndex = item.initialIndex; - item.positionViewAtIndex(item.initialIndex, ListView.SnapPosition); - root.syncing = false; - opacity = 1; - } - } - - Loader { - id: hourlyLoader - anchors.fill: parent - sourceComponent: hourlyComponent - active: root.visible && root.available - visible: root.showHourly - asynchronous: true - opacity: 0 - onLoaded: { - root.syncing = true; - item.currentIndex = item.initialIndex; - item.positionViewAtIndex(item.initialIndex, ListView.SnapPosition); - root.syncing = false; - opacity = 1; - } - } - } - } - - Component { - id: hourlyComponent - ListView { - id: hourlyList - anchors.fill: parent - orientation: ListView.Horizontal - spacing: Theme.spacingS - clip: true - snapMode: ListView.SnapToItem - highlightRangeMode: ListView.StrictlyEnforceRange - highlightMoveDuration: 0 - interactive: true - - property var cardHeight: height - property var cardWidth: ((hourlyList.width + hourlyList.spacing) / hourlyList.visibleCount) - hourlyList.spacing - property int initialIndex: (new Date()).getHours() - property bool dense: !SessionData.weatherHourlyDetailed - property int visibleCount: dense ? 10 : 5 - - model: WeatherService.weather.hourlyForecast?.length ?? 0 - - delegate: WeatherForecastCard { - width: hourlyList.cardWidth - height: hourlyList.cardHeight - dense: hourlyList.dense - daily: false - - date: { - const d = new Date(); - d.setHours(index); - return d; - } - forecastData: WeatherService.weather.hourlyForecast[index] - } - - onCurrentIndexChanged: if (!syncing) - root.syncFrom("hour") - - states: [ - State { - name: "denseState" - when: hourlyList.dense - PropertyChanges { - target: hourlyList - visibleCount: 10 - } - }, - State { - name: "normalState" - when: !hourlyList.dense - PropertyChanges { - target: hourlyList - visibleCount: 5 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "visibleCount" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - MouseArea { - anchors.fill: parent - onWheel: wheel => { - if (wheel.modifiers & Qt.ShiftModifier) { - if (wheel.angleDelta.y % 120 == 0 && wheel.angleDelta.x == 0) { - const newIndex = hourlyList.currentIndex - Math.sign(wheel.angleDelta.y); - if (newIndex < hourlyList.model && newIndex >= 0) { - hourlyList.currentIndex = newIndex; - wheel.accepted = true; - return; - } - } - } - wheel.accepted = false; - } - } - } - } - - Component { - id: dailyComponent - ListView { - id: dailyList - anchors.fill: parent - orientation: ListView.Horizontal - spacing: Theme.spacingS - clip: true - snapMode: ListView.SnapToItem - highlightRangeMode: ListView.StrictlyEnforceRange - highlightMoveDuration: 0 - interactive: true - - property var cardHeight: height - property var cardWidth: ((dailyList.width + dailyList.spacing) / dailyList.visibleCount) - dailyList.spacing - property int initialIndex: 0 - property bool dense: false - property int visibleCount: 7 - - model: WeatherService.weather.forecast?.length ?? 0 - - delegate: WeatherForecastCard { - width: dailyList.cardWidth - height: dailyList.cardHeight - dense: true - daily: true - - date: { - const date = new Date(); - date.setDate(date.getDate() + index); - return date; - } - forecastData: WeatherService.weather.forecast[index] - } - - onCurrentIndexChanged: if (!syncing) - root.syncFrom("day") - - MouseArea { - anchors.fill: parent - onWheel: wheel => { - if (wheel.modifiers & Qt.ShiftModifier) { - if (wheel.angleDelta.y % 120 == 0 && wheel.angleDelta.x == 0) { - const newIndex = dailyList.currentIndex - Math.sign(wheel.angleDelta.y); - if (newIndex < dailyList.model && newIndex >= 0) { - dailyList.currentIndex = newIndex; - wheel.accepted = true; - return; - } - } - } - wheel.accepted = false; - } - } - } - } -} |