lots of changes
This commit is contained in:
@@ -14,6 +14,7 @@ Singleton {
|
|||||||
property alias wallust: adapter.wallust
|
property alias wallust: adapter.wallust
|
||||||
property alias workspaceWidget: adapter.workspaceWidget
|
property alias workspaceWidget: adapter.workspaceWidget
|
||||||
property alias colors: adapter.colors
|
property alias colors: adapter.colors
|
||||||
|
property alias gpuType: adapter.gpuType
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
id: root
|
id: root
|
||||||
@@ -37,6 +38,7 @@ Singleton {
|
|||||||
property bool wallust: false
|
property bool wallust: false
|
||||||
property WorkspaceWidget workspaceWidget: WorkspaceWidget {}
|
property WorkspaceWidget workspaceWidget: WorkspaceWidget {}
|
||||||
property Colors colors: Colors {}
|
property Colors colors: Colors {}
|
||||||
|
property string gpuType: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-1
@@ -5,8 +5,10 @@ import Quickshell
|
|||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell.Services.Notifications
|
import Quickshell.Services.Notifications
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import ZShell
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
|
import qs.Paths
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
@@ -81,7 +83,7 @@ Singleton {
|
|||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
id: storage
|
id: storage
|
||||||
path: NotifPath.notifPath
|
path: `${Paths.state}/notifs.json`
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
const data = JSON.parse(text());
|
const data = JSON.parse(text());
|
||||||
@@ -90,6 +92,7 @@ Singleton {
|
|||||||
root.list.sort((a, b) => b.time - a.time);
|
root.list.sort((a, b) => b.time - a.time);
|
||||||
root.loaded = true;
|
root.loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoadFailed: err => {
|
onLoadFailed: err => {
|
||||||
if (err === FileViewError.FileNotFound) {
|
if (err === FileViewError.FileNotFound) {
|
||||||
root.loaded = true;
|
root.loaded = true;
|
||||||
@@ -144,6 +147,50 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly property LazyLoader dummyImageLoader: LazyLoader {
|
||||||
|
active: false
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
implicitWidth: 48
|
||||||
|
implicitHeight: 48
|
||||||
|
color: "transparent"
|
||||||
|
mask: Region {}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: Qt.resolvedUrl(notif.image)
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
cache: false
|
||||||
|
asynchronous: true
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
onStatusChanged: {
|
||||||
|
if (status !== Image.Ready)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const cacheKey = notif.appName + notif.summary + notif.id;
|
||||||
|
let h1 = 0xdeadbeef, h2 = 0x41c6ce57, ch;
|
||||||
|
for (let i = 0; i < cacheKey.length; i++) {
|
||||||
|
ch = cacheKey.charCodeAt(i);
|
||||||
|
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||||
|
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||||
|
}
|
||||||
|
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
|
||||||
|
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
||||||
|
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
|
||||||
|
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
||||||
|
const hash = (h2 >>> 0).toString(16).padStart(8, 0) + (h1 >>> 0).toString(16).padStart(8, 0);
|
||||||
|
|
||||||
|
const cache = `${Paths.notifimagecache}/${hash}.png`;
|
||||||
|
ZShellIo.saveItem(this, Qt.resolvedUrl(cache), () => {
|
||||||
|
notif.image = cache;
|
||||||
|
notif.dummyImageLoader.active = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly property Connections conn: Connections {
|
readonly property Connections conn: Connections {
|
||||||
target: notif.notification
|
target: notif.notification
|
||||||
|
|
||||||
@@ -169,6 +216,8 @@ Singleton {
|
|||||||
|
|
||||||
function onImageChanged(): void {
|
function onImageChanged(): void {
|
||||||
notif.image = notif.notification.image;
|
notif.image = notif.notification.image;
|
||||||
|
if (notif.notification?.image)
|
||||||
|
notif.dummyImageLoader.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onExpireTimeoutChanged(): void {
|
function onExpireTimeoutChanged(): void {
|
||||||
@@ -225,6 +274,8 @@ Singleton {
|
|||||||
appIcon = notification.appIcon;
|
appIcon = notification.appIcon;
|
||||||
appName = notification.appName;
|
appName = notification.appName;
|
||||||
image = notification.image;
|
image = notification.image;
|
||||||
|
if (notification?.image)
|
||||||
|
dummyImageLoader.active = true;
|
||||||
expireTimeout = notification.expireTimeout;
|
expireTimeout = notification.expireTimeout;
|
||||||
urgency = notification.urgency;
|
urgency = notification.urgency;
|
||||||
resident = notification.resident;
|
resident = notification.resident;
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import ZShell.Internal
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import qs.Paths
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias path: manager.path
|
||||||
|
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: QsWindow.window
|
||||||
|
|
||||||
|
function onDevicePixelRatioChanged(): void {
|
||||||
|
manager.updateSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CachingImageManager {
|
||||||
|
id: manager
|
||||||
|
|
||||||
|
item: root
|
||||||
|
cacheDir: Qt.resolvedUrl(Paths.imagecache)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,11 +4,33 @@ import Quickshell
|
|||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
|
import qs.Helpers
|
||||||
import ZShell.Models
|
import ZShell.Models
|
||||||
|
|
||||||
Searcher {
|
Searcher {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
readonly property string currentNamePath: WallpaperPath.currentWallpaperPath
|
||||||
|
|
||||||
|
property bool showPreview: false
|
||||||
|
readonly property string current: showPreview ? previewPath : actualCurrent
|
||||||
|
property string previewPath
|
||||||
|
property string actualCurrent: WallpaperPath.currentWallpaperPath
|
||||||
|
|
||||||
|
function setWallpaper(path: string): void {
|
||||||
|
actualCurrent = path;
|
||||||
|
WallpaperPath.currentWallpaperPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function preview(path: string): void {
|
||||||
|
previewPath = path;
|
||||||
|
showPreview = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopPreview(): void {
|
||||||
|
showPreview = false;
|
||||||
|
}
|
||||||
|
|
||||||
list: wallpapers.entries
|
list: wallpapers.entries
|
||||||
key: "relativePath"
|
key: "relativePath"
|
||||||
useFuzzy: true
|
useFuzzy: true
|
||||||
@@ -16,6 +38,15 @@ Searcher {
|
|||||||
forward: false
|
forward: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
path: root.currentNamePath
|
||||||
|
watchChanges: true
|
||||||
|
onFileChanged: reload()
|
||||||
|
onLoaded: {
|
||||||
|
root.actualCurrent = this.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FileSystemModel {
|
FileSystemModel {
|
||||||
id: wallpapers
|
id: wallpapers
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Text {
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string source: SearchWallpapers.current
|
||||||
|
property Image current: one
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onSourceChanged: {
|
||||||
|
if (!source) {
|
||||||
|
current = null;
|
||||||
|
} else if (current === one) {
|
||||||
|
two.update();
|
||||||
|
} else {
|
||||||
|
one.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
console.log(root.source)
|
||||||
|
if (source)
|
||||||
|
Qt.callLater(() => one.update());
|
||||||
|
}
|
||||||
|
|
||||||
|
Img {
|
||||||
|
id: one
|
||||||
|
}
|
||||||
|
|
||||||
|
Img {
|
||||||
|
id: two
|
||||||
|
}
|
||||||
|
|
||||||
|
component Img: CachingImage {
|
||||||
|
id: img
|
||||||
|
|
||||||
|
function update(): void {
|
||||||
|
if (path === root.source) {
|
||||||
|
root.current = this;
|
||||||
|
} else {
|
||||||
|
path = root.source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
scale: SearchWallpapers.showPreview ? 1 : 0.8
|
||||||
|
asynchronous: true
|
||||||
|
onStatusChanged: {
|
||||||
|
if (status === Image.Ready) {
|
||||||
|
root.current = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: State {
|
||||||
|
name: "visible"
|
||||||
|
when: root.current === img
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
img.opacity: 1
|
||||||
|
img.scale: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transitions: Transition {
|
||||||
|
Anim {
|
||||||
|
target: img
|
||||||
|
properties: "opacity,scale"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -83,13 +83,16 @@ TextField {
|
|||||||
Search.launch(appListLoader.item.currentItem.modelData);
|
Search.launch(appListLoader.item.currentItem.modelData);
|
||||||
launcherWindow.visible = false;
|
launcherWindow.visible = false;
|
||||||
} else if ( wallpaperPickerLoader.active ) {
|
} else if ( wallpaperPickerLoader.active ) {
|
||||||
WallpaperPath.currentWallpaperPath = wallpaperPickerLoader.item.currentItem.modelData.path;
|
SearchWallpapers.setWallpaper(wallpaperPickerLoader.item.currentItem.modelData.path)
|
||||||
if ( Config.wallust ) {
|
if ( Config.wallust ) {
|
||||||
Wallust.generateColors(WallpaperPath.currentWallpaperPath);
|
Wallust.generateColors(WallpaperPath.currentWallpaperPath);
|
||||||
}
|
}
|
||||||
|
closeAnim.start();
|
||||||
}
|
}
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
} else if ( event.key === Qt.Key_Escape ) {
|
} else if ( event.key === Qt.Key_Escape ) {
|
||||||
|
if ( wallpaperPickerLoader.active )
|
||||||
|
SearchWallpapers.stopPreview();
|
||||||
closeAnim.start();
|
closeAnim.start();
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ Repeater {
|
|||||||
root.flagChanged();
|
root.flagChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: groupColumn
|
id: groupColumn
|
||||||
required property string modelData
|
required property string modelData
|
||||||
@@ -28,6 +29,7 @@ Repeater {
|
|||||||
|
|
||||||
property bool shouldShow: false
|
property bool shouldShow: false
|
||||||
property bool isExpanded: false
|
property bool isExpanded: false
|
||||||
|
property bool collapseAnimRunning: false
|
||||||
|
|
||||||
function closeAll(): void {
|
function closeAll(): void {
|
||||||
for ( const n of NotifServer.notClosed.filter( n => n.appName === modelData ))
|
for ( const n of NotifServer.notClosed.filter( n => n.appName === modelData ))
|
||||||
@@ -49,7 +51,7 @@ Repeater {
|
|||||||
id: addTrans
|
id: addTrans
|
||||||
SequentialAnimation {
|
SequentialAnimation {
|
||||||
PauseAnimation {
|
PauseAnimation {
|
||||||
duration: ( addTrans.ViewTransition.index - addTrans.ViewTransition.targetIndexes[ 0 ]) * 50
|
duration: ( addTrans.ViewTransition.index - addTrans.ViewTransition.targetIndexes[ 0 ]) * 30
|
||||||
}
|
}
|
||||||
ParallelAnimation {
|
ParallelAnimation {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
@@ -77,6 +79,16 @@ Repeater {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: addTrans.ViewTransition.targetIndexes.length * 30 + 100
|
||||||
|
running: groupColumn.isExpanded
|
||||||
|
repeat: false
|
||||||
|
onTriggered: {
|
||||||
|
groupColumn.shouldShow = true;
|
||||||
|
console.log("ran timer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
move: Transition {
|
move: Transition {
|
||||||
id: moveTrans
|
id: moveTrans
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
@@ -84,6 +96,11 @@ Repeater {
|
|||||||
duration: 100;
|
duration: 100;
|
||||||
easing.type: Easing.OutCubic
|
easing.type: Easing.OutCubic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
properties: "opacity, scale";
|
||||||
|
to: 1.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -120,11 +137,11 @@ Repeater {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
groupColumn.shouldShow = false;
|
groupColumn.collapseAnimRunning = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NotifGroupRepeater { }
|
NotifGroupRepeater { id: groupRepeater }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,6 +259,12 @@ Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: currentIndex = SearchWallpapers.list.findIndex( w => w.path === WallpaperPath.currentWallpaperPath )
|
Component.onCompleted: currentIndex = SearchWallpapers.list.findIndex( w => w.path === WallpaperPath.currentWallpaperPath )
|
||||||
|
Component.onDestruction: SearchWallpapers.stopPreview()
|
||||||
|
|
||||||
|
onCurrentItemChanged: {
|
||||||
|
if ( currentItem )
|
||||||
|
SearchWallpapers.preview( currentItem.modelData.path );
|
||||||
|
}
|
||||||
|
|
||||||
cacheItemCount: 5
|
cacheItemCount: 5
|
||||||
snapMode: PathView.SnapToItem
|
snapMode: PathView.SnapToItem
|
||||||
|
|||||||
@@ -4,21 +4,21 @@ import QtQuick
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Daemons
|
import qs.Daemons
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: groupListView
|
id: groupListView
|
||||||
model: ScriptModel {
|
model: ScriptModel {
|
||||||
id: groupModel
|
id: groupModel
|
||||||
values: groupColumn.isExpanded ? groupColumn.notifications : groupColumn.notifications.slice( 0, 1 )
|
values: groupColumn.isExpanded || groupColumn.shouldShow ? groupColumn.notifications : groupColumn.notifications.slice( 0, 1 )
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: groupHeader
|
id: groupHeader
|
||||||
required property int index
|
required property int index
|
||||||
required property NotifServer.Notif modelData
|
required property NotifServer.Notif modelData
|
||||||
property alias notifHeight: groupHeader.height
|
property alias notifHeight: groupHeader.height
|
||||||
|
|
||||||
property bool previewHidden: groupColumn.shouldShow && index > 0
|
property bool previewHidden: !groupColumn.shouldShow && index > 0
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: contentColumn.height + 15
|
height: contentColumn.height + 15
|
||||||
@@ -26,10 +26,12 @@ Repeater {
|
|||||||
border.color: "#555555"
|
border.color: "#555555"
|
||||||
border.width: 1
|
border.width: 1
|
||||||
radius: 8
|
radius: 8
|
||||||
opacity: previewHidden ? 0 : 1.0
|
opacity: previewHidden ? 0 : 1
|
||||||
scale: previewHidden ? 0.7 : 1.0
|
scale: previewHidden ? 0.7 : 1.0
|
||||||
|
|
||||||
Component.onCompleted: modelData.lock(this);
|
Component.onCompleted: {
|
||||||
|
modelData.lock(this);
|
||||||
|
}
|
||||||
Component.onDestruction: modelData.unlock(this);
|
Component.onDestruction: modelData.unlock(this);
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -40,7 +42,6 @@ Repeater {
|
|||||||
groupHeader.modelData.actions[0].invoke();
|
groupHeader.modelData.actions[0].invoke();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
groupColumn.shouldShow = true;
|
|
||||||
groupColumn.isExpanded = true;
|
groupColumn.isExpanded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,7 +49,7 @@ Repeater {
|
|||||||
|
|
||||||
ParallelAnimation {
|
ParallelAnimation {
|
||||||
id: collapseAnim
|
id: collapseAnim
|
||||||
running: !groupColumn.shouldShow && index > 0
|
running: groupColumn.collapseAnimRunning
|
||||||
|
|
||||||
Anim {
|
Anim {
|
||||||
target: groupHeader
|
target: groupHeader
|
||||||
@@ -66,6 +67,8 @@ Repeater {
|
|||||||
}
|
}
|
||||||
onFinished: {
|
onFinished: {
|
||||||
groupColumn.isExpanded = false;
|
groupColumn.isExpanded = false;
|
||||||
|
groupColumn.shouldShow = false;
|
||||||
|
groupColumn.collapseAnimRunning = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,13 +110,6 @@ Repeater {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Behavior on height {
|
|
||||||
// Anim {
|
|
||||||
// duration: MaterialEasing.expressiveDefaultSpatialTime
|
|
||||||
// easing.bezierCurve: MaterialEasing.expressiveDefaultSpatial
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: contentColumn
|
id: contentColumn
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
@@ -122,7 +118,6 @@ Repeater {
|
|||||||
anchors.leftMargin: 10
|
anchors.leftMargin: 10
|
||||||
anchors.rightMargin: 10
|
anchors.rightMargin: 10
|
||||||
anchors.topMargin: 5
|
anchors.topMargin: 5
|
||||||
// width: parent.width - 20
|
|
||||||
spacing: 10
|
spacing: 10
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: infoRow
|
id: infoRow
|
||||||
@@ -130,19 +125,19 @@ Repeater {
|
|||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
IconImage {
|
IconImage {
|
||||||
source: groupHeader.modelData.image
|
source: groupHeader.modelData.image === "" ? Qt.resolvedUrl(groupHeader.modelData.appIcon) : Qt.resolvedUrl(groupHeader.modelData.image)
|
||||||
Layout.preferredWidth: 48
|
Layout.preferredWidth: 48
|
||||||
Layout.preferredHeight: 48
|
Layout.preferredHeight: 48
|
||||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||||
Layout.topMargin: 5
|
Layout.topMargin: 5
|
||||||
visible: groupHeader.modelData.image !== ""
|
visible: source !== ""
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
Text {
|
TextRender {
|
||||||
text: groupHeader.modelData.summary
|
text: groupHeader.modelData.summary
|
||||||
color: "white"
|
color: "white"
|
||||||
font.bold: true
|
font.bold: true
|
||||||
@@ -152,21 +147,26 @@ Repeater {
|
|||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
TextRender {
|
||||||
text: groupHeader.modelData.body
|
text: groupHeader.modelData.body
|
||||||
font.pointSize: 12
|
|
||||||
color: "#dddddd"
|
color: "#dddddd"
|
||||||
|
font.pointSize: 12
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
lineHeightMode: Text.FixedHeight
|
textFormat: Text.MarkdownText
|
||||||
lineHeight: 20
|
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
maximumLineCount: 5
|
maximumLineCount: 5
|
||||||
|
linkColor: Config.accentColor.accents.primaryAlt
|
||||||
|
|
||||||
|
onLinkActivated: link => {
|
||||||
|
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
||||||
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
TextRender {
|
||||||
text: groupHeader.modelData.timeStr
|
text: groupHeader.modelData.timeStr
|
||||||
font.pointSize: 10
|
font.pointSize: 10
|
||||||
color: "#666666"
|
color: "#666666"
|
||||||
@@ -191,7 +191,7 @@ Repeater {
|
|||||||
required property var modelData
|
required property var modelData
|
||||||
color: buttonArea.containsMouse ? "#15FFFFFF" : "#09FFFFFF"
|
color: buttonArea.containsMouse ? "#15FFFFFF" : "#09FFFFFF"
|
||||||
radius: 4
|
radius: 4
|
||||||
Text {
|
TextRender {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: actionButton.modelData.text
|
text: actionButton.modelData.text
|
||||||
color: "white"
|
color: "white"
|
||||||
@@ -220,7 +220,7 @@ Repeater {
|
|||||||
color: closeArea.containsMouse ? "#FF6077" : "transparent"
|
color: closeArea.containsMouse ? "#FF6077" : "transparent"
|
||||||
radius: 9
|
radius: 9
|
||||||
|
|
||||||
Text {
|
TextRender {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "✕"
|
text: "✕"
|
||||||
color: closeArea.containsMouse ? "white" : "#888888"
|
color: closeArea.containsMouse ? "white" : "#888888"
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ PanelWindow {
|
|||||||
id: showAnimation
|
id: showAnimation
|
||||||
target: backgroundRect
|
target: backgroundRect
|
||||||
property: "x"
|
property: "x"
|
||||||
to: root.bar.screen.width - backgroundRect.implicitWidth - 10
|
to: Math.round(root.bar.screen.width - backgroundRect.implicitWidth - 10)
|
||||||
from: root.bar.screen.width
|
from: root.bar.screen.width
|
||||||
duration: MaterialEasing.expressiveEffectsTime
|
duration: MaterialEasing.expressiveEffectsTime
|
||||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ pragma ComponentBehavior: Bound
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
|
id: root
|
||||||
property double memoryTotal: 1
|
property double memoryTotal: 1
|
||||||
property double memoryFree: 1
|
property double memoryFree: 1
|
||||||
property double memoryUsed: memoryTotal - memoryFree
|
property double memoryUsed: memoryTotal - memoryFree
|
||||||
@@ -19,6 +21,8 @@ Singleton {
|
|||||||
property double gpuUsage: 0
|
property double gpuUsage: 0
|
||||||
property double gpuMemUsage: 0
|
property double gpuMemUsage: 0
|
||||||
property double totalMem: 0
|
property double totalMem: 0
|
||||||
|
readonly property string gpuType: Config.gpuType.toUpperCase() || autoGpuType
|
||||||
|
property string autoGpuType: "NONE"
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
interval: 1
|
interval: 1
|
||||||
@@ -52,7 +56,9 @@ Singleton {
|
|||||||
|
|
||||||
previousCpuStats = { total, idle }
|
previousCpuStats = { total, idle }
|
||||||
}
|
}
|
||||||
|
if ( root.gpuType === "NVIDIA" ) {
|
||||||
processGpu.running = true
|
processGpu.running = true
|
||||||
|
}
|
||||||
|
|
||||||
interval = 1000
|
interval = 1000
|
||||||
}
|
}
|
||||||
@@ -61,10 +67,20 @@ Singleton {
|
|||||||
FileView { id: fileMeminfo; path: "/proc/meminfo" }
|
FileView { id: fileMeminfo; path: "/proc/meminfo" }
|
||||||
FileView { id: fileStat; path: "/proc/stat" }
|
FileView { id: fileStat; path: "/proc/stat" }
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: gpuTypeCheck
|
||||||
|
|
||||||
|
running: !Config.gpuType
|
||||||
|
command: ["sh", "-c", "if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then echo NVIDIA; elif ls /sys/class/drm/card*/device/gpu_busy_percent 2>/dev/null | grep -q .; then echo GENERIC; else echo NONE; fi"]
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: root.autoGpuType = text.trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: oneshotMem
|
id: oneshotMem
|
||||||
command: ["nvidia-smi", "--query-gpu=memory.total", "--format=csv,noheader,nounits"]
|
command: ["nvidia-smi", "--query-gpu=memory.total", "--format=csv,noheader,nounits"]
|
||||||
running: true
|
running: root.gpuType === "NVIDIA" && totalMem === 0
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
onStreamFinished: {
|
onStreamFinished: {
|
||||||
totalMem = Number(this.text.trim())
|
totalMem = Number(this.text.trim())
|
||||||
|
|||||||
@@ -146,11 +146,11 @@ PanelWindow {
|
|||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: 12
|
spacing: 12
|
||||||
IconImage {
|
IconImage {
|
||||||
source: rootItem.modelData.image
|
source: rootItem.modelData.image === "" ? Qt.resolvedUrl(rootItem.modelData.appIcon) : Qt.resolvedUrl(rootItem.modelData.image)
|
||||||
Layout.preferredWidth: 48
|
Layout.preferredWidth: 48
|
||||||
Layout.preferredHeight: 48
|
Layout.preferredHeight: 48
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignLeft
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignLeft
|
||||||
visible: rootItem.modelData.image !== ""
|
// visible: rootItem.modelData.image !== ""
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
@@ -185,10 +185,16 @@ PanelWindow {
|
|||||||
text: rootItem.modelData.body
|
text: rootItem.modelData.body
|
||||||
color: "#dddddd"
|
color: "#dddddd"
|
||||||
font.pointSize: 14
|
font.pointSize: 14
|
||||||
|
textFormat: Text.MarkdownText
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
maximumLineCount: 4
|
maximumLineCount: 4
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
linkColor: Config.accentColor.accents.primaryAlt
|
||||||
|
|
||||||
|
onLinkActivated: link => {
|
||||||
|
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ Singleton {
|
|||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
updatesProc.running = true
|
updatesProc.running = true
|
||||||
interval = 60000
|
interval = 5000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import ZShell
|
||||||
|
import Quickshell
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property string home: Quickshell.env("HOME")
|
||||||
|
readonly property string pictures: Quickshell.env("XDG_PICTURES_DIR") || `${home}/Pictures`
|
||||||
|
readonly property string videos: Quickshell.env("XDG_VIDEOS_DIR") || `${home}/Videos`
|
||||||
|
|
||||||
|
readonly property string data: `${Quickshell.env("XDG_DATA_HOME") || `${home}/.local/share`}/zshell`
|
||||||
|
readonly property string state: `${Quickshell.env("XDG_STATE_HOME") || `${home}/.local/state`}/zshell`
|
||||||
|
readonly property string cache: `${Quickshell.env("XDG_CACHE_HOME") || `${home}/.cache`}/zshell`
|
||||||
|
readonly property string config: `${Quickshell.env("XDG_CONFIG_HOME") || `${home}/.config`}/zshell`
|
||||||
|
|
||||||
|
readonly property string imagecache: `${cache}/imagecache`
|
||||||
|
readonly property string notifimagecache: `${imagecache}/notifs`
|
||||||
|
readonly property string wallsdir: Quickshell.env("ZSHELL_WALLPAPERS_DIR") || absolutePath(Config.wallpaperPath)
|
||||||
|
readonly property string recsdir: Quickshell.env("ZSHELL_RECORDINGS_DIR") || `${videos}/Recordings`
|
||||||
|
readonly property string libdir: Quickshell.env("ZSHELL_LIB_DIR") || "/usr/lib/zshell"
|
||||||
|
|
||||||
|
function toLocalFile(path: url): string {
|
||||||
|
path = Qt.resolvedUrl(path);
|
||||||
|
return path.toString() ? ZShellIo.toLocalFile(path) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function absolutePath(path: string): string {
|
||||||
|
return toLocalFile(path.replace("~", home));
|
||||||
|
}
|
||||||
|
|
||||||
|
function shortenHome(path: string): string {
|
||||||
|
return path.replace(home, "~");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,4 +3,10 @@ qml_module(ZShell-internal
|
|||||||
SOURCES
|
SOURCES
|
||||||
hyprextras.hpp hyprextras.cpp
|
hyprextras.hpp hyprextras.cpp
|
||||||
hyprdevices.hpp hyprdevices.cpp
|
hyprdevices.hpp hyprdevices.cpp
|
||||||
|
cachingimagemanager.hpp cachingimagemanager.cpp
|
||||||
|
LIBRARIES
|
||||||
|
Qt::Gui
|
||||||
|
Qt::Quick
|
||||||
|
Qt::Concurrent
|
||||||
|
Qt::Core
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,223 @@
|
|||||||
|
#include "cachingimagemanager.hpp"
|
||||||
|
|
||||||
|
#include <QtQuick/qquickwindow.h>
|
||||||
|
#include <qcryptographichash.h>
|
||||||
|
#include <qdir.h>
|
||||||
|
#include <qfileinfo.h>
|
||||||
|
#include <qfuturewatcher.h>
|
||||||
|
#include <qimagereader.h>
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qtconcurrentrun.h>
|
||||||
|
|
||||||
|
namespace ZShell::internal {
|
||||||
|
|
||||||
|
qreal CachingImageManager::effectiveScale() const {
|
||||||
|
if (m_item && m_item->window()) {
|
||||||
|
return m_item->window()->devicePixelRatio();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize CachingImageManager::effectiveSize() const {
|
||||||
|
if (!m_item) {
|
||||||
|
return QSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
const qreal scale = effectiveScale();
|
||||||
|
const QSize size = QSizeF(m_item->width() * scale, m_item->height() * scale).toSize();
|
||||||
|
m_item->setProperty("sourceSize", size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
QQuickItem* CachingImageManager::item() const {
|
||||||
|
return m_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CachingImageManager::setItem(QQuickItem* item) {
|
||||||
|
if (m_item == item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_widthConn) {
|
||||||
|
disconnect(m_widthConn);
|
||||||
|
}
|
||||||
|
if (m_heightConn) {
|
||||||
|
disconnect(m_heightConn);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_item = item;
|
||||||
|
emit itemChanged();
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
m_widthConn = connect(item, &QQuickItem::widthChanged, this, [this]() {
|
||||||
|
updateSource();
|
||||||
|
});
|
||||||
|
m_heightConn = connect(item, &QQuickItem::heightChanged, this, [this]() {
|
||||||
|
updateSource();
|
||||||
|
});
|
||||||
|
updateSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl CachingImageManager::cacheDir() const {
|
||||||
|
return m_cacheDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CachingImageManager::setCacheDir(const QUrl& cacheDir) {
|
||||||
|
if (m_cacheDir == cacheDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cacheDir = cacheDir;
|
||||||
|
if (!m_cacheDir.path().endsWith("/")) {
|
||||||
|
m_cacheDir.setPath(m_cacheDir.path() + "/");
|
||||||
|
}
|
||||||
|
emit cacheDirChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CachingImageManager::path() const {
|
||||||
|
return m_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CachingImageManager::setPath(const QString& path) {
|
||||||
|
if (m_path == path) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_path = path;
|
||||||
|
emit pathChanged();
|
||||||
|
|
||||||
|
if (!path.isEmpty()) {
|
||||||
|
updateSource(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CachingImageManager::updateSource() {
|
||||||
|
updateSource(m_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CachingImageManager::updateSource(const QString& path) {
|
||||||
|
if (path.isEmpty() || path == m_shaPath) {
|
||||||
|
// Path is empty or already calculating sha for path
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_shaPath = path;
|
||||||
|
|
||||||
|
const auto future = QtConcurrent::run(&CachingImageManager::sha256sum, path);
|
||||||
|
|
||||||
|
const auto watcher = new QFutureWatcher<QString>(this);
|
||||||
|
|
||||||
|
connect(watcher, &QFutureWatcher<QString>::finished, this, [watcher, path, this]() {
|
||||||
|
if (m_path != path) {
|
||||||
|
// Object is destroyed or path has changed, ignore
|
||||||
|
watcher->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QSize size = effectiveSize();
|
||||||
|
|
||||||
|
if (!m_item || !size.width() || !size.height()) {
|
||||||
|
watcher->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString fillMode = m_item->property("fillMode").toString();
|
||||||
|
// clang-format off
|
||||||
|
const QString filename = QString("%1@%2x%3-%4.png")
|
||||||
|
.arg(watcher->result()).arg(size.width()).arg(size.height())
|
||||||
|
.arg(fillMode == "PreserveAspectCrop" ? "crop" : fillMode == "PreserveAspectFit" ? "fit" : "stretch");
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
const QUrl cache = m_cacheDir.resolved(QUrl(filename));
|
||||||
|
if (m_cachePath == cache) {
|
||||||
|
watcher->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cachePath = cache;
|
||||||
|
emit cachePathChanged();
|
||||||
|
|
||||||
|
if (!cache.isLocalFile()) {
|
||||||
|
qWarning() << "CachingImageManager::updateSource: cachePath" << cache << "is not a local file";
|
||||||
|
watcher->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QImageReader reader(cache.toLocalFile());
|
||||||
|
if (reader.canRead()) {
|
||||||
|
m_item->setProperty("source", cache);
|
||||||
|
} else {
|
||||||
|
m_item->setProperty("source", QUrl::fromLocalFile(path));
|
||||||
|
createCache(path, cache.toLocalFile(), fillMode, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear current running sha if same
|
||||||
|
if (m_shaPath == path) {
|
||||||
|
m_shaPath = QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
watcher->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
|
watcher->setFuture(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl CachingImageManager::cachePath() const {
|
||||||
|
return m_cachePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CachingImageManager::createCache(
|
||||||
|
const QString& path, const QString& cache, const QString& fillMode, const QSize& size) const {
|
||||||
|
QThreadPool::globalInstance()->start([path, cache, fillMode, size] {
|
||||||
|
QImage image(path);
|
||||||
|
|
||||||
|
if (image.isNull()) {
|
||||||
|
qWarning() << "CachingImageManager::createCache: failed to read" << path;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
image.convertTo(QImage::Format_ARGB32);
|
||||||
|
|
||||||
|
if (fillMode == "PreserveAspectCrop") {
|
||||||
|
image = image.scaled(size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||||
|
} else if (fillMode == "PreserveAspectFit") {
|
||||||
|
image = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
} else {
|
||||||
|
image = image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fillMode == "PreserveAspectCrop" || fillMode == "PreserveAspectFit") {
|
||||||
|
QImage canvas(size, QImage::Format_ARGB32);
|
||||||
|
canvas.fill(Qt::transparent);
|
||||||
|
|
||||||
|
QPainter painter(&canvas);
|
||||||
|
painter.drawImage((size.width() - image.width()) / 2, (size.height() - image.height()) / 2, image);
|
||||||
|
painter.end();
|
||||||
|
|
||||||
|
image = canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString parent = QFileInfo(cache).absolutePath();
|
||||||
|
if (!QDir().mkpath(parent) || !image.save(cache)) {
|
||||||
|
qWarning() << "CachingImageManager::createCache: failed to save to" << cache;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CachingImageManager::sha256sum(const QString& path) {
|
||||||
|
QFile file(path);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
qWarning() << "CachingImageManager::sha256sum: failed to open" << path;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Sha256);
|
||||||
|
hash.addData(&file);
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
return hash.result().toHex();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZShell::internal
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtQuick/qquickitem.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qqmlintegration.h>
|
||||||
|
|
||||||
|
namespace ZShell::internal {
|
||||||
|
|
||||||
|
class CachingImageManager : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
|
||||||
|
Q_PROPERTY(QQuickItem* item READ item WRITE setItem NOTIFY itemChanged REQUIRED)
|
||||||
|
Q_PROPERTY(QUrl cacheDir READ cacheDir WRITE setCacheDir NOTIFY cacheDirChanged REQUIRED)
|
||||||
|
|
||||||
|
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
|
||||||
|
Q_PROPERTY(QUrl cachePath READ cachePath NOTIFY cachePathChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CachingImageManager(QObject* parent = nullptr)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_item(nullptr) {}
|
||||||
|
|
||||||
|
[[nodiscard]] QQuickItem* item() const;
|
||||||
|
void setItem(QQuickItem* item);
|
||||||
|
|
||||||
|
[[nodiscard]] QUrl cacheDir() const;
|
||||||
|
void setCacheDir(const QUrl& cacheDir);
|
||||||
|
|
||||||
|
[[nodiscard]] QString path() const;
|
||||||
|
void setPath(const QString& path);
|
||||||
|
|
||||||
|
[[nodiscard]] QUrl cachePath() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE void updateSource();
|
||||||
|
Q_INVOKABLE void updateSource(const QString& path);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void itemChanged();
|
||||||
|
void cacheDirChanged();
|
||||||
|
|
||||||
|
void pathChanged();
|
||||||
|
void cachePathChanged();
|
||||||
|
void usingCacheChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_shaPath;
|
||||||
|
|
||||||
|
QQuickItem* m_item;
|
||||||
|
QUrl m_cacheDir;
|
||||||
|
|
||||||
|
QString m_path;
|
||||||
|
QUrl m_cachePath;
|
||||||
|
|
||||||
|
QMetaObject::Connection m_widthConn;
|
||||||
|
QMetaObject::Connection m_heightConn;
|
||||||
|
|
||||||
|
[[nodiscard]] qreal effectiveScale() const;
|
||||||
|
[[nodiscard]] QSize effectiveSize() const;
|
||||||
|
|
||||||
|
void createCache(const QString& path, const QString& cache, const QString& fillMode, const QSize& size) const;
|
||||||
|
[[nodiscard]] static QString sha256sum(const QString& path);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZShell::internal
|
||||||
+1
-17
@@ -21,23 +21,7 @@ Scope {
|
|||||||
right: true
|
right: true
|
||||||
bottom: true
|
bottom: true
|
||||||
}
|
}
|
||||||
Image {
|
Background {}
|
||||||
id: wallpaperImage
|
|
||||||
anchors.fill: parent
|
|
||||||
source: WallpaperPath.currentWallpaperPath
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
|
|
||||||
smooth: true
|
|
||||||
asynchronous: true
|
|
||||||
retainWhileLoading: true
|
|
||||||
|
|
||||||
// Behavior on source {
|
|
||||||
// Anim {
|
|
||||||
// properties: "opacity"
|
|
||||||
// duration: 500
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user