shift-shell/containments/homescreens/halcyon/package/contents/ui/FavoritesGrid.qml

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

299 lines
10 KiB
QML
Raw Normal View History

// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
2023-03-05 02:40:06 +00:00
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import QtQml.Models
import org.kde.plasma.components 3.0 as PC3
2023-03-05 02:40:06 +00:00
import org.kde.draganddrop as DragDrop
2023-03-05 02:40:06 +00:00
import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.private.mobile.homescreen.halcyon as Halcyon
MobileShell.GridView {
id: root
required property var searchWidget
2024-07-27 03:47:44 +00:00
// don't set anchors.margins since we want everywhere to be draggable
required property bool twoColumn
2024-07-27 03:47:44 +00:00
signal openConfigureRequested()
signal requestOpenFolder(Halcyon.ApplicationFolder folder)
// search widget open gesture
property bool openingSearchWidget: false
property bool canOpenSearchWidget: false
property real oldVerticalOvershoot: verticalOvershoot
2024-07-27 03:47:44 +00:00
onVerticalOvershootChanged: {
if (dragging && canOpenSearchWidget && verticalOvershoot < 0) {
if (!openingSearchWidget) {
if (oldVerticalOvershoot === 0) {
openingSearchWidget = true;
root.searchWidget.startGesture();
}
} else {
let offset = -(verticalOvershoot - oldVerticalOvershoot);
root.searchWidget.updateGestureOffset(-offset);
}
}
oldVerticalOvershoot = verticalOvershoot;
}
onDraggingChanged: {
if (dragging) {
canOpenSearchWidget = root.contentY <= 0;
} else if (!dragging && openingSearchWidget) {
openingSearchWidget = false;
root.searchWidget.endGesture();
}
}
2023-03-05 02:40:06 +00:00
// open wallpaper menu when held on click
TapHandler {
onLongPressed: root.openConfigureRequested()
}
2024-07-27 03:47:44 +00:00
header: MobileShell.BaseItem {
topPadding: Math.round(root.height * 0.2)
bottomPadding: Kirigami.Units.gridUnit
// leftPadding: root.leftMargin
// rightPadding: root.rightMargin
implicitWidth: root.width
background: Rectangle {
color: 'transparent'
TapHandler { onLongPressed: root.openConfigureRequested() } // open wallpaper menu when held on click
}
contentItem: Clock {}
}
2024-07-27 03:47:44 +00:00
Keys.onReturnPressed: currentItem.appDelegate.launch()
model: DelegateModel {
id: visualModel
2023-03-05 23:52:40 +00:00
model: Halcyon.PinnedModel
2024-07-27 03:47:44 +00:00
delegate: Item {
id: delegateRoot
property int visualIndex: DelegateModel.itemsIndex
property alias appDelegate: appDelegate
width: root.cellWidth
height: root.cellHeight
2024-07-27 03:47:44 +00:00
function moveDragToCurrentPos(from, to) {
if (from !== to) {
visualModel.items.move(from, to);
2023-03-05 23:52:40 +00:00
Halcyon.PinnedModel.moveEntry(from, to);
}
}
2024-07-27 03:47:44 +00:00
function topDragEnter(drag) {
if (transitionAnim.running || appDelegate.drag.active) return; // don't do anything when reordering
2024-07-27 03:47:44 +00:00
let fromIndex = drag.source.visualIndex;
let delegateVisualIndex = appDelegate.visualIndex;
let reorderIndex = -1;
2024-07-27 03:47:44 +00:00
if (fromIndex < delegateVisualIndex) { // dragged item from above
// move to spot above
reorderIndex = delegateVisualIndex - (root.twoColumn ? 2 : 1);
} else { // dragged item from below
// move to current spot
reorderIndex = delegateVisualIndex;
}
2024-07-27 03:47:44 +00:00
if (reorderIndex >= 0 && reorderIndex < root.count) {
delegateRoot.moveDragToCurrentPos(fromIndex, reorderIndex)
}
}
2024-07-27 03:47:44 +00:00
function bottomDragEnter(drag) {
if (transitionAnim.running || appDelegate.drag.active) return; // don't do anything when reordering
2024-07-27 03:47:44 +00:00
let fromIndex = drag.source.visualIndex;
let delegateVisualIndex = appDelegate.visualIndex;
let reorderIndex = -1;
2024-07-27 03:47:44 +00:00
if (fromIndex < delegateVisualIndex) { // dragged item from above
// move to current spot
reorderIndex = delegateVisualIndex;
} else { // dragged item from below
// move to spot below
reorderIndex = delegateVisualIndex + (root.twoColumn ? 2 : 1);
}
2024-07-27 03:47:44 +00:00
if (reorderIndex >= 0 && reorderIndex < root.count) {
delegateRoot.moveDragToCurrentPos(fromIndex, reorderIndex);
}
}
// top drop area
DropArea {
id: topDropArea
anchors.top: parent.top
anchors.left: leftDropArea.right
anchors.right: rightDropArea.left
height: delegateRoot.height * 0.2
onEntered: (drag) => delegateRoot.topDragEnter(drag)
}
2024-07-27 03:47:44 +00:00
// bottom drop area
DropArea {
id: bottomDropArea
anchors.bottom: parent.bottom
anchors.left: leftDropArea.right
anchors.right: rightDropArea.left
height: delegateRoot.height * 0.2
onEntered: (drag) => delegateRoot.bottomDragEnter(drag)
}
2024-07-27 03:47:44 +00:00
// left drop area
DropArea {
id: leftDropArea
anchors.bottom: parent.bottom
anchors.top: parent.top
anchors.left: parent.left
width: root.twoColumn ? Math.max(appDelegate.leftPadding, delegateRoot.width * 0.1) : 0
onEntered: (drag) => delegateRoot.topDragEnter(drag)
}
2024-07-27 03:47:44 +00:00
// right drop area
DropArea {
id: rightDropArea
anchors.bottom: parent.bottom
anchors.top: parent.top
anchors.right: parent.right
width: root.twoColumn ? Math.max(appDelegate.rightPadding, delegateRoot.width * 0.1) : 0
onEntered: (drag) => delegateRoot.bottomDragEnter(drag)
}
2024-07-27 03:47:44 +00:00
// folder drop area
DropArea {
anchors.top: topDropArea.bottom
anchors.bottom: bottomDropArea.top
anchors.left: leftDropArea.right
anchors.right: rightDropArea.left
onEntered: (drag) => {
if (transitionAnim.running || appDelegate.drag.active || drag.source.isFolder) return; // don't do anything when reordering
folderAnim.to = 1;
folderAnim.restart();
}
onExited: () => {
folderAnim.to = 0;
folderAnim.restart();
}
onDropped: (drop) => {
if (transitionAnim.running || appDelegate.drag.active || drag.source.isFolder) return; // don't do anything when reordering
if (appDelegate.isFolder) {
2023-03-05 23:52:40 +00:00
Halcyon.PinnedModel.addAppToFolder(drop.source.visualIndex, appDelegate.visualIndex);
} else {
2023-03-05 23:52:40 +00:00
Halcyon.PinnedModel.createFolderFromApps(drop.source.visualIndex, appDelegate.visualIndex);
}
folderAnim.to = 0;
folderAnim.restart();
}
2024-07-27 03:47:44 +00:00
NumberAnimation {
id: folderAnim
target: appDelegate
properties: "dragFolderAnimationProgress"
duration: 100
}
}
2024-07-27 03:47:44 +00:00
// actual visual delegate
FavoritesAppDelegate {
id: appDelegate
visualIndex: delegateRoot.visualIndex
2024-07-27 03:47:44 +00:00
isFolder: model.isFolder
folder: model.folder
application: model.application
2024-07-27 03:47:44 +00:00
onFolderOpenRequested: root.requestOpenFolder(model.folder)
2024-07-27 03:47:44 +00:00
menuActions: [
Kirigami.Action {
icon.name: "emblem-favorite"
text: i18n("Remove from favourites")
2023-03-05 23:52:40 +00:00
onTriggered: Halcyon.PinnedModel.removeEntry(model.index)
}
]
2024-07-27 03:47:44 +00:00
implicitWidth: root.cellWidth
implicitHeight: visible ? root.cellHeight : 0
2024-07-27 03:47:44 +00:00
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
2024-07-27 03:47:44 +00:00
states: [
State {
when: appDelegate.drag.active
ParentChange {
target: appDelegate
parent: root
}
2024-07-27 03:47:44 +00:00
AnchorChanges {
target: appDelegate
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
]
}
}
}
2024-07-27 03:47:44 +00:00
// animations
displaced: Transition {
NumberAnimation {
id: transitionAnim
properties: "x,y"
easing.type: Easing.OutQuad
}
}
2024-07-27 03:47:44 +00:00
ColumnLayout {
id: placeholder
spacing: Kirigami.Units.gridUnit
visible: root.count == 0
opacity: 0.9
2024-07-27 03:47:44 +00:00
anchors.fill: parent
anchors.topMargin: Math.round(swipeView.height * 0.2) - (root.contentY - root.originY)
anchors.leftMargin: root.leftMargin
anchors.rightMargin: root.rightMargin
2024-07-27 03:47:44 +00:00
layer.enabled: true
layer.effect: MobileShell.TextDropShadow {}
2024-07-27 03:47:44 +00:00
Kirigami.Icon {
id: icon
Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter
implicitWidth: Kirigami.Units.iconSizes.large
implicitHeight: width
source: "arrow-left"
color: "white"
}
2024-07-27 03:47:44 +00:00
Kirigami.Heading {
Layout.fillWidth: true
Layout.maximumWidth: placeholder.width * 0.75
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
color: "white"
level: 3
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
text: i18n("Add applications to your favourites so they show up here.")
}
2024-07-27 03:47:44 +00:00
TapHandler {
onLongPressed: root.openConfigureRequested()
}
}
}