Warning, /plasma/plasma-mobile/containments/homescreens/halcyon/package/contents/ui/FavoritesGrid.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org> 0002 // SPDX-License-Identifier: LGPL-2.0-or-later 0003 0004 import QtQuick 0005 import QtQuick.Controls as QQC2 0006 import QtQuick.Layouts 0007 import QtQml.Models 0008 0009 import org.kde.plasma.components 3.0 as PC3 0010 import org.kde.draganddrop as DragDrop 0011 0012 import org.kde.kirigami as Kirigami 0013 import org.kde.plasma.private.mobileshell as MobileShell 0014 import org.kde.private.mobile.homescreen.halcyon as Halcyon 0015 0016 MobileShell.GridView { 0017 id: root 0018 required property var searchWidget 0019 0020 // don't set anchors.margins since we want everywhere to be draggable 0021 required property bool twoColumn 0022 0023 signal openConfigureRequested() 0024 signal requestOpenFolder(Halcyon.ApplicationFolder folder) 0025 0026 // search widget open gesture 0027 property bool openingSearchWidget: false 0028 property bool canOpenSearchWidget: false 0029 property real oldVerticalOvershoot: verticalOvershoot 0030 0031 onVerticalOvershootChanged: { 0032 if (dragging && canOpenSearchWidget && verticalOvershoot < 0) { 0033 if (!openingSearchWidget) { 0034 if (oldVerticalOvershoot === 0) { 0035 openingSearchWidget = true; 0036 root.searchWidget.startGesture(); 0037 } 0038 } else { 0039 let offset = -(verticalOvershoot - oldVerticalOvershoot); 0040 root.searchWidget.updateGestureOffset(-offset); 0041 } 0042 } 0043 oldVerticalOvershoot = verticalOvershoot; 0044 } 0045 onDraggingChanged: { 0046 if (dragging) { 0047 canOpenSearchWidget = root.contentY <= 0; 0048 } else if (!dragging && openingSearchWidget) { 0049 openingSearchWidget = false; 0050 root.searchWidget.endGesture(); 0051 } 0052 } 0053 0054 // open wallpaper menu when held on click 0055 TapHandler { 0056 onLongPressed: root.openConfigureRequested() 0057 } 0058 0059 header: MobileShell.BaseItem { 0060 topPadding: Math.round(root.height * 0.2) 0061 bottomPadding: Kirigami.Units.gridUnit 0062 // leftPadding: root.leftMargin 0063 // rightPadding: root.rightMargin 0064 implicitWidth: root.width 0065 0066 background: Rectangle { 0067 color: 'transparent' 0068 TapHandler { onLongPressed: root.openConfigureRequested() } // open wallpaper menu when held on click 0069 } 0070 contentItem: Clock {} 0071 } 0072 0073 Keys.onReturnPressed: currentItem.appDelegate.launch() 0074 model: DelegateModel { 0075 id: visualModel 0076 model: Halcyon.PinnedModel 0077 0078 delegate: Item { 0079 id: delegateRoot 0080 property int visualIndex: DelegateModel.itemsIndex 0081 property alias appDelegate: appDelegate 0082 0083 width: root.cellWidth 0084 height: root.cellHeight 0085 0086 function moveDragToCurrentPos(from, to) { 0087 if (from !== to) { 0088 visualModel.items.move(from, to); 0089 Halcyon.PinnedModel.moveEntry(from, to); 0090 } 0091 } 0092 0093 function topDragEnter(drag) { 0094 if (transitionAnim.running || appDelegate.drag.active) return; // don't do anything when reordering 0095 0096 let fromIndex = drag.source.visualIndex; 0097 let delegateVisualIndex = appDelegate.visualIndex; 0098 let reorderIndex = -1; 0099 0100 if (fromIndex < delegateVisualIndex) { // dragged item from above 0101 // move to spot above 0102 reorderIndex = delegateVisualIndex - (root.twoColumn ? 2 : 1); 0103 } else { // dragged item from below 0104 // move to current spot 0105 reorderIndex = delegateVisualIndex; 0106 } 0107 0108 if (reorderIndex >= 0 && reorderIndex < root.count) { 0109 delegateRoot.moveDragToCurrentPos(fromIndex, reorderIndex) 0110 } 0111 } 0112 0113 function bottomDragEnter(drag) { 0114 if (transitionAnim.running || appDelegate.drag.active) return; // don't do anything when reordering 0115 0116 let fromIndex = drag.source.visualIndex; 0117 let delegateVisualIndex = appDelegate.visualIndex; 0118 let reorderIndex = -1; 0119 0120 if (fromIndex < delegateVisualIndex) { // dragged item from above 0121 // move to current spot 0122 reorderIndex = delegateVisualIndex; 0123 } else { // dragged item from below 0124 // move to spot below 0125 reorderIndex = delegateVisualIndex + (root.twoColumn ? 2 : 1); 0126 } 0127 0128 if (reorderIndex >= 0 && reorderIndex < root.count) { 0129 delegateRoot.moveDragToCurrentPos(fromIndex, reorderIndex); 0130 } 0131 } 0132 0133 // top drop area 0134 DropArea { 0135 id: topDropArea 0136 anchors.top: parent.top 0137 anchors.left: leftDropArea.right 0138 anchors.right: rightDropArea.left 0139 height: delegateRoot.height * 0.2 0140 onEntered: (drag) => delegateRoot.topDragEnter(drag) 0141 } 0142 0143 // bottom drop area 0144 DropArea { 0145 id: bottomDropArea 0146 anchors.bottom: parent.bottom 0147 anchors.left: leftDropArea.right 0148 anchors.right: rightDropArea.left 0149 height: delegateRoot.height * 0.2 0150 onEntered: (drag) => delegateRoot.bottomDragEnter(drag) 0151 } 0152 0153 // left drop area 0154 DropArea { 0155 id: leftDropArea 0156 anchors.bottom: parent.bottom 0157 anchors.top: parent.top 0158 anchors.left: parent.left 0159 width: root.twoColumn ? Math.max(appDelegate.leftPadding, delegateRoot.width * 0.1) : 0 0160 onEntered: (drag) => delegateRoot.topDragEnter(drag) 0161 } 0162 0163 // right drop area 0164 DropArea { 0165 id: rightDropArea 0166 anchors.bottom: parent.bottom 0167 anchors.top: parent.top 0168 anchors.right: parent.right 0169 width: root.twoColumn ? Math.max(appDelegate.rightPadding, delegateRoot.width * 0.1) : 0 0170 onEntered: (drag) => delegateRoot.bottomDragEnter(drag) 0171 } 0172 0173 // folder drop area 0174 DropArea { 0175 anchors.top: topDropArea.bottom 0176 anchors.bottom: bottomDropArea.top 0177 anchors.left: leftDropArea.right 0178 anchors.right: rightDropArea.left 0179 onEntered: (drag) => { 0180 if (transitionAnim.running || appDelegate.drag.active || drag.source.isFolder) return; // don't do anything when reordering 0181 folderAnim.to = 1; 0182 folderAnim.restart(); 0183 } 0184 onExited: () => { 0185 folderAnim.to = 0; 0186 folderAnim.restart(); 0187 } 0188 onDropped: (drop) => { 0189 if (transitionAnim.running || appDelegate.drag.active || drag.source.isFolder) return; // don't do anything when reordering 0190 if (appDelegate.isFolder) { 0191 Halcyon.PinnedModel.addAppToFolder(drop.source.visualIndex, appDelegate.visualIndex); 0192 } else { 0193 Halcyon.PinnedModel.createFolderFromApps(drop.source.visualIndex, appDelegate.visualIndex); 0194 } 0195 folderAnim.to = 0; 0196 folderAnim.restart(); 0197 } 0198 0199 NumberAnimation { 0200 id: folderAnim 0201 target: appDelegate 0202 properties: "dragFolderAnimationProgress" 0203 duration: 100 0204 } 0205 } 0206 0207 // actual visual delegate 0208 FavoritesAppDelegate { 0209 id: appDelegate 0210 visualIndex: delegateRoot.visualIndex 0211 0212 isFolder: model.isFolder 0213 folder: model.folder 0214 application: model.application 0215 0216 onFolderOpenRequested: root.requestOpenFolder(model.folder) 0217 0218 menuActions: [ 0219 Kirigami.Action { 0220 icon.name: "emblem-favorite" 0221 text: i18n("Remove from favourites") 0222 onTriggered: Halcyon.PinnedModel.removeEntry(model.index) 0223 } 0224 ] 0225 0226 implicitWidth: root.cellWidth 0227 implicitHeight: visible ? root.cellHeight : 0 0228 0229 anchors.horizontalCenter: parent.horizontalCenter 0230 anchors.verticalCenter: parent.verticalCenter 0231 0232 states: [ 0233 State { 0234 when: appDelegate.drag.active 0235 ParentChange { 0236 target: appDelegate 0237 parent: root 0238 } 0239 0240 AnchorChanges { 0241 target: appDelegate 0242 anchors.horizontalCenter: undefined 0243 anchors.verticalCenter: undefined 0244 } 0245 } 0246 ] 0247 } 0248 } 0249 } 0250 0251 // animations 0252 displaced: Transition { 0253 NumberAnimation { 0254 id: transitionAnim 0255 properties: "x,y" 0256 easing.type: Easing.OutQuad 0257 } 0258 } 0259 0260 ColumnLayout { 0261 id: placeholder 0262 spacing: Kirigami.Units.gridUnit 0263 visible: root.count == 0 0264 opacity: 0.9 0265 0266 anchors.fill: parent 0267 anchors.topMargin: Math.round(swipeView.height * 0.2) - (root.contentY - root.originY) 0268 anchors.leftMargin: root.leftMargin 0269 anchors.rightMargin: root.rightMargin 0270 0271 layer.enabled: true 0272 layer.effect: MobileShell.TextDropShadow {} 0273 0274 Kirigami.Icon { 0275 id: icon 0276 Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter 0277 implicitWidth: Kirigami.Units.iconSizes.large 0278 implicitHeight: width 0279 source: "arrow-left" 0280 color: "white" 0281 } 0282 0283 Kirigami.Heading { 0284 Layout.fillWidth: true 0285 Layout.maximumWidth: placeholder.width * 0.75 0286 Layout.alignment: Qt.AlignTop | Qt.AlignHCenter 0287 color: "white" 0288 level: 3 0289 wrapMode: Text.Wrap 0290 horizontalAlignment: Text.AlignHCenter 0291 text: i18n("Add applications to your favourites so they show up here.") 0292 } 0293 0294 TapHandler { 0295 onLongPressed: root.openConfigureRequested() 0296 } 0297 } 0298 }