feat: settings is now json, refactor panels to be able to dismiss by clicking outside
This commit is contained in:
parent
8a3d610d22
commit
a498671ef1
36 changed files with 1282 additions and 1300 deletions
|
|
@ -5,7 +5,7 @@ import qs.Services
|
|||
import qs.Settings
|
||||
|
||||
ShellRoot {
|
||||
property string wallpaperSource: WallpaperManager.currentWallpaper !== "" && !Settings.useSWWW ? WallpaperManager.currentWallpaper : ""
|
||||
property string wallpaperSource: WallpaperManager.currentWallpaper !== "" && !Settings.settings.useSWWW ? WallpaperManager.currentWallpaper : ""
|
||||
PanelWindow {
|
||||
visible: wallpaperSource !== ""
|
||||
anchors {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ WlSessionLock {
|
|||
property bool authenticating: false
|
||||
property string password: ""
|
||||
property bool pamAvailable: typeof PamContext !== "undefined"
|
||||
property string weatherCity: Settings.weatherCity
|
||||
property string weatherCity: Settings.settings.weatherCity
|
||||
property var weatherData: null
|
||||
property string weatherError: ""
|
||||
property string weatherInfo: ""
|
||||
|
|
@ -161,7 +161,7 @@ WlSessionLock {
|
|||
id: avatarImage
|
||||
anchors.fill: parent
|
||||
anchors.margins: 4
|
||||
source: Settings.profileImage
|
||||
source: Settings.settings.profileImage
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
visible: false // Only show the masked version
|
||||
asynchronous: true
|
||||
|
|
@ -175,7 +175,7 @@ WlSessionLock {
|
|||
radius: avatarImage.width / 2
|
||||
visible: false
|
||||
}
|
||||
visible: Settings.profileImage !== ""
|
||||
visible: Settings.settings.profileImage !== ""
|
||||
}
|
||||
// Fallback icon
|
||||
Text {
|
||||
|
|
@ -184,7 +184,7 @@ WlSessionLock {
|
|||
font.family: "Material Symbols Outlined"
|
||||
font.pixelSize: 32
|
||||
color: Theme.onAccent
|
||||
visible: Settings.profileImage === ""
|
||||
visible: Settings.settings.profileImage === ""
|
||||
}
|
||||
// Glow effect
|
||||
layer.enabled: true
|
||||
|
|
@ -357,7 +357,7 @@ WlSessionLock {
|
|||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Text {
|
||||
text: weatherData && weatherData.current_weather ? (Settings.useFahrenheit ? `${Math.round(weatherData.current_weather.temperature * 9 / 5 + 32)}°F` : `${Math.round(weatherData.current_weather.temperature)}°C`) : (Settings.useFahrenheit ? "--°F" : "--°C")
|
||||
text: weatherData && weatherData.current_weather ? (Settings.settings.useFahrenheit ? `${Math.round(weatherData.current_weather.temperature * 9 / 5 + 32)}°F` : `${Math.round(weatherData.current_weather.temperature)}°C`) : (Settings.settings.useFahrenheit ? "--°F" : "--°C")
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 18
|
||||
color: Theme.textSecondary
|
||||
|
|
|
|||
|
|
@ -1,56 +1,30 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Components
|
||||
import qs.Settings
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Layouts
|
||||
import qs.Components
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property string configDir: Quickshell.configDir
|
||||
property string historyFilePath: configDir + "/notification_history.json"
|
||||
property bool hasUnread: notificationHistoryWin.hasUnread && !notificationHistoryWin.visible
|
||||
function addToHistory(notification) { notificationHistoryWin.addToHistory(notification) }
|
||||
width: 22; height: 22
|
||||
|
||||
// Bell icon/button
|
||||
Item {
|
||||
id: bell
|
||||
width: 22; height: 22
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: root.hasUnread ? "notifications_unread" : "notifications"
|
||||
font.family: mouseAreaBell.containsMouse ? "Material Symbols Rounded" : "Material Symbols Outlined"
|
||||
font.pixelSize: 16
|
||||
font.weight: root.hasUnread ? Font.Bold : Font.Normal
|
||||
color: mouseAreaBell.containsMouse ? Theme.accentPrimary : (root.hasUnread ? Theme.accentPrimary : Theme.textDisabled)
|
||||
}
|
||||
MouseArea {
|
||||
id: mouseAreaBell
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: notificationHistoryWin.visible = !notificationHistoryWin.visible
|
||||
}
|
||||
}
|
||||
|
||||
// The popup window
|
||||
PanelWindow {
|
||||
id: notificationHistoryWin
|
||||
width: 400
|
||||
property int maxPopupHeight: 500
|
||||
// The popup window
|
||||
PanelWithOverlay {
|
||||
id: notificationHistoryWin
|
||||
property string historyFilePath: Settings.settingsDir + "notification_history.json"
|
||||
property bool hasUnread: notificationHistoryWinRect.hasUnread && !notificationHistoryWinRect.visible
|
||||
function addToHistory(notification) { notificationHistoryWinRect.addToHistory(notification) }
|
||||
Rectangle {
|
||||
id: notificationHistoryWinRect
|
||||
implicitWidth: 400
|
||||
property int maxPopupHeight: 800
|
||||
property int minPopupHeight: 230
|
||||
property int contentHeight: headerRow.height + historyList.contentHeight + 56
|
||||
height: Math.max(Math.min(contentHeight, maxPopupHeight), minPopupHeight)
|
||||
color: "transparent"
|
||||
visible: false
|
||||
screen: Quickshell.primaryScreen
|
||||
focusable: true
|
||||
anchors.top: true
|
||||
anchors.right: true
|
||||
margins.top: 4
|
||||
margins.right: 4
|
||||
implicitHeight: Math.max(Math.min(contentHeight, maxPopupHeight), minPopupHeight)
|
||||
visible: parent.visible
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 4
|
||||
anchors.rightMargin: 4
|
||||
color: Theme.backgroundPrimary
|
||||
radius: 20
|
||||
|
||||
property int maxHistory: 100
|
||||
property bool hasUnread: false
|
||||
|
|
@ -62,25 +36,24 @@ Item {
|
|||
|
||||
FileView {
|
||||
id: historyFileView
|
||||
path: root.historyFilePath
|
||||
path: notificationHistoryWin.historyFilePath
|
||||
blockLoading: true
|
||||
printErrors: true
|
||||
watchChanges: true
|
||||
|
||||
|
||||
JsonAdapter {
|
||||
id: historyAdapter
|
||||
property var notifications: []
|
||||
}
|
||||
|
||||
onFileChanged: historyFileView.reload()
|
||||
onLoaded: notificationHistoryWin.loadHistory()
|
||||
onLoadFailed: function(error) {
|
||||
if (error.includes("No such file")) {
|
||||
historyAdapter.notifications = []
|
||||
writeAdapter()
|
||||
}
|
||||
onLoaded: notificationHistoryWinRect.loadHistory()
|
||||
onLoadFailed: function (error) {
|
||||
historyAdapter.notifications = [];
|
||||
historyFileView.writeAdapter();
|
||||
}
|
||||
Component.onCompleted: if (path) reload()
|
||||
Component.onCompleted: if (path)
|
||||
reload()
|
||||
}
|
||||
|
||||
function updateHasUnread() {
|
||||
|
|
@ -99,16 +72,18 @@ Item {
|
|||
|
||||
function loadHistory() {
|
||||
if (historyAdapter.notifications) {
|
||||
historyModel.clear()
|
||||
const notifications = historyAdapter.notifications
|
||||
const count = Math.min(notifications.length, maxHistory)
|
||||
historyModel.clear();
|
||||
const notifications = historyAdapter.notifications;
|
||||
const count = Math.min(notifications.length, maxHistory);
|
||||
for (let i = 0; i < count; i++) {
|
||||
let n = notifications[i]
|
||||
let n = notifications[i];
|
||||
if (typeof n === 'object' && n !== null) {
|
||||
if (n.read === undefined) n.read = false;
|
||||
if (n.read === undefined)
|
||||
n.read = false;
|
||||
// Mark as read if window is open
|
||||
if (visible) n.read = true;
|
||||
historyModel.append(n)
|
||||
if (notificationHistoryWinRect.visible)
|
||||
n.read = true;
|
||||
historyModel.append(n);
|
||||
}
|
||||
}
|
||||
updateHasUnread();
|
||||
|
|
@ -116,10 +91,10 @@ Item {
|
|||
}
|
||||
|
||||
function saveHistory() {
|
||||
const historyArray = []
|
||||
const count = Math.min(historyModel.count, maxHistory)
|
||||
const historyArray = [];
|
||||
const count = Math.min(historyModel.count, maxHistory);
|
||||
for (let i = 0; i < count; ++i) {
|
||||
let obj = historyModel.get(i)
|
||||
let obj = historyModel.get(i);
|
||||
if (typeof obj === 'object' && obj !== null) {
|
||||
historyArray.push({
|
||||
id: obj.id,
|
||||
|
|
@ -128,51 +103,55 @@ Item {
|
|||
body: obj.body,
|
||||
timestamp: obj.timestamp,
|
||||
read: obj.read === undefined ? false : obj.read
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
historyAdapter.notifications = historyArray
|
||||
Qt.callLater(function() {
|
||||
historyFileView.writeAdapter()
|
||||
})
|
||||
historyAdapter.notifications = historyArray;
|
||||
Qt.callLater(function () {
|
||||
historyFileView.writeAdapter();
|
||||
});
|
||||
updateHasUnread();
|
||||
}
|
||||
|
||||
function addToHistory(notification) {
|
||||
if (!notification.id) notification.id = Date.now()
|
||||
if (!notification.timestamp) notification.timestamp = new Date().toISOString()
|
||||
|
||||
if (!notification.id)
|
||||
notification.id = Date.now();
|
||||
if (!notification.timestamp)
|
||||
notification.timestamp = new Date().toISOString();
|
||||
|
||||
// Mark as read if window is open
|
||||
notification.read = visible
|
||||
|
||||
notification.read = visible;
|
||||
|
||||
// Remove duplicate by id
|
||||
for (let i = 0; i < historyModel.count; ++i) {
|
||||
if (historyModel.get(i).id === notification.id) {
|
||||
historyModel.remove(i)
|
||||
break
|
||||
historyModel.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
historyModel.insert(0, notification)
|
||||
|
||||
if (historyModel.count > maxHistory) historyModel.remove(maxHistory)
|
||||
saveHistory()
|
||||
|
||||
historyModel.insert(0, notification);
|
||||
|
||||
if (historyModel.count > maxHistory)
|
||||
historyModel.remove(maxHistory);
|
||||
saveHistory();
|
||||
}
|
||||
|
||||
function clearHistory() {
|
||||
historyModel.clear()
|
||||
historyAdapter.notifications = []
|
||||
historyFileView.writeAdapter()
|
||||
historyModel.clear();
|
||||
historyAdapter.notifications = [];
|
||||
historyFileView.writeAdapter();
|
||||
}
|
||||
|
||||
function formatTimestamp(ts) {
|
||||
if (!ts) return "";
|
||||
if (!ts)
|
||||
return "";
|
||||
var date = typeof ts === "number" ? new Date(ts) : new Date(Date.parse(ts));
|
||||
var y = date.getFullYear();
|
||||
var m = (date.getMonth()+1).toString().padStart(2,'0');
|
||||
var d = date.getDate().toString().padStart(2,'0');
|
||||
var h = date.getHours().toString().padStart(2,'0');
|
||||
var min = date.getMinutes().toString().padStart(2,'0');
|
||||
var m = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
var d = date.getDate().toString().padStart(2, '0');
|
||||
var h = date.getHours().toString().padStart(2, '0');
|
||||
var min = date.getMinutes().toString().padStart(2, '0');
|
||||
return `${y}-${m}-${d} ${h}:${min}`;
|
||||
}
|
||||
|
||||
|
|
@ -186,13 +165,14 @@ Item {
|
|||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) saveHistory();
|
||||
if (changed)
|
||||
saveHistory();
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: notificationHistoryWin.width
|
||||
height: notificationHistoryWin.height
|
||||
width: notificationHistoryWinRect.width
|
||||
height: notificationHistoryWinRect.height
|
||||
anchors.fill: parent
|
||||
color: Theme.backgroundPrimary
|
||||
radius: 20
|
||||
|
|
@ -205,10 +185,12 @@ Item {
|
|||
RowLayout {
|
||||
id: headerRow
|
||||
spacing: 4
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 4
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.preferredHeight: 52
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
Text {
|
||||
|
|
@ -218,7 +200,9 @@ Item {
|
|||
color: Theme.textPrimary
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Rectangle {
|
||||
id: clearAllButton
|
||||
width: 90
|
||||
|
|
@ -251,7 +235,7 @@ Item {
|
|||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: notificationHistoryWin.clearHistory()
|
||||
onClicked: notificationHistoryWinRect.clearHistory()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -264,11 +248,10 @@ Item {
|
|||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 56
|
||||
anchors.bottom: parent.bottom
|
||||
height: notificationHistoryWinRect.height - 56 - 12
|
||||
color: Theme.surfaceVariant
|
||||
radius: 20
|
||||
|
||||
|
|
@ -288,7 +271,10 @@ Item {
|
|||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
Item { id: topSpacer; height: (parent.height - historyList.height) / 2 }
|
||||
Item {
|
||||
id: topSpacer
|
||||
height: (parent.height - historyList.height) / 2
|
||||
}
|
||||
ListView {
|
||||
id: historyList
|
||||
width: parent.width
|
||||
|
|
@ -315,7 +301,7 @@ Item {
|
|||
anchors.margins: 14
|
||||
spacing: 6
|
||||
RowLayout {
|
||||
id: headerRow
|
||||
id: headerRow2
|
||||
spacing: 8
|
||||
Rectangle {
|
||||
id: iconBackground
|
||||
|
|
@ -349,14 +335,16 @@ Item {
|
|||
}
|
||||
Text {
|
||||
visible: !model.isPlaceholder
|
||||
text: model.timestamp ? notificationHistoryWin.formatTimestamp(model.timestamp) : ""
|
||||
text: model.timestamp ? notificationHistoryWinRect.formatTimestamp(model.timestamp) : ""
|
||||
color: Theme.textDisabled
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeCaption
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: model.summary || (model.isPlaceholder ? "You're all caught up!" : "")
|
||||
|
|
@ -382,7 +370,11 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Rectangle { width: 1; height: 24; color: "transparent" }
|
||||
Rectangle {
|
||||
width: 1
|
||||
height: 24
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: placeholderModel
|
||||
|
|
@ -396,4 +388,4 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
30
Widgets/Notification/NotificationIcon.qml
Normal file
30
Widgets/Notification/NotificationIcon.qml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Settings
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 22; height: 22
|
||||
|
||||
// Bell icon/button
|
||||
Item {
|
||||
id: bell
|
||||
width: 22; height: 22
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: notificationHistoryWin.hasUnread ? "notifications_unread" : "notifications"
|
||||
font.family: mouseAreaBell.containsMouse ? "Material Symbols Rounded" : "Material Symbols Outlined"
|
||||
font.pixelSize: 16
|
||||
font.weight: notificationHistoryWin.hasUnread ? Font.Bold : Font.Normal
|
||||
color: mouseAreaBell.containsMouse ? Theme.accentPrimary : (notificationHistoryWin.hasUnread ? Theme.accentPrimary : Theme.textDisabled)
|
||||
}
|
||||
MouseArea {
|
||||
id: mouseAreaBell
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: notificationHistoryWin.visible = !notificationHistoryWin.visible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -111,11 +111,7 @@ PanelWindow {
|
|||
border.width: 1.5
|
||||
|
||||
// Get all possible icon sources from notification
|
||||
property var iconSources: [
|
||||
rawNotification?.image || "",
|
||||
rawNotification?.appIcon || "",
|
||||
rawNotification?.icon || ""
|
||||
]
|
||||
property var iconSources: [rawNotification?.image || "", rawNotification?.appIcon || "", rawNotification?.icon || ""]
|
||||
|
||||
// Try to load notification icon
|
||||
Image {
|
||||
|
|
@ -131,7 +127,8 @@ PanelWindow {
|
|||
source: {
|
||||
for (var i = 0; i < iconBackground.iconSources.length; i++) {
|
||||
var icon = iconBackground.iconSources[i];
|
||||
if (!icon) continue;
|
||||
if (!icon)
|
||||
continue;
|
||||
|
||||
if (icon.includes("?path=")) {
|
||||
const [name, path] = icon.split("?path=");
|
||||
|
|
@ -202,7 +199,8 @@ PanelWindow {
|
|||
repeat: false
|
||||
onTriggered: {
|
||||
dismissAnimation.start();
|
||||
if (rawNotification) rawNotification.expire();
|
||||
if (rawNotification)
|
||||
rawNotification.expire();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -210,28 +208,63 @@ PanelWindow {
|
|||
anchors.fill: parent
|
||||
onClicked: {
|
||||
dismissAnimation.start();
|
||||
if (rawNotification) rawNotification.dismiss();
|
||||
if (rawNotification)
|
||||
rawNotification.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: dismissAnimation
|
||||
NumberAnimation { target: notificationDelegate; property: "opacity"; to: 0; duration: 150 }
|
||||
NumberAnimation { target: notificationDelegate; property: "height"; to: 0; duration: 150 }
|
||||
NumberAnimation { target: notificationDelegate; property: "x"; to: width; duration: 150; easing.type: Easing.InQuad }
|
||||
NumberAnimation {
|
||||
target: notificationDelegate
|
||||
property: "opacity"
|
||||
to: 0
|
||||
duration: 150
|
||||
}
|
||||
NumberAnimation {
|
||||
target: notificationDelegate
|
||||
property: "height"
|
||||
to: 0
|
||||
duration: 150
|
||||
}
|
||||
NumberAnimation {
|
||||
target: notificationDelegate
|
||||
property: "x"
|
||||
to: width
|
||||
duration: 150
|
||||
easing.type: Easing.InQuad
|
||||
}
|
||||
onFinished: {
|
||||
var idx = notificationRepeater.indexOf(notificationDelegate);
|
||||
if (idx !== -1) {
|
||||
notificationModel.remove(idx);
|
||||
for (let i = 0; i < notificationModel.count; i++) {
|
||||
if (notificationModel.get(i).id === notificationDelegate.id) {
|
||||
notificationModel.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: appearAnimation
|
||||
NumberAnimation { target: notificationDelegate; property: "opacity"; to: 1; duration: 150 }
|
||||
NumberAnimation { target: notificationDelegate; property: "height"; to: contentRow.height + 20; duration: 150 }
|
||||
NumberAnimation { target: notificationDelegate; property: "x"; to: 0; duration: 150; easing.type: Easing.OutQuad }
|
||||
NumberAnimation {
|
||||
target: notificationDelegate
|
||||
property: "opacity"
|
||||
to: 1
|
||||
duration: 150
|
||||
}
|
||||
NumberAnimation {
|
||||
target: notificationDelegate
|
||||
property: "height"
|
||||
to: contentRow.height + 20
|
||||
duration: 150
|
||||
}
|
||||
NumberAnimation {
|
||||
target: notificationDelegate
|
||||
property: "x"
|
||||
to: 0
|
||||
duration: 150
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
@ -240,18 +273,21 @@ PanelWindow {
|
|||
height = 0;
|
||||
x = width;
|
||||
appearAnimation.start();
|
||||
var idx = notificationRepeater.indexOf(notificationDelegate);
|
||||
if (idx !== -1) {
|
||||
var oldItem = notificationModel.get(idx);
|
||||
notificationModel.set(idx, {
|
||||
id: oldItem.id,
|
||||
appName: oldItem.appName,
|
||||
summary: oldItem.summary,
|
||||
body: oldItem.body,
|
||||
rawNotification: oldItem.rawNotification,
|
||||
appeared: true,
|
||||
dismissed: oldItem.dismissed
|
||||
});
|
||||
for (let i = 0; i < notificationModel.count; i++) {
|
||||
if (notificationModel.get(i).id === notificationDelegate.id) {
|
||||
var oldItem = notificationModel.get(i);
|
||||
notificationModel.set(i, {
|
||||
id: oldItem.id,
|
||||
appName: oldItem.appName,
|
||||
summary: oldItem.summary,
|
||||
body: oldItem.body,
|
||||
rawNotification: oldItem.rawNotification,
|
||||
appeared: true,
|
||||
read: oldItem.read,
|
||||
dismissed: oldItem.dismissed
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -263,7 +299,7 @@ PanelWindow {
|
|||
target: Quickshell
|
||||
function onScreensChanged() {
|
||||
if (window.screen) {
|
||||
x = window.screen.width - width - 20
|
||||
x = window.screen.width - width - 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import qs.Services
|
|||
import qs.Settings
|
||||
|
||||
ShellRoot {
|
||||
property string wallpaperSource: WallpaperManager.currentWallpaper !== "" && !Settings.useSWWW ? WallpaperManager.currentWallpaper : ""
|
||||
property string wallpaperSource: WallpaperManager.currentWallpaper !== "" && !Settings.settings.useSWWW ? WallpaperManager.currentWallpaper : ""
|
||||
PanelWindow {
|
||||
visible: wallpaperSource !== ""
|
||||
anchors {
|
||||
|
|
|
|||
|
|
@ -22,19 +22,6 @@ Item {
|
|||
hoverEnabled: true
|
||||
onClicked: {
|
||||
if (sidebarPopup.visible) {
|
||||
// Close all modals if open
|
||||
if (sidebarPopup.settingsModal && sidebarPopup.settingsModal.visible) {
|
||||
sidebarPopup.settingsModal.visible = false;
|
||||
}
|
||||
if (sidebarPopup.wallpaperPanelModal && sidebarPopup.wallpaperPanelModal.visible) {
|
||||
sidebarPopup.wallpaperPanelModal.visible = false;
|
||||
}
|
||||
if (sidebarPopup.wifiPanelModal && sidebarPopup.wifiPanelModal.visible) {
|
||||
sidebarPopup.wifiPanelModal.visible = false;
|
||||
}
|
||||
if (sidebarPopup.bluetoothPanelModal && sidebarPopup.bluetoothPanelModal.visible) {
|
||||
sidebarPopup.bluetoothPanelModal.visible = false;
|
||||
}
|
||||
sidebarPopup.hidePopup();
|
||||
} else {
|
||||
sidebarPopup.showAt();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import qs.Settings
|
||||
|
||||
ColumnLayout {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import qs.Settings
|
||||
|
||||
|
|
@ -9,19 +9,10 @@ Rectangle {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 340
|
||||
color: Theme.surface
|
||||
Layout.topMargin: 12
|
||||
radius: 18
|
||||
border.color: "transparent"
|
||||
border.width: 0
|
||||
Layout.bottomMargin: 16
|
||||
property bool showActiveWindowIcon: false
|
||||
signal showAWIconChanged(bool showActiveWindowIcon)
|
||||
property bool showSystemInfoInBar: true
|
||||
signal showSystemInfoChanged(bool showSystemInfoInBar)
|
||||
property bool showMediaInBar: false
|
||||
signal showMediaChanged(bool showMediaInBar)
|
||||
property string visualizerType: Settings.visualizerType
|
||||
signal visualizerTypeUpdated(string type)
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
|
@ -66,7 +57,7 @@ Rectangle {
|
|||
id: avatarImage
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
source: Settings.profileImage
|
||||
source: Settings.settings.profileImage
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
visible: false
|
||||
asynchronous: true
|
||||
|
|
@ -83,7 +74,7 @@ Rectangle {
|
|||
radius: avatarImage.width / 2
|
||||
visible: false
|
||||
}
|
||||
visible: Settings.profileImage !== ""
|
||||
visible: Settings.settings.profileImage !== ""
|
||||
}
|
||||
|
||||
// Fallback icon
|
||||
|
|
@ -93,7 +84,7 @@ Rectangle {
|
|||
font.family: "Material Symbols Outlined"
|
||||
font.pixelSize: 18
|
||||
color: Theme.accentPrimary
|
||||
visible: Settings.profileImage === ""
|
||||
visible: Settings.settings.profileImage === ""
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +101,7 @@ Rectangle {
|
|||
id: profileImageInput
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
text: Settings.profileImage
|
||||
text: Settings.settings.profileImage
|
||||
font.pixelSize: 13
|
||||
color: Theme.textPrimary
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
|
|
@ -120,7 +111,7 @@ Rectangle {
|
|||
activeFocusOnTab: true
|
||||
inputMethodHints: Qt.ImhNone
|
||||
onTextChanged: {
|
||||
Settings.profileImage = text
|
||||
Settings.settings.profileImage = text
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
|
@ -154,8 +145,8 @@ Rectangle {
|
|||
width: 52
|
||||
height: 32
|
||||
radius: 16
|
||||
color: showActiveWindowIcon ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: showActiveWindowIcon ? Theme.accentPrimary : Theme.outline
|
||||
color: Settings.settings.showActiveWindowIcon ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: Settings.settings.showActiveWindowIcon ? Theme.accentPrimary : Theme.outline
|
||||
border.width: 2
|
||||
|
||||
Rectangle {
|
||||
|
|
@ -167,7 +158,7 @@ Rectangle {
|
|||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
y: 2
|
||||
x: showActiveWindowIcon ? customSwitch.width - width - 2 : 2
|
||||
x: Settings.settings.showActiveWindowIcon ? customSwitch.width - width - 2 : 2
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||
|
|
@ -177,7 +168,7 @@ Rectangle {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
showAWIconChanged(!showActiveWindowIcon)
|
||||
Settings.settings.showActiveWindowIcon = !Settings.settings.showActiveWindowIcon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -206,8 +197,8 @@ Rectangle {
|
|||
width: 52
|
||||
height: 32
|
||||
radius: 16
|
||||
color: showSystemInfoInBar ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: showSystemInfoInBar ? Theme.accentPrimary : Theme.outline
|
||||
color: Settings.settings.showSystemInfoInBar ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: Settings.settings.showSystemInfoInBar ? Theme.accentPrimary : Theme.outline
|
||||
border.width: 2
|
||||
|
||||
Rectangle {
|
||||
|
|
@ -219,7 +210,7 @@ Rectangle {
|
|||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
y: 2
|
||||
x: showSystemInfoInBar ? customSwitch2.width - width - 2 : 2
|
||||
x: Settings.settings.showSystemInfoInBar ? customSwitch2.width - width - 2 : 2
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||
|
|
@ -229,7 +220,7 @@ Rectangle {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
showSystemInfoChanged(!showSystemInfoInBar)
|
||||
Settings.settings.showSystemInfoInBar = !Settings.settings.showSystemInfoInBar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -258,8 +249,8 @@ Rectangle {
|
|||
width: 52
|
||||
height: 32
|
||||
radius: 16
|
||||
color: showMediaInBar ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: showMediaInBar ? Theme.accentPrimary : Theme.outline
|
||||
color: Settings.settings.showMediaInBar ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: Settings.settings.showMediaInBar ? Theme.accentPrimary : Theme.outline
|
||||
border.width: 2
|
||||
|
||||
Rectangle {
|
||||
|
|
@ -271,7 +262,7 @@ Rectangle {
|
|||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
y: 2
|
||||
x: showMediaInBar ? customSwitch3.width - width - 2 : 2
|
||||
x: Settings.settings.showMediaInBar ? customSwitch3.width - width - 2 : 2
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||
|
|
@ -281,7 +272,7 @@ Rectangle {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
showMediaChanged(!showMediaInBar)
|
||||
Settings.settings.showMediaInBar = !Settings.settings.showMediaInBar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -318,9 +309,9 @@ Rectangle {
|
|||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: visualizerType === "fire" ? "Fire" :
|
||||
visualizerType === "diamond" ? "Diamond" :
|
||||
visualizerType === "radial" ? "Radial" : "Radial"
|
||||
text: Settings.settings.visualizerType === "fire" ? "Fire" :
|
||||
Settings.settings.visualizerType === "diamond" ? "Diamond" :
|
||||
Settings.settings.visualizerType === "radial" ? "Radial" : "Radial"
|
||||
font.pixelSize: 13
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
|
@ -350,19 +341,19 @@ Rectangle {
|
|||
MenuItem {
|
||||
text: "Fire"
|
||||
onTriggered: {
|
||||
visualizerTypeUpdated("fire")
|
||||
Settings.settings.visualizerType = "fire"
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: "Diamond"
|
||||
onTriggered: {
|
||||
visualizerTypeUpdated("diamond")
|
||||
Settings.settings.visualizerType = "diamond"
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: "Radial"
|
||||
onTriggered: {
|
||||
visualizerTypeUpdated("radial")
|
||||
Settings.settings.visualizerType = "radial"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -394,7 +385,7 @@ Rectangle {
|
|||
id: videoPathInput
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
text: Settings.videoPath !== undefined ? Settings.videoPath : ""
|
||||
text: Settings.settings.videoPath !== undefined ? Settings.settings.videoPath : ""
|
||||
font.pixelSize: 13
|
||||
color: Theme.textPrimary
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
|
|
@ -403,7 +394,7 @@ Rectangle {
|
|||
activeFocusOnTab: true
|
||||
inputMethodHints: Qt.ImhUrlCharactersOnly
|
||||
onTextChanged: {
|
||||
Settings.videoPath = text
|
||||
Settings.settings.videoPath = text
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Settings
|
||||
|
|
@ -22,24 +22,6 @@ PanelWindow {
|
|||
//border.width: 1
|
||||
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
||||
|
||||
// Local properties for editing (not saved until apply)
|
||||
property string tempWeatherCity: (Settings.weatherCity !== undefined && Settings.weatherCity !== null) ? Settings.weatherCity : ""
|
||||
property bool tempUseFahrenheit: Settings.useFahrenheit
|
||||
property string tempProfileImage: (Settings.profileImage !== undefined && Settings.profileImage !== null) ? Settings.profileImage : ""
|
||||
property string tempWallpaperFolder: (Settings.wallpaperFolder !== undefined && Settings.wallpaperFolder !== null) ? Settings.wallpaperFolder : ""
|
||||
property bool tempShowActiveWindowIcon: Settings.showActiveWindowIcon
|
||||
property bool tempUseSWWW: Settings.useSWWW
|
||||
property bool tempRandomWallpaper: Settings.randomWallpaper
|
||||
property bool tempUseWallpaperTheme: Settings.useWallpaperTheme
|
||||
property int tempWallpaperInterval: Settings.wallpaperInterval
|
||||
property string tempWallpaperResize: Settings.wallpaperResize
|
||||
property int tempTransitionFps: Settings.transitionFps
|
||||
property string tempTransitionType: Settings.transitionType
|
||||
property real tempTransitionDuration: Settings.transitionDuration
|
||||
property bool tempShowSystemInfoInBar: Settings.showSystemInfoInBar
|
||||
property bool tempShowMediaInBar: Settings.showMediaInBar
|
||||
property string tempVisualizerType: Settings.visualizerType
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Theme.backgroundPrimary
|
||||
|
|
@ -145,14 +127,6 @@ PanelWindow {
|
|||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
anchors.margins: 16
|
||||
weatherCity: (typeof tempWeatherCity !== 'undefined' && tempWeatherCity !== null) ? tempWeatherCity : ""
|
||||
useFahrenheit: tempUseFahrenheit
|
||||
onCityChanged: function (city) {
|
||||
tempWeatherCity = city;
|
||||
}
|
||||
onTemperatureUnitChanged: function (useFahrenheit) {
|
||||
tempUseFahrenheit = useFahrenheit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -164,22 +138,6 @@ PanelWindow {
|
|||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
anchors.margins: 16
|
||||
showActiveWindowIcon: tempShowActiveWindowIcon
|
||||
onShowAWIconChanged: function (showActiveWindowIcon) {
|
||||
tempShowActiveWindowIcon = showActiveWindowIcon;
|
||||
}
|
||||
showSystemInfoInBar: tempShowSystemInfoInBar
|
||||
onShowSystemInfoChanged: function (showSystemInfoInBar) {
|
||||
tempShowSystemInfoInBar = showSystemInfoInBar;
|
||||
}
|
||||
showMediaInBar: tempShowMediaInBar
|
||||
onShowMediaChanged: function (showMediaInBar) {
|
||||
tempShowMediaInBar = showMediaInBar;
|
||||
}
|
||||
visualizerType: tempVisualizerType
|
||||
onVisualizerTypeUpdated: function (type) {
|
||||
tempVisualizerType = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -192,118 +150,15 @@ PanelWindow {
|
|||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
anchors.margins: 16
|
||||
wallpaperFolder: (typeof tempWallpaperFolder !== 'undefined' && tempWallpaperFolder !== null) ? tempWallpaperFolder : ""
|
||||
useSWWW: tempUseSWWW
|
||||
randomWallpaper: tempRandomWallpaper
|
||||
useWallpaperTheme: tempUseWallpaperTheme
|
||||
wallpaperInterval: tempWallpaperInterval
|
||||
wallpaperResize: tempWallpaperResize
|
||||
transitionFps: tempTransitionFps
|
||||
transitionType: tempTransitionType
|
||||
transitionDuration: tempTransitionDuration
|
||||
onWallpaperFolderEdited: function (folder) {
|
||||
tempWallpaperFolder = folder;
|
||||
}
|
||||
onUseSWWWChangedUpdated: function(useSWWW) {
|
||||
tempUseSWWW = useSWWW;
|
||||
}
|
||||
onRandomWallpaperChangedUpdated: function(randomWallpaper) {
|
||||
tempRandomWallpaper = randomWallpaper;
|
||||
}
|
||||
onUseWallpaperThemeChangedUpdated: function(useWallpaperTheme) {
|
||||
tempUseWallpaperTheme = useWallpaperTheme;
|
||||
}
|
||||
onWallpaperIntervalChangedUpdated: function(wallpaperInterval) {
|
||||
tempWallpaperInterval = wallpaperInterval;
|
||||
}
|
||||
onWallpaperResizeChangedUpdated: function(resize) {
|
||||
tempWallpaperResize = resize;
|
||||
}
|
||||
onTransitionFpsChangedUpdated: function(fps) {
|
||||
tempTransitionFps = fps;
|
||||
}
|
||||
onTransitionTypeChangedUpdated: function(type) {
|
||||
tempTransitionType = type;
|
||||
}
|
||||
onTransitionDurationChangedUpdated: function(duration) {
|
||||
tempTransitionDuration = duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Button
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 52
|
||||
radius: 16
|
||||
color: applyButtonArea.containsMouse ? Theme.accentPrimary : Theme.accentPrimary
|
||||
border.color: "transparent"
|
||||
border.width: 0
|
||||
opacity: 1.0
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "Apply Changes"
|
||||
font.pixelSize: 17
|
||||
font.bold: true
|
||||
color: applyButtonArea.containsMouse ? Theme.onAccent : Theme.onAccent
|
||||
}
|
||||
MouseArea {
|
||||
id: applyButtonArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
Settings.weatherCity = (typeof tempWeatherCity !== 'undefined' && tempWeatherCity !== null) ? tempWeatherCity : "";
|
||||
Settings.useFahrenheit = tempUseFahrenheit;
|
||||
Settings.profileImage = (typeof tempProfileImage !== 'undefined' && tempProfileImage !== null) ? tempProfileImage : "";
|
||||
Settings.wallpaperFolder = (typeof tempWallpaperFolder !== 'undefined' && tempWallpaperFolder !== null) ? tempWallpaperFolder : "";
|
||||
Settings.showActiveWindowIcon = tempShowActiveWindowIcon;
|
||||
Settings.useSWWW = tempUseSWWW;
|
||||
Settings.randomWallpaper = tempRandomWallpaper;
|
||||
Settings.useWallpaperTheme = tempUseWallpaperTheme;
|
||||
Settings.wallpaperInterval = tempWallpaperInterval;
|
||||
Settings.wallpaperResize = tempWallpaperResize;
|
||||
Settings.transitionFps = tempTransitionFps;
|
||||
Settings.transitionType = tempTransitionType;
|
||||
Settings.transitionDuration = tempTransitionDuration;
|
||||
Settings.showSystemInfoInBar = tempShowSystemInfoInBar;
|
||||
Settings.showMediaInBar = tempShowMediaInBar;
|
||||
Settings.visualizerType = tempVisualizerType;
|
||||
Settings.saveSettings();
|
||||
if (typeof weather !== 'undefined' && weather) {
|
||||
weather.fetchCityWeather();
|
||||
}
|
||||
settingsModal.closeSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function to open the modal and initialize temp values
|
||||
function openSettings() {
|
||||
tempWeatherCity = (Settings.weatherCity !== undefined && Settings.weatherCity !== null) ? Settings.weatherCity : "";
|
||||
tempUseFahrenheit = Settings.useFahrenheit;
|
||||
tempShowActiveWindowIcon = Settings.showActiveWindowIcon;
|
||||
tempProfileImage = (Settings.profileImage !== undefined && Settings.profileImage !== null) ? Settings.profileImage : "";
|
||||
tempWallpaperFolder = (Settings.wallpaperFolder !== undefined && Settings.wallpaperFolder !== null) ? Settings.wallpaperFolder : "";
|
||||
if (tempWallpaperFolder === undefined || tempWallpaperFolder === null)
|
||||
tempWallpaperFolder = "";
|
||||
|
||||
// Initialize wallpaper settings
|
||||
tempUseSWWW = Settings.useSWWW;
|
||||
tempRandomWallpaper = Settings.randomWallpaper;
|
||||
tempUseWallpaperTheme = Settings.useWallpaperTheme;
|
||||
tempWallpaperInterval = Settings.wallpaperInterval;
|
||||
tempWallpaperResize = Settings.wallpaperResize;
|
||||
tempTransitionFps = Settings.transitionFps;
|
||||
tempTransitionType = Settings.transitionType;
|
||||
tempTransitionDuration = Settings.transitionDuration;
|
||||
tempShowSystemInfoInBar = Settings.showSystemInfoInBar;
|
||||
tempShowMediaInBar = Settings.showMediaInBar;
|
||||
tempVisualizerType = Settings.visualizerType;
|
||||
|
||||
function openSettings() {
|
||||
visible = true;
|
||||
// Force focus on the text input after a short delay
|
||||
focusTimer.start();
|
||||
|
|
|
|||
|
|
@ -1,35 +1,15 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import qs.Settings
|
||||
|
||||
Rectangle {
|
||||
id: wallpaperSettingsCard
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 680
|
||||
Layout.topMargin: 12
|
||||
color: Theme.surface
|
||||
radius: 18
|
||||
|
||||
// Property for binding
|
||||
property string wallpaperFolder: ""
|
||||
signal wallpaperFolderEdited(string folder)
|
||||
property bool useSWWW: false
|
||||
signal useSWWWChangedUpdated(bool useSWWW)
|
||||
property bool randomWallpaper: false
|
||||
signal randomWallpaperChangedUpdated(bool randomWallpaper)
|
||||
property bool useWallpaperTheme: false
|
||||
signal useWallpaperThemeChangedUpdated(bool useWallpaperTheme)
|
||||
property int wallpaperInterval: 300
|
||||
signal wallpaperIntervalChangedUpdated(int wallpaperInterval)
|
||||
property string wallpaperResize: "crop"
|
||||
signal wallpaperResizeChangedUpdated(string resize)
|
||||
property int transitionFps: 60
|
||||
signal transitionFpsChangedUpdated(int fps)
|
||||
property string transitionType: "random"
|
||||
signal transitionTypeChangedUpdated(string type)
|
||||
property real transitionDuration: 1.1
|
||||
signal transitionDurationChangedUpdated(real duration)
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
|
@ -74,7 +54,7 @@ Rectangle {
|
|||
anchors.rightMargin: 12
|
||||
anchors.topMargin: 6
|
||||
anchors.bottomMargin: 6
|
||||
text: wallpaperFolder
|
||||
text: Settings.settings.wallpaperFolder
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 13
|
||||
color: Theme.textPrimary
|
||||
|
|
@ -84,7 +64,7 @@ Rectangle {
|
|||
activeFocusOnTab: true
|
||||
inputMethodHints: Qt.ImhUrlCharactersOnly
|
||||
onTextChanged: {
|
||||
wallpaperFolderEdited(text)
|
||||
Settings.settings.wallpaperFolder = text
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
|
@ -116,8 +96,8 @@ Rectangle {
|
|||
width: 52
|
||||
height: 32
|
||||
radius: 16
|
||||
color: useSWWW ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: useSWWW ? Theme.accentPrimary : Theme.outline
|
||||
color: Settings.settings.useSWWW ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: Settings.settings.useSWWW ? Theme.accentPrimary : Theme.outline
|
||||
border.width: 2
|
||||
|
||||
Rectangle {
|
||||
|
|
@ -129,7 +109,7 @@ Rectangle {
|
|||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
y: 2
|
||||
x: useSWWW ? swwwSwitch.width - width - 2 : 2
|
||||
x: Settings.settings.useSWWW ? swwwSwitch.width - width - 2 : 2
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||
|
|
@ -139,7 +119,7 @@ Rectangle {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
useSWWWChangedUpdated(!useSWWW)
|
||||
Settings.settings.useSWWW = !Settings.settings.useSWWW
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -168,8 +148,8 @@ Rectangle {
|
|||
width: 52
|
||||
height: 32
|
||||
radius: 16
|
||||
color: randomWallpaper ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: randomWallpaper ? Theme.accentPrimary : Theme.outline
|
||||
color: Settings.settings.randomWallpaper ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: Settings.settings.randomWallpaper ? Theme.accentPrimary : Theme.outline
|
||||
border.width: 2
|
||||
|
||||
Rectangle {
|
||||
|
|
@ -181,7 +161,7 @@ Rectangle {
|
|||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
y: 2
|
||||
x: randomWallpaper ? randomWallpaperSwitch.width - width - 2 : 2
|
||||
x: Settings.settings.randomWallpaper ? randomWallpaperSwitch.width - width - 2 : 2
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||
|
|
@ -191,7 +171,7 @@ Rectangle {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
randomWallpaperChangedUpdated(!randomWallpaper)
|
||||
Settings.settings.randomWallpaper = !Settings.settings.randomWallpaper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -220,8 +200,8 @@ Rectangle {
|
|||
width: 52
|
||||
height: 32
|
||||
radius: 16
|
||||
color: useWallpaperTheme ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: useWallpaperTheme ? Theme.accentPrimary : Theme.outline
|
||||
color: Settings.settings.useWallpaperTheme ? Theme.accentPrimary : Theme.surfaceVariant
|
||||
border.color: Settings.settings.useWallpaperTheme ? Theme.accentPrimary : Theme.outline
|
||||
border.width: 2
|
||||
|
||||
Rectangle {
|
||||
|
|
@ -233,7 +213,7 @@ Rectangle {
|
|||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
y: 2
|
||||
x: useWallpaperTheme ? wallpaperThemeSwitch.width - width - 2 : 2
|
||||
x: Settings.settings.useWallpaperTheme ? wallpaperThemeSwitch.width - width - 2 : 2
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||
|
|
@ -243,7 +223,7 @@ Rectangle {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
useWallpaperThemeChangedUpdated(!useWallpaperTheme)
|
||||
Settings.settings.useWallpaperTheme = !Settings.settings.useWallpaperTheme
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -269,7 +249,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
Text {
|
||||
text: wallpaperInterval
|
||||
text: Settings.settings.wallpaperInterval
|
||||
font.pixelSize: 13
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
|
@ -281,7 +261,7 @@ Rectangle {
|
|||
from: 10
|
||||
to: 900
|
||||
stepSize: 10
|
||||
value: wallpaperInterval
|
||||
value: Settings.settings.wallpaperInterval
|
||||
snapMode: Slider.SnapAlways
|
||||
|
||||
background: Rectangle {
|
||||
|
|
@ -314,7 +294,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onMoved: {
|
||||
wallpaperIntervalChangedUpdated(Math.round(value))
|
||||
Settings.settings.wallpaperInterval = Math.round(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -337,7 +317,7 @@ Rectangle {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40
|
||||
model: ["no", "crop", "fit", "stretch"]
|
||||
currentIndex: model.indexOf(wallpaperResize)
|
||||
currentIndex: model.indexOf(Settings.settings.wallpaperResize)
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 120
|
||||
|
|
@ -409,7 +389,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onActivated: {
|
||||
wallpaperResizeChangedUpdated(model[index])
|
||||
Settings.settings.wallpaperResize = model[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -432,7 +412,7 @@ Rectangle {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40
|
||||
model: ["none", "simple", "fade", "left", "right", "top", "bottom", "wipe", "wave", "grow", "center", "any", "outer", "random"]
|
||||
currentIndex: model.indexOf(transitionType)
|
||||
currentIndex: model.indexOf(Settings.settings.transitionType)
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 120
|
||||
|
|
@ -504,7 +484,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onActivated: {
|
||||
transitionTypeChangedUpdated(model[index])
|
||||
Settings.settings.transitionType = model[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -529,7 +509,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
Text {
|
||||
text: transitionFps
|
||||
text: Settings.settings.transitionFps
|
||||
font.pixelSize: 13
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
|
@ -541,7 +521,7 @@ Rectangle {
|
|||
from: 30
|
||||
to: 500
|
||||
stepSize: 5
|
||||
value: transitionFps
|
||||
value: Settings.settings.transitionFps
|
||||
snapMode: Slider.SnapAlways
|
||||
|
||||
background: Rectangle {
|
||||
|
|
@ -574,7 +554,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onMoved: {
|
||||
transitionFpsChangedUpdated(Math.round(value))
|
||||
Settings.settings.transitionFps = Math.round(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -599,7 +579,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
Text {
|
||||
text: transitionDuration.toFixed(3)
|
||||
text: Settings.settings.transitionDuration.toFixed(3)
|
||||
font.pixelSize: 13
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
|
@ -611,7 +591,7 @@ Rectangle {
|
|||
from: 0.250
|
||||
to: 10.0
|
||||
stepSize: 0.050
|
||||
value: transitionDuration
|
||||
value: Settings.settings.transitionDuration
|
||||
snapMode: Slider.SnapAlways
|
||||
|
||||
background: Rectangle {
|
||||
|
|
@ -644,7 +624,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onMoved: {
|
||||
transitionDurationChangedUpdated(value)
|
||||
Settings.settings.transitionDuration = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,14 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Settings
|
||||
|
||||
Rectangle {
|
||||
id: weatherSettingsCard
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 180
|
||||
Layout.topMargin: 12
|
||||
color: Theme.surface
|
||||
radius: 18
|
||||
|
||||
// Properties for binding
|
||||
property string weatherCity: ""
|
||||
property bool useFahrenheit: false
|
||||
|
||||
signal cityChanged(string city)
|
||||
signal temperatureUnitChanged(bool useFahrenheit)
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 18
|
||||
|
|
@ -76,7 +67,7 @@ Rectangle {
|
|||
anchors.rightMargin: 12
|
||||
anchors.topMargin: 6
|
||||
anchors.bottomMargin: 6
|
||||
text: weatherCity
|
||||
text: Settings.settings.weatherCity
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 13
|
||||
color: Theme.textPrimary
|
||||
|
|
@ -88,7 +79,7 @@ Rectangle {
|
|||
inputMethodHints: Qt.ImhNone
|
||||
|
||||
onTextChanged: {
|
||||
cityChanged(text)
|
||||
Settings.settings.weatherCity = text
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
|
@ -137,11 +128,11 @@ Rectangle {
|
|||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
y: 2
|
||||
x: useFahrenheit ? customSwitch.width - width - 2 : 2
|
||||
x: Settings.settings.useFahrenheit ? customSwitch.width - width - 2 : 2
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: useFahrenheit ? "\u00b0F" : "\u00b0C"
|
||||
text: Settings.settings.useFahrenheit ? "\u00b0F" : "\u00b0C"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 12
|
||||
font.bold: true
|
||||
|
|
@ -156,7 +147,7 @@ Rectangle {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
temperatureUnitChanged(!useFahrenheit)
|
||||
Settings.settings.useFahrenheit = !Settings.settings.useFahrenheit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell.Wayland
|
||||
import Quickshell
|
||||
import Quickshell.Bluetooth
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import qs.Settings
|
||||
import qs.Components
|
||||
|
|
|
|||
|
|
@ -7,386 +7,422 @@ import qs.Settings
|
|||
import qs.Widgets.Sidebar.Config
|
||||
import qs.Components
|
||||
|
||||
PanelWindow {
|
||||
id: panelPopup
|
||||
implicitWidth: 500
|
||||
implicitHeight: 800
|
||||
visible: false
|
||||
color: "transparent"
|
||||
screen: modelData
|
||||
anchors.top: true
|
||||
anchors.right: true
|
||||
margins.top: 0
|
||||
WlrLayershell.keyboardFocus: (settingsModal.visible && mouseArea.containsMouse) ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
|
||||
// Animation properties
|
||||
property real slideOffset: width
|
||||
property bool isAnimating: false
|
||||
PanelWithOverlay {
|
||||
id: sidebarPopup
|
||||
|
||||
function showAt() {
|
||||
if (!visible) {
|
||||
visible = true;
|
||||
forceActiveFocus();
|
||||
slideAnim.from = width;
|
||||
slideAnim.to = 0;
|
||||
slideAnim.running = true;
|
||||
if (weather) weather.startWeatherFetch();
|
||||
if (systemWidget) systemWidget.panelVisible = true;
|
||||
if (quickAccessWidget) quickAccessWidget.panelVisible = true;
|
||||
}
|
||||
sidebarPopupRect.showAt();
|
||||
}
|
||||
|
||||
function hidePopup() {
|
||||
if (visible) {
|
||||
slideAnim.from = 0;
|
||||
slideAnim.to = width;
|
||||
slideAnim.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: slideAnim
|
||||
target: panelPopup
|
||||
property: "slideOffset"
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
|
||||
onStopped: {
|
||||
if (panelPopup.slideOffset === panelPopup.width) {
|
||||
panelPopup.visible = false;
|
||||
// Stop monitoring and background tasks when hidden
|
||||
if (weather) weather.stopWeatherFetch();
|
||||
if (systemWidget) systemWidget.panelVisible = false;
|
||||
if (quickAccessWidget) quickAccessWidget.panelVisible = false;
|
||||
}
|
||||
panelPopup.isAnimating = false;
|
||||
}
|
||||
|
||||
onStarted: {
|
||||
panelPopup.isAnimating = true;
|
||||
}
|
||||
sidebarPopupRect.hidePopup();
|
||||
}
|
||||
|
||||
property int leftPadding: 20
|
||||
property int bottomPadding: 20
|
||||
function show() {
|
||||
sidebarPopupRect.showAt();
|
||||
}
|
||||
|
||||
function dismiss() {
|
||||
sidebarPopupRect.hidePopup();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: mainRectangle
|
||||
width: parent.width - leftPadding
|
||||
height: parent.height - bottomPadding
|
||||
id: sidebarPopupRect
|
||||
implicitWidth: 500
|
||||
implicitHeight: 800
|
||||
visible: parent.visible
|
||||
color: "transparent"
|
||||
anchors.top: parent.top
|
||||
x: leftPadding + slideOffset
|
||||
y: 0
|
||||
color: Theme.backgroundPrimary
|
||||
bottomLeftRadius: 20
|
||||
z: 0
|
||||
|
||||
Behavior on x {
|
||||
enabled: !panelPopup.isAnimating
|
||||
NumberAnimation { duration: 300; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
anchors.right: parent.right
|
||||
|
||||
property alias settingsModal: settingsModal
|
||||
property alias wallpaperPanelModal: wallpaperPanelModal
|
||||
property alias wifiPanelModal: wifiPanel.panel
|
||||
property alias bluetoothPanelModal: bluetoothPanel.panel
|
||||
SettingsModal {
|
||||
id: settingsModal
|
||||
}
|
||||
// Animation properties
|
||||
property real slideOffset: width
|
||||
property bool isAnimating: false
|
||||
|
||||
Item {
|
||||
anchors.fill: mainRectangle
|
||||
x: slideOffset
|
||||
|
||||
Behavior on x {
|
||||
enabled: !panelPopup.isAnimating
|
||||
NumberAnimation { duration: 300; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
spacing: 16
|
||||
|
||||
System {
|
||||
id: systemWidget
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
z: 3
|
||||
function showAt() {
|
||||
if (!sidebarPopup.visible) {
|
||||
sidebarPopup.visible = true;
|
||||
forceActiveFocus();
|
||||
slideAnim.from = width;
|
||||
slideAnim.to = 0;
|
||||
slideAnim.running = true;
|
||||
if (weather)
|
||||
weather.startWeatherFetch();
|
||||
if (systemWidget)
|
||||
systemWidget.panelVisible = true;
|
||||
if (quickAccessWidget)
|
||||
quickAccessWidget.panelVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
Weather {
|
||||
id: weather
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
z: 2
|
||||
function hidePopup() {
|
||||
if (sidebarPopupRect.settingsModal && sidebarPopupRect.settingsModal.visible) {
|
||||
sidebarPopupRect.settingsModal.visible = false;
|
||||
}
|
||||
|
||||
// Music and System Monitor row
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Music {
|
||||
z: 2
|
||||
if (sidebarPopupRect.wallpaperPanelModal && sidebarPopupRect.wallpaperPanelModal.visible) {
|
||||
sidebarPopupRect.wallpaperPanelModal.visible = false;
|
||||
}
|
||||
if (sidebarPopupRect.wifiPanelModal && sidebarPopupRect.wifiPanelModal.visible) {
|
||||
sidebarPopupRect.wifiPanelModal.visible = false;
|
||||
}
|
||||
if (sidebarPopupRect.bluetoothPanelModal && sidebarPopupRect.bluetoothPanelModal.visible) {
|
||||
sidebarPopupRect.bluetoothPanelModal.visible = false;
|
||||
}
|
||||
if (sidebarPopup.visible) {
|
||||
slideAnim.from = 0;
|
||||
slideAnim.to = width;
|
||||
slideAnim.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
SystemMonitor {
|
||||
id: systemMonitor
|
||||
z: 2
|
||||
NumberAnimation {
|
||||
id: slideAnim
|
||||
target: sidebarPopupRect
|
||||
property: "slideOffset"
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
|
||||
onStopped: {
|
||||
if (sidebarPopupRect.slideOffset === sidebarPopupRect.width) {
|
||||
sidebarPopup.visible = false;
|
||||
// Stop monitoring and background tasks when hidden
|
||||
if (weather)
|
||||
weather.stopWeatherFetch();
|
||||
if (systemWidget)
|
||||
systemWidget.panelVisible = false;
|
||||
if (quickAccessWidget)
|
||||
quickAccessWidget.panelVisible = false;
|
||||
}
|
||||
sidebarPopupRect.isAnimating = false;
|
||||
}
|
||||
|
||||
onStarted: {
|
||||
sidebarPopupRect.isAnimating = true;
|
||||
}
|
||||
}
|
||||
|
||||
property int leftPadding: 20
|
||||
property int bottomPadding: 20
|
||||
|
||||
Rectangle {
|
||||
id: mainRectangle
|
||||
width: sidebarPopupRect.width - sidebarPopupRect.leftPadding
|
||||
height: sidebarPopupRect.height - sidebarPopupRect.bottomPadding
|
||||
anchors.top: sidebarPopupRect.top
|
||||
x: sidebarPopupRect.leftPadding + sidebarPopupRect.slideOffset
|
||||
y: 0
|
||||
color: Theme.backgroundPrimary
|
||||
bottomLeftRadius: 20
|
||||
z: 0
|
||||
|
||||
Behavior on x {
|
||||
enabled: !sidebarPopupRect.isAnimating
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property alias settingsModal: settingsModal
|
||||
property alias wallpaperPanelModal: wallpaperPanelModal
|
||||
property alias wifiPanelModal: wifiPanel.panel
|
||||
property alias bluetoothPanelModal: bluetoothPanel.panel
|
||||
SettingsModal {
|
||||
id: settingsModal
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: mainRectangle
|
||||
x: sidebarPopupRect.slideOffset
|
||||
|
||||
Behavior on x {
|
||||
enabled: !sidebarPopupRect.isAnimating
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
// Power profile, Wifi and Bluetooth row
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.preferredHeight: 80
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
spacing: 16
|
||||
z: 3
|
||||
|
||||
PowerProfile {
|
||||
System {
|
||||
id: systemWidget
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
z: 3
|
||||
}
|
||||
|
||||
Weather {
|
||||
id: weather
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
z: 2
|
||||
}
|
||||
|
||||
// Music and System Monitor row
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Music {
|
||||
z: 2
|
||||
}
|
||||
|
||||
SystemMonitor {
|
||||
id: systemMonitor
|
||||
z: 2
|
||||
}
|
||||
}
|
||||
|
||||
// Power profile, Wifi and Bluetooth row
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.preferredHeight: 80
|
||||
}
|
||||
spacing: 16
|
||||
z: 3
|
||||
|
||||
// Network card containing Wifi and Bluetooth
|
||||
Rectangle {
|
||||
Layout.preferredHeight: 80
|
||||
Layout.preferredWidth: 140
|
||||
Layout.fillWidth: false
|
||||
color: Theme.surface
|
||||
radius: 18
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 20
|
||||
|
||||
// Wifi button
|
||||
Rectangle {
|
||||
id: wifiButton
|
||||
width: 36; height: 36
|
||||
radius: 18
|
||||
border.color: Theme.accentPrimary
|
||||
border.width: 1
|
||||
color: wifiButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
|
||||
PowerProfile {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.preferredHeight: 80
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "wifi"
|
||||
font.family: "Material Symbols Outlined"
|
||||
font.pixelSize: 22
|
||||
color: wifiButtonArea.containsMouse
|
||||
? Theme.backgroundPrimary
|
||||
: Theme.accentPrimary
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
// Network card containing Wifi and Bluetooth
|
||||
Rectangle {
|
||||
Layout.preferredHeight: 80
|
||||
Layout.preferredWidth: 140
|
||||
Layout.fillWidth: false
|
||||
color: Theme.surface
|
||||
radius: 18
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 20
|
||||
|
||||
// Wifi button
|
||||
Rectangle {
|
||||
id: wifiButton
|
||||
width: 36
|
||||
height: 36
|
||||
radius: 18
|
||||
border.color: Theme.accentPrimary
|
||||
border.width: 1
|
||||
color: wifiButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "wifi"
|
||||
font.family: "Material Symbols Outlined"
|
||||
font.pixelSize: 22
|
||||
color: wifiButtonArea.containsMouse ? Theme.backgroundPrimary : Theme.accentPrimary
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wifiButtonArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: wifiPanel.showAt()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wifiButtonArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: wifiPanel.showAt()
|
||||
}
|
||||
}
|
||||
|
||||
// Bluetooth button
|
||||
Rectangle {
|
||||
id: bluetoothButton
|
||||
width: 36; height: 36
|
||||
radius: 18
|
||||
border.color: Theme.accentPrimary
|
||||
border.width: 1
|
||||
color: bluetoothButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
|
||||
// Bluetooth button
|
||||
Rectangle {
|
||||
id: bluetoothButton
|
||||
width: 36
|
||||
height: 36
|
||||
radius: 18
|
||||
border.color: Theme.accentPrimary
|
||||
border.width: 1
|
||||
color: bluetoothButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "bluetooth"
|
||||
font.family: "Material Symbols Outlined"
|
||||
font.pixelSize: 22
|
||||
color: bluetoothButtonArea.containsMouse
|
||||
? Theme.backgroundPrimary
|
||||
: Theme.accentPrimary
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "bluetooth"
|
||||
font.family: "Material Symbols Outlined"
|
||||
font.pixelSize: 22
|
||||
color: bluetoothButtonArea.containsMouse ? Theme.backgroundPrimary : Theme.accentPrimary
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: bluetoothButtonArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: bluetoothPanel.showAt()
|
||||
MouseArea {
|
||||
id: bluetoothButtonArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: bluetoothPanel.showAt()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hidden panel components for modal functionality
|
||||
WifiPanel {
|
||||
id: wifiPanel
|
||||
visible: false
|
||||
}
|
||||
BluetoothPanel {
|
||||
id: bluetoothPanel
|
||||
visible: false
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
// QuickAccess widget
|
||||
QuickAccess {
|
||||
id: quickAccessWidget
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: -16
|
||||
z: 2
|
||||
isRecording: sidebarPopupRect.isRecording
|
||||
|
||||
onRecordingRequested: {
|
||||
startRecording();
|
||||
}
|
||||
|
||||
onStopRecordingRequested: {
|
||||
stopRecording();
|
||||
}
|
||||
|
||||
onRecordingStateMismatch: function (actualState) {
|
||||
isRecording = actualState;
|
||||
quickAccessWidget.isRecording = actualState;
|
||||
}
|
||||
|
||||
onSettingsRequested: {
|
||||
settingsModal.visible = true;
|
||||
}
|
||||
onWallpaperRequested: {
|
||||
wallpaperPanelModal.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Keys.onEscapePressed: sidebarPopupRect.hidePopup()
|
||||
}
|
||||
|
||||
// Recording properties
|
||||
property bool isRecording: false
|
||||
property var recordingProcess: null
|
||||
property var recordingPid: null
|
||||
|
||||
// Start screen recording
|
||||
function startRecording() {
|
||||
var currentDate = new Date();
|
||||
var hours = String(currentDate.getHours()).padStart(2, '0');
|
||||
var minutes = String(currentDate.getMinutes()).padStart(2, '0');
|
||||
var day = String(currentDate.getDate()).padStart(2, '0');
|
||||
var month = String(currentDate.getMonth() + 1).padStart(2, '0');
|
||||
var year = currentDate.getFullYear();
|
||||
|
||||
var filename = hours + "-" + minutes + "-" + day + "-" + month + "-" + year + ".mp4";
|
||||
var outputPath = Settings.settings.videoPath + filename;
|
||||
var command = "gpu-screen-recorder -w portal -f 60 -a default_output -o " + outputPath;
|
||||
var qmlString = 'import Quickshell.Io; Process { command: ["sh", "-c", "' + command + '"]; running: true }';
|
||||
|
||||
recordingProcess = Qt.createQmlObject(qmlString, sidebarPopup);
|
||||
isRecording = true;
|
||||
quickAccessWidget.isRecording = true;
|
||||
}
|
||||
|
||||
// Stop recording with cleanup
|
||||
function stopRecording() {
|
||||
if (recordingProcess && isRecording) {
|
||||
var stopQmlString = 'import Quickshell.Io; Process { command: ["sh", "-c", "pkill -SIGINT -f \'gpu-screen-recorder.*portal\'"]; running: true; onExited: function() { destroy() } }';
|
||||
|
||||
var stopProcess = Qt.createQmlObject(stopQmlString, sidebarPopup);
|
||||
|
||||
var cleanupTimer = Qt.createQmlObject('import QtQuick; Timer { interval: 3000; running: true; repeat: false }', sidebarPopup);
|
||||
cleanupTimer.triggered.connect(function () {
|
||||
if (recordingProcess) {
|
||||
recordingProcess.running = false;
|
||||
recordingProcess.destroy();
|
||||
recordingProcess = null;
|
||||
}
|
||||
|
||||
var forceKillQml = 'import Quickshell.Io; Process { command: ["sh", "-c", "pkill -9 -f \'gpu-screen-recorder.*portal\' 2>/dev/null || true"]; running: true; onExited: function() { destroy() } }';
|
||||
var forceKillProcess = Qt.createQmlObject(forceKillQml, sidebarPopup);
|
||||
|
||||
cleanupTimer.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
// Hidden panel components for modal functionality
|
||||
WifiPanel {
|
||||
id: wifiPanel
|
||||
visible: false
|
||||
}
|
||||
BluetoothPanel {
|
||||
id: bluetoothPanel
|
||||
visible: false
|
||||
}
|
||||
isRecording = false;
|
||||
quickAccessWidget.isRecording = false;
|
||||
recordingPid = null;
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
// Clean up processes on destruction
|
||||
Component.onDestruction: {
|
||||
if (isRecording) {
|
||||
stopRecording();
|
||||
}
|
||||
if (recordingProcess) {
|
||||
recordingProcess.running = false;
|
||||
recordingProcess.destroy();
|
||||
recordingProcess = null;
|
||||
}
|
||||
}
|
||||
|
||||
// QuickAccess widget
|
||||
QuickAccess {
|
||||
id: quickAccessWidget
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: -16
|
||||
z: 2
|
||||
isRecording: panelPopup.isRecording
|
||||
|
||||
onRecordingRequested: {
|
||||
startRecording()
|
||||
}
|
||||
|
||||
onStopRecordingRequested: {
|
||||
stopRecording()
|
||||
}
|
||||
|
||||
onRecordingStateMismatch: function(actualState) {
|
||||
isRecording = actualState
|
||||
quickAccessWidget.isRecording = actualState
|
||||
}
|
||||
|
||||
onSettingsRequested: {
|
||||
settingsModal.visible = true
|
||||
}
|
||||
onWallpaperRequested: {
|
||||
wallpaperPanelModal.visible = true
|
||||
Corners {
|
||||
id: sidebarCornerLeft
|
||||
position: "bottomright"
|
||||
size: 1.1
|
||||
fillColor: Theme.backgroundPrimary
|
||||
anchors.top: mainRectangle.top
|
||||
offsetX: -447 + sidebarPopupRect.slideOffset
|
||||
offsetY: 0
|
||||
|
||||
Behavior on offsetX {
|
||||
enabled: !sidebarPopupRect.isAnimating
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
Keys.onEscapePressed: panelPopup.hidePopup()
|
||||
}
|
||||
|
||||
onVisibleChanged: if (!visible) {/* cleanup if needed */}
|
||||
|
||||
// Update height when screen changes
|
||||
onScreenChanged: {
|
||||
if (screen) {
|
||||
// Height is now hardcoded to 720, no need to update
|
||||
}
|
||||
}
|
||||
|
||||
// Recording properties
|
||||
property bool isRecording: false
|
||||
property var recordingProcess: null
|
||||
property var recordingPid: null
|
||||
|
||||
// Start screen recording
|
||||
function startRecording() {
|
||||
var currentDate = new Date()
|
||||
var hours = String(currentDate.getHours()).padStart(2, '0')
|
||||
var minutes = String(currentDate.getMinutes()).padStart(2, '0')
|
||||
var day = String(currentDate.getDate()).padStart(2, '0')
|
||||
var month = String(currentDate.getMonth() + 1).padStart(2, '0')
|
||||
var year = currentDate.getFullYear()
|
||||
Corners {
|
||||
id: sidebarCornerBottom
|
||||
position: "bottomright"
|
||||
size: 1.1
|
||||
fillColor: Theme.backgroundPrimary
|
||||
offsetX: 33 + sidebarPopupRect.slideOffset
|
||||
offsetY: 46
|
||||
|
||||
var filename = hours + "-" + minutes + "-" + day + "-" + month + "-" + year + ".mp4"
|
||||
var outputPath = Settings.videoPath + filename
|
||||
var command = "gpu-screen-recorder -w portal -f 60 -a default_output -o " + outputPath
|
||||
var qmlString = 'import Quickshell.Io; Process { command: ["sh", "-c", "' + command + '"]; running: true }'
|
||||
|
||||
recordingProcess = Qt.createQmlObject(qmlString, panelPopup)
|
||||
isRecording = true
|
||||
quickAccessWidget.isRecording = true
|
||||
}
|
||||
|
||||
// Stop recording with cleanup
|
||||
function stopRecording() {
|
||||
if (recordingProcess && isRecording) {
|
||||
var stopQmlString = 'import Quickshell.Io; Process { command: ["sh", "-c", "pkill -SIGINT -f \'gpu-screen-recorder.*portal\'"]; running: true; onExited: function() { destroy() } }'
|
||||
|
||||
var stopProcess = Qt.createQmlObject(stopQmlString, panelPopup)
|
||||
|
||||
var cleanupTimer = Qt.createQmlObject('import QtQuick; Timer { interval: 3000; running: true; repeat: false }', panelPopup)
|
||||
cleanupTimer.triggered.connect(function() {
|
||||
if (recordingProcess) {
|
||||
recordingProcess.running = false
|
||||
recordingProcess.destroy()
|
||||
recordingProcess = null
|
||||
Behavior on offsetX {
|
||||
enabled: !sidebarPopupRect.isAnimating
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
var forceKillQml = 'import Quickshell.Io; Process { command: ["sh", "-c", "pkill -9 -f \'gpu-screen-recorder.*portal\' 2>/dev/null || true"]; running: true; onExited: function() { destroy() } }'
|
||||
var forceKillProcess = Qt.createQmlObject(forceKillQml, panelPopup)
|
||||
|
||||
cleanupTimer.destroy()
|
||||
})
|
||||
}
|
||||
|
||||
isRecording = false
|
||||
quickAccessWidget.isRecording = false
|
||||
recordingPid = null
|
||||
}
|
||||
|
||||
// Clean up processes on destruction
|
||||
Component.onDestruction: {
|
||||
if (isRecording) {
|
||||
stopRecording()
|
||||
}
|
||||
if (recordingProcess) {
|
||||
recordingProcess.running = false
|
||||
recordingProcess.destroy()
|
||||
recordingProcess = null
|
||||
}
|
||||
}
|
||||
|
||||
Corners {
|
||||
id: sidebarCornerLeft
|
||||
position: "bottomright"
|
||||
size: 1.1
|
||||
fillColor: Theme.backgroundPrimary
|
||||
anchors.top: mainRectangle.top
|
||||
offsetX: -447 + panelPopup.slideOffset
|
||||
offsetY: 0
|
||||
|
||||
Behavior on offsetX {
|
||||
enabled: !panelPopup.isAnimating
|
||||
NumberAnimation { duration: 300; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
Corners {
|
||||
id: sidebarCornerBottom
|
||||
position: "bottomright"
|
||||
size: 1.1
|
||||
fillColor: Theme.backgroundPrimary
|
||||
offsetX: 33 + panelPopup.slideOffset
|
||||
offsetY: 46
|
||||
|
||||
Behavior on offsetX {
|
||||
enabled: !panelPopup.isAnimating
|
||||
NumberAnimation { duration: 300; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
WallpaperPanel {
|
||||
id: wallpaperPanelModal
|
||||
visible: false
|
||||
Component.onCompleted: {
|
||||
if (parent) {
|
||||
wallpaperPanelModal.anchors.top = parent.top;
|
||||
wallpaperPanelModal.anchors.right = parent.right;
|
||||
}
|
||||
}
|
||||
// Add a close button inside WallpaperPanel.qml for user to close the modal
|
||||
|
||||
WallpaperPanel {
|
||||
id: wallpaperPanelModal
|
||||
visible: false
|
||||
Component.onCompleted: {
|
||||
if (parent) {
|
||||
wallpaperPanelModal.anchors.top = parent.top;
|
||||
wallpaperPanelModal.anchors.right = parent.right;
|
||||
}
|
||||
}
|
||||
// Add a close button inside WallpaperPanel.qml for user to close the modal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell.Services.UPower
|
||||
import qs.Settings
|
||||
import qs.Components
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ Rectangle {
|
|||
source: Image {
|
||||
id: avatarImage
|
||||
anchors.fill: parent
|
||||
source: Settings.profileImage !== undefined ? Settings.profileImage : ""
|
||||
source: Settings.settings.profileImage !== undefined ? Settings.settings.profileImage : ""
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
cache: false
|
||||
|
|
@ -66,7 +66,7 @@ Rectangle {
|
|||
radius: 22
|
||||
visible: false
|
||||
}
|
||||
visible: Settings.profileImage !== undefined && Settings.profileImage !== ""
|
||||
visible: Settings.settings.profileImage !== undefined && Settings.settings.profileImage !== ""
|
||||
z: 1
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ Rectangle {
|
|||
font.family: "Material Symbols Outlined"
|
||||
font.pixelSize: 24
|
||||
color: Theme.onAccent
|
||||
visible: Settings.profileImage === undefined || Settings.profileImage === ""
|
||||
visible: Settings.settings.profileImage === undefined || Settings.settings.profileImage === ""
|
||||
z: 0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell.Io
|
||||
import qs.Components
|
||||
import qs.Services
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Widgets
|
||||
|
|
@ -126,8 +126,8 @@ PanelWindow {
|
|||
anchors.margins: 4
|
||||
color: Qt.darker(Theme.backgroundPrimary, 1.1)
|
||||
radius: 12
|
||||
border.color: Settings.currentWallpaper === modelData ? Theme.accentPrimary : Theme.outline
|
||||
border.width: Settings.currentWallpaper === modelData ? 3 : 1
|
||||
border.color: Settings.settings.currentWallpaper === modelData ? Theme.accentPrimary : Theme.outline
|
||||
border.width: Settings.settings.currentWallpaper === modelData ? 3 : 1
|
||||
Image {
|
||||
id: wallpaperImage
|
||||
anchors.fill: parent
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import qs.Settings
|
||||
import "../../../Helpers/Weather.js" as WeatherHelper
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ Rectangle {
|
|||
color: "transparent"
|
||||
anchors.horizontalCenterOffset: -2
|
||||
|
||||
property string city: Settings.weatherCity !== undefined ? Settings.weatherCity : ""
|
||||
property string city: Settings.settings.weatherCity !== undefined ? Settings.settings.weatherCity : ""
|
||||
property var weatherData: null
|
||||
property string errorString: ""
|
||||
property bool isVisible: false
|
||||
|
|
@ -95,7 +95,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
Text {
|
||||
text: weatherData && weatherData.current_weather ? ((Settings.useFahrenheit !== undefined ? Settings.useFahrenheit : false) ? `${Math.round(weatherData.current_weather.temperature * 9/5 + 32)}°F` : `${Math.round(weatherData.current_weather.temperature)}°C`) : ((Settings.useFahrenheit !== undefined ? Settings.useFahrenheit : false) ? "--°F" : "--°C")
|
||||
text: weatherData && weatherData.current_weather ? ((Settings.settings.useFahrenheit !== undefined ? Settings.settings.useFahrenheit : false) ? `${Math.round(weatherData.current_weather.temperature * 9/5 + 32)}°F` : `${Math.round(weatherData.current_weather.temperature)}°C`) : ((Settings.settings.useFahrenheit !== undefined ? Settings.settings.useFahrenheit : false) ? "--°F" : "--°C")
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 24
|
||||
font.bold: true
|
||||
|
|
@ -151,7 +151,7 @@ Rectangle {
|
|||
}
|
||||
Text {
|
||||
// High/low temp
|
||||
text: weatherData && weatherData.daily ? ((Settings.useFahrenheit !== undefined ? Settings.useFahrenheit : false) ? `${Math.round(weatherData.daily.temperature_2m_max[index] * 9/5 + 32)}° / ${Math.round(weatherData.daily.temperature_2m_min[index] * 9/5 + 32)}°` : `${Math.round(weatherData.daily.temperature_2m_max[index])}° / ${Math.round(weatherData.daily.temperature_2m_min[index])}°`) : ((Settings.useFahrenheit !== undefined ? Settings.useFahrenheit : false) ? "--° / --°" : "--° / --°")
|
||||
text: weatherData && weatherData.daily ? ((Settings.settings.useFahrenheit !== undefined ? Settings.settings.useFahrenheit : false) ? `${Math.round(weatherData.daily.temperature_2m_max[index] * 9/5 + 32)}° / ${Math.round(weatherData.daily.temperature_2m_min[index] * 9/5 + 32)}°` : `${Math.round(weatherData.daily.temperature_2m_max[index])}° / ${Math.round(weatherData.daily.temperature_2m_min[index])}°`) : ((Settings.settings.useFahrenheit !== undefined ? Settings.settings.useFahrenheit : false) ? "--° / --°" : "--° / --°")
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 12
|
||||
color: Theme.textPrimary
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue