Merge settings window to main #23
@@ -79,6 +79,7 @@ JsonObject {
|
|||||||
property int normal: 17 * scale
|
property int normal: 17 * scale
|
||||||
property real scale: 1
|
property real scale: 1
|
||||||
property int small: 12 * scale
|
property int small: 12 * scale
|
||||||
|
property int smallest: 8 * scale
|
||||||
}
|
}
|
||||||
component Spacing: JsonObject {
|
component Spacing: JsonObject {
|
||||||
property int large: 20 * scale
|
property int large: 20 * scale
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ Shape {
|
|||||||
|
|
||||||
Modules.Background {
|
Modules.Background {
|
||||||
invertBottomRounding: wrapper.x <= 0
|
invertBottomRounding: wrapper.x <= 0
|
||||||
startX: wrapper.x - 8
|
rounding: root.panels.popouts.currentName.startsWith("updates") ? Appearance.rounding.normal : Appearance.rounding.smallest
|
||||||
|
startX: wrapper.x - rounding
|
||||||
startY: wrapper.y
|
startY: wrapper.y
|
||||||
wrapper: root.panels.popouts
|
wrapper: root.panels.popouts
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int availableUpdates: 0
|
||||||
|
property double now: Date.now()
|
||||||
|
property var updates: ({})
|
||||||
|
|
||||||
|
function formatUpdateTime(timestamp) {
|
||||||
|
const diffMs = root.now - timestamp;
|
||||||
|
const minuteMs = 60 * 1000;
|
||||||
|
const hourMs = 60 * minuteMs;
|
||||||
|
const dayMs = 24 * hourMs;
|
||||||
|
|
||||||
|
if (diffMs < minuteMs)
|
||||||
|
return "just now";
|
||||||
|
|
||||||
|
if (diffMs < hourMs)
|
||||||
|
return Math.floor(diffMs / minuteMs) + " min ago";
|
||||||
|
|
||||||
|
if (diffMs < 48 * hourMs)
|
||||||
|
return Math.floor(diffMs / hourMs) + " hr ago";
|
||||||
|
|
||||||
|
return Qt.formatDateTime(new Date(timestamp), "dd hh:mm");
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 1
|
||||||
|
repeat: true
|
||||||
|
running: true
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
updatesProc.running = true;
|
||||||
|
interval = 5000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 60000
|
||||||
|
repeat: true
|
||||||
|
running: true
|
||||||
|
|
||||||
|
onTriggered: root.now = Date.now()
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: updatesProc
|
||||||
|
|
||||||
|
command: ["checkupdates"]
|
||||||
|
running: false
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
const output = this.text;
|
||||||
|
const lines = output.trim().split("\n").filter(line => line.length > 0);
|
||||||
|
|
||||||
|
const oldMap = root.updates;
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
root.updates = lines.reduce((acc, pkg) => {
|
||||||
|
acc[pkg] = oldMap[pkg] ?? now;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
root.availableUpdates = lines.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ ShapePath {
|
|||||||
readonly property bool flatten: wrapper.height < rounding * 2
|
readonly property bool flatten: wrapper.height < rounding * 2
|
||||||
property real ibr: invertBottomRounding ? -1 : 1
|
property real ibr: invertBottomRounding ? -1 : 1
|
||||||
required property bool invertBottomRounding
|
required property bool invertBottomRounding
|
||||||
readonly property real rounding: 8
|
property real rounding: Appearance.rounding.smallest
|
||||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||||
required property Wrapper wrapper
|
required property Wrapper wrapper
|
||||||
|
|
||||||
|
|||||||
+16
-11
@@ -4,16 +4,17 @@ import Quickshell
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Modules as Bar
|
import qs.Modules
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Modules.UPower
|
import qs.Modules.UPower
|
||||||
import qs.Modules.Network
|
import qs.Modules.Network
|
||||||
|
import qs.Modules.Updates
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Bar.Wrapper popouts
|
required property Wrapper popouts
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
readonly property int vPadding: 6
|
readonly property int vPadding: 6
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
@@ -47,6 +48,10 @@ RowLayout {
|
|||||||
popouts.currentName = "upower";
|
popouts.currentName = "upower";
|
||||||
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
||||||
popouts.hasCurrent = true;
|
popouts.hasCurrent = true;
|
||||||
|
} else if (id === "updates") {
|
||||||
|
popouts.currentName = "updates";
|
||||||
|
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
||||||
|
popouts.hasCurrent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +78,7 @@ RowLayout {
|
|||||||
roleValue: "workspaces"
|
roleValue: "workspaces"
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
sourceComponent: Bar.Workspaces {
|
sourceComponent: Workspaces {
|
||||||
screen: root.screen
|
screen: root.screen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,7 +88,7 @@ RowLayout {
|
|||||||
roleValue: "audio"
|
roleValue: "audio"
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
sourceComponent: Bar.AudioWidget {
|
sourceComponent: AudioWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,7 +97,7 @@ RowLayout {
|
|||||||
roleValue: "tray"
|
roleValue: "tray"
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
sourceComponent: Bar.TrayWidget {
|
sourceComponent: TrayWidget {
|
||||||
loader: root
|
loader: root
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
}
|
}
|
||||||
@@ -103,7 +108,7 @@ RowLayout {
|
|||||||
roleValue: "resources"
|
roleValue: "resources"
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
sourceComponent: Bar.Resources {
|
sourceComponent: Resources {
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +118,7 @@ RowLayout {
|
|||||||
roleValue: "updates"
|
roleValue: "updates"
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
sourceComponent: Bar.UpdatesWidget {
|
sourceComponent: UpdatesWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +127,7 @@ RowLayout {
|
|||||||
roleValue: "notifBell"
|
roleValue: "notifBell"
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
sourceComponent: Bar.NotifBell {
|
sourceComponent: NotifBell {
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
}
|
}
|
||||||
@@ -133,7 +138,7 @@ RowLayout {
|
|||||||
roleValue: "clock"
|
roleValue: "clock"
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
sourceComponent: Bar.Clock {
|
sourceComponent: Clock {
|
||||||
loader: root
|
loader: root
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
@@ -145,7 +150,7 @@ RowLayout {
|
|||||||
roleValue: "activeWindow"
|
roleValue: "activeWindow"
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
sourceComponent: Bar.WindowTitle {
|
sourceComponent: WindowTitle {
|
||||||
bar: root
|
bar: root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +178,7 @@ RowLayout {
|
|||||||
roleValue: "media"
|
roleValue: "media"
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
delegate: WrappedLoader {
|
||||||
sourceComponent: Bar.MediaWidget {
|
sourceComponent: MediaWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import qs.Components
|
|||||||
import qs.Modules.WSOverview
|
import qs.Modules.WSOverview
|
||||||
import qs.Modules.Network
|
import qs.Modules.Network
|
||||||
import qs.Modules.UPower
|
import qs.Modules.UPower
|
||||||
|
import qs.Modules.Updates
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -92,6 +93,14 @@ Item {
|
|||||||
wrapper: root.wrapper
|
wrapper: root.wrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Popout {
|
||||||
|
name: "updates"
|
||||||
|
|
||||||
|
sourceComponent: UpdatesPopout {
|
||||||
|
wrapper: root.wrapper
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
component Popout: Loader {
|
component Popout: Loader {
|
||||||
|
|||||||
@@ -1,392 +0,0 @@
|
|||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import Quickshell
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Qt5Compat.GraphicalEffects
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import QtQml
|
|
||||||
import qs.Effects
|
|
||||||
import qs.Config
|
|
||||||
|
|
||||||
PanelWindow {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property color backgroundColor: DynamicColors.tPalette.m3surface
|
|
||||||
required property PanelWindow bar
|
|
||||||
property int biggestWidth: 0
|
|
||||||
property color disabledHighlightColor: DynamicColors.layer(DynamicColors.palette.m3primaryContainer, 0)
|
|
||||||
property color disabledTextColor: DynamicColors.layer(DynamicColors.palette.m3onSurface, 0)
|
|
||||||
property int entryHeight: 30
|
|
||||||
property alias focusGrab: grab.active
|
|
||||||
property color highlightColor: DynamicColors.tPalette.m3primaryContainer
|
|
||||||
property int menuItemCount: menuOpener.children.values.length
|
|
||||||
property var menuStack: []
|
|
||||||
property real scaleValue: 0
|
|
||||||
property color textColor: DynamicColors.palette.m3onSurface
|
|
||||||
required property point trayItemRect
|
|
||||||
required property QsMenuHandle trayMenu
|
|
||||||
|
|
||||||
signal finishedLoading
|
|
||||||
signal menuActionTriggered
|
|
||||||
|
|
||||||
function goBack() {
|
|
||||||
if (root.menuStack.length > 0) {
|
|
||||||
menuChangeAnimation.start();
|
|
||||||
root.biggestWidth = 0;
|
|
||||||
root.trayMenu = root.menuStack.pop();
|
|
||||||
listLayout.positionViewAtBeginning();
|
|
||||||
backEntry.visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateMask() {
|
|
||||||
root.mask.changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
// onTrayMenuChanged: {
|
|
||||||
// listLayout.forceLayout();
|
|
||||||
// }
|
|
||||||
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
mask: Region {
|
|
||||||
id: mask
|
|
||||||
|
|
||||||
item: menuRect
|
|
||||||
}
|
|
||||||
|
|
||||||
onMenuActionTriggered: {
|
|
||||||
if (root.menuStack.length > 0) {
|
|
||||||
backEntry.visible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onVisibleChanged: {
|
|
||||||
if (!visible)
|
|
||||||
root.menuStack.pop();
|
|
||||||
backEntry.visible = false;
|
|
||||||
|
|
||||||
openAnim.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
QsMenuOpener {
|
|
||||||
id: menuOpener
|
|
||||||
|
|
||||||
menu: root.trayMenu
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
bottom: true
|
|
||||||
left: true
|
|
||||||
right: true
|
|
||||||
top: true
|
|
||||||
}
|
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
|
||||||
id: grab
|
|
||||||
|
|
||||||
active: false
|
|
||||||
windows: [root]
|
|
||||||
|
|
||||||
onCleared: {
|
|
||||||
closeAnim.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SequentialAnimation {
|
|
||||||
id: menuChangeAnimation
|
|
||||||
|
|
||||||
ParallelAnimation {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: MaterialEasing.standardTime / 2
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
from: 0
|
|
||||||
property: "x"
|
|
||||||
target: translateAnim
|
|
||||||
to: -listLayout.width / 2
|
|
||||||
}
|
|
||||||
|
|
||||||
NumberAnimation {
|
|
||||||
duration: MaterialEasing.standardTime / 2
|
|
||||||
easing.bezierCurve: MaterialEasing.standard
|
|
||||||
from: 1
|
|
||||||
property: "opacity"
|
|
||||||
target: columnLayout
|
|
||||||
to: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyAction {
|
|
||||||
property: "menu"
|
|
||||||
target: columnLayout
|
|
||||||
}
|
|
||||||
|
|
||||||
ParallelAnimation {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: MaterialEasing.standardTime / 2
|
|
||||||
easing.bezierCurve: MaterialEasing.standard
|
|
||||||
from: 0
|
|
||||||
property: "opacity"
|
|
||||||
target: columnLayout
|
|
||||||
to: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
NumberAnimation {
|
|
||||||
duration: MaterialEasing.standardTime / 2
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
from: listLayout.width / 2
|
|
||||||
property: "x"
|
|
||||||
target: translateAnim
|
|
||||||
to: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParallelAnimation {
|
|
||||||
id: closeAnim
|
|
||||||
|
|
||||||
onFinished: {
|
|
||||||
root.visible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: MaterialEasing.expressiveEffectsTime
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
property: "implicitHeight"
|
|
||||||
target: menuRect
|
|
||||||
to: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: MaterialEasing.expressiveEffectsTime
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
from: 1
|
|
||||||
property: "opacity"
|
|
||||||
targets: [menuRect, shadowRect]
|
|
||||||
to: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParallelAnimation {
|
|
||||||
id: openAnim
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: MaterialEasing.expressiveEffectsTime
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
from: 0
|
|
||||||
property: "implicitHeight"
|
|
||||||
target: menuRect
|
|
||||||
to: listLayout.contentHeight + (root.menuStack.length > 0 ? root.entryHeight + 10 : 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: MaterialEasing.expressiveEffectsTime
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
from: 0
|
|
||||||
property: "opacity"
|
|
||||||
targets: [menuRect, shadowRect]
|
|
||||||
to: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShadowRect {
|
|
||||||
id: shadowRect
|
|
||||||
|
|
||||||
anchors.fill: menuRect
|
|
||||||
radius: menuRect.radius
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: menuRect
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
color: root.backgroundColor
|
|
||||||
implicitHeight: listLayout.contentHeight + (root.menuStack.length > 0 ? root.entryHeight + 10 : 10)
|
|
||||||
implicitWidth: listLayout.contentWidth + 10
|
|
||||||
radius: 8
|
|
||||||
x: Math.round(root.trayItemRect.x - (menuRect.implicitWidth / 2) + 11)
|
|
||||||
y: Math.round(root.trayItemRect.y - 5)
|
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: MaterialEasing.expressiveEffectsTime
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on implicitWidth {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: MaterialEasing.expressiveEffectsTime
|
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: columnLayout
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: 5
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
transform: [
|
|
||||||
Translate {
|
|
||||||
id: translateAnim
|
|
||||||
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
id: listLayout
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: contentHeight
|
|
||||||
contentHeight: contentItem.childrenRect.height
|
|
||||||
contentWidth: root.biggestWidth
|
|
||||||
model: menuOpener.children
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
delegate: Rectangle {
|
|
||||||
id: menuItem
|
|
||||||
|
|
||||||
property var child: QsMenuOpener {
|
|
||||||
menu: menuItem.modelData
|
|
||||||
}
|
|
||||||
property bool containsMouseAndEnabled: mouseArea.containsMouse && menuItem.modelData.enabled
|
|
||||||
property bool containsMouseAndNotEnabled: mouseArea.containsMouse && !menuItem.modelData.enabled
|
|
||||||
required property int index
|
|
||||||
required property QsMenuEntry modelData
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
color: menuItem.modelData.isSeparator ? "#20FFFFFF" : containsMouseAndEnabled ? root.highlightColor : containsMouseAndNotEnabled ? root.disabledHighlightColor : "transparent"
|
|
||||||
height: menuItem.modelData.isSeparator ? 1 : root.entryHeight
|
|
||||||
radius: 4
|
|
||||||
visible: true
|
|
||||||
width: widthMetrics.width + (menuItem.modelData.icon ?? "" ? 30 : 0) + (menuItem.modelData.hasChildren ? 30 : 0) + 20
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
CAnim {
|
|
||||||
duration: 150
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
var biggestWidth = root.biggestWidth;
|
|
||||||
var currentWidth = widthMetrics.width + (menuItem.modelData.icon ?? "" ? 30 : 0) + (menuItem.modelData.hasChildren ? 30 : 0) + 20;
|
|
||||||
if (currentWidth > biggestWidth) {
|
|
||||||
root.biggestWidth = currentWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextMetrics {
|
|
||||||
id: widthMetrics
|
|
||||||
|
|
||||||
text: menuItem.modelData.text
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: mouseArea
|
|
||||||
|
|
||||||
acceptedButtons: Qt.LeftButton
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
preventStealing: true
|
|
||||||
propagateComposedEvents: true
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (!menuItem.modelData.hasChildren) {
|
|
||||||
if (menuItem.modelData.enabled) {
|
|
||||||
menuItem.modelData.triggered();
|
|
||||||
closeAnim.start();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
root.menuStack.push(root.trayMenu);
|
|
||||||
menuChangeAnimation.start();
|
|
||||||
root.biggestWidth = 0;
|
|
||||||
root.trayMenu = menuItem.modelData;
|
|
||||||
listLayout.positionViewAtBeginning();
|
|
||||||
root.menuActionTriggered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: menuText
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
|
||||||
Layout.leftMargin: 10
|
|
||||||
color: menuItem.modelData.enabled ? root.textColor : root.disabledTextColor
|
|
||||||
text: menuItem.modelData.text
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: iconImage
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
|
||||||
Layout.maximumHeight: 20
|
|
||||||
Layout.maximumWidth: 20
|
|
||||||
Layout.rightMargin: 10
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
layer.enabled: true
|
|
||||||
source: menuItem.modelData.icon
|
|
||||||
sourceSize.height: height
|
|
||||||
sourceSize.width: width
|
|
||||||
|
|
||||||
layer.effect: ColorOverlay {
|
|
||||||
color: menuItem.modelData.enabled ? "white" : "gray"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: textArrow
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
|
||||||
Layout.bottomMargin: 5
|
|
||||||
Layout.maximumHeight: 20
|
|
||||||
Layout.maximumWidth: 20
|
|
||||||
Layout.rightMargin: 10
|
|
||||||
color: menuItem.modelData.enabled ? "white" : "gray"
|
|
||||||
text: ""
|
|
||||||
visible: menuItem.modelData.hasChildren ?? false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: backEntry
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: root.entryHeight
|
|
||||||
color: mouseAreaBack.containsMouse ? "#15FFFFFF" : "transparent"
|
|
||||||
radius: 4
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: mouseAreaBack
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
root.goBack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: 10
|
|
||||||
color: "white"
|
|
||||||
text: "Back "
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import qs.Modules
|
|
||||||
|
|
||||||
Singleton {
|
|
||||||
property int availableUpdates: 0
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
interval: 1
|
|
||||||
repeat: true
|
|
||||||
running: true
|
|
||||||
|
|
||||||
onTriggered: {
|
|
||||||
updatesProc.running = true;
|
|
||||||
interval = 5000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: updatesProc
|
|
||||||
|
|
||||||
command: ["checkupdates"]
|
|
||||||
running: false
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
const output = this.text;
|
|
||||||
const lines = output.trim().split("\n").filter(line => line.length > 0);
|
|
||||||
availableUpdates = lines.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var wrapper
|
||||||
|
|
||||||
|
implicitHeight: profiles.implicitHeight + Appearance.padding.small
|
||||||
|
implicitWidth: profiles.implicitWidth + Appearance.padding.small * 2
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: profiles
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: updatesList.contentHeight + Appearance.padding.small * 2
|
||||||
|
implicitWidth: updatesList.contentWidth + Appearance.padding.small * 2
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
CustomListView {
|
||||||
|
id: updatesList
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
contentHeight: childrenRect.height
|
||||||
|
contentWidth: 600
|
||||||
|
implicitHeight: contentHeight
|
||||||
|
implicitWidth: contentWidth
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
delegate: CustomRect {
|
||||||
|
id: update
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
readonly property list<string> sections: modelData.update.split(" ")
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: 50 + Appearance.padding.smaller * 2
|
||||||
|
radius: Appearance.rounding.small - Appearance.padding.small
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.smaller
|
||||||
|
anchors.rightMargin: Appearance.padding.smaller
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
font.pointSize: Appearance.font.size.large * 2
|
||||||
|
text: "package_2"
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 25
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: update.sections[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
text: Updates.formatUpdateTime(update.modelData.timestamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: 300
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: versionFrom
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: 125
|
||||||
|
color: DynamicColors.palette.m3tertiary
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: update.sections[1]
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
color: DynamicColors.palette.m3secondary
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: "arrow_right_alt"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: versionTo
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: 120
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: update.sections[3]
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model: ScriptModel {
|
||||||
|
id: script
|
||||||
|
|
||||||
|
objectProp: "update"
|
||||||
|
values: Object.entries(Updates.updates).sort((a, b) => b[1] - a[1]).map(([update, timestamp]) => ({
|
||||||
|
update,
|
||||||
|
timestamp
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import QtQuick
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
|
import qs.Helpers
|
||||||
import qs.Config
|
import qs.Config
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
Reference in New Issue
Block a user