feat: initial video wallpaper implementation
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import ZShell.Config
|
||||
@@ -9,7 +11,7 @@ Item {
|
||||
id: root
|
||||
|
||||
required property bool isCurrent
|
||||
required property var modelData // FileSystemEntry-like {path, relativePath}
|
||||
required property var modelData
|
||||
required property real tileHeight
|
||||
required property real tileWidth
|
||||
required property ScreenState screenState
|
||||
@@ -29,25 +31,75 @@ Item {
|
||||
radius: Tokens.rounding.small
|
||||
y: Tokens.padding.large
|
||||
|
||||
MaterialIcon {
|
||||
Loader {
|
||||
active: opacity > 0
|
||||
anchors.centerIn: parent
|
||||
color: Colors.tPalette.m3outline
|
||||
fontStyle: Tokens.font.icon.builders.extraLarge.scale(2).weight(Font.DemiBold).build()
|
||||
text: "image"
|
||||
opacity: img.status === Image.Ready ? 0 : 1
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
sourceComponent: CustomRect {
|
||||
color: Colors.palette.m3primaryContainer
|
||||
implicitHeight: loadingIndicator.implicitSize + Tokens.padding.large * 2
|
||||
implicitWidth: loadingIndicator.implicitSize + Tokens.padding.large * 2
|
||||
radius: Tokens.rounding.full
|
||||
|
||||
LoadingIndicator {
|
||||
id: loadingIndicator
|
||||
|
||||
anchors.centerIn: parent
|
||||
containsIcon: true
|
||||
implicitSize: Math.min(image.width, image.height) * 0.3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CachingImage {
|
||||
id: img
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
cache: true
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
height: root.tileHeight
|
||||
path: root.modelData ? root.modelData.path : ""
|
||||
path: root.modelData ? root.modelData.thumbnailPath : ""
|
||||
smooth: root.isCurrent
|
||||
sourceSize.height: root.tileHeight
|
||||
sourceSize.width: root.tileHeight * (16 / 9)
|
||||
width: root.tileHeight * (16 / 9)
|
||||
|
||||
opacity: status === Image.Ready ? 1 : 0
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.SlowEffects
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
opacity: root.modelData.isVideo && img.status === Image.Ready ? 1 : 0
|
||||
active: opacity > 0
|
||||
anchors.centerIn: parent
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.SlowEffects
|
||||
}
|
||||
}
|
||||
|
||||
sourceComponent: CustomRect {
|
||||
implicitWidth: videoIcon.implicitWidth + Tokens.padding.extraLarge * 2
|
||||
implicitHeight: implicitWidth
|
||||
radius: Tokens.rounding.full
|
||||
color: Colors.tPalette.m3surface
|
||||
|
||||
MaterialIcon {
|
||||
id: videoIcon
|
||||
anchors.centerIn: parent
|
||||
text: "video_library"
|
||||
fontStyle: Tokens.font.icon.extraLarge
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StateLayer {
|
||||
|
||||
@@ -41,8 +41,7 @@ orientation: Qt.Vertical
|
||||
opacity: img.status === Image.Ready ? 0 : 1
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
Anim {}
|
||||
}
|
||||
sourceComponent: CustomRect {
|
||||
color: Colors.palette.m3primaryContainer
|
||||
@@ -66,18 +65,43 @@ orientation: Qt.Vertical
|
||||
anchors.fill: parent
|
||||
asynchronous: true
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
opacity: status === Image.Ready ? 1 : 0
|
||||
retainWhileLoading: true
|
||||
sourceSize: {
|
||||
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
|
||||
return Qt.size(width * dpr, height * dpr);
|
||||
}
|
||||
|
||||
opacity: status === Image.Ready ? 1 : 0
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.SlowEffects
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
opacity: root.modelData.isVideo && img.status === Image.Ready ? 1 : 0
|
||||
active: opacity > 0
|
||||
anchors.centerIn: parent
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.SlowEffects
|
||||
}
|
||||
}
|
||||
|
||||
sourceComponent: CustomRect {
|
||||
implicitWidth: videoIcon.implicitWidth + Tokens.padding.extraLarge * 2
|
||||
implicitHeight: implicitWidth
|
||||
radius: Tokens.rounding.full
|
||||
color: Colors.tPalette.m3surface
|
||||
|
||||
MaterialIcon {
|
||||
id: videoIcon
|
||||
anchors.centerIn: parent
|
||||
text: "video_library"
|
||||
fontStyle: Tokens.font.icon.extraLarge
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ import qs.Services
|
||||
Item {
|
||||
id: wrapper
|
||||
|
||||
property int buttonRowHeight: Tokens.padding.large * 3
|
||||
readonly property bool isVideo: Wallpapers.currentIsVideo
|
||||
readonly property var currentScreen: screens.length > selectedScreenIndex ? screens[selectedScreenIndex] : null
|
||||
readonly property real maxZoom: 5.0
|
||||
readonly property bool changesMade: {
|
||||
cropRevision;
|
||||
|
||||
@@ -25,9 +27,9 @@ Item {
|
||||
|
||||
return Math.abs(r.x - t.x) > 0.5 || Math.abs(r.y - t.y) > 0.5 || Math.abs(r.zoom - t.zoom) > 0.001;
|
||||
}
|
||||
|
||||
property int buttonRowHeight: Tokens.padding.large * 3
|
||||
property int cropRevision: 0
|
||||
readonly property var currentScreen: screens.length > selectedScreenIndex ? screens[selectedScreenIndex] : null
|
||||
readonly property real maxZoom: 5.0
|
||||
property var screens: []
|
||||
property int selectedScreenIndex: 0
|
||||
property bool shouldBeActive: true
|
||||
@@ -127,7 +129,7 @@ Item {
|
||||
anchors.rightMargin: Tokens.padding.extraLarge * 2
|
||||
anchors.top: parent.top
|
||||
|
||||
active: wrapper.screens.length > 1
|
||||
active: wrapper.screens.length > 1 && !wrapper.isVideo
|
||||
|
||||
sourceComponent: ButtonRow {
|
||||
id: screenSelector
|
||||
@@ -163,6 +165,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
implicitHeight: 30
|
||||
enabled: !wrapper.isVideo
|
||||
|
||||
CustomSlider {
|
||||
id: zoomSlider
|
||||
@@ -274,7 +277,7 @@ Item {
|
||||
opacity: status === Image.Ready ? 1 : 0
|
||||
retainWhileLoading: true
|
||||
smooth: true
|
||||
source: Wallpapers.current
|
||||
source: Wallpapers.currentThumbnail
|
||||
sourceSize.height: {
|
||||
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
|
||||
return imageSlot.height * dpr;
|
||||
@@ -285,12 +288,37 @@ Item {
|
||||
type: Anim.SlowEffects
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
opacity: wrapper.isVideo && scaledImg.status === Image.Ready ? 1 : 0
|
||||
active: opacity > 0
|
||||
anchors.centerIn: parent
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
type: Anim.SlowEffects
|
||||
}
|
||||
}
|
||||
|
||||
sourceComponent: CustomRect {
|
||||
implicitWidth: videoIcon.implicitWidth + Tokens.padding.extraLarge * 2
|
||||
implicitHeight: implicitWidth
|
||||
radius: Tokens.rounding.full
|
||||
color: Colors.tPalette.m3surface
|
||||
|
||||
MaterialIcon {
|
||||
id: videoIcon
|
||||
anchors.centerIn: parent
|
||||
text: "video_library"
|
||||
fontStyle: Tokens.font.icon.extraLarge
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: cropRectLoader
|
||||
|
||||
active: scaledImg.status === Image.Ready
|
||||
active: scaledImg.status === Image.Ready && !wrapper.isVideo
|
||||
|
||||
sourceComponent: Component {
|
||||
CustomRect {
|
||||
@@ -333,7 +361,6 @@ Item {
|
||||
y = t.y;
|
||||
}
|
||||
|
||||
// Where the rect should be according to saved data (same rules as a restore).
|
||||
function savedTarget() {
|
||||
const data = Wallpapers.getCrop(wrapper.currentScreen.name);
|
||||
const hasCrop = data && (Math.abs(data.x) > 0.001 || Math.abs(data.y) > 0.001 || Math.abs(data.width - 1.0) > 0.001 || Math.abs(data.height - 1.0) > 0.001);
|
||||
@@ -436,9 +463,10 @@ Item {
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
cursorShape: pressed ? Qt.ClosedHandCursor : insideCropRect(mouseX, mouseY) ? Qt.OpenHandCursor : Qt.PointingHandCursor
|
||||
cursorShape: wrapper.isVideo ? Qt.ArrowCursor : pressed ? Qt.ClosedHandCursor : insideCropRect(mouseX, mouseY) ? Qt.OpenHandCursor : Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
preventStealing: true
|
||||
enabled: !wrapper.isVideo
|
||||
|
||||
onPositionChanged: mouse => {
|
||||
if (pressed) {
|
||||
|
||||
@@ -52,11 +52,12 @@ orientation: Qt.Vertical
|
||||
}
|
||||
|
||||
WallItem {
|
||||
id: wallItem
|
||||
required property FileSystemEntry modelData
|
||||
|
||||
enabled: modelData
|
||||
opacity: modelData ? 1 : 0
|
||||
source: String(modelData?.path ?? "")
|
||||
source: String(modelData?.thumbnailPath ?? "")
|
||||
|
||||
onClicked: {
|
||||
Wallpapers.setWallpaper(modelData.path);
|
||||
|
||||
Reference in New Issue
Block a user