feat: launcher wallpaper selector
This commit is contained in:
parent
d01194d1fc
commit
00d3c1a472
13 changed files with 429 additions and 105 deletions
|
|
@ -5,11 +5,14 @@ import QtQuick
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
readonly property int maxShown: 8
|
readonly property int maxShown: 8
|
||||||
|
readonly property int maxWallpapers: 9 // Warning: even numbers look bad
|
||||||
readonly property string actionPrefix: ">"
|
readonly property string actionPrefix: ">"
|
||||||
readonly property Sizes sizes: Sizes {}
|
readonly property Sizes sizes: Sizes {}
|
||||||
|
|
||||||
component Sizes: QtObject {
|
component Sizes: QtObject {
|
||||||
readonly property int width: 600
|
readonly property int itemWidth: 600
|
||||||
readonly property int itemHeight: 57
|
readonly property int itemHeight: 57
|
||||||
|
readonly property int wallpaperWidth: 280
|
||||||
|
readonly property int wallpaperHeight: 200
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@ PaddedRect {
|
||||||
required property Actions.Action modelData
|
required property Actions.Action modelData
|
||||||
required property var list
|
required property var list
|
||||||
|
|
||||||
implicitWidth: ListView.view.width
|
|
||||||
implicitHeight: LauncherConfig.sizes.itemHeight
|
implicitHeight: LauncherConfig.sizes.itemHeight
|
||||||
padding: [Appearance.padding.smaller, Appearance.padding.larger]
|
padding: [Appearance.padding.smaller, Appearance.padding.larger]
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,12 @@ PaddedRect {
|
||||||
required property DesktopEntry modelData
|
required property DesktopEntry modelData
|
||||||
required property Scope launcher
|
required property Scope launcher
|
||||||
|
|
||||||
implicitWidth: ListView.view.width
|
|
||||||
implicitHeight: LauncherConfig.sizes.itemHeight
|
implicitHeight: LauncherConfig.sizes.itemHeight
|
||||||
padding: [Appearance.padding.smaller, Appearance.padding.normal]
|
padding: [Appearance.padding.smaller, Appearance.padding.normal]
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,17 +30,12 @@ ListView {
|
||||||
onValuesChanged: root.currentIndex = 0
|
onValuesChanged: root.currentIndex = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
clip: true
|
|
||||||
spacing: Appearance.spacing.small
|
spacing: Appearance.spacing.small
|
||||||
orientation: Qt.Vertical
|
orientation: Qt.Vertical
|
||||||
implicitHeight: (LauncherConfig.sizes.itemHeight + spacing) * Math.min(LauncherConfig.maxShown, count) - spacing
|
implicitHeight: (LauncherConfig.sizes.itemHeight + spacing) * Math.min(LauncherConfig.maxShown, count) - spacing
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.margins: root.padding
|
|
||||||
|
|
||||||
highlightMoveDuration: Appearance.anim.durations.normal
|
highlightMoveDuration: Appearance.anim.durations.normal
|
||||||
|
highlightResizeDuration: 0
|
||||||
|
|
||||||
highlight: StyledRect {
|
highlight: StyledRect {
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
|
|
@ -111,13 +106,6 @@ ListView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.large
|
|
||||||
easing.bezierCurve: Appearance.anim.curves.emphasizedDecel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on isAction {
|
Behavior on isAction {
|
||||||
SequentialAnimation {
|
SequentialAnimation {
|
||||||
ParallelAnimation {
|
ParallelAnimation {
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,12 @@ import QtQuick.Shapes
|
||||||
Shape {
|
Shape {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
required property real wrapperWidth
|
||||||
required property real realWrapperHeight
|
required property real realWrapperHeight
|
||||||
readonly property int rounding: Appearance.rounding.large
|
readonly property int rounding: Appearance.rounding.large
|
||||||
readonly property int roundingY: Math.min(rounding, realWrapperHeight / 2)
|
readonly property int roundingY: Math.min(rounding, realWrapperHeight / 2)
|
||||||
readonly property real wrapperHeight: realWrapperHeight - 1 // Pixel issues :sob:
|
readonly property real wrapperHeight: realWrapperHeight - 1 // Pixel issues :sob:
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
preferredRendererType: Shape.CurveRenderer
|
preferredRendererType: Shape.CurveRenderer
|
||||||
|
|
@ -41,7 +40,7 @@ Shape {
|
||||||
radiusY: root.roundingY
|
radiusY: root.roundingY
|
||||||
}
|
}
|
||||||
PathLine {
|
PathLine {
|
||||||
x: wrapper.width - root.rounding * 2
|
x: root.wrapperWidth - root.rounding * 2
|
||||||
}
|
}
|
||||||
PathArc {
|
PathArc {
|
||||||
relativeX: root.rounding
|
relativeX: root.rounding
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import "root:/widgets"
|
import "root:/widgets"
|
||||||
import "root:/services"
|
import "root:/services"
|
||||||
import "root:/config"
|
import "root:/config"
|
||||||
|
|
@ -13,7 +15,7 @@ Item {
|
||||||
readonly property int spacing: Appearance.spacing.normal
|
readonly property int spacing: Appearance.spacing.normal
|
||||||
readonly property int rounding: Appearance.rounding.large
|
readonly property int rounding: Appearance.rounding.large
|
||||||
|
|
||||||
implicitWidth: LauncherConfig.sizes.width
|
implicitWidth: listWrapper.width + padding * 2
|
||||||
implicitHeight: search.height + listWrapper.height + padding * 2 + spacing
|
implicitHeight: search.height + listWrapper.height + padding * 2 + spacing
|
||||||
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
@ -24,26 +26,23 @@ Item {
|
||||||
|
|
||||||
color: Appearance.alpha(Appearance.colours.m3surfaceContainerHigh, true)
|
color: Appearance.alpha(Appearance.colours.m3surfaceContainerHigh, true)
|
||||||
radius: root.rounding
|
radius: root.rounding
|
||||||
implicitHeight: Math.max(empty.height, list.height) + root.padding * 2
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
implicitWidth: list.width + root.padding * 2
|
||||||
anchors.right: parent.right
|
implicitHeight: list.height + root.padding * 2
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.bottom: search.top
|
anchors.bottom: search.top
|
||||||
anchors.bottomMargin: root.spacing
|
anchors.bottomMargin: root.spacing
|
||||||
anchors.margins: root.padding
|
anchors.margins: root.padding
|
||||||
|
|
||||||
AppList {
|
ContentList {
|
||||||
id: list
|
id: list
|
||||||
|
|
||||||
padding: root.padding
|
|
||||||
search: search
|
|
||||||
launcher: root.launcher
|
launcher: root.launcher
|
||||||
}
|
search: search
|
||||||
|
padding: root.padding
|
||||||
EmptyIndicator {
|
spacing: root.spacing
|
||||||
id: empty
|
rounding: root.rounding
|
||||||
|
|
||||||
empty: list.count === 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,18 +67,22 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
if (list.currentItem) {
|
const currentItem = list.currentList?.currentItem;
|
||||||
if (list.isAction)
|
if (currentItem) {
|
||||||
list.currentItem.modelData.onClicked(list);
|
if (list.showWallpapers) {
|
||||||
else {
|
// TODO
|
||||||
Apps.launch(list.currentItem?.modelData);
|
console.log(currentItem.modelData.path);
|
||||||
|
} else if (text.startsWith(LauncherConfig.actionPrefix)) {
|
||||||
|
currentItem.modelData.onClicked(list.currentList);
|
||||||
|
} else {
|
||||||
|
Apps.launch(currentItem.modelData);
|
||||||
root.launcher.launcherVisible = false;
|
root.launcher.launcherVisible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onUpPressed: list.decrementCurrentIndex()
|
Keys.onUpPressed: list.currentList?.decrementCurrentIndex()
|
||||||
Keys.onDownPressed: list.incrementCurrentIndex()
|
Keys.onDownPressed: list.currentList?.incrementCurrentIndex()
|
||||||
|
|
||||||
Keys.onEscapePressed: root.launcher.launcherVisible = false
|
Keys.onEscapePressed: root.launcher.launcherVisible = false
|
||||||
|
|
||||||
|
|
@ -91,7 +94,9 @@ Item {
|
||||||
search.forceActiveFocus();
|
search.forceActiveFocus();
|
||||||
else {
|
else {
|
||||||
search.text = "";
|
search.text = "";
|
||||||
list.currentIndex = 0;
|
const current = list.currentList;
|
||||||
|
if (current)
|
||||||
|
current.currentIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
193
modules/launcher/ContentList.qml
Normal file
193
modules/launcher/ContentList.qml
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import "root:/widgets"
|
||||||
|
import "root:/services"
|
||||||
|
import "root:/config"
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Scope launcher
|
||||||
|
required property TextField search
|
||||||
|
required property int padding
|
||||||
|
required property int spacing
|
||||||
|
required property int rounding
|
||||||
|
|
||||||
|
property bool showWallpapers: search.text.startsWith(`${LauncherConfig.actionPrefix}wallpaper `)
|
||||||
|
property var currentList: (showWallpapers ? wallpaperList : appList).item
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: root.padding
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
state: showWallpapers ? "wallpapers" : "apps"
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "apps"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.implicitWidth: LauncherConfig.sizes.itemWidth
|
||||||
|
root.implicitHeight: Math.max(empty.height, appList.height)
|
||||||
|
appList.active: true
|
||||||
|
}
|
||||||
|
|
||||||
|
AnchorChanges {
|
||||||
|
anchors.left: root.parent.left
|
||||||
|
anchors.right: root.parent.right
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "wallpapers"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.implicitWidth: Math.max(LauncherConfig.sizes.itemWidth, wallpaperList.width)
|
||||||
|
root.implicitHeight: LauncherConfig.sizes.wallpaperHeight
|
||||||
|
wallpaperList.active: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
transitions: Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "*"
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
target: root
|
||||||
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
duration: Appearance.anim.durations.small
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
targets: [appList, wallpaperList]
|
||||||
|
properties: "active"
|
||||||
|
}
|
||||||
|
ParallelAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
target: root
|
||||||
|
properties: "implicitWidth,implicitHeight"
|
||||||
|
duration: Appearance.anim.durations.large
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.emphasized
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: root
|
||||||
|
property: "opacity"
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
duration: Appearance.anim.durations.large
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: appList
|
||||||
|
|
||||||
|
active: false
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
sourceComponent: AppList {
|
||||||
|
padding: root.padding
|
||||||
|
search: root.search
|
||||||
|
launcher: root.launcher
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: wallpaperList
|
||||||
|
|
||||||
|
active: false
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
sourceComponent: WallpaperList {
|
||||||
|
search: root.search
|
||||||
|
launcher: root.launcher
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: empty
|
||||||
|
|
||||||
|
opacity: root.currentList.count === 0 ? 1 : 0
|
||||||
|
scale: root.currentList.count === 0 ? 1 : 0.5
|
||||||
|
|
||||||
|
implicitWidth: icon.width + text.width + Appearance.spacing.small
|
||||||
|
implicitHeight: icon.height
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
text: "manage_search"
|
||||||
|
color: Appearance.colours.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: text
|
||||||
|
|
||||||
|
anchors.left: icon.right
|
||||||
|
anchors.leftMargin: Appearance.spacing.small
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
text: qsTr("No results")
|
||||||
|
color: Appearance.colours.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
font.weight: 500
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on scale {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.large
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.emphasizedDecel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.large
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.emphasizedDecel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
import "root:/widgets"
|
|
||||||
import "root:/config"
|
|
||||||
import QtQuick
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property bool empty
|
|
||||||
|
|
||||||
active: false
|
|
||||||
opacity: 0
|
|
||||||
scale: 0
|
|
||||||
asynchronous: true
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
sourceComponent: Item {
|
|
||||||
implicitWidth: childrenRect.width
|
|
||||||
implicitHeight: icon.height
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
id: icon
|
|
||||||
|
|
||||||
text: "manage_search"
|
|
||||||
color: Appearance.colours.m3outline
|
|
||||||
font.pointSize: Appearance.font.size.extraLarge
|
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
anchors.left: icon.right
|
|
||||||
anchors.leftMargin: Appearance.spacing.small
|
|
||||||
anchors.verticalCenter: icon.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("No matching apps found")
|
|
||||||
color: Appearance.colours.m3outline
|
|
||||||
font.pointSize: Appearance.font.size.larger
|
|
||||||
font.weight: 500
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
states: State {
|
|
||||||
name: "visible"
|
|
||||||
when: root.empty
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
root.active: true
|
|
||||||
root.opacity: 1
|
|
||||||
root.scale: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transitions: Transition {
|
|
||||||
NumberAnimation {
|
|
||||||
properties: "opacity,scale"
|
|
||||||
duration: Appearance.anim.durations.large
|
|
||||||
easing.type: Easing.BezierSpline
|
|
||||||
easing.bezierCurve: Appearance.anim.curves.standard
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -21,23 +21,31 @@ Scope {
|
||||||
keyboardFocus: root.launcherVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
keyboardFocus: root.launcherVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||||
visible: wrapper.shouldBeVisible
|
visible: wrapper.shouldBeVisible
|
||||||
|
|
||||||
width: content.width + bg.rounding * 2
|
|
||||||
mask: Region {
|
mask: Region {
|
||||||
item: wrapper
|
item: wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors.top: true
|
anchors.top: true
|
||||||
|
anchors.left: true
|
||||||
anchors.bottom: true
|
anchors.bottom: true
|
||||||
|
anchors.right: true
|
||||||
|
|
||||||
Background {
|
Background {
|
||||||
id: bg
|
id: bg
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
wrapperWidth: wrapper.width
|
||||||
realWrapperHeight: Math.min(wrapper.height, content.height)
|
realWrapperHeight: Math.min(wrapper.height, content.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
Wrapper {
|
Wrapper {
|
||||||
id: wrapper
|
id: wrapper
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
implicitWidth: content.width + bg.rounding * 2
|
||||||
|
|
||||||
launcherVisible: root.launcherVisible
|
launcherVisible: root.launcherVisible
|
||||||
contentHeight: content.height
|
contentHeight: content.height
|
||||||
|
|
||||||
|
|
|
||||||
91
modules/launcher/WallpaperItem.qml
Normal file
91
modules/launcher/WallpaperItem.qml
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
import "root:/widgets"
|
||||||
|
import "root:/services"
|
||||||
|
import "root:/config"
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Wallpapers.Wallpaper modelData
|
||||||
|
|
||||||
|
scale: PathView.isCurrentItem ? 1 : PathView.onPath ? 0.8 : 0
|
||||||
|
opacity: PathView.onPath ? 1 : 0
|
||||||
|
z: PathView.isCurrentItem ? 1 : 0
|
||||||
|
|
||||||
|
implicitWidth: image.width + Appearance.padding.larger * 2
|
||||||
|
implicitHeight: image.height + label.height + Appearance.spacing.small / 2 + Appearance.padding.normal * 2
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
radius: Appearance.rounding.normal
|
||||||
|
|
||||||
|
function onClicked(): void {
|
||||||
|
console.log("clicked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
y: Appearance.padding.normal
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
source: `file://${root.modelData.path}`
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
smooth: !root.PathView.view.moving
|
||||||
|
|
||||||
|
width: LauncherConfig.sizes.wallpaperWidth
|
||||||
|
height: width / 16 * 9
|
||||||
|
sourceSize.width: width
|
||||||
|
sourceSize.height: height
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: mask
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
visible: false
|
||||||
|
anchors.fill: image
|
||||||
|
width: image.width
|
||||||
|
height: image.height
|
||||||
|
radius: Appearance.rounding.normal
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
anchors.fill: image
|
||||||
|
source: image
|
||||||
|
maskEnabled: true
|
||||||
|
maskSource: mask
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
anchors.top: image.bottom
|
||||||
|
anchors.topMargin: Appearance.spacing.small / 2
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
renderType: Text.QtRendering
|
||||||
|
text: root.modelData.name
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on scale {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
modules/launcher/WallpaperList.qml
Normal file
44
modules/launcher/WallpaperList.qml
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import "root:/widgets"
|
||||||
|
import "root:/services"
|
||||||
|
import "root:/config"
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
PathView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property TextField search
|
||||||
|
required property Scope launcher
|
||||||
|
|
||||||
|
model: ScriptModel {
|
||||||
|
values: {
|
||||||
|
const list = Wallpapers.fuzzyQuery(root.search.text.split(" ").slice(1).join(" "));
|
||||||
|
if (list.length > 1 && list.length % 2 === 0)
|
||||||
|
list.length -= 1; // Always show odd number
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
onValuesChanged: root.currentIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: Math.min(LauncherConfig.maxWallpapers, count) * (LauncherConfig.sizes.wallpaperWidth * 0.8 + Appearance.padding.larger * 2)
|
||||||
|
pathItemCount: LauncherConfig.maxWallpapers
|
||||||
|
cacheItemCount: 4
|
||||||
|
|
||||||
|
snapMode: PathView.SnapToItem
|
||||||
|
preferredHighlightBegin: 0.5
|
||||||
|
preferredHighlightEnd: 0.5
|
||||||
|
highlightRangeMode: PathView.StrictlyEnforceRange
|
||||||
|
highlightMoveDuration: Appearance.anim.durations.short
|
||||||
|
|
||||||
|
delegate: WallpaperItem {}
|
||||||
|
|
||||||
|
path: Path {
|
||||||
|
startY: root.height / 2
|
||||||
|
|
||||||
|
PathLine {
|
||||||
|
x: root.width
|
||||||
|
relativeY: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,8 +8,6 @@ Item {
|
||||||
required property real contentHeight
|
required property real contentHeight
|
||||||
property bool shouldBeVisible
|
property bool shouldBeVisible
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
height: 0
|
height: 0
|
||||||
|
|
|
||||||
53
services/Wallpapers.qml
Normal file
53
services/Wallpapers.qml
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import "root:/utils/scripts/fuzzysort.js" as Fuzzy
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import QtQuick
|
||||||
|
import Qt.labs.platform
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property string path: `${StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]}/Wallpapers`
|
||||||
|
|
||||||
|
property list<Wallpaper> list
|
||||||
|
|
||||||
|
readonly property list<var> preppedPaths: list.map(w => ({
|
||||||
|
path: Fuzzy.prepare(w.path),
|
||||||
|
wall: w
|
||||||
|
}))
|
||||||
|
|
||||||
|
function fuzzyQuery(search: string): var {
|
||||||
|
return Fuzzy.go(search, preppedPaths, {
|
||||||
|
all: true,
|
||||||
|
keys: ["name", "path"],
|
||||||
|
scoreFn: r => r[0].score * 0.9 + r[1].score * 0.1
|
||||||
|
}).map(r => r.obj.wall);
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
running: true
|
||||||
|
command: ["fd", ".", root.path.slice(7), "-t", "f", "-e", "jpg", "-e", "jpeg", "-e", "png", "-e", "svg"]
|
||||||
|
stdout: SplitParser {
|
||||||
|
splitMarker: ""
|
||||||
|
onRead: data => {
|
||||||
|
const list = data.trim().split("\n");
|
||||||
|
root.list = list.map(p => wallpaperComp.createObject(root, {
|
||||||
|
path: p
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component Wallpaper: QtObject {
|
||||||
|
required property string path
|
||||||
|
readonly property string name: path.slice(path.lastIndexOf("/") + 1, path.lastIndexOf("."))
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: wallpaperComp
|
||||||
|
|
||||||
|
Wallpaper {}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue