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
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
.qmlls.ini
|
||||||
46
Bar/Bar.qml
46
Bar/Bar.qml
|
|
@ -59,7 +59,7 @@ Scope {
|
||||||
SystemInfo {
|
SystemInfo {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
Media {
|
Media {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
@ -83,8 +83,7 @@ Scope {
|
||||||
anchors.rightMargin: 18
|
anchors.rightMargin: 18
|
||||||
spacing: 12
|
spacing: 12
|
||||||
|
|
||||||
NotificationHistory {
|
NotificationIcon {
|
||||||
id: notificationHistoryWin
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,20 +131,22 @@ Scope {
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: topCornerPanel
|
id: topLeftPanel
|
||||||
anchors.top: true
|
anchors.top: true
|
||||||
anchors.left: true
|
anchors.left: true
|
||||||
anchors.right: true
|
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
screen: modelData
|
screen: modelData
|
||||||
margins.top: 36
|
margins.top: 36
|
||||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
visible: true
|
visible: true
|
||||||
|
WlrLayershell.layer: WlrLayer.Background
|
||||||
|
aboveWindows: false
|
||||||
|
WlrLayershell.namespace: "swww-daemon"
|
||||||
implicitHeight: 24
|
implicitHeight: 24
|
||||||
|
|
||||||
Corners {
|
Corners {
|
||||||
id: topleftCorner
|
id: topLeftCorner
|
||||||
position: "bottomleft"
|
position: "bottomleft"
|
||||||
size: 1.3
|
size: 1.3
|
||||||
fillColor: (Theme.backgroundPrimary !== undefined && Theme.backgroundPrimary !== null) ? Theme.backgroundPrimary : "#222"
|
fillColor: (Theme.backgroundPrimary !== undefined && Theme.backgroundPrimary !== null) ? Theme.backgroundPrimary : "#222"
|
||||||
|
|
@ -153,9 +154,25 @@ Scope {
|
||||||
offsetY: 0
|
offsetY: 0
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: topRightPanel
|
||||||
|
anchors.top: true
|
||||||
|
anchors.right: true
|
||||||
|
color: "transparent"
|
||||||
|
screen: modelData
|
||||||
|
margins.top: 36
|
||||||
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
|
visible: true
|
||||||
|
WlrLayershell.layer: WlrLayer.Background
|
||||||
|
aboveWindows: false
|
||||||
|
WlrLayershell.namespace: "swww-daemon"
|
||||||
|
|
||||||
|
implicitHeight: 24
|
||||||
|
|
||||||
Corners {
|
Corners {
|
||||||
id: toprightCorner
|
id: topRightCorner
|
||||||
position: "bottomright"
|
position: "bottomright"
|
||||||
size: 1.3
|
size: 1.3
|
||||||
fillColor: (Theme.backgroundPrimary !== undefined && Theme.backgroundPrimary !== null) ? Theme.backgroundPrimary : "#222"
|
fillColor: (Theme.backgroundPrimary !== undefined && Theme.backgroundPrimary !== null) ? Theme.backgroundPrimary : "#222"
|
||||||
|
|
@ -173,6 +190,9 @@ Scope {
|
||||||
screen: modelData
|
screen: modelData
|
||||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
visible: true
|
visible: true
|
||||||
|
WlrLayershell.layer: WlrLayer.Background
|
||||||
|
aboveWindows: false
|
||||||
|
WlrLayershell.namespace: "swww-daemon"
|
||||||
|
|
||||||
implicitHeight: 24
|
implicitHeight: 24
|
||||||
|
|
||||||
|
|
@ -188,13 +208,16 @@ Scope {
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: bottomRightCornerPanel
|
id: bottomRightPanel
|
||||||
anchors.bottom: true
|
anchors.bottom: true
|
||||||
anchors.right: true
|
anchors.right: true
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
screen: modelData
|
screen: modelData
|
||||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
visible: true
|
visible: true
|
||||||
|
WlrLayershell.layer: WlrLayer.Background
|
||||||
|
aboveWindows: false
|
||||||
|
WlrLayershell.namespace: "swww-daemon"
|
||||||
|
|
||||||
implicitHeight: 24
|
implicitHeight: 24
|
||||||
|
|
||||||
|
|
@ -208,13 +231,8 @@ Scope {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: tabViewerLoader
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This alias exposes the visual bar's visibility to the outside world
|
// This alias exposes the visual bar's visibility to the outside world
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,11 @@ PanelWindow {
|
||||||
anchors.top: true
|
anchors.top: true
|
||||||
anchors.left: true
|
anchors.left: true
|
||||||
anchors.right: true
|
anchors.right: true
|
||||||
|
focusable: false
|
||||||
margins.top: barHeight
|
margins.top: barHeight
|
||||||
visible: !activeWindowWrapper.finallyHidden
|
visible: !activeWindowWrapper.finallyHidden
|
||||||
implicitHeight: activeWindowTitleContainer.height
|
implicitHeight: activeWindowTitleContainer.height
|
||||||
implicitWidth: activeWindowTitleContainer.x
|
implicitWidth: 0
|
||||||
property int barHeight: 36
|
property int barHeight: 36
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
|
|
@ -104,7 +105,7 @@ PanelWindow {
|
||||||
bottomLeftRadius: Math.max(0, width / 2)
|
bottomLeftRadius: Math.max(0, width / 2)
|
||||||
bottomRightRadius: Math.max(0, width / 2)
|
bottomRightRadius: Math.max(0, width / 2)
|
||||||
|
|
||||||
width: Math.min(barBackground.width - 200, activeWindowTitle.implicitWidth + (Settings.showActiveWindowIcon ? 28 : 22))
|
width: Math.min(barBackground.width - 200, activeWindowTitle.implicitWidth + (Settings.settings.showActiveWindowIcon ? 28 : 22))
|
||||||
height: activeWindowTitle.implicitHeight + 12
|
height: activeWindowTitle.implicitHeight + 12
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
|
@ -118,7 +119,7 @@ PanelWindow {
|
||||||
anchors.leftMargin: 6
|
anchors.leftMargin: 6
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
source: ToplevelManager?.activeToplevel ? getIcon() : ""
|
source: ToplevelManager?.activeToplevel ? getIcon() : ""
|
||||||
visible: Settings.showActiveWindowIcon
|
visible: Settings.settings.showActiveWindowIcon
|
||||||
anchors.verticalCenterOffset: -3
|
anchors.verticalCenterOffset: -3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,12 +130,12 @@ PanelWindow {
|
||||||
color: Theme.textSecondary
|
color: Theme.textSecondary
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
anchors.left: icon.right
|
anchors.left: icon.right
|
||||||
anchors.leftMargin: Settings.showActiveWindowIcon ? 4 : 6
|
anchors.leftMargin: Settings.settings.showActiveWindowIcon ? 4 : 6
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 6
|
anchors.rightMargin: 6
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.verticalCenterOffset: -3
|
anchors.verticalCenterOffset: -3
|
||||||
horizontalAlignment: Settings.showActiveWindowIcon ? Text.AlignRight : Text.AlignHCenter
|
horizontalAlignment: Settings.settings.showActiveWindowIcon ? Text.AlignRight : Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,380 +5,422 @@ import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
import Qt5Compat.GraphicalEffects
|
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import "../../Helpers/Fuzzysort.js" as Fuzzysort
|
import "../../Helpers/Fuzzysort.js" as Fuzzysort
|
||||||
|
|
||||||
PanelWindow {
|
PanelWithOverlay {
|
||||||
id: appLauncherPanel
|
id: appLauncherPanel
|
||||||
implicitWidth: 460
|
|
||||||
implicitHeight: 640
|
|
||||||
color: "transparent"
|
|
||||||
visible: false
|
|
||||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
|
||||||
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
|
||||||
screen: (typeof modelData !== 'undefined' ? modelData : null)
|
|
||||||
property bool shouldBeVisible: false
|
|
||||||
|
|
||||||
anchors.top: true
|
|
||||||
margins.top: 36
|
|
||||||
|
|
||||||
function showAt() {
|
function showAt() {
|
||||||
visible = true;
|
appLauncherPanelRect.showAt();
|
||||||
shouldBeVisible = true;
|
|
||||||
searchField.forceActiveFocus()
|
|
||||||
root.selectedIndex = 0;
|
|
||||||
root.appModel = DesktopEntries.applications.values;
|
|
||||||
root.updateFilter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hidePanel() {
|
function hidePanel() {
|
||||||
shouldBeVisible = false;
|
appLauncherPanelRect.hidePanel();
|
||||||
searchField.text = "";
|
}
|
||||||
root.selectedIndex = 0;
|
|
||||||
|
function show() {
|
||||||
|
appLauncherPanelRect.showAt();
|
||||||
|
}
|
||||||
|
|
||||||
|
function dismiss() {
|
||||||
|
appLauncherPanelRect.hidePanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: appLauncherPanelRect
|
||||||
width: 400
|
implicitWidth: 460
|
||||||
height: 640
|
implicitHeight: 640
|
||||||
x: (parent.width - width) / 2
|
color: "transparent"
|
||||||
color: Theme.backgroundPrimary
|
visible: parent.visible
|
||||||
bottomLeftRadius: 28
|
property bool shouldBeVisible: false
|
||||||
bottomRightRadius: 28
|
anchors.top: parent.top
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
property var appModel: DesktopEntries.applications.values
|
function showAt() {
|
||||||
property var filteredApps: []
|
appLauncherPanel.visible = true;
|
||||||
property int selectedIndex: 0
|
shouldBeVisible = true;
|
||||||
property int targetY: (parent.height - height) / 2
|
searchField.forceActiveFocus();
|
||||||
y: appLauncherPanel.shouldBeVisible ? targetY : -height
|
root.selectedIndex = 0;
|
||||||
Behavior on y {
|
root.appModel = DesktopEntries.applications.values;
|
||||||
NumberAnimation { duration: 300; easing.type: Easing.OutCubic }
|
root.updateFilter();
|
||||||
}
|
}
|
||||||
scale: appLauncherPanel.shouldBeVisible ? 1 : 0
|
|
||||||
Behavior on scale {
|
function hidePanel() {
|
||||||
NumberAnimation { duration: 200; easing.type: Easing.InOutCubic }
|
shouldBeVisible = false;
|
||||||
}
|
searchField.text = "";
|
||||||
onScaleChanged: {
|
|
||||||
if (scale === 0 && !appLauncherPanel.shouldBeVisible) {
|
|
||||||
appLauncherPanel.visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function isMathExpression(str) {
|
|
||||||
return /^[-+*/().0-9\s]+$/.test(str);
|
|
||||||
}
|
|
||||||
function safeEval(expr) {
|
|
||||||
try {
|
|
||||||
return Function('return (' + expr + ')')();
|
|
||||||
} catch (e) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function updateFilter() {
|
|
||||||
var query = searchField.text ? searchField.text.toLowerCase() : "";
|
|
||||||
var apps = root.appModel.slice();
|
|
||||||
var results = [];
|
|
||||||
// Calculator mode: starts with '='
|
|
||||||
if (query.startsWith("=")) {
|
|
||||||
var expr = searchField.text.slice(1).trim();
|
|
||||||
if (expr && isMathExpression(expr)) {
|
|
||||||
var value = safeEval(expr);
|
|
||||||
if (value !== undefined && value !== null && value !== "") {
|
|
||||||
results.push({
|
|
||||||
isCalculator: true,
|
|
||||||
name: `Calculator: ${expr} = ${value}`,
|
|
||||||
result: value,
|
|
||||||
expr: expr,
|
|
||||||
icon: "calculate"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!query || query.startsWith("=")) {
|
|
||||||
results = results.concat(apps.sort(function(a, b) {
|
|
||||||
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
var fuzzyResults = Fuzzysort.go(query, apps, { keys: ["name", "comment", "genericName"] });
|
|
||||||
results = results.concat(fuzzyResults.map(function(r) { return r.obj; }));
|
|
||||||
}
|
|
||||||
root.filteredApps = results;
|
|
||||||
root.selectedIndex = 0;
|
root.selectedIndex = 0;
|
||||||
}
|
}
|
||||||
function selectNext() {
|
|
||||||
if (filteredApps.length > 0)
|
|
||||||
selectedIndex = Math.min(selectedIndex + 1, filteredApps.length - 1);
|
|
||||||
}
|
|
||||||
function selectPrev() {
|
|
||||||
if (filteredApps.length > 0)
|
|
||||||
selectedIndex = Math.max(selectedIndex - 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function activateSelected() {
|
Rectangle {
|
||||||
if (filteredApps.length === 0)
|
id: root
|
||||||
return;
|
width: 460
|
||||||
|
height: 640
|
||||||
|
x: (parent.width - width) / 2
|
||||||
|
color: Theme.backgroundPrimary
|
||||||
|
bottomLeftRadius: 28
|
||||||
|
bottomRightRadius: 28
|
||||||
|
|
||||||
var modelData = filteredApps[selectedIndex];
|
property var appModel: DesktopEntries.applications.values
|
||||||
|
property var filteredApps: []
|
||||||
if (modelData.isCalculator) {
|
property int selectedIndex: 0
|
||||||
Qt.callLater(function() {
|
property int targetY: (parent.height - height) / 2
|
||||||
Quickshell.clipboardText = String(modelData.result);
|
y: appLauncherPanelRect.shouldBeVisible ? targetY : -height
|
||||||
Quickshell.execDetached([
|
Behavior on y {
|
||||||
"notify-send",
|
NumberAnimation {
|
||||||
"Calculator Result",
|
duration: 300
|
||||||
`${modelData.expr} = ${modelData.result} (copied to clipboard)`
|
easing.type: Easing.OutCubic
|
||||||
]);
|
|
||||||
});
|
|
||||||
} else if (modelData.execute) {
|
|
||||||
modelData.execute();
|
|
||||||
} else {
|
|
||||||
var execCmd = modelData.execString || modelData.exec || "";
|
|
||||||
if (execCmd) {
|
|
||||||
execCmd = execCmd.replace(/\s?%[fFuUdDnNiCkvm]/g, '');
|
|
||||||
Quickshell.execDetached(["sh", "-c", execCmd.trim()]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
scale: appLauncherPanelRect.shouldBeVisible ? 1 : 0
|
||||||
appLauncherPanel.hidePanel();
|
Behavior on scale {
|
||||||
searchField.text = "";
|
NumberAnimation {
|
||||||
}
|
duration: 200
|
||||||
|
easing.type: Easing.InOutCubic
|
||||||
Component.onCompleted: updateFilter()
|
}
|
||||||
|
}
|
||||||
ColumnLayout {
|
onScaleChanged: {
|
||||||
anchors.left: parent.left
|
if (scale === 0 && !appLauncherPanelRect.shouldBeVisible) {
|
||||||
anchors.right: parent.right
|
appLauncherPanel.visible = false;
|
||||||
anchors.top: parent.top
|
}
|
||||||
anchors.bottom: parent.bottom
|
}
|
||||||
anchors.margins: 32
|
function isMathExpression(str) {
|
||||||
spacing: 18
|
return /^[-+*/().0-9\s]+$/.test(str);
|
||||||
|
}
|
||||||
// Search Bar
|
function safeEval(expr) {
|
||||||
Rectangle {
|
try {
|
||||||
id: searchBar
|
return Function('return (' + expr + ')')();
|
||||||
color: Theme.surfaceVariant
|
} catch (e) {
|
||||||
radius: 22
|
return undefined;
|
||||||
height: 48
|
}
|
||||||
Layout.fillWidth: true
|
}
|
||||||
border.color: searchField.activeFocus ? Theme.accentPrimary : Theme.outline
|
function updateFilter() {
|
||||||
border.width: searchField.activeFocus ? 2 : 1
|
var query = searchField.text ? searchField.text.toLowerCase() : "";
|
||||||
|
var apps = root.appModel.slice();
|
||||||
RowLayout {
|
var results = [];
|
||||||
anchors.left: parent.left
|
// Calculator mode: starts with '='
|
||||||
anchors.right: parent.right
|
if (query.startsWith("=")) {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
var expr = searchField.text.slice(1).trim();
|
||||||
anchors.leftMargin: 14
|
if (expr && isMathExpression(expr)) {
|
||||||
anchors.rightMargin: 14
|
var value = safeEval(expr);
|
||||||
spacing: 10
|
if (value !== undefined && value !== null && value !== "") {
|
||||||
Text {
|
results.push({
|
||||||
text: "search"
|
isCalculator: true,
|
||||||
font.family: "Material Symbols Outlined"
|
name: `Calculator: ${expr} = ${value}`,
|
||||||
font.pixelSize: Theme.fontSizeHeader
|
result: value,
|
||||||
color: searchField.activeFocus ? Theme.accentPrimary : Theme.textSecondary
|
expr: expr,
|
||||||
verticalAlignment: Text.AlignVCenter
|
icon: "calculate"
|
||||||
Layout.alignment: Qt.AlignVCenter
|
});
|
||||||
}
|
}
|
||||||
TextField {
|
|
||||||
id: searchField
|
|
||||||
placeholderText: "Search apps..."
|
|
||||||
color: Theme.textPrimary
|
|
||||||
placeholderTextColor: Theme.textSecondary
|
|
||||||
background: null
|
|
||||||
font.family: Theme.fontFamily
|
|
||||||
font.pixelSize: Theme.fontSizeBody
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
onTextChanged: root.updateFilter()
|
|
||||||
selectedTextColor: Theme.onAccent
|
|
||||||
selectionColor: Theme.accentPrimary
|
|
||||||
padding: 0
|
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
|
||||||
leftPadding: 0
|
|
||||||
rightPadding: 0
|
|
||||||
topPadding: 0
|
|
||||||
bottomPadding: 0
|
|
||||||
font.bold: true
|
|
||||||
Component.onCompleted: contentItem.cursorColor = Theme.textPrimary
|
|
||||||
onActiveFocusChanged: contentItem.cursorColor = Theme.textPrimary
|
|
||||||
|
|
||||||
Keys.onDownPressed: root.selectNext()
|
|
||||||
Keys.onUpPressed: root.selectPrev()
|
|
||||||
Keys.onEnterPressed: root.activateSelected()
|
|
||||||
Keys.onReturnPressed: root.activateSelected()
|
|
||||||
Keys.onEscapePressed: appLauncherPanel.hidePanel()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Behavior on border.color { ColorAnimation { duration: 120 } }
|
if (!query || query.startsWith("=")) {
|
||||||
Behavior on border.width { NumberAnimation { duration: 120 } }
|
results = results.concat(apps.sort(function (a, b) {
|
||||||
|
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
var fuzzyResults = Fuzzysort.go(query, apps, {
|
||||||
|
keys: ["name", "comment", "genericName"]
|
||||||
|
});
|
||||||
|
results = results.concat(fuzzyResults.map(function (r) {
|
||||||
|
return r.obj;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
root.filteredApps = results;
|
||||||
|
root.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
function selectNext() {
|
||||||
|
if (filteredApps.length > 0)
|
||||||
|
selectedIndex = Math.min(selectedIndex + 1, filteredApps.length - 1);
|
||||||
|
}
|
||||||
|
function selectPrev() {
|
||||||
|
if (filteredApps.length > 0)
|
||||||
|
selectedIndex = Math.max(selectedIndex - 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// App List Card
|
function activateSelected() {
|
||||||
Rectangle {
|
if (filteredApps.length === 0)
|
||||||
color: Theme.surface
|
return;
|
||||||
radius: 20
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
clip: true
|
|
||||||
anchors.margins: 0
|
|
||||||
property int innerPadding: 16
|
|
||||||
|
|
||||||
Item {
|
var modelData = filteredApps[selectedIndex];
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
if (modelData.isCalculator) {
|
||||||
anchors.right: parent.right
|
Qt.callLater(function () {
|
||||||
height: parent.innerPadding
|
Quickshell.clipboardText = String(modelData.result);
|
||||||
visible: false
|
Quickshell.execDetached(["notify-send", "Calculator Result", `${modelData.expr} = ${modelData.result} (copied to clipboard)`]);
|
||||||
|
});
|
||||||
|
} else if (modelData.execute) {
|
||||||
|
modelData.execute();
|
||||||
|
} else {
|
||||||
|
var execCmd = modelData.execString || modelData.exec || "";
|
||||||
|
if (execCmd) {
|
||||||
|
execCmd = execCmd.replace(/\s?%[fFuUdDnNiCkvm]/g, '');
|
||||||
|
Quickshell.execDetached(["sh", "-c", execCmd.trim()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
appLauncherPanel.hidePanel();
|
||||||
id: appList
|
searchField.text = "";
|
||||||
anchors.fill: parent
|
}
|
||||||
anchors.margins: parent.innerPadding
|
|
||||||
spacing: 2
|
|
||||||
model: root.filteredApps
|
|
||||||
currentIndex: root.selectedIndex
|
|
||||||
delegate: Item {
|
|
||||||
id: appDelegate
|
|
||||||
width: appList.width
|
|
||||||
height: 48
|
|
||||||
property bool hovered: mouseArea.containsMouse
|
|
||||||
property bool isSelected: index === root.selectedIndex
|
|
||||||
|
|
||||||
Rectangle {
|
Component.onCompleted: updateFilter()
|
||||||
anchors.fill: parent
|
|
||||||
color: hovered || isSelected ? Theme.accentPrimary : "transparent"
|
ColumnLayout {
|
||||||
radius: 12
|
anchors.left: parent.left
|
||||||
border.color: hovered || isSelected ? Theme.accentPrimary : "transparent"
|
anchors.right: parent.right
|
||||||
border.width: hovered || isSelected ? 2 : 0
|
anchors.top: parent.top
|
||||||
Behavior on color { ColorAnimation { duration: 120 } }
|
anchors.bottom: parent.bottom
|
||||||
Behavior on border.color { ColorAnimation { duration: 120 } }
|
anchors.margins: 32
|
||||||
Behavior on border.width { NumberAnimation { duration: 120 } }
|
spacing: 18
|
||||||
|
|
||||||
|
// Search Bar
|
||||||
|
Rectangle {
|
||||||
|
id: searchBar
|
||||||
|
color: Theme.surfaceVariant
|
||||||
|
radius: 22
|
||||||
|
height: 48
|
||||||
|
Layout.fillWidth: true
|
||||||
|
border.color: searchField.activeFocus ? Theme.accentPrimary : Theme.outline
|
||||||
|
border.width: searchField.activeFocus ? 2 : 1
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: 14
|
||||||
|
anchors.rightMargin: 14
|
||||||
|
spacing: 10
|
||||||
|
Text {
|
||||||
|
text: "search"
|
||||||
|
font.family: "Material Symbols Outlined"
|
||||||
|
font.pixelSize: Theme.fontSizeHeader
|
||||||
|
color: searchField.activeFocus ? Theme.accentPrimary : Theme.textSecondary
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
}
|
}
|
||||||
|
TextField {
|
||||||
|
id: searchField
|
||||||
|
placeholderText: "Search apps..."
|
||||||
|
color: Theme.textPrimary
|
||||||
|
placeholderTextColor: Theme.textSecondary
|
||||||
|
background: null
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
font.pixelSize: Theme.fontSizeBody
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
onTextChanged: root.updateFilter()
|
||||||
|
selectedTextColor: Theme.onAccent
|
||||||
|
selectionColor: Theme.accentPrimary
|
||||||
|
padding: 0
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
leftPadding: 0
|
||||||
|
rightPadding: 0
|
||||||
|
topPadding: 0
|
||||||
|
bottomPadding: 0
|
||||||
|
font.bold: true
|
||||||
|
Component.onCompleted: contentItem.cursorColor = Theme.textPrimary
|
||||||
|
onActiveFocusChanged: contentItem.cursorColor = Theme.textPrimary
|
||||||
|
|
||||||
RowLayout {
|
Keys.onDownPressed: root.selectNext()
|
||||||
anchors.fill: parent
|
Keys.onUpPressed: root.selectPrev()
|
||||||
anchors.leftMargin: 10
|
Keys.onEnterPressed: root.activateSelected()
|
||||||
anchors.rightMargin: 10
|
Keys.onReturnPressed: root.activateSelected()
|
||||||
spacing: 10
|
Keys.onEscapePressed: appLauncherPanel.hidePanel()
|
||||||
Item {
|
|
||||||
width: 28; height: 28
|
|
||||||
property bool iconLoaded: !modelData.isCalculator && iconImg.status === Image.Ready && iconImg.source !== "" && iconImg.status !== Image.Error
|
|
||||||
Image {
|
|
||||||
id: iconImg
|
|
||||||
anchors.fill: parent
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
smooth: true
|
|
||||||
cache: false
|
|
||||||
asynchronous: true
|
|
||||||
source: modelData.isCalculator ? "qrc:/icons/calculate.svg" : Quickshell.iconPath(modelData.icon, "application-x-executable")
|
|
||||||
visible: modelData.isCalculator || parent.iconLoaded
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
visible: !modelData.isCalculator && !parent.iconLoaded
|
|
||||||
text: "broken_image"
|
|
||||||
font.family: "Material Symbols Outlined"
|
|
||||||
font.pixelSize: Theme.fontSizeHeader
|
|
||||||
color: Theme.accentPrimary
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: 1
|
|
||||||
Text {
|
|
||||||
text: modelData.name
|
|
||||||
color: hovered || isSelected ? Theme.onAccent : Theme.textPrimary
|
|
||||||
font.family: Theme.fontFamily
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
font.bold: hovered || isSelected
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
elide: Text.ElideRight
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
text: modelData.isCalculator ? (modelData.expr + " = " + modelData.result)
|
|
||||||
: (modelData.comment || modelData.genericName || "No description available")
|
|
||||||
color: hovered || isSelected ? Theme.onAccent : Theme.textSecondary
|
|
||||||
font.family: Theme.fontFamily
|
|
||||||
font.pixelSize: Theme.fontSizeCaption
|
|
||||||
font.italic: !(modelData.comment || modelData.genericName)
|
|
||||||
opacity: (modelData.comment || modelData.genericName) ? 1.0 : 0.6
|
|
||||||
elide: Text.ElideRight
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item { Layout.fillWidth: true }
|
|
||||||
Text {
|
|
||||||
text: modelData.isCalculator ? "content_copy" : "chevron_right"
|
|
||||||
font.family: "Material Symbols Outlined"
|
|
||||||
font.pixelSize: Theme.fontSizeBody
|
|
||||||
color: hovered || isSelected ? Theme.onAccent : Theme.textSecondary
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Rectangle {
|
Behavior on border.color {
|
||||||
id: ripple
|
ColorAnimation {
|
||||||
anchors.fill: parent
|
duration: 120
|
||||||
color: Theme.onAccent
|
|
||||||
opacity: 0.0
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
MouseArea {
|
Behavior on border.width {
|
||||||
id: mouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
onClicked: {
|
|
||||||
ripple.opacity = 0.18
|
|
||||||
rippleNumberAnimation.start()
|
|
||||||
root.selectedIndex = index
|
|
||||||
root.activateSelected()
|
|
||||||
}
|
|
||||||
onPressed: ripple.opacity = 0.18
|
|
||||||
onReleased: ripple.opacity = 0.0
|
|
||||||
}
|
|
||||||
|
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
id: rippleNumberAnimation
|
duration: 120
|
||||||
target: ripple
|
|
||||||
property: "opacity"
|
|
||||||
to: 0.0
|
|
||||||
duration: 320
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
// App List Card
|
||||||
anchors.left: parent.left
|
Rectangle {
|
||||||
anchors.right: parent.right
|
color: Theme.surface
|
||||||
anchors.bottom: parent.bottom
|
radius: 20
|
||||||
height: 1
|
Layout.fillWidth: true
|
||||||
color: Theme.outline
|
Layout.fillHeight: true
|
||||||
opacity: index === appList.count - 1 ? 0 : 0.10
|
clip: true
|
||||||
|
property int innerPadding: 16
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: parent.innerPadding
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: appList
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: parent.innerPadding
|
||||||
|
spacing: 2
|
||||||
|
model: root.filteredApps
|
||||||
|
currentIndex: root.selectedIndex
|
||||||
|
delegate: Item {
|
||||||
|
id: appDelegate
|
||||||
|
width: appList.width
|
||||||
|
height: 48
|
||||||
|
property bool hovered: mouseArea.containsMouse
|
||||||
|
property bool isSelected: index === root.selectedIndex
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: hovered || isSelected ? Theme.accentPrimary : "transparent"
|
||||||
|
radius: 12
|
||||||
|
border.color: hovered || isSelected ? Theme.accentPrimary : "transparent"
|
||||||
|
border.width: hovered || isSelected ? 2 : 0
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: 120
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on border.color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: 120
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on border.width {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 120
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
spacing: 10
|
||||||
|
Item {
|
||||||
|
width: 28
|
||||||
|
height: 28
|
||||||
|
property bool iconLoaded: !modelData.isCalculator && iconImg.status === Image.Ready && iconImg.source !== "" && iconImg.status !== Image.Error
|
||||||
|
Image {
|
||||||
|
id: iconImg
|
||||||
|
anchors.fill: parent
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
smooth: true
|
||||||
|
cache: false
|
||||||
|
asynchronous: true
|
||||||
|
source: modelData.isCalculator ? "qrc:/icons/calculate.svg" : Quickshell.iconPath(modelData.icon, "application-x-executable")
|
||||||
|
visible: modelData.isCalculator || parent.iconLoaded
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
visible: !modelData.isCalculator && !parent.iconLoaded
|
||||||
|
text: "broken_image"
|
||||||
|
font.family: "Material Symbols Outlined"
|
||||||
|
font.pixelSize: Theme.fontSizeHeader
|
||||||
|
color: Theme.accentPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 1
|
||||||
|
Text {
|
||||||
|
text: modelData.name
|
||||||
|
color: hovered || isSelected ? Theme.onAccent : Theme.textPrimary
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.bold: hovered || isSelected
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: modelData.isCalculator ? (modelData.expr + " = " + modelData.result) : (modelData.comment || modelData.genericName || "No description available")
|
||||||
|
color: hovered || isSelected ? Theme.onAccent : Theme.textSecondary
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
font.pixelSize: Theme.fontSizeCaption
|
||||||
|
font.italic: !(modelData.comment || modelData.genericName)
|
||||||
|
opacity: (modelData.comment || modelData.genericName) ? 1.0 : 0.6
|
||||||
|
elide: Text.ElideRight
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: modelData.isCalculator ? "content_copy" : "chevron_right"
|
||||||
|
font.family: "Material Symbols Outlined"
|
||||||
|
font.pixelSize: Theme.fontSizeBody
|
||||||
|
color: hovered || isSelected ? Theme.onAccent : Theme.textSecondary
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: ripple
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Theme.onAccent
|
||||||
|
opacity: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: {
|
||||||
|
ripple.opacity = 0.18;
|
||||||
|
rippleNumberAnimation.start();
|
||||||
|
root.selectedIndex = index;
|
||||||
|
root.activateSelected();
|
||||||
|
}
|
||||||
|
onPressed: ripple.opacity = 0.18
|
||||||
|
onReleased: ripple.opacity = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: rippleNumberAnimation
|
||||||
|
target: ripple
|
||||||
|
property: "opacity"
|
||||||
|
to: 0.0
|
||||||
|
duration: 320
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
height: 1
|
||||||
|
color: Theme.outline
|
||||||
|
opacity: index === appList.count - 1 ? 0 : 0.10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Corners {
|
Corners {
|
||||||
id: launcherCornerRight
|
id: launcherCornerRight
|
||||||
position: "bottomleft"
|
position: "bottomleft"
|
||||||
size: 1.1
|
size: 1.1
|
||||||
fillColor: Theme.backgroundPrimary
|
fillColor: Theme.backgroundPrimary
|
||||||
anchors.top: root.top
|
anchors.top: root.top
|
||||||
offsetX: 396
|
offsetX: 416
|
||||||
offsetY: 0
|
offsetY: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Corners {
|
Corners {
|
||||||
id: launcherCornerLeft
|
id: launcherCornerLeft
|
||||||
position: "bottomright"
|
position: "bottomright"
|
||||||
size: 1.1
|
size: 1.1
|
||||||
fillColor: Theme.backgroundPrimary
|
fillColor: Theme.backgroundPrimary
|
||||||
anchors.top: root.top
|
anchors.top: root.top
|
||||||
offsetX: -396
|
offsetX: -416
|
||||||
offsetY: 0
|
offsetY: 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
@ -10,7 +10,7 @@ Item {
|
||||||
id: mediaControl
|
id: mediaControl
|
||||||
width: visible ? mediaRow.width : 0
|
width: visible ? mediaRow.width : 0
|
||||||
height: 36
|
height: 36
|
||||||
visible: Settings.showMediaInBar && MusicManager.currentPlayer
|
visible: Settings.settings.showMediaInBar && MusicManager.currentPlayer
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: mediaRow
|
id: mediaRow
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import qs.Services
|
||||||
Row {
|
Row {
|
||||||
id: layout
|
id: layout
|
||||||
spacing: 10
|
spacing: 10
|
||||||
visible: Settings.showSystemInfoInBar
|
visible: Settings.settings.showSystemInfoInBar
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: cpuUsageLayout
|
id: cpuUsageLayout
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ Item {
|
||||||
height: usableOuter * 2
|
height: usableOuter * 2
|
||||||
|
|
||||||
onOuterRadiusChanged: () => {
|
onOuterRadiusChanged: () => {
|
||||||
usableOuter = Settings.visualizerType === "fire" ? outerRadius * 0.85 : outerRadius;
|
usableOuter = Settings.settings.visualizerType === "fire" ? outerRadius * 0.85 : outerRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
|
@ -25,25 +25,25 @@ Item {
|
||||||
property real value: root.values[index]
|
property real value: root.values[index]
|
||||||
property real angle: (index / root.values.length) * 360
|
property real angle: (index / root.values.length) * 360
|
||||||
width: Math.max(2, (root.innerRadius * 2 * Math.PI) / root.values.length - 4)
|
width: Math.max(2, (root.innerRadius * 2 * Math.PI) / root.values.length - 4)
|
||||||
height: Settings.visualizerType === "diamond" ? value * 2 * (usableOuter - root.innerRadius) : value * (usableOuter - root.innerRadius)
|
height: Settings.settings.visualizerType === "diamond" ? value * 2 * (usableOuter - root.innerRadius) : value * (usableOuter - root.innerRadius)
|
||||||
radius: width / 2
|
radius: width / 2
|
||||||
color: root.fillColor
|
color: root.fillColor
|
||||||
border.color: root.strokeColor
|
border.color: root.strokeColor
|
||||||
border.width: root.strokeWidth
|
border.width: root.strokeWidth
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
|
|
||||||
x: Settings.visualizerType === "radial" ? root.width / 2 - width / 2 : root.width / 2 + root.innerRadius * Math.cos(Math.PI / 2 + 2 * Math.PI * index / root.values.length) - width / 2
|
x: Settings.settings.visualizerType === "radial" ? root.width / 2 - width / 2 : root.width / 2 + root.innerRadius * Math.cos(Math.PI / 2 + 2 * Math.PI * index / root.values.length) - width / 2
|
||||||
|
|
||||||
y: Settings.visualizerType === "radial" ? root.height / 2 - height : Settings.visualizerType === "diamond" ? root.height / 2 - root.innerRadius * Math.sin(Math.PI / 2 + 2 * Math.PI * index / root.values.length) - height / 2 : root.height / 2 - root.innerRadius * Math.sin(Math.PI / 2 + 2 * Math.PI * index / root.values.length) - height
|
y: Settings.settings.visualizerType === "radial" ? root.height / 2 - height : Settings.settings.visualizerType === "diamond" ? root.height / 2 - root.innerRadius * Math.sin(Math.PI / 2 + 2 * Math.PI * index / root.values.length) - height / 2 : root.height / 2 - root.innerRadius * Math.sin(Math.PI / 2 + 2 * Math.PI * index / root.values.length) - height
|
||||||
transform: [
|
transform: [
|
||||||
Rotation {
|
Rotation {
|
||||||
origin.x: width / 2
|
origin.x: width / 2
|
||||||
origin.y: Settings.visualizerType === "diamond" ? height / 2 : height
|
origin.y: Settings.settings.visualizerType === "diamond" ? height / 2 : height
|
||||||
angle: Settings.visualizerType === "radial" ? (index / root.values.length) * 360 : Settings.visualizerType === "fire" ? 0 : (index / root.values.length) * 360 - 90
|
angle: Settings.settings.visualizerType === "radial" ? (index / root.values.length) * 360 : Settings.settings.visualizerType === "fire" ? 0 : (index / root.values.length) * 360 - 90
|
||||||
},
|
},
|
||||||
Translate {
|
Translate {
|
||||||
x: Settings.visualizerType === "radial" ? root.innerRadius * Math.cos(2 * Math.PI * index / root.values.length) : 0
|
x: Settings.settings.visualizerType === "radial" ? root.innerRadius * Math.cos(2 * Math.PI * index / root.values.length) : 0
|
||||||
y: Settings.visualizerType === "radial" ? root.innerRadius * Math.sin(2 * Math.PI * index / root.values.length) : 0
|
y: Settings.settings.visualizerType === "radial" ? root.innerRadius * Math.sin(2 * Math.PI * index / root.values.length) : 0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
44
Components/PanelWithOverlay.qml
Normal file
44
Components/PanelWithOverlay.qml
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import qs.Settings
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: outerPanel
|
||||||
|
property bool showOverlay: true
|
||||||
|
property int topMargin: 36
|
||||||
|
property color overlayColor: showOverlay ? Theme.overlay : "transparent"
|
||||||
|
|
||||||
|
function dismiss() {
|
||||||
|
visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: screen.width
|
||||||
|
implicitHeight: screen.height
|
||||||
|
color: visible ? overlayColor : "transparent"
|
||||||
|
visible: false
|
||||||
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
|
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||||
|
screen: (typeof modelData !== 'undefined' ? modelData : null)
|
||||||
|
anchors.top: true
|
||||||
|
anchors.left: true
|
||||||
|
anchors.right: true
|
||||||
|
anchors.bottom: true
|
||||||
|
margins.top: topMargin
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: outerPanel.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: 350
|
||||||
|
easing.type: Easing.InOutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
|
||||||
import QtQuick.Window 2.15
|
import QtQuick.Window 2.15
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
|
|
||||||
|
|
@ -12,8 +11,9 @@ Window {
|
||||||
flags: Qt.ToolTip | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
|
flags: Qt.ToolTip | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
visible: false
|
visible: false
|
||||||
minimumWidth: Math.max(minimumWidth, tooltipText.implicitWidth + 24)
|
|
||||||
minimumHeight: Math.max(minimumHeight, tooltipText.implicitHeight + 16)
|
minimumWidth: tooltipText.implicitWidth + 24
|
||||||
|
minimumHeight: tooltipText.implicitHeight + 16
|
||||||
property var _timerObj: null
|
property var _timerObj: null
|
||||||
onTooltipVisibleChanged: {
|
onTooltipVisibleChanged: {
|
||||||
if (tooltipVisible) {
|
if (tooltipVisible) {
|
||||||
|
|
@ -33,26 +33,32 @@ Window {
|
||||||
x = pos.x - width / 2 + targetItem.width / 2;
|
x = pos.x - width / 2 + targetItem.width / 2;
|
||||||
y = pos.y + 12;
|
y = pos.y + 12;
|
||||||
visible = true;
|
visible = true;
|
||||||
console.log("StyledTooltip _showNow called");
|
|
||||||
console.log("StyledTooltip Theme.textPrimary:", Theme.textPrimary);
|
|
||||||
}
|
}
|
||||||
function _hideNow() {
|
function _hideNow() {
|
||||||
visible = false;
|
visible = false;
|
||||||
if (_timerObj) { _timerObj.destroy(); _timerObj = null; }
|
if (_timerObj) { _timerObj.destroy(); _timerObj = null; }
|
||||||
}
|
}
|
||||||
Connections {
|
Connections {
|
||||||
target: targetItem
|
target: tooltipWindow.targetItem
|
||||||
onXChanged: if (tooltipWindow.visible) tooltipWindow._showNow()
|
function onXChanged() {
|
||||||
onYChanged: if (tooltipWindow.visible) tooltipWindow._showNow()
|
if (tooltipWindow.visible) tooltipWindow._showNow()
|
||||||
onWidthChanged: if (tooltipWindow.visible) tooltipWindow._showNow()
|
}
|
||||||
onHeightChanged: if (tooltipWindow.visible) tooltipWindow._showNow()
|
function onYChanged() {
|
||||||
|
if (tooltipWindow.visible) tooltipWindow._showNow()
|
||||||
|
}
|
||||||
|
function onWidthChanged() {
|
||||||
|
if (tooltipWindow.visible) tooltipWindow._showNow()
|
||||||
|
}
|
||||||
|
function onHeightChanged() {
|
||||||
|
if (tooltipWindow.visible) tooltipWindow._showNow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Component.onCompleted: console.log("Tooltip window loaded")
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
radius: 6
|
radius: 6
|
||||||
color: "#222"
|
color: "#222"
|
||||||
border.color: Theme.border || "#444"
|
border.color: Theme.backgroundTertiary || "#444"
|
||||||
border.width: 1
|
border.width: 1
|
||||||
opacity: 0.97
|
opacity: 0.97
|
||||||
z: 1
|
z: 1
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Layouts 1.15
|
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property var tabsModel: [] // [{icon: "videocam", label: "Video"}, ...]
|
property var tabsModel: []
|
||||||
property int currentIndex: 0
|
property int currentIndex: 0
|
||||||
signal tabChanged(int index)
|
signal tabChanged(int index)
|
||||||
|
|
||||||
|
|
@ -16,17 +15,20 @@ Item {
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.tabsModel
|
model: root.tabsModel
|
||||||
delegate: Column {
|
delegate: Rectangle {
|
||||||
width: 56
|
id: tabWrapper
|
||||||
spacing: 2
|
implicitHeight: tab.height
|
||||||
|
implicitWidth: 56
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
property bool hovered: false
|
property bool hovered: false
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.currentIndex !== index) {
|
if (currentIndex !== index) {
|
||||||
root.currentIndex = index;
|
currentIndex = index;
|
||||||
root.tabChanged(index);
|
tabChanged(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
|
@ -35,43 +37,41 @@ Item {
|
||||||
onExited: parent.hovered = false
|
onExited: parent.hovered = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Icon
|
ColumnLayout {
|
||||||
Text {
|
id: tab
|
||||||
text: modelData.icon
|
spacing: 2
|
||||||
font.family: "Material Symbols Outlined"
|
anchors.centerIn: parent
|
||||||
font.pixelSize: 22
|
Layout.fillWidth: true
|
||||||
color: index === root.currentIndex
|
Layout.fillHeight: true
|
||||||
? (Theme ? Theme.accentPrimary : "#7C3AED")
|
|
||||||
: parent.hovered
|
|
||||||
? (Theme ? Theme.accentPrimary : "#7C3AED")
|
|
||||||
: (Theme ? Theme.textSecondary : "#444")
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Label
|
// Icon
|
||||||
Text {
|
Text {
|
||||||
text: modelData.label
|
text: modelData.icon
|
||||||
font.pixelSize: 12
|
font.family: "Material Symbols Outlined"
|
||||||
font.bold: index === root.currentIndex
|
font.pixelSize: 22
|
||||||
color: index === root.currentIndex
|
color: index === root.currentIndex ? (Theme ? Theme.accentPrimary : "#7C3AED") : tabWrapper.hovered ? (Theme ? Theme.accentPrimary : "#7C3AED") : (Theme ? Theme.textSecondary : "#444")
|
||||||
? (Theme ? Theme.accentPrimary : "#7C3AED")
|
Layout.alignment: Qt.AlignCenter
|
||||||
: parent.hovered
|
}
|
||||||
? (Theme ? Theme.accentPrimary : "#7C3AED")
|
|
||||||
: (Theme ? Theme.textSecondary : "#444")
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Underline for active tab
|
// Label
|
||||||
Rectangle {
|
Text {
|
||||||
width: 24
|
text: modelData.label
|
||||||
height: 2
|
font.pixelSize: 12
|
||||||
radius: 1
|
font.bold: index === root.currentIndex
|
||||||
color: index === root.currentIndex
|
color: index === root.currentIndex ? (Theme ? Theme.accentPrimary : "#7C3AED") : tabWrapper.hovered ? (Theme ? Theme.accentPrimary : "#7C3AED") : (Theme ? Theme.textSecondary : "#444")
|
||||||
? (Theme ? Theme.accentPrimary : "#7C3AED")
|
Layout.alignment: Qt.AlignCenter
|
||||||
: "transparent"
|
}
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
|
// Underline for active tab
|
||||||
|
Rectangle {
|
||||||
|
width: 24
|
||||||
|
height: 2
|
||||||
|
radius: 1
|
||||||
|
color: index === root.currentIndex ? (Theme ? Theme.accentPrimary : "#7C3AED") : "transparent"
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import Quickshell.Io
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
property var appLauncherPanel
|
property var appLauncherPanel
|
||||||
property var lockScreen
|
property var lockScreen
|
||||||
property var tabViewer
|
|
||||||
|
|
||||||
target: "globalIPC"
|
target: "globalIPC"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,18 @@ Singleton {
|
||||||
toggleRandomWallpaper();
|
toggleRandomWallpaper();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
property string wallpaperDirectory: Settings.wallpaperFolder
|
property string wallpaperDirectory: Settings.settings.wallpaperFolder
|
||||||
property var wallpaperList: []
|
property var wallpaperList: []
|
||||||
property string currentWallpaper: Settings.currentWallpaper
|
property string currentWallpaper: Settings.settings.currentWallpaper
|
||||||
property bool scanning: false
|
property bool scanning: false
|
||||||
property string transitionType: Settings.transitionType
|
property string transitionType: Settings.settings.transitionType
|
||||||
property var randomChoices: ["fade", "left", "right", "top", "bottom", "wipe", "wave", "grow", "center", "any", "outer"]
|
property var randomChoices: ["fade", "left", "right", "top", "bottom", "wipe", "wave", "grow", "center", "any", "outer"]
|
||||||
|
|
||||||
function loadWallpapers() {
|
function loadWallpapers() {
|
||||||
scanning = true;
|
scanning = true;
|
||||||
wallpaperList = [];
|
wallpaperList = [];
|
||||||
folderModel.folder = "";
|
folderModel.folder = "";
|
||||||
folderModel.folder = "file://" + (Settings.wallpaperFolder !== undefined ? Settings.wallpaperFolder : "");
|
folderModel.folder = "file://" + (Settings.settings.wallpaperFolder !== undefined ? Settings.settings.wallpaperFolder : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeWallpaper(path) {
|
function changeWallpaper(path) {
|
||||||
|
|
@ -36,14 +36,13 @@ Singleton {
|
||||||
function setCurrentWallpaper(path, isInitial) {
|
function setCurrentWallpaper(path, isInitial) {
|
||||||
currentWallpaper = path;
|
currentWallpaper = path;
|
||||||
if (!isInitial) {
|
if (!isInitial) {
|
||||||
Settings.currentWallpaper = path;
|
Settings.settings.currentWallpaper = path;
|
||||||
Settings.saveSettings();
|
|
||||||
}
|
}
|
||||||
if (Settings.useSWWW) {
|
if (Settings.settings.useSWWW) {
|
||||||
if (Settings.transitionType === "random") {
|
if (Settings.settings.transitionType === "random") {
|
||||||
transitionType = randomChoices[Math.floor(Math.random() * randomChoices.length)];
|
transitionType = randomChoices[Math.floor(Math.random() * randomChoices.length)];
|
||||||
} else {
|
} else {
|
||||||
transitionType = Settings.transitionType;
|
transitionType = Settings.settings.transitionType;
|
||||||
}
|
}
|
||||||
changeWallpaperProcess.running = true;
|
changeWallpaperProcess.running = true;
|
||||||
}
|
}
|
||||||
|
|
@ -60,16 +59,16 @@ Singleton {
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleRandomWallpaper() {
|
function toggleRandomWallpaper() {
|
||||||
if (Settings.randomWallpaper && !randomWallpaperTimer.running) {
|
if (Settings.settings.randomWallpaper && !randomWallpaperTimer.running) {
|
||||||
randomWallpaperTimer.start();
|
randomWallpaperTimer.start();
|
||||||
setRandomWallpaper();
|
setRandomWallpaper();
|
||||||
} else if (!Settings.randomWallpaper && randomWallpaperTimer.running) {
|
} else if (!Settings.settings.randomWallpaper && randomWallpaperTimer.running) {
|
||||||
randomWallpaperTimer.stop();
|
randomWallpaperTimer.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function restartRandomWallpaperTimer() {
|
function restartRandomWallpaperTimer() {
|
||||||
if (Settings.randomWallpaper) {
|
if (Settings.settings.randomWallpaper) {
|
||||||
randomWallpaperTimer.stop();
|
randomWallpaperTimer.stop();
|
||||||
randomWallpaperTimer.start();
|
randomWallpaperTimer.start();
|
||||||
setRandomWallpaper();
|
setRandomWallpaper();
|
||||||
|
|
@ -77,14 +76,14 @@ Singleton {
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateTheme() {
|
function generateTheme() {
|
||||||
if (Settings.useWallpaperTheme) {
|
if (Settings.settings.useWallpaperTheme) {
|
||||||
generateThemeProcess.running = true;
|
generateThemeProcess.running = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: randomWallpaperTimer
|
id: randomWallpaperTimer
|
||||||
interval: Settings.wallpaperInterval * 1000
|
interval: Settings.settings.wallpaperInterval * 1000
|
||||||
running: false
|
running: false
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: setRandomWallpaper()
|
onTriggered: setRandomWallpaper()
|
||||||
|
|
@ -100,7 +99,7 @@ Singleton {
|
||||||
if (status === FolderListModel.Ready) {
|
if (status === FolderListModel.Ready) {
|
||||||
var files = [];
|
var files = [];
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
var fileph = (Settings.wallpaperFolder !== undefined ? Settings.wallpaperFolder : "") + "/" + get(i, "fileName");
|
var fileph = (Settings.settings.wallpaperFolder !== undefined ? Settings.settings.wallpaperFolder : "") + "/" + get(i, "fileName");
|
||||||
files.push(fileph);
|
files.push(fileph);
|
||||||
}
|
}
|
||||||
wallpaperList = files;
|
wallpaperList = files;
|
||||||
|
|
@ -111,7 +110,7 @@ Singleton {
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: changeWallpaperProcess
|
id: changeWallpaperProcess
|
||||||
command: ["swww", "img", "--resize", Settings.wallpaperResize, "--transition-fps", Settings.transitionFps.toString(), "--transition-type", transitionType, "--transition-duration", Settings.transitionDuration.toString(), currentWallpaper]
|
command: ["swww", "img", "--resize", Settings.settings.wallpaperResize, "--transition-fps", Settings.settings.transitionFps.toString(), "--transition-type", transitionType, "--transition-duration", Settings.settings.transitionDuration.toString(), currentWallpaper]
|
||||||
running: false
|
running: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ Singleton {
|
||||||
id: i,
|
id: i,
|
||||||
idx: ws.id,
|
idx: ws.id,
|
||||||
name: ws.name || "",
|
name: ws.name || "",
|
||||||
output: ws.monitor.name || "",
|
output: ws.monitor?.name || "",
|
||||||
isActive: ws.active === true,
|
isActive: ws.active === true,
|
||||||
isFocused: ws.focused === true,
|
isFocused: ws.focused === true,
|
||||||
isUrgent: ws.urgent === true
|
isUrgent: ws.urgent === true
|
||||||
|
|
|
||||||
|
|
@ -1,98 +1,66 @@
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtCore
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
QtObject {
|
Singleton {
|
||||||
|
|
||||||
Component.onCompleted: {
|
property string shellName: "Noctalia"
|
||||||
Qt.application.name = "quickshell"
|
property string settingsDir: Quickshell.env("HOME") + "/.config/" + shellName + "/"
|
||||||
Qt.application.organization = "quickshell"
|
property string settingsFile: settingsDir + "Settings.json"
|
||||||
Qt.application.domain = "quickshell.app"
|
property var settings: settingAdapter
|
||||||
loadSettings()
|
|
||||||
}
|
|
||||||
property string weatherCity: "Dinslaken"
|
|
||||||
property string profileImage: "/home/" + Quickshell.env("USER") + "/.face"
|
|
||||||
property bool useFahrenheit: false
|
|
||||||
property string wallpaperFolder: "/usr/share/wallpapers"
|
|
||||||
property string currentWallpaper: ""
|
|
||||||
property string videoPath: "~/Videos/"
|
|
||||||
property bool showActiveWindowIcon: false
|
|
||||||
property bool useSWWW: false
|
|
||||||
property bool randomWallpaper: false
|
|
||||||
property bool useWallpaperTheme: false
|
|
||||||
property bool showSystemInfoInBar: true
|
|
||||||
property bool showMediaInBar: false
|
|
||||||
property int wallpaperInterval: 300
|
|
||||||
property string wallpaperResize: "crop"
|
|
||||||
property int transitionFps: 60
|
|
||||||
property string transitionType: "random"
|
|
||||||
property real transitionDuration: 1.1
|
|
||||||
property string visualizerType: "radial" // Options: "fire", "diamond", "radial"
|
|
||||||
|
|
||||||
// Settings persistence
|
Item {
|
||||||
property var settings: Settings {
|
Component.onCompleted: {
|
||||||
category: "quickshell"
|
// ensure settings dir
|
||||||
|
Quickshell.execDetached(["mkdir", "-p", settingsDir]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSettings() {
|
FileView {
|
||||||
weatherCity = settings.value("weatherCity", weatherCity)
|
id: settingFileView
|
||||||
profileImage = settings.value("profileImage", profileImage)
|
path: settingsFile
|
||||||
let tempUnit = settings.value("weatherTempUnit", "celsius")
|
watchChanges: true
|
||||||
useFahrenheit = (tempUnit === "fahrenheit")
|
onFileChanged: reload()
|
||||||
wallpaperFolder = settings.value("wallpaperFolder", wallpaperFolder)
|
onAdapterUpdated: writeAdapter()
|
||||||
currentWallpaper = settings.value("currentWallpaper", currentWallpaper)
|
Component.onCompleted: function() {
|
||||||
videoPath = settings.value("videoPath", videoPath)
|
reload()
|
||||||
let showActiveWindowIconFlag = settings.value("showActiveWindowIconFlag", "false")
|
}
|
||||||
showActiveWindowIcon = showActiveWindowIconFlag === "true"
|
onLoaded: function() {
|
||||||
let showSystemInfoInBarFlag = settings.value("showSystemInfoInBarFlag", "true")
|
WallpaperManager.setCurrentWallpaper(settings.currentWallpaper, true);
|
||||||
showSystemInfoInBar = showSystemInfoInBarFlag === "true"
|
}
|
||||||
let showMediaInBarFlag = settings.value("showMediaInBarFlag", "true")
|
onLoadFailed: function(error) {
|
||||||
showMediaInBar = showMediaInBarFlag === "true"
|
settingAdapter = {}
|
||||||
let useSWWWFlag = settings.value("useSWWWFlag", "false")
|
writeAdapter()
|
||||||
useSWWW = useSWWWFlag === "true"
|
}
|
||||||
let randomWallpaperFlag = settings.value("randomWallpaperFlag", "false")
|
JsonAdapter {
|
||||||
randomWallpaper = randomWallpaperFlag === "true"
|
id: settingAdapter
|
||||||
let useWallpaperThemeFlag = settings.value("useWallpaperThemeFlag", "false")
|
property string weatherCity: "Dinslaken"
|
||||||
useWallpaperTheme = useWallpaperThemeFlag === "true"
|
property string profileImage: Quickshell.env("HOME") + "/.face"
|
||||||
wallpaperInterval = settings.value("wallpaperInterval", wallpaperInterval)
|
property bool useFahrenheit: false
|
||||||
wallpaperResize = settings.value("wallpaperResize", wallpaperResize)
|
property string wallpaperFolder: "/usr/share/wallpapers"
|
||||||
transitionFps = settings.value("transitionFps", transitionFps)
|
property string currentWallpaper: ""
|
||||||
transitionType = settings.value("transitionType", transitionType)
|
property string videoPath: "~/Videos/"
|
||||||
transitionDuration = settings.value("transitionDuration", transitionDuration)
|
property bool showActiveWindowIcon: false
|
||||||
visualizerType = settings.value("visualizerType", visualizerType)
|
property bool showSystemInfoInBar: false
|
||||||
|
property bool showMediaInBar: false
|
||||||
WallpaperManager.setCurrentWallpaper(currentWallpaper, true);
|
property bool useSWWW: false
|
||||||
|
property bool randomWallpaper: false
|
||||||
|
property bool useWallpaperTheme: false
|
||||||
|
property int wallpaperInterval: 300
|
||||||
|
property string wallpaperResize: "crop"
|
||||||
|
property int transitionFps: 60
|
||||||
|
property string transitionType: "random"
|
||||||
|
property real transitionDuration: 1.1
|
||||||
|
property string visualizerType: "radial"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSettings() {
|
Connections {
|
||||||
settings.setValue("weatherCity", weatherCity)
|
target: settingAdapter
|
||||||
settings.setValue("profileImage", profileImage)
|
function onRandomWallpaperChanged() { WallpaperManager.toggleRandomWallpaper() }
|
||||||
settings.setValue("weatherTempUnit", useFahrenheit ? "fahrenheit" : "celsius")
|
function onWallpaperIntervalChanged() { WallpaperManager.restartRandomWallpaperTimer() }
|
||||||
settings.setValue("wallpaperFolder", wallpaperFolder)
|
function onWallpaperFolderChanged() { WallpaperManager.loadWallpapers() }
|
||||||
settings.setValue("currentWallpaper", currentWallpaper)
|
|
||||||
settings.setValue("videoPath", videoPath)
|
|
||||||
settings.setValue("showActiveWindowIconFlag", showActiveWindowIcon ? "true" : "false")
|
|
||||||
settings.setValue("showSystemInfoInBarFlag", showSystemInfoInBar ? "true" : "false")
|
|
||||||
settings.setValue("showMediaInBarFlag", showMediaInBar ? "true" : "false")
|
|
||||||
settings.setValue("useSWWWFlag", useSWWW ? "true" : "false")
|
|
||||||
settings.setValue("randomWallpaperFlag", randomWallpaper ? "true" : "false")
|
|
||||||
settings.setValue("useWallpaperThemeFlag", useWallpaperTheme ? "true" : "false")
|
|
||||||
settings.setValue("wallpaperInterval", wallpaperInterval)
|
|
||||||
settings.setValue("wallpaperResize", wallpaperResize)
|
|
||||||
settings.setValue("transitionFps", transitionFps)
|
|
||||||
settings.setValue("transitionType", transitionType)
|
|
||||||
settings.setValue("transitionDuration", transitionDuration)
|
|
||||||
settings.setValue("visualizerType", visualizerType)
|
|
||||||
settings.sync()
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Property change handlers to auto-save (all commented out for explicit save only)
|
|
||||||
// onWeatherCityChanged: saveSettings()
|
|
||||||
// onProfileImageChanged: saveSettings()
|
|
||||||
// onUseFahrenheitChanged: saveSettings()
|
|
||||||
onRandomWallpaperChanged: WallpaperManager.toggleRandomWallpaper()
|
|
||||||
onWallpaperIntervalChanged: WallpaperManager.restartRandomWallpaperTimer()
|
|
||||||
onWallpaperFolderChanged: WallpaperManager.loadWallpapers()
|
|
||||||
}
|
|
||||||
|
|
@ -3,6 +3,7 @@ pragma Singleton
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import qs.Settings
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
@ -14,11 +15,16 @@ Singleton {
|
||||||
// FileView to load theme data from JSON file
|
// FileView to load theme data from JSON file
|
||||||
FileView {
|
FileView {
|
||||||
id: themeFile
|
id: themeFile
|
||||||
path: Quickshell.configDir + "/Settings/Theme.json"
|
path: Settings.settingsDir + "Theme.json"
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
onFileChanged: reload()
|
onFileChanged: reload()
|
||||||
onAdapterUpdated: writeAdapter()
|
onAdapterUpdated: writeAdapter()
|
||||||
|
onLoadFailed: function(error) {
|
||||||
|
if (error.includes("No such file")) {
|
||||||
|
themeData = {}
|
||||||
|
writeAdapter()
|
||||||
|
}
|
||||||
|
}
|
||||||
JsonAdapter {
|
JsonAdapter {
|
||||||
id: themeData
|
id: themeData
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,4 +44,4 @@ check_contrast = true
|
||||||
# target: ABSOLUTE path in which to place a file with generated templated values.
|
# target: ABSOLUTE path in which to place a file with generated templated values.
|
||||||
# ¡ If either one is a directory, then both SHOULD be one. !
|
# ¡ If either one is a directory, then both SHOULD be one. !
|
||||||
# zathura = { template = 'zathura', target = '~/.config/zathura/zathurarc' }
|
# zathura = { template = 'zathura', target = '~/.config/zathura/zathurarc' }
|
||||||
Quickshell = { template = 'quickshell.json', target = 'Settings/Theme.json' }
|
Quickshell = { template = 'quickshell.json', target = '~/.config/Noctalia/Theme.json' }
|
||||||
|
|
@ -5,7 +5,7 @@ import qs.Services
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
property string wallpaperSource: WallpaperManager.currentWallpaper !== "" && !Settings.useSWWW ? WallpaperManager.currentWallpaper : ""
|
property string wallpaperSource: WallpaperManager.currentWallpaper !== "" && !Settings.settings.useSWWW ? WallpaperManager.currentWallpaper : ""
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
visible: wallpaperSource !== ""
|
visible: wallpaperSource !== ""
|
||||||
anchors {
|
anchors {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ WlSessionLock {
|
||||||
property bool authenticating: false
|
property bool authenticating: false
|
||||||
property string password: ""
|
property string password: ""
|
||||||
property bool pamAvailable: typeof PamContext !== "undefined"
|
property bool pamAvailable: typeof PamContext !== "undefined"
|
||||||
property string weatherCity: Settings.weatherCity
|
property string weatherCity: Settings.settings.weatherCity
|
||||||
property var weatherData: null
|
property var weatherData: null
|
||||||
property string weatherError: ""
|
property string weatherError: ""
|
||||||
property string weatherInfo: ""
|
property string weatherInfo: ""
|
||||||
|
|
@ -161,7 +161,7 @@ WlSessionLock {
|
||||||
id: avatarImage
|
id: avatarImage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 4
|
anchors.margins: 4
|
||||||
source: Settings.profileImage
|
source: Settings.settings.profileImage
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
visible: false // Only show the masked version
|
visible: false // Only show the masked version
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
|
|
@ -175,7 +175,7 @@ WlSessionLock {
|
||||||
radius: avatarImage.width / 2
|
radius: avatarImage.width / 2
|
||||||
visible: false
|
visible: false
|
||||||
}
|
}
|
||||||
visible: Settings.profileImage !== ""
|
visible: Settings.settings.profileImage !== ""
|
||||||
}
|
}
|
||||||
// Fallback icon
|
// Fallback icon
|
||||||
Text {
|
Text {
|
||||||
|
|
@ -184,7 +184,7 @@ WlSessionLock {
|
||||||
font.family: "Material Symbols Outlined"
|
font.family: "Material Symbols Outlined"
|
||||||
font.pixelSize: 32
|
font.pixelSize: 32
|
||||||
color: Theme.onAccent
|
color: Theme.onAccent
|
||||||
visible: Settings.profileImage === ""
|
visible: Settings.settings.profileImage === ""
|
||||||
}
|
}
|
||||||
// Glow effect
|
// Glow effect
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
|
|
@ -357,7 +357,7 @@ WlSessionLock {
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
Text {
|
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.family: Theme.fontFamily
|
||||||
font.pixelSize: 18
|
font.pixelSize: 18
|
||||||
color: Theme.textSecondary
|
color: Theme.textSecondary
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,30 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Components
|
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
|
||||||
Item {
|
// The popup window
|
||||||
id: root
|
PanelWithOverlay {
|
||||||
property string configDir: Quickshell.configDir
|
id: notificationHistoryWin
|
||||||
property string historyFilePath: configDir + "/notification_history.json"
|
property string historyFilePath: Settings.settingsDir + "notification_history.json"
|
||||||
property bool hasUnread: notificationHistoryWin.hasUnread && !notificationHistoryWin.visible
|
property bool hasUnread: notificationHistoryWinRect.hasUnread && !notificationHistoryWinRect.visible
|
||||||
function addToHistory(notification) { notificationHistoryWin.addToHistory(notification) }
|
function addToHistory(notification) { notificationHistoryWinRect.addToHistory(notification) }
|
||||||
width: 22; height: 22
|
Rectangle {
|
||||||
|
id: notificationHistoryWinRect
|
||||||
// Bell icon/button
|
implicitWidth: 400
|
||||||
Item {
|
property int maxPopupHeight: 800
|
||||||
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
|
|
||||||
property int minPopupHeight: 230
|
property int minPopupHeight: 230
|
||||||
property int contentHeight: headerRow.height + historyList.contentHeight + 56
|
property int contentHeight: headerRow.height + historyList.contentHeight + 56
|
||||||
height: Math.max(Math.min(contentHeight, maxPopupHeight), minPopupHeight)
|
implicitHeight: Math.max(Math.min(contentHeight, maxPopupHeight), minPopupHeight)
|
||||||
color: "transparent"
|
visible: parent.visible
|
||||||
visible: false
|
anchors.top: parent.top
|
||||||
screen: Quickshell.primaryScreen
|
anchors.right: parent.right
|
||||||
focusable: true
|
anchors.topMargin: 4
|
||||||
anchors.top: true
|
anchors.rightMargin: 4
|
||||||
anchors.right: true
|
color: Theme.backgroundPrimary
|
||||||
margins.top: 4
|
radius: 20
|
||||||
margins.right: 4
|
|
||||||
|
|
||||||
property int maxHistory: 100
|
property int maxHistory: 100
|
||||||
property bool hasUnread: false
|
property bool hasUnread: false
|
||||||
|
|
@ -62,25 +36,24 @@ Item {
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
id: historyFileView
|
id: historyFileView
|
||||||
path: root.historyFilePath
|
path: notificationHistoryWin.historyFilePath
|
||||||
blockLoading: true
|
blockLoading: true
|
||||||
printErrors: true
|
printErrors: true
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
|
|
||||||
JsonAdapter {
|
JsonAdapter {
|
||||||
id: historyAdapter
|
id: historyAdapter
|
||||||
property var notifications: []
|
property var notifications: []
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileChanged: historyFileView.reload()
|
onFileChanged: historyFileView.reload()
|
||||||
onLoaded: notificationHistoryWin.loadHistory()
|
onLoaded: notificationHistoryWinRect.loadHistory()
|
||||||
onLoadFailed: function(error) {
|
onLoadFailed: function (error) {
|
||||||
if (error.includes("No such file")) {
|
historyAdapter.notifications = [];
|
||||||
historyAdapter.notifications = []
|
historyFileView.writeAdapter();
|
||||||
writeAdapter()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Component.onCompleted: if (path) reload()
|
Component.onCompleted: if (path)
|
||||||
|
reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateHasUnread() {
|
function updateHasUnread() {
|
||||||
|
|
@ -99,16 +72,18 @@ Item {
|
||||||
|
|
||||||
function loadHistory() {
|
function loadHistory() {
|
||||||
if (historyAdapter.notifications) {
|
if (historyAdapter.notifications) {
|
||||||
historyModel.clear()
|
historyModel.clear();
|
||||||
const notifications = historyAdapter.notifications
|
const notifications = historyAdapter.notifications;
|
||||||
const count = Math.min(notifications.length, maxHistory)
|
const count = Math.min(notifications.length, maxHistory);
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
let n = notifications[i]
|
let n = notifications[i];
|
||||||
if (typeof n === 'object' && n !== null) {
|
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
|
// Mark as read if window is open
|
||||||
if (visible) n.read = true;
|
if (notificationHistoryWinRect.visible)
|
||||||
historyModel.append(n)
|
n.read = true;
|
||||||
|
historyModel.append(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateHasUnread();
|
updateHasUnread();
|
||||||
|
|
@ -116,10 +91,10 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveHistory() {
|
function saveHistory() {
|
||||||
const historyArray = []
|
const historyArray = [];
|
||||||
const count = Math.min(historyModel.count, maxHistory)
|
const count = Math.min(historyModel.count, maxHistory);
|
||||||
for (let i = 0; i < count; ++i) {
|
for (let i = 0; i < count; ++i) {
|
||||||
let obj = historyModel.get(i)
|
let obj = historyModel.get(i);
|
||||||
if (typeof obj === 'object' && obj !== null) {
|
if (typeof obj === 'object' && obj !== null) {
|
||||||
historyArray.push({
|
historyArray.push({
|
||||||
id: obj.id,
|
id: obj.id,
|
||||||
|
|
@ -128,51 +103,55 @@ Item {
|
||||||
body: obj.body,
|
body: obj.body,
|
||||||
timestamp: obj.timestamp,
|
timestamp: obj.timestamp,
|
||||||
read: obj.read === undefined ? false : obj.read
|
read: obj.read === undefined ? false : obj.read
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
historyAdapter.notifications = historyArray
|
historyAdapter.notifications = historyArray;
|
||||||
Qt.callLater(function() {
|
Qt.callLater(function () {
|
||||||
historyFileView.writeAdapter()
|
historyFileView.writeAdapter();
|
||||||
})
|
});
|
||||||
updateHasUnread();
|
updateHasUnread();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToHistory(notification) {
|
function addToHistory(notification) {
|
||||||
if (!notification.id) notification.id = Date.now()
|
if (!notification.id)
|
||||||
if (!notification.timestamp) notification.timestamp = new Date().toISOString()
|
notification.id = Date.now();
|
||||||
|
if (!notification.timestamp)
|
||||||
|
notification.timestamp = new Date().toISOString();
|
||||||
|
|
||||||
// Mark as read if window is open
|
// Mark as read if window is open
|
||||||
notification.read = visible
|
notification.read = visible;
|
||||||
|
|
||||||
// Remove duplicate by id
|
// Remove duplicate by id
|
||||||
for (let i = 0; i < historyModel.count; ++i) {
|
for (let i = 0; i < historyModel.count; ++i) {
|
||||||
if (historyModel.get(i).id === notification.id) {
|
if (historyModel.get(i).id === notification.id) {
|
||||||
historyModel.remove(i)
|
historyModel.remove(i);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
historyModel.insert(0, notification)
|
historyModel.insert(0, notification);
|
||||||
|
|
||||||
if (historyModel.count > maxHistory) historyModel.remove(maxHistory)
|
if (historyModel.count > maxHistory)
|
||||||
saveHistory()
|
historyModel.remove(maxHistory);
|
||||||
|
saveHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearHistory() {
|
function clearHistory() {
|
||||||
historyModel.clear()
|
historyModel.clear();
|
||||||
historyAdapter.notifications = []
|
historyAdapter.notifications = [];
|
||||||
historyFileView.writeAdapter()
|
historyFileView.writeAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatTimestamp(ts) {
|
function formatTimestamp(ts) {
|
||||||
if (!ts) return "";
|
if (!ts)
|
||||||
|
return "";
|
||||||
var date = typeof ts === "number" ? new Date(ts) : new Date(Date.parse(ts));
|
var date = typeof ts === "number" ? new Date(ts) : new Date(Date.parse(ts));
|
||||||
var y = date.getFullYear();
|
var y = date.getFullYear();
|
||||||
var m = (date.getMonth()+1).toString().padStart(2,'0');
|
var m = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||||
var d = date.getDate().toString().padStart(2,'0');
|
var d = date.getDate().toString().padStart(2, '0');
|
||||||
var h = date.getHours().toString().padStart(2,'0');
|
var h = date.getHours().toString().padStart(2, '0');
|
||||||
var min = date.getMinutes().toString().padStart(2,'0');
|
var min = date.getMinutes().toString().padStart(2, '0');
|
||||||
return `${y}-${m}-${d} ${h}:${min}`;
|
return `${y}-${m}-${d} ${h}:${min}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -186,13 +165,14 @@ Item {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (changed) saveHistory();
|
if (changed)
|
||||||
|
saveHistory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: notificationHistoryWin.width
|
width: notificationHistoryWinRect.width
|
||||||
height: notificationHistoryWin.height
|
height: notificationHistoryWinRect.height
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Theme.backgroundPrimary
|
color: Theme.backgroundPrimary
|
||||||
radius: 20
|
radius: 20
|
||||||
|
|
@ -205,10 +185,12 @@ Item {
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: headerRow
|
id: headerRow
|
||||||
spacing: 4
|
spacing: 4
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 4
|
anchors.topMargin: 4
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.preferredHeight: 52
|
||||||
anchors.leftMargin: 16
|
anchors.leftMargin: 16
|
||||||
anchors.rightMargin: 16
|
anchors.rightMargin: 16
|
||||||
Text {
|
Text {
|
||||||
|
|
@ -218,7 +200,9 @@ Item {
|
||||||
color: Theme.textPrimary
|
color: Theme.textPrimary
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
}
|
}
|
||||||
Item { Layout.fillWidth: true }
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: clearAllButton
|
id: clearAllButton
|
||||||
width: 90
|
width: 90
|
||||||
|
|
@ -251,7 +235,7 @@ Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: notificationHistoryWin.clearHistory()
|
onClicked: notificationHistoryWinRect.clearHistory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -264,11 +248,10 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 56
|
anchors.topMargin: 56
|
||||||
anchors.bottom: parent.bottom
|
height: notificationHistoryWinRect.height - 56 - 12
|
||||||
color: Theme.surfaceVariant
|
color: Theme.surfaceVariant
|
||||||
radius: 20
|
radius: 20
|
||||||
|
|
||||||
|
|
@ -288,7 +271,10 @@ Item {
|
||||||
Column {
|
Column {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
Item { id: topSpacer; height: (parent.height - historyList.height) / 2 }
|
Item {
|
||||||
|
id: topSpacer
|
||||||
|
height: (parent.height - historyList.height) / 2
|
||||||
|
}
|
||||||
ListView {
|
ListView {
|
||||||
id: historyList
|
id: historyList
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
@ -315,7 +301,7 @@ Item {
|
||||||
anchors.margins: 14
|
anchors.margins: 14
|
||||||
spacing: 6
|
spacing: 6
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: headerRow
|
id: headerRow2
|
||||||
spacing: 8
|
spacing: 8
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: iconBackground
|
id: iconBackground
|
||||||
|
|
@ -349,14 +335,16 @@ Item {
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
visible: !model.isPlaceholder
|
visible: !model.isPlaceholder
|
||||||
text: model.timestamp ? notificationHistoryWin.formatTimestamp(model.timestamp) : ""
|
text: model.timestamp ? notificationHistoryWinRect.formatTimestamp(model.timestamp) : ""
|
||||||
color: Theme.textDisabled
|
color: Theme.textDisabled
|
||||||
font.family: Theme.fontFamily
|
font.family: Theme.fontFamily
|
||||||
font.pixelSize: Theme.fontSizeCaption
|
font.pixelSize: Theme.fontSizeCaption
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item { Layout.fillWidth: true }
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: model.summary || (model.isPlaceholder ? "You're all caught up!" : "")
|
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 {
|
ListModel {
|
||||||
id: placeholderModel
|
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
|
border.width: 1.5
|
||||||
|
|
||||||
// Get all possible icon sources from notification
|
// Get all possible icon sources from notification
|
||||||
property var iconSources: [
|
property var iconSources: [rawNotification?.image || "", rawNotification?.appIcon || "", rawNotification?.icon || ""]
|
||||||
rawNotification?.image || "",
|
|
||||||
rawNotification?.appIcon || "",
|
|
||||||
rawNotification?.icon || ""
|
|
||||||
]
|
|
||||||
|
|
||||||
// Try to load notification icon
|
// Try to load notification icon
|
||||||
Image {
|
Image {
|
||||||
|
|
@ -131,7 +127,8 @@ PanelWindow {
|
||||||
source: {
|
source: {
|
||||||
for (var i = 0; i < iconBackground.iconSources.length; i++) {
|
for (var i = 0; i < iconBackground.iconSources.length; i++) {
|
||||||
var icon = iconBackground.iconSources[i];
|
var icon = iconBackground.iconSources[i];
|
||||||
if (!icon) continue;
|
if (!icon)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (icon.includes("?path=")) {
|
if (icon.includes("?path=")) {
|
||||||
const [name, path] = icon.split("?path=");
|
const [name, path] = icon.split("?path=");
|
||||||
|
|
@ -202,7 +199,8 @@ PanelWindow {
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
dismissAnimation.start();
|
dismissAnimation.start();
|
||||||
if (rawNotification) rawNotification.expire();
|
if (rawNotification)
|
||||||
|
rawNotification.expire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,28 +208,63 @@ PanelWindow {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
dismissAnimation.start();
|
dismissAnimation.start();
|
||||||
if (rawNotification) rawNotification.dismiss();
|
if (rawNotification)
|
||||||
|
rawNotification.dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParallelAnimation {
|
ParallelAnimation {
|
||||||
id: dismissAnimation
|
id: dismissAnimation
|
||||||
NumberAnimation { target: notificationDelegate; property: "opacity"; to: 0; duration: 150 }
|
NumberAnimation {
|
||||||
NumberAnimation { target: notificationDelegate; property: "height"; to: 0; duration: 150 }
|
target: notificationDelegate
|
||||||
NumberAnimation { target: notificationDelegate; property: "x"; to: width; duration: 150; easing.type: Easing.InQuad }
|
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: {
|
onFinished: {
|
||||||
var idx = notificationRepeater.indexOf(notificationDelegate);
|
for (let i = 0; i < notificationModel.count; i++) {
|
||||||
if (idx !== -1) {
|
if (notificationModel.get(i).id === notificationDelegate.id) {
|
||||||
notificationModel.remove(idx);
|
notificationModel.remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParallelAnimation {
|
ParallelAnimation {
|
||||||
id: appearAnimation
|
id: appearAnimation
|
||||||
NumberAnimation { target: notificationDelegate; property: "opacity"; to: 1; duration: 150 }
|
NumberAnimation {
|
||||||
NumberAnimation { target: notificationDelegate; property: "height"; to: contentRow.height + 20; duration: 150 }
|
target: notificationDelegate
|
||||||
NumberAnimation { target: notificationDelegate; property: "x"; to: 0; duration: 150; easing.type: Easing.OutQuad }
|
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: {
|
Component.onCompleted: {
|
||||||
|
|
@ -240,18 +273,21 @@ PanelWindow {
|
||||||
height = 0;
|
height = 0;
|
||||||
x = width;
|
x = width;
|
||||||
appearAnimation.start();
|
appearAnimation.start();
|
||||||
var idx = notificationRepeater.indexOf(notificationDelegate);
|
for (let i = 0; i < notificationModel.count; i++) {
|
||||||
if (idx !== -1) {
|
if (notificationModel.get(i).id === notificationDelegate.id) {
|
||||||
var oldItem = notificationModel.get(idx);
|
var oldItem = notificationModel.get(i);
|
||||||
notificationModel.set(idx, {
|
notificationModel.set(i, {
|
||||||
id: oldItem.id,
|
id: oldItem.id,
|
||||||
appName: oldItem.appName,
|
appName: oldItem.appName,
|
||||||
summary: oldItem.summary,
|
summary: oldItem.summary,
|
||||||
body: oldItem.body,
|
body: oldItem.body,
|
||||||
rawNotification: oldItem.rawNotification,
|
rawNotification: oldItem.rawNotification,
|
||||||
appeared: true,
|
appeared: true,
|
||||||
dismissed: oldItem.dismissed
|
read: oldItem.read,
|
||||||
});
|
dismissed: oldItem.dismissed
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +299,7 @@ PanelWindow {
|
||||||
target: Quickshell
|
target: Quickshell
|
||||||
function onScreensChanged() {
|
function onScreensChanged() {
|
||||||
if (window.screen) {
|
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
|
import qs.Settings
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
property string wallpaperSource: WallpaperManager.currentWallpaper !== "" && !Settings.useSWWW ? WallpaperManager.currentWallpaper : ""
|
property string wallpaperSource: WallpaperManager.currentWallpaper !== "" && !Settings.settings.useSWWW ? WallpaperManager.currentWallpaper : ""
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
visible: wallpaperSource !== ""
|
visible: wallpaperSource !== ""
|
||||||
anchors {
|
anchors {
|
||||||
|
|
|
||||||
|
|
@ -22,19 +22,6 @@ Item {
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (sidebarPopup.visible) {
|
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();
|
sidebarPopup.hidePopup();
|
||||||
} else {
|
} else {
|
||||||
sidebarPopup.showAt();
|
sidebarPopup.showAt();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
|
|
||||||
|
|
@ -9,19 +9,10 @@ Rectangle {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 340
|
Layout.preferredHeight: 340
|
||||||
color: Theme.surface
|
color: Theme.surface
|
||||||
Layout.topMargin: 12
|
|
||||||
radius: 18
|
radius: 18
|
||||||
border.color: "transparent"
|
border.color: "transparent"
|
||||||
border.width: 0
|
border.width: 0
|
||||||
Layout.bottomMargin: 16
|
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 {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -66,7 +57,7 @@ Rectangle {
|
||||||
id: avatarImage
|
id: avatarImage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 2
|
anchors.margins: 2
|
||||||
source: Settings.profileImage
|
source: Settings.settings.profileImage
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
visible: false
|
visible: false
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
|
|
@ -83,7 +74,7 @@ Rectangle {
|
||||||
radius: avatarImage.width / 2
|
radius: avatarImage.width / 2
|
||||||
visible: false
|
visible: false
|
||||||
}
|
}
|
||||||
visible: Settings.profileImage !== ""
|
visible: Settings.settings.profileImage !== ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback icon
|
// Fallback icon
|
||||||
|
|
@ -93,7 +84,7 @@ Rectangle {
|
||||||
font.family: "Material Symbols Outlined"
|
font.family: "Material Symbols Outlined"
|
||||||
font.pixelSize: 18
|
font.pixelSize: 18
|
||||||
color: Theme.accentPrimary
|
color: Theme.accentPrimary
|
||||||
visible: Settings.profileImage === ""
|
visible: Settings.settings.profileImage === ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,7 +101,7 @@ Rectangle {
|
||||||
id: profileImageInput
|
id: profileImageInput
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 12
|
anchors.margins: 12
|
||||||
text: Settings.profileImage
|
text: Settings.settings.profileImage
|
||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
color: Theme.textPrimary
|
color: Theme.textPrimary
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
@ -120,7 +111,7 @@ Rectangle {
|
||||||
activeFocusOnTab: true
|
activeFocusOnTab: true
|
||||||
inputMethodHints: Qt.ImhNone
|
inputMethodHints: Qt.ImhNone
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
Settings.profileImage = text
|
Settings.settings.profileImage = text
|
||||||
}
|
}
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -154,8 +145,8 @@ Rectangle {
|
||||||
width: 52
|
width: 52
|
||||||
height: 32
|
height: 32
|
||||||
radius: 16
|
radius: 16
|
||||||
color: showActiveWindowIcon ? Theme.accentPrimary : Theme.surfaceVariant
|
color: Settings.settings.showActiveWindowIcon ? Theme.accentPrimary : Theme.surfaceVariant
|
||||||
border.color: showActiveWindowIcon ? Theme.accentPrimary : Theme.outline
|
border.color: Settings.settings.showActiveWindowIcon ? Theme.accentPrimary : Theme.outline
|
||||||
border.width: 2
|
border.width: 2
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -167,7 +158,7 @@ Rectangle {
|
||||||
border.color: Theme.outline
|
border.color: Theme.outline
|
||||||
border.width: 1
|
border.width: 1
|
||||||
y: 2
|
y: 2
|
||||||
x: showActiveWindowIcon ? customSwitch.width - width - 2 : 2
|
x: Settings.settings.showActiveWindowIcon ? customSwitch.width - width - 2 : 2
|
||||||
|
|
||||||
Behavior on x {
|
Behavior on x {
|
||||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||||
|
|
@ -177,7 +168,7 @@ Rectangle {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
showAWIconChanged(!showActiveWindowIcon)
|
Settings.settings.showActiveWindowIcon = !Settings.settings.showActiveWindowIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -206,8 +197,8 @@ Rectangle {
|
||||||
width: 52
|
width: 52
|
||||||
height: 32
|
height: 32
|
||||||
radius: 16
|
radius: 16
|
||||||
color: showSystemInfoInBar ? Theme.accentPrimary : Theme.surfaceVariant
|
color: Settings.settings.showSystemInfoInBar ? Theme.accentPrimary : Theme.surfaceVariant
|
||||||
border.color: showSystemInfoInBar ? Theme.accentPrimary : Theme.outline
|
border.color: Settings.settings.showSystemInfoInBar ? Theme.accentPrimary : Theme.outline
|
||||||
border.width: 2
|
border.width: 2
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -219,7 +210,7 @@ Rectangle {
|
||||||
border.color: Theme.outline
|
border.color: Theme.outline
|
||||||
border.width: 1
|
border.width: 1
|
||||||
y: 2
|
y: 2
|
||||||
x: showSystemInfoInBar ? customSwitch2.width - width - 2 : 2
|
x: Settings.settings.showSystemInfoInBar ? customSwitch2.width - width - 2 : 2
|
||||||
|
|
||||||
Behavior on x {
|
Behavior on x {
|
||||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||||
|
|
@ -229,7 +220,7 @@ Rectangle {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
showSystemInfoChanged(!showSystemInfoInBar)
|
Settings.settings.showSystemInfoInBar = !Settings.settings.showSystemInfoInBar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -258,8 +249,8 @@ Rectangle {
|
||||||
width: 52
|
width: 52
|
||||||
height: 32
|
height: 32
|
||||||
radius: 16
|
radius: 16
|
||||||
color: showMediaInBar ? Theme.accentPrimary : Theme.surfaceVariant
|
color: Settings.settings.showMediaInBar ? Theme.accentPrimary : Theme.surfaceVariant
|
||||||
border.color: showMediaInBar ? Theme.accentPrimary : Theme.outline
|
border.color: Settings.settings.showMediaInBar ? Theme.accentPrimary : Theme.outline
|
||||||
border.width: 2
|
border.width: 2
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -271,7 +262,7 @@ Rectangle {
|
||||||
border.color: Theme.outline
|
border.color: Theme.outline
|
||||||
border.width: 1
|
border.width: 1
|
||||||
y: 2
|
y: 2
|
||||||
x: showMediaInBar ? customSwitch3.width - width - 2 : 2
|
x: Settings.settings.showMediaInBar ? customSwitch3.width - width - 2 : 2
|
||||||
|
|
||||||
Behavior on x {
|
Behavior on x {
|
||||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||||
|
|
@ -281,7 +272,7 @@ Rectangle {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
showMediaChanged(!showMediaInBar)
|
Settings.settings.showMediaInBar = !Settings.settings.showMediaInBar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -318,9 +309,9 @@ Rectangle {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: 12
|
anchors.leftMargin: 12
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: visualizerType === "fire" ? "Fire" :
|
text: Settings.settings.visualizerType === "fire" ? "Fire" :
|
||||||
visualizerType === "diamond" ? "Diamond" :
|
Settings.settings.visualizerType === "diamond" ? "Diamond" :
|
||||||
visualizerType === "radial" ? "Radial" : "Radial"
|
Settings.settings.visualizerType === "radial" ? "Radial" : "Radial"
|
||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
color: Theme.textPrimary
|
color: Theme.textPrimary
|
||||||
}
|
}
|
||||||
|
|
@ -350,19 +341,19 @@ Rectangle {
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Fire"
|
text: "Fire"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
visualizerTypeUpdated("fire")
|
Settings.settings.visualizerType = "fire"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Diamond"
|
text: "Diamond"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
visualizerTypeUpdated("diamond")
|
Settings.settings.visualizerType = "diamond"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Radial"
|
text: "Radial"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
visualizerTypeUpdated("radial")
|
Settings.settings.visualizerType = "radial"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -394,7 +385,7 @@ Rectangle {
|
||||||
id: videoPathInput
|
id: videoPathInput
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 12
|
anchors.margins: 12
|
||||||
text: Settings.videoPath !== undefined ? Settings.videoPath : ""
|
text: Settings.settings.videoPath !== undefined ? Settings.settings.videoPath : ""
|
||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
color: Theme.textPrimary
|
color: Theme.textPrimary
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
@ -403,7 +394,7 @@ Rectangle {
|
||||||
activeFocusOnTab: true
|
activeFocusOnTab: true
|
||||||
inputMethodHints: Qt.ImhUrlCharactersOnly
|
inputMethodHints: Qt.ImhUrlCharactersOnly
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
Settings.videoPath = text
|
Settings.settings.videoPath = text
|
||||||
}
|
}
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
|
|
@ -22,24 +22,6 @@ PanelWindow {
|
||||||
//border.width: 1
|
//border.width: 1
|
||||||
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
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 {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Theme.backgroundPrimary
|
color: Theme.backgroundPrimary
|
||||||
|
|
@ -145,14 +127,6 @@ PanelWindow {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
anchors.margins: 16
|
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.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
anchors.margins: 16
|
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.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
anchors.margins: 16
|
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 to open the modal and initialize temp values
|
||||||
function openSettings() {
|
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;
|
|
||||||
|
|
||||||
visible = true;
|
visible = true;
|
||||||
// Force focus on the text input after a short delay
|
// Force focus on the text input after a short delay
|
||||||
focusTimer.start();
|
focusTimer.start();
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,15 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: wallpaperSettingsCard
|
id: wallpaperSettingsCard
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 680
|
Layout.preferredHeight: 680
|
||||||
Layout.topMargin: 12
|
|
||||||
color: Theme.surface
|
color: Theme.surface
|
||||||
radius: 18
|
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 {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -74,7 +54,7 @@ Rectangle {
|
||||||
anchors.rightMargin: 12
|
anchors.rightMargin: 12
|
||||||
anchors.topMargin: 6
|
anchors.topMargin: 6
|
||||||
anchors.bottomMargin: 6
|
anchors.bottomMargin: 6
|
||||||
text: wallpaperFolder
|
text: Settings.settings.wallpaperFolder
|
||||||
font.family: Theme.fontFamily
|
font.family: Theme.fontFamily
|
||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
color: Theme.textPrimary
|
color: Theme.textPrimary
|
||||||
|
|
@ -84,7 +64,7 @@ Rectangle {
|
||||||
activeFocusOnTab: true
|
activeFocusOnTab: true
|
||||||
inputMethodHints: Qt.ImhUrlCharactersOnly
|
inputMethodHints: Qt.ImhUrlCharactersOnly
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
wallpaperFolderEdited(text)
|
Settings.settings.wallpaperFolder = text
|
||||||
}
|
}
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -116,8 +96,8 @@ Rectangle {
|
||||||
width: 52
|
width: 52
|
||||||
height: 32
|
height: 32
|
||||||
radius: 16
|
radius: 16
|
||||||
color: useSWWW ? Theme.accentPrimary : Theme.surfaceVariant
|
color: Settings.settings.useSWWW ? Theme.accentPrimary : Theme.surfaceVariant
|
||||||
border.color: useSWWW ? Theme.accentPrimary : Theme.outline
|
border.color: Settings.settings.useSWWW ? Theme.accentPrimary : Theme.outline
|
||||||
border.width: 2
|
border.width: 2
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -129,7 +109,7 @@ Rectangle {
|
||||||
border.color: Theme.outline
|
border.color: Theme.outline
|
||||||
border.width: 1
|
border.width: 1
|
||||||
y: 2
|
y: 2
|
||||||
x: useSWWW ? swwwSwitch.width - width - 2 : 2
|
x: Settings.settings.useSWWW ? swwwSwitch.width - width - 2 : 2
|
||||||
|
|
||||||
Behavior on x {
|
Behavior on x {
|
||||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||||
|
|
@ -139,7 +119,7 @@ Rectangle {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
useSWWWChangedUpdated(!useSWWW)
|
Settings.settings.useSWWW = !Settings.settings.useSWWW
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -168,8 +148,8 @@ Rectangle {
|
||||||
width: 52
|
width: 52
|
||||||
height: 32
|
height: 32
|
||||||
radius: 16
|
radius: 16
|
||||||
color: randomWallpaper ? Theme.accentPrimary : Theme.surfaceVariant
|
color: Settings.settings.randomWallpaper ? Theme.accentPrimary : Theme.surfaceVariant
|
||||||
border.color: randomWallpaper ? Theme.accentPrimary : Theme.outline
|
border.color: Settings.settings.randomWallpaper ? Theme.accentPrimary : Theme.outline
|
||||||
border.width: 2
|
border.width: 2
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -181,7 +161,7 @@ Rectangle {
|
||||||
border.color: Theme.outline
|
border.color: Theme.outline
|
||||||
border.width: 1
|
border.width: 1
|
||||||
y: 2
|
y: 2
|
||||||
x: randomWallpaper ? randomWallpaperSwitch.width - width - 2 : 2
|
x: Settings.settings.randomWallpaper ? randomWallpaperSwitch.width - width - 2 : 2
|
||||||
|
|
||||||
Behavior on x {
|
Behavior on x {
|
||||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||||
|
|
@ -191,7 +171,7 @@ Rectangle {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
randomWallpaperChangedUpdated(!randomWallpaper)
|
Settings.settings.randomWallpaper = !Settings.settings.randomWallpaper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -220,8 +200,8 @@ Rectangle {
|
||||||
width: 52
|
width: 52
|
||||||
height: 32
|
height: 32
|
||||||
radius: 16
|
radius: 16
|
||||||
color: useWallpaperTheme ? Theme.accentPrimary : Theme.surfaceVariant
|
color: Settings.settings.useWallpaperTheme ? Theme.accentPrimary : Theme.surfaceVariant
|
||||||
border.color: useWallpaperTheme ? Theme.accentPrimary : Theme.outline
|
border.color: Settings.settings.useWallpaperTheme ? Theme.accentPrimary : Theme.outline
|
||||||
border.width: 2
|
border.width: 2
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -233,7 +213,7 @@ Rectangle {
|
||||||
border.color: Theme.outline
|
border.color: Theme.outline
|
||||||
border.width: 1
|
border.width: 1
|
||||||
y: 2
|
y: 2
|
||||||
x: useWallpaperTheme ? wallpaperThemeSwitch.width - width - 2 : 2
|
x: Settings.settings.useWallpaperTheme ? wallpaperThemeSwitch.width - width - 2 : 2
|
||||||
|
|
||||||
Behavior on x {
|
Behavior on x {
|
||||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||||
|
|
@ -243,7 +223,7 @@ Rectangle {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
useWallpaperThemeChangedUpdated(!useWallpaperTheme)
|
Settings.settings.useWallpaperTheme = !Settings.settings.useWallpaperTheme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +249,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: wallpaperInterval
|
text: Settings.settings.wallpaperInterval
|
||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
color: Theme.textPrimary
|
color: Theme.textPrimary
|
||||||
}
|
}
|
||||||
|
|
@ -281,7 +261,7 @@ Rectangle {
|
||||||
from: 10
|
from: 10
|
||||||
to: 900
|
to: 900
|
||||||
stepSize: 10
|
stepSize: 10
|
||||||
value: wallpaperInterval
|
value: Settings.settings.wallpaperInterval
|
||||||
snapMode: Slider.SnapAlways
|
snapMode: Slider.SnapAlways
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
|
|
@ -314,7 +294,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoved: {
|
onMoved: {
|
||||||
wallpaperIntervalChangedUpdated(Math.round(value))
|
Settings.settings.wallpaperInterval = Math.round(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -337,7 +317,7 @@ Rectangle {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 40
|
Layout.preferredHeight: 40
|
||||||
model: ["no", "crop", "fit", "stretch"]
|
model: ["no", "crop", "fit", "stretch"]
|
||||||
currentIndex: model.indexOf(wallpaperResize)
|
currentIndex: model.indexOf(Settings.settings.wallpaperResize)
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
implicitWidth: 120
|
implicitWidth: 120
|
||||||
|
|
@ -409,7 +389,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivated: {
|
onActivated: {
|
||||||
wallpaperResizeChangedUpdated(model[index])
|
Settings.settings.wallpaperResize = model[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -432,7 +412,7 @@ Rectangle {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 40
|
Layout.preferredHeight: 40
|
||||||
model: ["none", "simple", "fade", "left", "right", "top", "bottom", "wipe", "wave", "grow", "center", "any", "outer", "random"]
|
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 {
|
background: Rectangle {
|
||||||
implicitWidth: 120
|
implicitWidth: 120
|
||||||
|
|
@ -504,7 +484,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivated: {
|
onActivated: {
|
||||||
transitionTypeChangedUpdated(model[index])
|
Settings.settings.transitionType = model[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -529,7 +509,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: transitionFps
|
text: Settings.settings.transitionFps
|
||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
color: Theme.textPrimary
|
color: Theme.textPrimary
|
||||||
}
|
}
|
||||||
|
|
@ -541,7 +521,7 @@ Rectangle {
|
||||||
from: 30
|
from: 30
|
||||||
to: 500
|
to: 500
|
||||||
stepSize: 5
|
stepSize: 5
|
||||||
value: transitionFps
|
value: Settings.settings.transitionFps
|
||||||
snapMode: Slider.SnapAlways
|
snapMode: Slider.SnapAlways
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
|
|
@ -574,7 +554,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoved: {
|
onMoved: {
|
||||||
transitionFpsChangedUpdated(Math.round(value))
|
Settings.settings.transitionFps = Math.round(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -599,7 +579,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: transitionDuration.toFixed(3)
|
text: Settings.settings.transitionDuration.toFixed(3)
|
||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
color: Theme.textPrimary
|
color: Theme.textPrimary
|
||||||
}
|
}
|
||||||
|
|
@ -611,7 +591,7 @@ Rectangle {
|
||||||
from: 0.250
|
from: 0.250
|
||||||
to: 10.0
|
to: 10.0
|
||||||
stepSize: 0.050
|
stepSize: 0.050
|
||||||
value: transitionDuration
|
value: Settings.settings.transitionDuration
|
||||||
snapMode: Slider.SnapAlways
|
snapMode: Slider.SnapAlways
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
|
|
@ -644,7 +624,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoved: {
|
onMoved: {
|
||||||
transitionDurationChangedUpdated(value)
|
Settings.settings.transitionDuration = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,14 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: weatherSettingsCard
|
id: weatherSettingsCard
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 180
|
Layout.preferredHeight: 180
|
||||||
Layout.topMargin: 12
|
|
||||||
color: Theme.surface
|
color: Theme.surface
|
||||||
radius: 18
|
radius: 18
|
||||||
|
|
||||||
// Properties for binding
|
|
||||||
property string weatherCity: ""
|
|
||||||
property bool useFahrenheit: false
|
|
||||||
|
|
||||||
signal cityChanged(string city)
|
|
||||||
signal temperatureUnitChanged(bool useFahrenheit)
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 18
|
anchors.margins: 18
|
||||||
|
|
@ -76,7 +67,7 @@ Rectangle {
|
||||||
anchors.rightMargin: 12
|
anchors.rightMargin: 12
|
||||||
anchors.topMargin: 6
|
anchors.topMargin: 6
|
||||||
anchors.bottomMargin: 6
|
anchors.bottomMargin: 6
|
||||||
text: weatherCity
|
text: Settings.settings.weatherCity
|
||||||
font.family: Theme.fontFamily
|
font.family: Theme.fontFamily
|
||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
color: Theme.textPrimary
|
color: Theme.textPrimary
|
||||||
|
|
@ -88,7 +79,7 @@ Rectangle {
|
||||||
inputMethodHints: Qt.ImhNone
|
inputMethodHints: Qt.ImhNone
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
cityChanged(text)
|
Settings.settings.weatherCity = text
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
|
@ -137,11 +128,11 @@ Rectangle {
|
||||||
border.color: Theme.outline
|
border.color: Theme.outline
|
||||||
border.width: 1
|
border.width: 1
|
||||||
y: 2
|
y: 2
|
||||||
x: useFahrenheit ? customSwitch.width - width - 2 : 2
|
x: Settings.settings.useFahrenheit ? customSwitch.width - width - 2 : 2
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: useFahrenheit ? "\u00b0F" : "\u00b0C"
|
text: Settings.settings.useFahrenheit ? "\u00b0F" : "\u00b0C"
|
||||||
font.family: Theme.fontFamily
|
font.family: Theme.fontFamily
|
||||||
font.pixelSize: 12
|
font.pixelSize: 12
|
||||||
font.bold: true
|
font.bold: true
|
||||||
|
|
@ -156,7 +147,7 @@ Rectangle {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
temperatureUnitChanged(!useFahrenheit)
|
Settings.settings.useFahrenheit = !Settings.settings.useFahrenheit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Bluetooth
|
import Quickshell.Bluetooth
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
import qs.Components
|
import qs.Components
|
||||||
|
|
|
||||||
|
|
@ -7,386 +7,422 @@ import qs.Settings
|
||||||
import qs.Widgets.Sidebar.Config
|
import qs.Widgets.Sidebar.Config
|
||||||
import qs.Components
|
import qs.Components
|
||||||
|
|
||||||
PanelWindow {
|
PanelWithOverlay {
|
||||||
id: panelPopup
|
id: sidebarPopup
|
||||||
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
|
|
||||||
|
|
||||||
function showAt() {
|
function showAt() {
|
||||||
if (!visible) {
|
sidebarPopupRect.showAt();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hidePopup() {
|
function hidePopup() {
|
||||||
if (visible) {
|
sidebarPopupRect.hidePopup();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
property int leftPadding: 20
|
function show() {
|
||||||
property int bottomPadding: 20
|
sidebarPopupRect.showAt();
|
||||||
|
}
|
||||||
|
|
||||||
|
function dismiss() {
|
||||||
|
sidebarPopupRect.hidePopup();
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: mainRectangle
|
id: sidebarPopupRect
|
||||||
width: parent.width - leftPadding
|
implicitWidth: 500
|
||||||
height: parent.height - bottomPadding
|
implicitHeight: 800
|
||||||
|
visible: parent.visible
|
||||||
|
color: "transparent"
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
x: leftPadding + slideOffset
|
anchors.right: parent.right
|
||||||
y: 0
|
|
||||||
color: Theme.backgroundPrimary
|
|
||||||
bottomLeftRadius: 20
|
|
||||||
z: 0
|
|
||||||
|
|
||||||
Behavior on x {
|
|
||||||
enabled: !panelPopup.isAnimating
|
|
||||||
NumberAnimation { duration: 300; easing.type: Easing.OutCubic }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property alias settingsModal: settingsModal
|
// Animation properties
|
||||||
property alias wallpaperPanelModal: wallpaperPanelModal
|
property real slideOffset: width
|
||||||
property alias wifiPanelModal: wifiPanel.panel
|
property bool isAnimating: false
|
||||||
property alias bluetoothPanelModal: bluetoothPanel.panel
|
|
||||||
SettingsModal {
|
|
||||||
id: settingsModal
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
function showAt() {
|
||||||
anchors.fill: mainRectangle
|
if (!sidebarPopup.visible) {
|
||||||
x: slideOffset
|
sidebarPopup.visible = true;
|
||||||
|
forceActiveFocus();
|
||||||
Behavior on x {
|
slideAnim.from = width;
|
||||||
enabled: !panelPopup.isAnimating
|
slideAnim.to = 0;
|
||||||
NumberAnimation { duration: 300; easing.type: Easing.OutCubic }
|
slideAnim.running = true;
|
||||||
}
|
if (weather)
|
||||||
|
weather.startWeatherFetch();
|
||||||
MouseArea {
|
if (systemWidget)
|
||||||
id: mouseArea
|
systemWidget.panelVisible = true;
|
||||||
anchors.fill: parent
|
if (quickAccessWidget)
|
||||||
hoverEnabled: true
|
quickAccessWidget.panelVisible = true;
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: 20
|
|
||||||
spacing: 16
|
|
||||||
|
|
||||||
System {
|
|
||||||
id: systemWidget
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
z: 3
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Weather {
|
function hidePopup() {
|
||||||
id: weather
|
if (sidebarPopupRect.settingsModal && sidebarPopupRect.settingsModal.visible) {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
sidebarPopupRect.settingsModal.visible = false;
|
||||||
z: 2
|
|
||||||
}
|
}
|
||||||
|
if (sidebarPopupRect.wallpaperPanelModal && sidebarPopupRect.wallpaperPanelModal.visible) {
|
||||||
// Music and System Monitor row
|
sidebarPopupRect.wallpaperPanelModal.visible = false;
|
||||||
RowLayout {
|
}
|
||||||
spacing: 12
|
if (sidebarPopupRect.wifiPanelModal && sidebarPopupRect.wifiPanelModal.visible) {
|
||||||
Layout.fillWidth: true
|
sidebarPopupRect.wifiPanelModal.visible = false;
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
|
|
||||||
Music {
|
|
||||||
z: 2
|
|
||||||
}
|
}
|
||||||
|
if (sidebarPopupRect.bluetoothPanelModal && sidebarPopupRect.bluetoothPanelModal.visible) {
|
||||||
|
sidebarPopupRect.bluetoothPanelModal.visible = false;
|
||||||
|
}
|
||||||
|
if (sidebarPopup.visible) {
|
||||||
|
slideAnim.from = 0;
|
||||||
|
slideAnim.to = width;
|
||||||
|
slideAnim.running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SystemMonitor {
|
NumberAnimation {
|
||||||
id: systemMonitor
|
id: slideAnim
|
||||||
z: 2
|
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
|
MouseArea {
|
||||||
RowLayout {
|
id: mouseArea
|
||||||
Layout.alignment: Qt.AlignLeft
|
anchors.fill: parent
|
||||||
Layout.preferredHeight: 80
|
hoverEnabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 20
|
||||||
spacing: 16
|
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.alignment: Qt.AlignLeft
|
||||||
Layout.preferredHeight: 80
|
Layout.preferredHeight: 80
|
||||||
}
|
spacing: 16
|
||||||
|
z: 3
|
||||||
|
|
||||||
// Network card containing Wifi and Bluetooth
|
PowerProfile {
|
||||||
Rectangle {
|
Layout.alignment: Qt.AlignLeft
|
||||||
Layout.preferredHeight: 80
|
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 {
|
// Network card containing Wifi and Bluetooth
|
||||||
anchors.centerIn: parent
|
Rectangle {
|
||||||
text: "wifi"
|
Layout.preferredHeight: 80
|
||||||
font.family: "Material Symbols Outlined"
|
Layout.preferredWidth: 140
|
||||||
font.pixelSize: 22
|
Layout.fillWidth: false
|
||||||
color: wifiButtonArea.containsMouse
|
color: Theme.surface
|
||||||
? Theme.backgroundPrimary
|
radius: 18
|
||||||
: Theme.accentPrimary
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
Row {
|
||||||
horizontalAlignment: Text.AlignHCenter
|
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 {
|
// Bluetooth button
|
||||||
id: wifiButtonArea
|
Rectangle {
|
||||||
anchors.fill: parent
|
id: bluetoothButton
|
||||||
hoverEnabled: true
|
width: 36
|
||||||
cursorShape: Qt.PointingHandCursor
|
height: 36
|
||||||
onClicked: wifiPanel.showAt()
|
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 {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "bluetooth"
|
text: "bluetooth"
|
||||||
font.family: "Material Symbols Outlined"
|
font.family: "Material Symbols Outlined"
|
||||||
font.pixelSize: 22
|
font.pixelSize: 22
|
||||||
color: bluetoothButtonArea.containsMouse
|
color: bluetoothButtonArea.containsMouse ? Theme.backgroundPrimary : Theme.accentPrimary
|
||||||
? Theme.backgroundPrimary
|
verticalAlignment: Text.AlignVCenter
|
||||||
: Theme.accentPrimary
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
}
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: bluetoothButtonArea
|
id: bluetoothButtonArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: bluetoothPanel.showAt()
|
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
|
isRecording = false;
|
||||||
WifiPanel {
|
quickAccessWidget.isRecording = false;
|
||||||
id: wifiPanel
|
recordingPid = null;
|
||||||
visible: false
|
}
|
||||||
}
|
|
||||||
BluetoothPanel {
|
|
||||||
id: bluetoothPanel
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
// Clean up processes on destruction
|
||||||
Layout.fillHeight: true
|
Component.onDestruction: {
|
||||||
|
if (isRecording) {
|
||||||
|
stopRecording();
|
||||||
}
|
}
|
||||||
|
if (recordingProcess) {
|
||||||
|
recordingProcess.running = false;
|
||||||
|
recordingProcess.destroy();
|
||||||
|
recordingProcess = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// QuickAccess widget
|
Corners {
|
||||||
QuickAccess {
|
id: sidebarCornerLeft
|
||||||
id: quickAccessWidget
|
position: "bottomright"
|
||||||
Layout.alignment: Qt.AlignHCenter
|
size: 1.1
|
||||||
Layout.topMargin: -16
|
fillColor: Theme.backgroundPrimary
|
||||||
z: 2
|
anchors.top: mainRectangle.top
|
||||||
isRecording: panelPopup.isRecording
|
offsetX: -447 + sidebarPopupRect.slideOffset
|
||||||
|
offsetY: 0
|
||||||
onRecordingRequested: {
|
|
||||||
startRecording()
|
Behavior on offsetX {
|
||||||
}
|
enabled: !sidebarPopupRect.isAnimating
|
||||||
|
NumberAnimation {
|
||||||
onStopRecordingRequested: {
|
duration: 300
|
||||||
stopRecording()
|
easing.type: Easing.OutCubic
|
||||||
}
|
|
||||||
|
|
||||||
onRecordingStateMismatch: function(actualState) {
|
|
||||||
isRecording = actualState
|
|
||||||
quickAccessWidget.isRecording = actualState
|
|
||||||
}
|
|
||||||
|
|
||||||
onSettingsRequested: {
|
|
||||||
settingsModal.visible = true
|
|
||||||
}
|
|
||||||
onWallpaperRequested: {
|
|
||||||
wallpaperPanelModal.visible = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Keys.onEscapePressed: panelPopup.hidePopup()
|
|
||||||
}
|
|
||||||
|
|
||||||
onVisibleChanged: if (!visible) {/* cleanup if needed */}
|
Corners {
|
||||||
|
id: sidebarCornerBottom
|
||||||
// Update height when screen changes
|
position: "bottomright"
|
||||||
onScreenChanged: {
|
size: 1.1
|
||||||
if (screen) {
|
fillColor: Theme.backgroundPrimary
|
||||||
// Height is now hardcoded to 720, no need to update
|
offsetX: 33 + sidebarPopupRect.slideOffset
|
||||||
}
|
offsetY: 46
|
||||||
}
|
|
||||||
|
|
||||||
// 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"
|
Behavior on offsetX {
|
||||||
var outputPath = Settings.videoPath + filename
|
enabled: !sidebarPopupRect.isAnimating
|
||||||
var command = "gpu-screen-recorder -w portal -f 60 -a default_output -o " + outputPath
|
NumberAnimation {
|
||||||
var qmlString = 'import Quickshell.Io; Process { command: ["sh", "-c", "' + command + '"]; running: true }'
|
duration: 300
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import Quickshell.Services.UPower
|
import Quickshell.Services.UPower
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
import qs.Components
|
import qs.Components
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ Rectangle {
|
||||||
source: Image {
|
source: Image {
|
||||||
id: avatarImage
|
id: avatarImage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: Settings.profileImage !== undefined ? Settings.profileImage : ""
|
source: Settings.settings.profileImage !== undefined ? Settings.settings.profileImage : ""
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
cache: false
|
cache: false
|
||||||
|
|
@ -66,7 +66,7 @@ Rectangle {
|
||||||
radius: 22
|
radius: 22
|
||||||
visible: false
|
visible: false
|
||||||
}
|
}
|
||||||
visible: Settings.profileImage !== undefined && Settings.profileImage !== ""
|
visible: Settings.settings.profileImage !== undefined && Settings.settings.profileImage !== ""
|
||||||
z: 1
|
z: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@ Rectangle {
|
||||||
font.family: "Material Symbols Outlined"
|
font.family: "Material Symbols Outlined"
|
||||||
font.pixelSize: 24
|
font.pixelSize: 24
|
||||||
color: Theme.onAccent
|
color: Theme.onAccent
|
||||||
visible: Settings.profileImage === undefined || Settings.profileImage === ""
|
visible: Settings.settings.profileImage === undefined || Settings.settings.profileImage === ""
|
||||||
z: 0
|
z: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
|
|
@ -126,8 +126,8 @@ PanelWindow {
|
||||||
anchors.margins: 4
|
anchors.margins: 4
|
||||||
color: Qt.darker(Theme.backgroundPrimary, 1.1)
|
color: Qt.darker(Theme.backgroundPrimary, 1.1)
|
||||||
radius: 12
|
radius: 12
|
||||||
border.color: Settings.currentWallpaper === modelData ? Theme.accentPrimary : Theme.outline
|
border.color: Settings.settings.currentWallpaper === modelData ? Theme.accentPrimary : Theme.outline
|
||||||
border.width: Settings.currentWallpaper === modelData ? 3 : 1
|
border.width: Settings.settings.currentWallpaper === modelData ? 3 : 1
|
||||||
Image {
|
Image {
|
||||||
id: wallpaperImage
|
id: wallpaperImage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import qs.Settings
|
import qs.Settings
|
||||||
import "../../../Helpers/Weather.js" as WeatherHelper
|
import "../../../Helpers/Weather.js" as WeatherHelper
|
||||||
|
|
||||||
|
|
@ -11,7 +11,7 @@ Rectangle {
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
anchors.horizontalCenterOffset: -2
|
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 var weatherData: null
|
||||||
property string errorString: ""
|
property string errorString: ""
|
||||||
property bool isVisible: false
|
property bool isVisible: false
|
||||||
|
|
@ -95,7 +95,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Text {
|
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.family: Theme.fontFamily
|
||||||
font.pixelSize: 24
|
font.pixelSize: 24
|
||||||
font.bold: true
|
font.bold: true
|
||||||
|
|
@ -151,7 +151,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
// High/low temp
|
// 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.family: Theme.fontFamily
|
||||||
font.pixelSize: 12
|
font.pixelSize: 12
|
||||||
color: Theme.textPrimary
|
color: Theme.textPrimary
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue