mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-08-03 18:24:46 +00:00
homescreens/halcyon: Add initial folders implementation
This commit is contained in:
parent
1629733d7e
commit
564c3f9e81
7 changed files with 516 additions and 78 deletions
|
|
@ -54,6 +54,16 @@ void ApplicationFolder::setName(QString &name)
|
||||||
Q_EMIT saveRequested();
|
Q_EMIT saveRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Application *> ApplicationFolder::appPreviews()
|
||||||
|
{
|
||||||
|
QList<Application *> previews;
|
||||||
|
// we give a maximum of 4 icons
|
||||||
|
for (int i = 0; i < std::min(m_applications.length(), 4); ++i) {
|
||||||
|
previews.push_back(m_applications[i]);
|
||||||
|
}
|
||||||
|
return previews;
|
||||||
|
}
|
||||||
|
|
||||||
QList<Application *> ApplicationFolder::applications()
|
QList<Application *> ApplicationFolder::applications()
|
||||||
{
|
{
|
||||||
return m_applications;
|
return m_applications;
|
||||||
|
|
@ -66,6 +76,28 @@ void ApplicationFolder::setApplications(QList<Application *> applications)
|
||||||
Q_EMIT saveRequested();
|
Q_EMIT saveRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApplicationFolder::moveEntry(int fromRow, int toRow)
|
||||||
|
{
|
||||||
|
if (fromRow < 0 || toRow < 0 || fromRow >= m_applications.length() || toRow >= m_applications.length() || fromRow == toRow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (toRow > fromRow) {
|
||||||
|
++toRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toRow > fromRow) {
|
||||||
|
Application *app = m_applications.at(fromRow);
|
||||||
|
m_applications.insert(toRow, app);
|
||||||
|
m_applications.takeAt(fromRow);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Application *app = m_applications.takeAt(fromRow);
|
||||||
|
m_applications.insert(toRow, app);
|
||||||
|
}
|
||||||
|
Q_EMIT applicationsChanged();
|
||||||
|
Q_EMIT saveRequested();
|
||||||
|
}
|
||||||
|
|
||||||
void ApplicationFolder::addApp(const QString &storageId, int row)
|
void ApplicationFolder::addApp(const QString &storageId, int row)
|
||||||
{
|
{
|
||||||
if (row < 0 || row > m_applications.size()) {
|
if (row < 0 || row > m_applications.size()) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ class ApplicationFolder : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||||
|
Q_PROPERTY(QList<Application *> appPreviews READ appPreviews NOTIFY applicationsChanged)
|
||||||
Q_PROPERTY(QList<Application *> applications READ applications NOTIFY applicationsChanged)
|
Q_PROPERTY(QList<Application *> applications READ applications NOTIFY applicationsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -33,9 +34,12 @@ public:
|
||||||
QString name() const;
|
QString name() const;
|
||||||
void setName(QString &name);
|
void setName(QString &name);
|
||||||
|
|
||||||
|
QList<Application *> appPreviews();
|
||||||
|
|
||||||
QList<Application *> applications();
|
QList<Application *> applications();
|
||||||
void setApplications(QList<Application *> applications);
|
void setApplications(QList<Application *> applications);
|
||||||
|
|
||||||
|
Q_INVOKABLE void moveEntry(int fromRow, int toRow);
|
||||||
Q_INVOKABLE void addApp(const QString &storageId, int row);
|
Q_INVOKABLE void addApp(const QString &storageId, int row);
|
||||||
Q_INVOKABLE void removeApp(int row);
|
Q_INVOKABLE void removeApp(int row);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,58 +19,61 @@ import org.kde.kirigami 2.19 as Kirigami
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: delegate
|
id: delegate
|
||||||
|
|
||||||
property int visualIndex: 0
|
property int visualIndex: 0
|
||||||
|
|
||||||
property real leftPadding
|
property real leftPadding
|
||||||
property real rightPadding
|
property real rightPadding
|
||||||
|
|
||||||
property alias iconItem: icon
|
// whether this delegate is a folder
|
||||||
property var application
|
property bool isFolder
|
||||||
|
|
||||||
|
// folder object
|
||||||
|
property var folder
|
||||||
|
readonly property string folderName: folder ? folder.name : ""
|
||||||
|
|
||||||
|
// app object
|
||||||
|
property var application
|
||||||
readonly property string applicationName: application ? application.name : ""
|
readonly property string applicationName: application ? application.name : ""
|
||||||
readonly property string applicationStorageId: application ? application.storageId : ""
|
readonly property string applicationStorageId: application ? application.storageId : ""
|
||||||
readonly property string applicationIcon: application ? application.icon : ""
|
readonly property string applicationIcon: application ? application.icon : ""
|
||||||
|
|
||||||
signal launch(int x, int y, var source, string title, string storageId)
|
signal folderOpenRequested()
|
||||||
signal dragStarted(string imageSource, int x, int y, string mimeData)
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
onLaunch: {
|
|
||||||
if (icon !== "") {
|
|
||||||
MobileShell.HomeScreenControls.openAppLaunchAnimation(
|
|
||||||
icon,
|
|
||||||
title,
|
|
||||||
delegate.iconItem.Kirigami.ScenePosition.x + delegate.iconItem.width/2,
|
|
||||||
delegate.iconItem.Kirigami.ScenePosition.y + delegate.iconItem.height/2,
|
|
||||||
Math.min(delegate.iconItem.width, delegate.iconItem.height));
|
|
||||||
}
|
|
||||||
|
|
||||||
application.setMinimizedDelegate(delegate);
|
|
||||||
application.runApplication();
|
|
||||||
}
|
|
||||||
|
|
||||||
function openContextMenu() {
|
function openContextMenu() {
|
||||||
dialogLoader.active = true;
|
dialogLoader.active = true;
|
||||||
dialogLoader.item.open();
|
dialogLoader.item.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
function launchApp() {
|
function launch() {
|
||||||
if (application.running) {
|
if (isFolder) {
|
||||||
delegate.launch(0, 0, "", applicationName, applicationStorageId);
|
folderOpenRequested();
|
||||||
} else {
|
} else {
|
||||||
delegate.launch(delegate.x + (PlasmaCore.Units.smallSpacing * 2), delegate.y + (PlasmaCore.Units.smallSpacing * 2), icon.source, applicationName, applicationStorageId);
|
if (application.running) {
|
||||||
|
launchAppWithAnim(0, 0, "", applicationName, applicationStorageId);
|
||||||
|
} else {
|
||||||
|
launchAppWithAnim(delegate.x + (PlasmaCore.Units.smallSpacing * 2), delegate.y + (PlasmaCore.Units.smallSpacing * 2), iconLoader.source, applicationName, applicationStorageId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function launchAppWithAnim(x: int, y: int, source, title: string, storageId: string) {
|
||||||
|
if (source !== "") {
|
||||||
|
MobileShell.HomeScreenControls.openAppLaunchAnimation(
|
||||||
|
source,
|
||||||
|
title,
|
||||||
|
iconLoader.Kirigami.ScenePosition.x + iconLoader.width/2,
|
||||||
|
iconLoader.Kirigami.ScenePosition.y + iconLoader.height/2,
|
||||||
|
Math.min(iconLoader.width, iconLoader.height));
|
||||||
|
}
|
||||||
|
|
||||||
|
application.setMinimizedDelegate(delegate);
|
||||||
|
application.runApplication();
|
||||||
|
}
|
||||||
|
|
||||||
property bool inDrag: false
|
property bool inDrag: false
|
||||||
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
onClicked: (mouse.button === Qt.RightButton) ? openContextMenu() : launchApp();
|
onClicked: (mouse.button === Qt.RightButton) ? openContextMenu() : launch();
|
||||||
onReleased: {
|
onReleased: {
|
||||||
parent.Drag.drop();
|
parent.Drag.drop();
|
||||||
inDrag = false;
|
inDrag = false;
|
||||||
|
|
@ -131,37 +134,15 @@ MouseArea {
|
||||||
}
|
}
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
PlasmaCore.IconItem {
|
Loader {
|
||||||
id: icon
|
id: iconLoader
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignLeft
|
Layout.alignment: Qt.AlignLeft
|
||||||
Layout.minimumWidth: Layout.minimumHeight
|
Layout.minimumWidth: Layout.minimumHeight
|
||||||
Layout.preferredWidth: Layout.minimumHeight
|
Layout.preferredWidth: Layout.minimumHeight
|
||||||
Layout.minimumHeight: parent.height
|
Layout.minimumHeight: parent.height
|
||||||
Layout.preferredHeight: Layout.minimumHeight
|
Layout.preferredHeight: Layout.minimumHeight
|
||||||
|
|
||||||
usesPlasmaTheme: false
|
sourceComponent: delegate.isFolder ? folderIconComponent : appIconComponent
|
||||||
source: delegate.applicationIcon
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors {
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
bottom: parent.bottom
|
|
||||||
}
|
|
||||||
visible: application ? application.running : false
|
|
||||||
radius: width
|
|
||||||
width: PlasmaCore.Units.smallSpacing
|
|
||||||
height: width
|
|
||||||
color: PlasmaCore.Theme.highlightColor
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.enabled: true
|
|
||||||
layer.effect: DropShadow {
|
|
||||||
verticalOffset: 1
|
|
||||||
radius: 4
|
|
||||||
samples: 6
|
|
||||||
color: Qt.rgba(0, 0, 0, 0.5)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
PlasmaComponents.Label {
|
||||||
|
|
@ -175,7 +156,7 @@ MouseArea {
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
|
||||||
text: delegate.applicationName
|
text: delegate.isFolder ? delegate.folderName : delegate.applicationName
|
||||||
|
|
||||||
font.pointSize: PlasmaCore.Theme.defaultFont.pointSize
|
font.pointSize: PlasmaCore.Theme.defaultFont.pointSize
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
|
|
@ -189,6 +170,96 @@ MouseArea {
|
||||||
color: Qt.rgba(0, 0, 0, 0.5)
|
color: Qt.rgba(0, 0, 0, 0.5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kirigami.Icon {
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.minimumWidth: Layout.minimumHeight
|
||||||
|
Layout.preferredWidth: Layout.minimumHeight
|
||||||
|
Layout.minimumHeight: Math.round(parent.height * 0.5)
|
||||||
|
Layout.preferredHeight: Layout.minimumHeight
|
||||||
|
|
||||||
|
isMask: true
|
||||||
|
color: 'white'
|
||||||
|
source: 'arrow-right'
|
||||||
|
visible: delegate.isFolder
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: DropShadow {
|
||||||
|
verticalOffset: 1
|
||||||
|
radius: 4
|
||||||
|
samples: 6
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: appIconComponent
|
||||||
|
|
||||||
|
PlasmaCore.IconItem {
|
||||||
|
usesPlasmaTheme: false
|
||||||
|
source: delegate.isFolder ? 'document-open-folder' : delegate.applicationIcon
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
visible: application ? application.running : false
|
||||||
|
radius: width
|
||||||
|
width: PlasmaCore.Units.smallSpacing
|
||||||
|
height: width
|
||||||
|
color: PlasmaCore.Theme.highlightColor
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: DropShadow {
|
||||||
|
verticalOffset: 1
|
||||||
|
radius: 4
|
||||||
|
samples: 6
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: folderIconComponent
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: PlasmaCore.Units.smallSpacing
|
||||||
|
color: Qt.rgba(255, 255, 255, 0.2)
|
||||||
|
radius: PlasmaCore.Units.smallSpacing
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
id: grid
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: PlasmaCore.Units.smallSpacing
|
||||||
|
columns: 2
|
||||||
|
spacing: PlasmaCore.Units.smallSpacing
|
||||||
|
|
||||||
|
property var previews: model.folder.appPreviews
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: grid.previews
|
||||||
|
delegate: Kirigami.Icon {
|
||||||
|
implicitWidth: (grid.width - PlasmaCore.Units.smallSpacing) / 2
|
||||||
|
implicitHeight: (grid.width - PlasmaCore.Units.smallSpacing) / 2
|
||||||
|
source: modelData.icon
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: DropShadow {
|
||||||
|
verticalOffset: 1
|
||||||
|
radius: 4
|
||||||
|
samples: 3
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,20 +18,15 @@ import org.kde.phone.homescreen.halcyon 1.0 as Halcyon
|
||||||
|
|
||||||
GridView {
|
GridView {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property var searchWidget
|
required property var searchWidget
|
||||||
|
|
||||||
signal openConfigureRequested()
|
signal openConfigureRequested()
|
||||||
|
signal requestOpenFolder(Halcyon.ApplicationFolder folder)
|
||||||
readonly property real twoColumnThreshold: PlasmaCore.Units.gridUnit * 10
|
|
||||||
readonly property bool twoColumn: root.width / 2 > twoColumnThreshold
|
|
||||||
|
|
||||||
cellWidth: twoColumn ? root.width / 2 : root.width
|
|
||||||
cellHeight: delegateHeight
|
|
||||||
|
|
||||||
// don't set anchors.margins since we want everywhere to be draggable
|
// don't set anchors.margins since we want everywhere to be draggable
|
||||||
readonly property real leftMargin: Math.round(parent.width * 0.1)
|
required property real leftMargin
|
||||||
readonly property real rightMargin: Math.round(parent.width * 0.1)
|
required property real rightMargin
|
||||||
readonly property real delegateHeight: PlasmaCore.Units.gridUnit * 3
|
required property bool twoColumn
|
||||||
|
|
||||||
// search widget open gesture
|
// search widget open gesture
|
||||||
property bool openingSearchWidget: false
|
property bool openingSearchWidget: false
|
||||||
|
|
@ -63,7 +58,7 @@ GridView {
|
||||||
}
|
}
|
||||||
|
|
||||||
header: MobileShell.BaseItem {
|
header: MobileShell.BaseItem {
|
||||||
topPadding: Math.round(swipeView.height * 0.2)
|
topPadding: Math.round(root.height * 0.2)
|
||||||
bottomPadding: PlasmaCore.Units.largeSpacing
|
bottomPadding: PlasmaCore.Units.largeSpacing
|
||||||
leftPadding: root.leftMargin
|
leftPadding: root.leftMargin
|
||||||
rightPadding: root.rightMargin
|
rightPadding: root.rightMargin
|
||||||
|
|
@ -82,8 +77,6 @@ GridView {
|
||||||
|
|
||||||
delegate: DropArea {
|
delegate: DropArea {
|
||||||
id: delegateRoot
|
id: delegateRoot
|
||||||
property var application: model.application
|
|
||||||
|
|
||||||
property int modelIndex
|
property int modelIndex
|
||||||
property int visualIndex: DelegateModel.itemsIndex
|
property int visualIndex: DelegateModel.itemsIndex
|
||||||
|
|
||||||
|
|
@ -106,12 +99,12 @@ GridView {
|
||||||
FavoritesAppDelegate {
|
FavoritesAppDelegate {
|
||||||
id: appDelegate
|
id: appDelegate
|
||||||
visualIndex: delegateRoot.visualIndex
|
visualIndex: delegateRoot.visualIndex
|
||||||
application: delegateRoot.application
|
|
||||||
|
|
||||||
anchors {
|
isFolder: model.isFolder
|
||||||
horizontalCenter: parent.horizontalCenter
|
folder: model.folder
|
||||||
verticalCenter: parent.verticalCenter
|
application: model.application
|
||||||
}
|
|
||||||
|
onFolderOpenRequested: root.requestOpenFolder(model.folder)
|
||||||
|
|
||||||
readonly property bool isLeftColumn: !root.twoColumn || ((visualIndex % 2) === 0)
|
readonly property bool isLeftColumn: !root.twoColumn || ((visualIndex % 2) === 0)
|
||||||
readonly property bool isRightColumn: !root.twoColumn || ((visualIndex % 2) !== 0)
|
readonly property bool isRightColumn: !root.twoColumn || ((visualIndex % 2) !== 0)
|
||||||
|
|
@ -121,6 +114,9 @@ GridView {
|
||||||
implicitWidth: root.cellWidth
|
implicitWidth: root.cellWidth
|
||||||
implicitHeight: visible ? root.cellHeight : 0
|
implicitHeight: visible ? root.cellHeight : 0
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
when: appDelegate.drag.active
|
when: appDelegate.drag.active
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
|
||||||
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Controls 2.15 as QQC2
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQml.Models 2.15
|
||||||
|
|
||||||
|
import org.kde.plasma.plasmoid 2.0
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||||
|
import org.kde.plasma.components 3.0 as PC3
|
||||||
|
import org.kde.draganddrop 2.0 as DragDrop
|
||||||
|
|
||||||
|
import org.kde.kirigami 2.19 as Kirigami
|
||||||
|
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||||
|
import org.kde.phone.homescreen.halcyon 1.0 as Halcyon
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property bool interactive
|
||||||
|
required property var searchWidget
|
||||||
|
|
||||||
|
readonly property real twoColumnThreshold: PlasmaCore.Units.gridUnit * 10
|
||||||
|
readonly property bool twoColumn: root.width / 2 > twoColumnThreshold
|
||||||
|
|
||||||
|
readonly property real cellWidth: twoColumn ? root.width / 2 : root.width
|
||||||
|
readonly property real cellHeight: delegateHeight
|
||||||
|
|
||||||
|
readonly property real leftMargin: Math.round(parent.width * 0.1)
|
||||||
|
readonly property real rightMargin: Math.round(parent.width * 0.1)
|
||||||
|
readonly property real delegateHeight: PlasmaCore.Units.gridUnit * 3
|
||||||
|
|
||||||
|
property bool folderShown: false
|
||||||
|
onFolderShownChanged: folderShown ? openFolderAnim.restart() : closeFolderAnim.restart()
|
||||||
|
|
||||||
|
signal openConfigureRequested()
|
||||||
|
|
||||||
|
FavoritesGrid {
|
||||||
|
id: favoritesGrid
|
||||||
|
anchors.fill: parent
|
||||||
|
interactive: root.interactive
|
||||||
|
searchWidget: root.searchWidget
|
||||||
|
|
||||||
|
cellWidth: root.cellWidth
|
||||||
|
cellHeight: root.cellHeight
|
||||||
|
|
||||||
|
leftMargin: root.leftMargin
|
||||||
|
rightMargin: root.rightMargin
|
||||||
|
twoColumn: root.twoColumn
|
||||||
|
|
||||||
|
onOpenConfigureRequested: root.openConfigureRequested()
|
||||||
|
onRequestOpenFolder: (folder) => {
|
||||||
|
folderGrid.folder = folder;
|
||||||
|
root.folderShown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
property real translateX: 0
|
||||||
|
transform: Translate { x: favoritesGrid.translateX }
|
||||||
|
visible: opacity !== 0
|
||||||
|
}
|
||||||
|
|
||||||
|
FolderGrid {
|
||||||
|
id: folderGrid
|
||||||
|
anchors.fill: parent
|
||||||
|
folder: null
|
||||||
|
|
||||||
|
interactive: root.interactive
|
||||||
|
|
||||||
|
cellWidth: root.cellWidth
|
||||||
|
cellHeight: root.cellHeight
|
||||||
|
|
||||||
|
leftMargin: root.leftMargin
|
||||||
|
rightMargin: root.rightMargin
|
||||||
|
twoColumn: root.twoColumn
|
||||||
|
|
||||||
|
onOpenConfigureRequested: root.openConfigureRequested()
|
||||||
|
onCloseRequested: root.folderShown = false
|
||||||
|
|
||||||
|
property real translateX: 0
|
||||||
|
transform: Translate { x: folderGrid.translateX }
|
||||||
|
opacity: 0
|
||||||
|
visible: opacity !== 0
|
||||||
|
}
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: openFolderAnim
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
target: favoritesGrid
|
||||||
|
properties: 'translateX'
|
||||||
|
duration: 200
|
||||||
|
from: 0
|
||||||
|
to: -PlasmaCore.Units.gridUnit
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: favoritesGrid
|
||||||
|
properties: 'opacity'
|
||||||
|
duration: 200
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
target: folderGrid
|
||||||
|
properties: 'translateX'
|
||||||
|
duration: 200
|
||||||
|
from: PlasmaCore.Units.gridUnit
|
||||||
|
to: 0
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: folderGrid
|
||||||
|
properties: 'opacity'
|
||||||
|
duration: 200
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: closeFolderAnim
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
target: folderGrid
|
||||||
|
properties: 'translateX'
|
||||||
|
duration: 200
|
||||||
|
from: 0
|
||||||
|
to: PlasmaCore.Units.gridUnit
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: folderGrid
|
||||||
|
properties: 'opacity'
|
||||||
|
duration: 200
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
target: favoritesGrid
|
||||||
|
properties: 'translateX'
|
||||||
|
duration: 200
|
||||||
|
from: -PlasmaCore.Units.gridUnit
|
||||||
|
to: 0
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
target: favoritesGrid
|
||||||
|
properties: 'opacity'
|
||||||
|
duration: 200
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,168 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
|
||||||
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Controls 2.15 as QQC2
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQml.Models 2.15
|
||||||
|
import QtGraphicalEffects 1.12
|
||||||
|
|
||||||
|
import org.kde.plasma.plasmoid 2.0
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||||
|
import org.kde.plasma.components 3.0 as PC3
|
||||||
|
import org.kde.draganddrop 2.0 as DragDrop
|
||||||
|
|
||||||
|
import org.kde.kirigami 2.19 as Kirigami
|
||||||
|
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||||
|
import org.kde.phone.homescreen.halcyon 1.0 as Halcyon
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
id: root
|
||||||
|
property Halcyon.ApplicationFolder folder: null
|
||||||
|
|
||||||
|
property string folderName: folder ? folder.name : ""
|
||||||
|
property var folderModel: folder ? folder.applications : []
|
||||||
|
|
||||||
|
// don't set anchors.margins since we want everywhere to be draggable
|
||||||
|
required property real leftMargin
|
||||||
|
required property real rightMargin
|
||||||
|
required property bool twoColumn
|
||||||
|
|
||||||
|
signal openConfigureRequested()
|
||||||
|
signal closeRequested()
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onLongPressed: root.openConfigureRequested()
|
||||||
|
onTapped: root.closeRequested()
|
||||||
|
}
|
||||||
|
|
||||||
|
header: MobileShell.BaseItem {
|
||||||
|
topPadding: Math.round(root.height * 0.2)
|
||||||
|
bottomPadding: PlasmaCore.Units.largeSpacing
|
||||||
|
leftPadding: root.leftMargin
|
||||||
|
rightPadding: root.rightMargin
|
||||||
|
implicitWidth: root.width
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: 'transparent'
|
||||||
|
TapHandler {
|
||||||
|
onLongPressed: root.openConfigureRequested()
|
||||||
|
onTapped: root.closeRequested()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contentItem: RowLayout {
|
||||||
|
spacing: PlasmaCore.Units.gridUnit
|
||||||
|
Kirigami.Icon {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.preferredHeight: PlasmaCore.Units.iconSizes.small
|
||||||
|
Layout.preferredWidth: PlasmaCore.Units.iconSizes.small
|
||||||
|
isMask: true
|
||||||
|
color: 'white'
|
||||||
|
source: 'arrow-left'
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: DropShadow {
|
||||||
|
verticalOffset: 1
|
||||||
|
radius: 4
|
||||||
|
samples: 6
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QQC2.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: root.folderName
|
||||||
|
color: "white"
|
||||||
|
style: Text.Normal
|
||||||
|
styleColor: "transparent"
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
|
||||||
|
elide: Text.ElideRight
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
maximumLineCount: 2
|
||||||
|
|
||||||
|
font.weight: Font.Bold
|
||||||
|
font.pointSize: 18
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: DropShadow {
|
||||||
|
verticalOffset: 1
|
||||||
|
radius: 4
|
||||||
|
samples: 6
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: DelegateModel {
|
||||||
|
id: visualModel
|
||||||
|
model: root.folderModel
|
||||||
|
|
||||||
|
delegate: DropArea {
|
||||||
|
id: delegateRoot
|
||||||
|
property var application: model.application
|
||||||
|
|
||||||
|
property int modelIndex
|
||||||
|
property int visualIndex: DelegateModel.itemsIndex
|
||||||
|
|
||||||
|
width: root.cellWidth
|
||||||
|
height: root.cellHeight
|
||||||
|
|
||||||
|
onEntered: (drag) => {
|
||||||
|
let from = (drag.source as MobileShell.BaseItem).visualIndex;
|
||||||
|
let to = appDelegate.visualIndex;
|
||||||
|
visualModel.items.move(from, to);
|
||||||
|
root.folder.moveEntry(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
//onDropped: (drag) => {
|
||||||
|
//let from = modelIndex;
|
||||||
|
//let to = (drag.source as MobileShell.BaseItem).visualIndex
|
||||||
|
//Halcyon.PinnedModel.moveEntry(from, to);
|
||||||
|
//}
|
||||||
|
|
||||||
|
FavoritesAppDelegate {
|
||||||
|
id: appDelegate
|
||||||
|
visualIndex: delegateRoot.visualIndex
|
||||||
|
|
||||||
|
isFolder: false
|
||||||
|
application: modelData
|
||||||
|
|
||||||
|
readonly property bool isLeftColumn: !root.twoColumn || ((visualIndex % 2) === 0)
|
||||||
|
readonly property bool isRightColumn: !root.twoColumn || ((visualIndex % 2) !== 0)
|
||||||
|
leftPadding: isLeftColumn ? root.leftMargin : 0
|
||||||
|
rightPadding: isRightColumn ? root.rightMargin : 0
|
||||||
|
|
||||||
|
implicitWidth: root.cellWidth
|
||||||
|
implicitHeight: visible ? root.cellHeight : 0
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
when: appDelegate.drag.active
|
||||||
|
ParentChange {
|
||||||
|
target: appDelegate
|
||||||
|
parent: root
|
||||||
|
}
|
||||||
|
|
||||||
|
AnchorChanges {
|
||||||
|
target: appDelegate
|
||||||
|
anchors.horizontalCenter: undefined
|
||||||
|
anchors.verticalCenter: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// animations
|
||||||
|
displaced: Transition {
|
||||||
|
NumberAnimation {
|
||||||
|
properties: "x,y"
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,11 +25,9 @@ Item {
|
||||||
|
|
||||||
function triggerHomescreen() {
|
function triggerHomescreen() {
|
||||||
swipeView.setCurrentIndex(0);
|
swipeView.setCurrentIndex(0);
|
||||||
favouritesList.contentY = favouritesList.originY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function openConfigure() {
|
function openConfigure() {
|
||||||
console.log('triggered')
|
|
||||||
plasmoid.action("configure").trigger();
|
plasmoid.action("configure").trigger();
|
||||||
plasmoid.editMode = false;
|
plasmoid.editMode = false;
|
||||||
}
|
}
|
||||||
|
|
@ -54,11 +52,10 @@ Item {
|
||||||
onLongPressed: root.openConfigure()
|
onLongPressed: root.openConfigure()
|
||||||
}
|
}
|
||||||
|
|
||||||
FavoritesGrid {
|
FavoritesView {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
searchWidget: root.searchWidget
|
searchWidget: root.searchWidget
|
||||||
interactive: root.interactive
|
interactive: root.interactive
|
||||||
|
|
||||||
onOpenConfigureRequested: root.openConfigure()
|
onOpenConfigureRequested: root.openConfigure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue