Warning, /plasma/plasma-mobile/containments/homescreens/halcyon/package/contents/ui/FavoritesAppDelegate.qml is written in an unsupported language. File is not indexed.

0001 // SPDX-FileCopyrightText: 2022 Devin Lin <espidev@gmail.com>
0002 // SPDX-License-Identifier: GPL-2.0-or-later
0003 
0004 import QtQuick
0005 import QtQuick.Layouts
0006 import QtQuick.Controls as Controls
0007 import QtQuick.Effects
0008 
0009 import org.kde.plasma.core as PlasmaCore
0010 import org.kde.plasma.components 3.0 as PlasmaComponents
0011 import org.kde.kquickcontrolsaddons 2.0
0012 
0013 import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager 
0014 import org.kde.plasma.private.mobileshell as MobileShell
0015 import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
0016 import org.kde.plasma.private.mobileshell.state as MobileShellState
0017 
0018 import org.kde.kirigami 2.19 as Kirigami
0019 
0020 Item {
0021     id: delegate
0022 
0023     property int visualIndex: 0
0024     property real dragFolderAnimationProgress: 0
0025     
0026     property list<Kirigami.Action> menuActions
0027     
0028     // whether this delegate is a folder
0029     property bool isFolder
0030     
0031     // folder object
0032     property var folder
0033     readonly property string folderName: folder ? folder.name : ""
0034     
0035     // app object
0036     property var application
0037     readonly property string applicationName: application ? application.name : ""
0038     readonly property string applicationStorageId: application ? application.storageId : ""
0039     readonly property string applicationIcon: application ? application.icon : ""
0040     
0041     signal folderOpenRequested()
0042     
0043     property alias drag: mouseArea.drag
0044     Drag.active: delegate.drag.active
0045     Drag.source: delegate
0046     Drag.hotSpot.x: delegate.width / 2
0047     Drag.hotSpot.y: delegate.height / 2
0048     
0049     // close context menu if drag move
0050     onXChanged: {
0051         if (dialogLoader.item) {
0052             dialogLoader.item.close()
0053         }
0054     }
0055     onYChanged: {
0056         if (dialogLoader.item) {
0057             dialogLoader.item.close()
0058         }
0059     }
0060     
0061     function openContextMenu() {
0062         dialogLoader.active = true;
0063         dialogLoader.item.open();
0064     }
0065     
0066     function launch() {
0067         if (isFolder) {
0068             folderOpenRequested();
0069         } else {
0070             if (application.running) {
0071                 launchAppWithAnim(0, 0, "", applicationName, applicationStorageId);
0072             } else {
0073                 launchAppWithAnim(delegate.x + (Kirigami.Units.smallSpacing * 2), delegate.y + (Kirigami.Units.smallSpacing * 2), delegate.applicationIcon, applicationName, applicationStorageId);
0074             }
0075         }
0076     }
0077     
0078     function launchAppWithAnim(x: int, y: int, source, title: string, storageId: string) {
0079          if (source !== "") {
0080             MobileShellState.ShellDBusClient.openAppLaunchAnimation(
0081                     source,
0082                     title,
0083                     iconLoader.Kirigami.ScenePosition.x + iconLoader.width/2,
0084                     iconLoader.Kirigami.ScenePosition.y + iconLoader.height/2,
0085                     Math.min(iconLoader.width, iconLoader.height));
0086         }
0087 
0088         application.setMinimizedDelegate(delegate);
0089         MobileShell.AppLaunch.launchOrActivateApp(application.storageId);
0090     }
0091     
0092     Loader {
0093         id: dialogLoader
0094         active: false
0095         
0096         sourceComponent: PlasmaComponents.Menu {
0097             id: menu
0098             title: label.text
0099             closePolicy: PlasmaComponents.Menu.CloseOnReleaseOutside | PlasmaComponents.Menu.CloseOnEscape
0100             
0101             Repeater {
0102                 model: menuActions
0103                 delegate: PlasmaComponents.MenuItem {
0104                     icon.name: modelData.iconName
0105                     text: modelData.text
0106                     onClicked: modelData.triggered()
0107                 }
0108             }
0109             
0110             onClosed: dialogLoader.active = false
0111         }
0112     }
0113     
0114     MouseArea {
0115         id: mouseArea
0116         
0117         anchors.fill: parent
0118         
0119         property bool inDrag: false
0120     
0121         cursorShape: Qt.PointingHandCursor
0122         acceptedButtons: Qt.LeftButton | Qt.RightButton
0123         onReleased: {
0124             delegate.Drag.drop();
0125             inDrag = false;
0126         }
0127         onPressAndHold: { inDrag = true; openContextMenu() }
0128         drag.target: inDrag ? delegate : undefined
0129         
0130         // grow/shrink animation
0131         property real zoomScale: 1
0132         transform: Scale {
0133             origin.x: mouseArea.width / 2; 
0134             origin.y: mouseArea.height / 2; 
0135             xScale: mouseArea.zoomScale
0136             yScale: mouseArea.zoomScale
0137         }
0138         
0139         property bool launchAppRequested: false
0140         
0141         NumberAnimation on zoomScale {
0142             id: shrinkAnim
0143             running: false
0144             duration: ShellSettings.Settings.animationsEnabled ? 80 : 1
0145             to: ShellSettings.Settings.animationsEnabled ? 0.95 : 1
0146             onFinished: {
0147                 if (!mouseArea.pressed) {
0148                     growAnim.restart();
0149                 }
0150             }
0151         }
0152         
0153         NumberAnimation on zoomScale {
0154             id: growAnim
0155             running: false
0156             duration: ShellSettings.Settings.animationsEnabled ? 80 : 1
0157             to: 1
0158             onFinished: {
0159                 if (mouseArea.launchAppRequested) {
0160                     delegate.launch();
0161                     mouseArea.launchAppRequested = false;
0162                 }
0163             }
0164         }
0165         
0166         onPressedChanged: {
0167             if (pressed) {
0168                 growAnim.stop();
0169                 shrinkAnim.restart();
0170             } else if (!pressed && !shrinkAnim.running) {
0171                 growAnim.restart();
0172             }
0173         }
0174         
0175         // launch app handled by press animation
0176         onClicked: mouse => {
0177             if (mouse.button === Qt.RightButton) {
0178                 openContextMenu();
0179             } else {
0180                 launchAppRequested = true;
0181             }
0182         }
0183         
0184         HoverHandler {
0185             id: hoverHandler
0186             acceptedDevices: PointerDevice.Mouse
0187             acceptedPointerTypes: PointerDevice.Generic
0188         }
0189         
0190         Rectangle {
0191             anchors.fill: parent
0192             radius: height / 2        
0193             color: mouseArea.pressed ? Qt.rgba(255, 255, 255, 0.2) : "transparent"
0194         }
0195         
0196         RowLayout {
0197             id: rowLayout
0198             anchors {
0199                 fill: parent
0200                 leftMargin: Kirigami.Units.smallSpacing * 2
0201                 topMargin: Kirigami.Units.smallSpacing
0202                 rightMargin: Kirigami.Units.smallSpacing * 2
0203                 bottomMargin: Kirigami.Units.smallSpacing
0204             }
0205             spacing: 0
0206 
0207             Loader {
0208                 id: iconLoader
0209                 Layout.alignment: Qt.AlignLeft
0210                 Layout.minimumWidth: Layout.minimumHeight
0211                 Layout.preferredWidth: Layout.minimumHeight
0212                 Layout.minimumHeight: parent.height
0213                 Layout.preferredHeight: Layout.minimumHeight
0214 
0215                 sourceComponent: delegate.isFolder ? folderIconComponent : appIconComponent
0216             }
0217 
0218             PlasmaComponents.Label {
0219                 id: label
0220                 visible: text.length > 0
0221                 textFormat: Text.MarkdownText
0222 
0223                 Layout.fillWidth: true
0224                 Layout.leftMargin: Kirigami.Units.smallSpacing * 2
0225                 Layout.rightMargin: Kirigami.Units.gridUnit
0226                 wrapMode: Text.WordWrap
0227                 maximumLineCount: 1
0228                 elide: Text.ElideRight
0229 
0230                 text: delegate.isFolder ? delegate.folderName : delegate.applicationName
0231 
0232                 font.pointSize: Kirigami.Theme.defaultFont.pointSize
0233                 font.weight: Font.Bold
0234                 color: "white"
0235                 
0236                 layer.enabled: true
0237                 layer.effect: MobileShell.TextDropShadow {}
0238             }
0239             
0240             Kirigami.Icon {
0241                 Layout.alignment: Qt.AlignRight
0242                 Layout.preferredWidth: Kirigami.Units.iconSizes.small
0243                 Layout.preferredHeight: Kirigami.Units.iconSizes.small
0244 
0245                 isMask: true
0246                 color: 'white'
0247                 source: 'arrow-right'
0248                 visible: delegate.isFolder
0249 
0250                 layer.enabled: true
0251                 layer.effect: MultiEffect {
0252                     shadowEnabled: true
0253                     shadowVerticalOffset: 1
0254                     blurMax: 8
0255                     shadowOpacity: 0.7
0256                 }
0257             }
0258         }
0259     }
0260     
0261     Component {
0262         id: appIconComponent
0263         
0264         Item {
0265             Rectangle {
0266                 anchors.fill: parent
0267                 anchors.margins: Kirigami.Units.smallSpacing
0268                 color: Qt.rgba(255, 255, 255, 0.2)
0269                 radius: Kirigami.Units.smallSpacing
0270                 opacity: delegate.dragFolderAnimationProgress
0271             }
0272             
0273             Kirigami.Icon {
0274                 id: icon
0275                 anchors.fill: parent
0276                 source: delegate.isFolder ? 'document-open-folder' : delegate.applicationIcon
0277                 
0278                 transform: Scale { 
0279                     origin.x: icon.width / 2 
0280                     origin.y: icon.height / 2
0281                     xScale: 1 - delegate.dragFolderAnimationProgress * 0.5
0282                     yScale: 1 - delegate.dragFolderAnimationProgress * 0.5
0283                 }
0284 
0285                 Rectangle {
0286                     anchors {
0287                         horizontalCenter: parent.horizontalCenter
0288                         bottom: parent.bottom
0289                     }
0290                     visible: application ? application.running : false
0291                     radius: width
0292                     width: Kirigami.Units.smallSpacing
0293                     height: width
0294                     color: Kirigami.Theme.highlightColor
0295                 }
0296                 
0297                 layer.enabled: true
0298                 layer.effect: MultiEffect {
0299                     shadowEnabled: true
0300                     shadowVerticalOffset: 1
0301                     blurMax: 16
0302                     shadowOpacity: 0.5
0303                 }
0304             }
0305         }
0306     }
0307     
0308     Component {
0309         id: folderIconComponent
0310         
0311         Item {
0312             Rectangle {
0313                 id: rect
0314                 anchors.fill: parent
0315                 anchors.margins: Kirigami.Units.smallSpacing
0316                 color: Qt.rgba(255, 255, 255, 0.2)
0317                 radius: Kirigami.Units.smallSpacing
0318                 
0319                 transform: Scale { 
0320                     origin.x: rect.width / 2 
0321                     origin.y: rect.height / 2
0322                     xScale: 1 + delegate.dragFolderAnimationProgress * 0.5
0323                     yScale: 1 + delegate.dragFolderAnimationProgress * 0.5
0324                 }
0325             }
0326             
0327             Grid {
0328                 id: grid
0329                 anchors.fill: parent
0330                 anchors.margins: Kirigami.Units.smallSpacing * 2
0331                 columns: 2
0332                 spacing: Kirigami.Units.smallSpacing
0333                 
0334                 property var previews: model.folder.appPreviews
0335                 
0336                 Repeater {
0337                     model: grid.previews
0338                     delegate: Kirigami.Icon {
0339                         implicitWidth: (grid.width - Kirigami.Units.smallSpacing) / 2
0340                         implicitHeight: (grid.width - Kirigami.Units.smallSpacing) / 2
0341                         source: modelData.icon
0342                         
0343                         layer.enabled: true
0344                         layer.effect: MultiEffect {
0345                             shadowEnabled: true
0346                             shadowVerticalOffset: 1
0347                             blurMax: 16
0348                             shadowOpacity: 0.6
0349                         }
0350                     }
0351                 }
0352             }
0353         }
0354     }
0355 }
0356 
0357 
0358