Commit b7f1a5b3 authored by Devin Lin's avatar Devin Lin 🎨
Browse files

homescreens/halcyon: Add drag and drop reordering of favourites

parent 6a0fcc83
Pipeline #196869 passed with stage
in 1 minute and 6 seconds
......@@ -19,6 +19,11 @@ QQC2.AbstractButton {
*/
property alias cursorShape: hoverHandler.cursorShape
/**
* Alias to MouseArea used in the button.
*/
property alias mouseArea: mouseArea
/**
* Whether a mouse is hovering over the button (not touch).
*/
......
......@@ -17,11 +17,16 @@ import org.kde.phone.homescreen.halcyon 1.0 as Halcyon
import org.kde.kirigami 2.19 as Kirigami
MobileShell.ExtendedAbstractButton {
MouseArea {
id: delegate
property int visualIndex: 0
property real leftPadding
property real rightPadding
property alias iconItem: icon
property Halcyon.Application application: model.application
property var application
readonly property string applicationName: application ? application.name : ""
readonly property string applicationStorageId: application ? application.storageId : ""
......@@ -30,6 +35,11 @@ MobileShell.ExtendedAbstractButton {
signal launch(int x, int y, var source, string title, string storageId)
signal dragStarted(string imageSource, int x, int y, string mimeData)
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
onLaunch: {
if (icon !== "") {
MobileShell.HomeScreenControls.openAppLaunchAnimation(
......@@ -57,9 +67,27 @@ MobileShell.ExtendedAbstractButton {
}
}
onRightClickPressed: openContextMenu()
onClicked: launchApp();
onPressAndHold: openContextMenu()
property bool inDrag: false
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: (mouse.button === Qt.RightButton) ? openContextMenu() : launchApp();
onReleased: {
parent.Drag.drop();
inDrag = false;
}
onPressAndHold: { inDrag = true; openContextMenu() }
drag.target: inDrag ? delegate : undefined
Drag.active: delegate.drag.active
Drag.source: delegate
Drag.hotSpot.x: delegate.width / 2
Drag.hotSpot.y: delegate.height / 2
HoverHandler {
id: hoverHandler
acceptedDevices: PointerDevice.Mouse
acceptedPointerTypes: PointerDevice.GenericPointer
}
Loader {
id: dialogLoader
......@@ -80,79 +108,86 @@ MobileShell.ExtendedAbstractButton {
}
}
Rectangle {
Item {
id: baseItem
anchors.fill: parent
radius: height / 2
color: delegate.pressed ? Qt.rgba(255, 255, 255, 0.2) : (delegate.mouseHovered ? Qt.rgba(255, 255, 255, 0.1) : "transparent")
}
RowLayout {
id: rowLayout
anchors {
fill: parent
leftMargin: PlasmaCore.Units.smallSpacing * 2
topMargin: PlasmaCore.Units.smallSpacing
rightMargin: PlasmaCore.Units.smallSpacing * 2
bottomMargin: PlasmaCore.Units.smallSpacing
Rectangle {
anchors.fill: parent
anchors.leftMargin: delegate.leftPadding
anchors.rightMargin: delegate.rightPadding
radius: height / 2
color: delegate.pressed ? Qt.rgba(255, 255, 255, 0.2) : (hoverHandler.hovered ? Qt.rgba(255, 255, 255, 0.1) : "transparent")
}
spacing: 0
PlasmaCore.IconItem {
id: icon
Layout.alignment: Qt.AlignLeft
Layout.minimumWidth: Layout.minimumHeight
Layout.preferredWidth: Layout.minimumHeight
Layout.minimumHeight: parent.height
Layout.preferredHeight: Layout.minimumHeight
usesPlasmaTheme: false
source: 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
RowLayout {
id: rowLayout
anchors {
fill: parent
leftMargin: PlasmaCore.Units.smallSpacing * 2 + delegate.leftPadding
topMargin: PlasmaCore.Units.smallSpacing
rightMargin: PlasmaCore.Units.smallSpacing * 2 + delegate.rightPadding
bottomMargin: PlasmaCore.Units.smallSpacing
}
layer.enabled: true
layer.effect: DropShadow {
verticalOffset: 1
radius: 4
samples: 6
color: Qt.rgba(0, 0, 0, 0.5)
spacing: 0
PlasmaCore.IconItem {
id: icon
Layout.alignment: Qt.AlignLeft
Layout.minimumWidth: Layout.minimumHeight
Layout.preferredWidth: Layout.minimumHeight
Layout.minimumHeight: parent.height
Layout.preferredHeight: Layout.minimumHeight
usesPlasmaTheme: false
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 {
id: label
visible: text.length > 0
Layout.fillWidth: true
Layout.leftMargin: PlasmaCore.Units.smallSpacing * 2
Layout.rightMargin: PlasmaCore.Units.largeSpacing
wrapMode: Text.WordWrap
maximumLineCount: 1
elide: Text.ElideRight
text: applicationName
font.pointSize: PlasmaCore.Theme.defaultFont.pointSize
font.weight: Font.Bold
color: "white"
layer.enabled: true
layer.effect: DropShadow {
verticalOffset: 1
radius: 4
samples: 6
color: Qt.rgba(0, 0, 0, 0.5)
PlasmaComponents.Label {
id: label
visible: text.length > 0
Layout.fillWidth: true
Layout.leftMargin: PlasmaCore.Units.smallSpacing * 2
Layout.rightMargin: PlasmaCore.Units.largeSpacing
wrapMode: Text.WordWrap
maximumLineCount: 1
elide: Text.ElideRight
text: delegate.applicationName
font.pointSize: PlasmaCore.Theme.defaultFont.pointSize
font.weight: Font.Bold
color: "white"
layer.enabled: true
layer.effect: DropShadow {
verticalOffset: 1
radius: 4
samples: 6
color: Qt.rgba(0, 0, 0, 0.5)
}
}
}
}
......
......@@ -4,6 +4,7 @@
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
......@@ -56,7 +57,11 @@ GridView {
}
}
model: Halcyon.PinnedModel
// open wallpaper menu when held on click
TapHandler {
onLongPressed: root.openConfigureRequested()
}
header: MobileShell.BaseItem {
topPadding: Math.round(swipeView.height * 0.2)
bottomPadding: PlasmaCore.Units.largeSpacing
......@@ -71,22 +76,76 @@ GridView {
contentItem: Clock {}
}
delegate: MobileShell.BaseItem {
id: baseItem
readonly property bool isLeftColumn: !root.twoColumn || ((model.index % 2) === 0)
readonly property bool isRightColumn: !root.twoColumn || ((model.index % 2) !== 0)
leftPadding: isLeftColumn ? root.leftMargin : 0
rightPadding: isRightColumn ? root.rightMargin : 0
model: DelegateModel {
id: visualModel
model: Halcyon.PinnedModel
contentItem: FavoritesAppDelegate {
implicitWidth: root.cellWidth - (baseItem.isLeftColumn ? root.leftMargin : 0) - (baseItem.isRightColumn ? root.rightMargin : 0)
implicitHeight: visible ? root.cellHeight : 0
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);
Halcyon.PinnedModel.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
application: delegateRoot.application
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
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
states: [
State {
when: appDelegate.drag.active
ParentChange {
target: appDelegate
parent: root
}
AnchorChanges {
target: appDelegate
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
]
}
}
}
// open wallpaper menu when held on click
TapHandler {
onLongPressed: root.openConfigureRequested()
// animations
displaced: Transition {
NumberAnimation {
properties: "x,y"
easing.type: Easing.OutQuad
}
}
ColumnLayout {
......
......@@ -106,6 +106,40 @@ void PinnedModel::removeFolder(int row)
save();
}
void PinnedModel::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;
}
beginMoveRows(QModelIndex(), fromRow, fromRow, QModelIndex(), toRow);
if (toRow > fromRow) {
Application *app = m_applications.at(fromRow);
m_applications.insert(toRow, app);
m_applications.takeAt(fromRow);
ApplicationFolder *folder = m_folders.at(fromRow);
m_folders.insert(toRow, folder);
m_folders.takeAt(fromRow);
} else {
Application *app = m_applications.takeAt(fromRow);
m_applications.insert(toRow, app);
ApplicationFolder *folder = m_folders.takeAt(fromRow);
m_folders.insert(toRow, folder);
}
endMoveRows();
save();
// HACK: didn't seem to persist
m_applet->config().sync();
}
void PinnedModel::load()
{
if (!m_applet) {
......
......@@ -41,6 +41,8 @@ public:
Q_INVOKABLE void addFolder(QString name, int row);
Q_INVOKABLE void removeFolder(int row);
Q_INVOKABLE void moveEntry(int fromRow, int toRow);
Q_INVOKABLE void load();
void save();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment