mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-08-03 18:24:46 +00:00
Rework app drawer layout and open/close behaviour logic
This commit is contained in:
parent
d7b7290451
commit
b091ce2ac3
13 changed files with 871 additions and 361 deletions
258
components/mobilehomescreencomponents/qml/AbstractAppDrawer.qml
Normal file
258
components/mobilehomescreencomponents/qml/AbstractAppDrawer.qml
Normal file
|
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Marco Martin <mart@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Controls 2.15 as Controls
|
||||||
|
|
||||||
|
import org.kde.plasma.plasmoid 2.0
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
import org.kde.plasma.components 3.0 as PC3
|
||||||
|
import org.kde.plasma.extras 2.0 as PlasmaExtra
|
||||||
|
import org.kde.kirigami 2.10 as Kirigami
|
||||||
|
|
||||||
|
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
|
||||||
|
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||||
|
|
||||||
|
import org.kde.plasma.private.mobilehomescreencomponents 0.1 as HomeScreenComponents
|
||||||
|
|
||||||
|
import "private"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
enum Status {
|
||||||
|
Closed,
|
||||||
|
Peeking,
|
||||||
|
Open
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MovementDirection {
|
||||||
|
None = 0,
|
||||||
|
Up,
|
||||||
|
Down
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property int status: {
|
||||||
|
if (flickable.contentY >= topMargin.height) {
|
||||||
|
return AbstractAppDrawer.Status.Open;
|
||||||
|
} else if (flickable.contentY > 0) {
|
||||||
|
return AbstractAppDrawer.Status.Peeking;
|
||||||
|
} else {
|
||||||
|
return AbstractAppDrawer.Status.Closed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property real offset: 0
|
||||||
|
property real closedPositionOffset: 0
|
||||||
|
|
||||||
|
property real leftPadding: 0
|
||||||
|
property real topPadding: 0
|
||||||
|
property real bottomPadding: 100
|
||||||
|
property real rightPadding: 0
|
||||||
|
|
||||||
|
property alias flickable: view
|
||||||
|
|
||||||
|
property var contentItem
|
||||||
|
property real contentWidth: holdingColumn.width
|
||||||
|
|
||||||
|
required property int headerHeight
|
||||||
|
required property var headerItem
|
||||||
|
|
||||||
|
signal launched
|
||||||
|
signal dragStarted
|
||||||
|
|
||||||
|
readonly property int reservedSpaceForLabel: metrics.height
|
||||||
|
property int availableCellHeight: PlasmaCore.Units.iconSizes.huge + reservedSpaceForLabel
|
||||||
|
|
||||||
|
readonly property real openFactor: factorNormalize(flickable.contentY / (units.gridUnit * 10))
|
||||||
|
|
||||||
|
// height from top of screen that the drawer starts
|
||||||
|
readonly property real drawerTopMargin: height - topPadding - bottomPadding - closedPositionOffset
|
||||||
|
|
||||||
|
//BEGIN functions
|
||||||
|
|
||||||
|
function goToBeginning() {
|
||||||
|
scrollAnim.to = drawerTopMargin;
|
||||||
|
scrollAnim.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
if (root.status === AbstractAppDrawer.Status.Open) {
|
||||||
|
flickable.flick(0,1);
|
||||||
|
} else {
|
||||||
|
goToBeginning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
if (root.status !== AbstractAppDrawer.Status.Closed) {
|
||||||
|
scrollAnim.to = 0;
|
||||||
|
scrollAnim.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// snap the drawer to an open or close position
|
||||||
|
function snapDrawerStatus() {
|
||||||
|
if (flickable.contentY > topMargin.height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flickable.movementDirection === AbstractAppDrawer.MovementDirection.Up) {
|
||||||
|
if (flickable.contentY > topMargin.height / 8) { // over one eighth of the screen
|
||||||
|
open();
|
||||||
|
} else {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (flickable.contentY < 7 * topMargin.height / 8) { // over one eighth of the screen
|
||||||
|
close();
|
||||||
|
} else {
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function factorNormalize(num) {
|
||||||
|
return Math.min(1, Math.max(0, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
//END functions
|
||||||
|
|
||||||
|
Drag.dragType: Drag.Automatic
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: scrollAnim
|
||||||
|
target: flickable
|
||||||
|
properties: "contentY"
|
||||||
|
duration: PlasmaCore.Units.longDuration * 2
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
easing.amplitude: 2.0
|
||||||
|
}
|
||||||
|
|
||||||
|
PC3.Label {
|
||||||
|
id: metrics
|
||||||
|
text: "M\nM"
|
||||||
|
visible: false
|
||||||
|
font.pointSize: PlasmaCore.Theme.defaultFont.pointSize * 0.9
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom divider
|
||||||
|
GradientBar {
|
||||||
|
opacity: root.status !== AbstractAppDrawer.Status.Closed ? 0.6 : 0
|
||||||
|
visible: root.bottomPadding > 0
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: root.bottomPadding - height
|
||||||
|
}
|
||||||
|
|
||||||
|
// physical position of drawer is handled through this flickable
|
||||||
|
Flickable {
|
||||||
|
id: view
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
// We have a situation where this vertical flickable conflicts with the horizontal flickable used for homescreen pages.
|
||||||
|
// This flickable is on top of the other, so we disable it when it isn't open.
|
||||||
|
// We do the initial open gesture in private/DragGestureHandler.qml
|
||||||
|
interactive: contentY > PlasmaCore.Units.gridUnit
|
||||||
|
|
||||||
|
contentHeight: column.implicitHeight
|
||||||
|
contentWidth: -1
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
|
||||||
|
// snap
|
||||||
|
onMovementEnded: root.snapDrawerStatus()
|
||||||
|
|
||||||
|
property int movementDirection: AbstractAppDrawer.MovementDirection.None
|
||||||
|
property real oldContentY
|
||||||
|
onContentYChanged: { // update state
|
||||||
|
movementDirection = oldContentY > contentY ? AbstractAppDrawer.MovementDirection.Down : AbstractAppDrawer.MovementDirection.Up;
|
||||||
|
oldContentY = contentY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
width: view.width
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
// margin of the drawer from the top
|
||||||
|
Rectangle {
|
||||||
|
id: topMargin
|
||||||
|
color: "transparent"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: root.drawerTopMargin
|
||||||
|
|
||||||
|
OpenDrawerButton {
|
||||||
|
id: openDrawerButton
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
factor: root.openFactor
|
||||||
|
flickable: view
|
||||||
|
onOpenRequested: root.open();
|
||||||
|
onCloseRequested: root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// actual drawer
|
||||||
|
Controls.Control {
|
||||||
|
id: drawerFlickable
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: root.height
|
||||||
|
|
||||||
|
visible: view.interactive // this is so that the favourites strip can be interacted with
|
||||||
|
leftPadding: root.leftPadding; topPadding: root.topPadding
|
||||||
|
rightPadding: root.rightPadding; bottomPadding: root.bottomPadding
|
||||||
|
|
||||||
|
// drawer background
|
||||||
|
background: Rectangle {
|
||||||
|
id: scrim
|
||||||
|
color: "black"
|
||||||
|
opacity: 0.6 * root.openFactor
|
||||||
|
|
||||||
|
// remove radius
|
||||||
|
radius: view.contentY > (topMargin.height - PlasmaCore.Units.gridUnit) ? 0 : PlasmaCore.Units.gridUnit
|
||||||
|
Behavior on radius {
|
||||||
|
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opacity: root.openFactor
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
id: holdingColumn
|
||||||
|
width: view.width
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
// drawer header
|
||||||
|
Controls.Control {
|
||||||
|
id: flickableHeader
|
||||||
|
Layout.preferredHeight: root.headerHeight
|
||||||
|
Layout.fillWidth: true
|
||||||
|
leftPadding: 0; rightPadding: 0; topPadding: 0; bottomPadding: 0
|
||||||
|
|
||||||
|
contentItem: root.headerItem
|
||||||
|
}
|
||||||
|
|
||||||
|
// drawer body
|
||||||
|
Controls.Control {
|
||||||
|
id: flickableBody
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
leftPadding: 0; rightPadding: 0; topPadding: 0; bottomPadding: 0
|
||||||
|
|
||||||
|
contentItem: root.contentItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,306 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2021 Marco Martin <mart@kde.org>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import QtQuick 2.14
|
|
||||||
import QtQuick.Layouts 1.1
|
|
||||||
|
|
||||||
import org.kde.plasma.plasmoid 2.0
|
|
||||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
|
||||||
import org.kde.plasma.components 3.0 as PC3
|
|
||||||
//import org.kde.kquickcontrolsaddons 2.0
|
|
||||||
import org.kde.kirigami 2.10 as Kirigami
|
|
||||||
|
|
||||||
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
|
|
||||||
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
|
||||||
|
|
||||||
import org.kde.plasma.private.mobilehomescreencomponents 0.1 as HomeScreenComponents
|
|
||||||
|
|
||||||
import "private"
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
enum Status {
|
|
||||||
Closed,
|
|
||||||
Peeking,
|
|
||||||
Open
|
|
||||||
}
|
|
||||||
|
|
||||||
enum MovementDirection {
|
|
||||||
None = 0,
|
|
||||||
Up,
|
|
||||||
Down
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property int status: {
|
|
||||||
if (view.contentY >= -view.originY - view.height) {
|
|
||||||
return AppDrawer.Status.Open;
|
|
||||||
} else if (view.contentY > -view.originY - view.height*2 + closedPositionOffset*2) {
|
|
||||||
return AppDrawer.Status.Peeking;
|
|
||||||
} else {
|
|
||||||
return AppDrawer.Status.Closed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property real offset: 0
|
|
||||||
property real closedPositionOffset: 0
|
|
||||||
|
|
||||||
property real leftPadding: 0
|
|
||||||
property real topPadding: 0
|
|
||||||
property real bottomPadding: 100
|
|
||||||
property real rightPadding: 0
|
|
||||||
|
|
||||||
readonly property int columns: Math.floor(view.width / cellWidth)
|
|
||||||
property alias cellWidth: view.cellWidth
|
|
||||||
property alias cellHeight: view.cellHeight
|
|
||||||
signal launched
|
|
||||||
signal dragStarted
|
|
||||||
|
|
||||||
readonly property int reservedSpaceForLabel: metrics.height
|
|
||||||
property int availableCellHeight: PlasmaCore.Units.iconSizes.huge + reservedSpaceForLabel
|
|
||||||
|
|
||||||
property alias flickable: view
|
|
||||||
|
|
||||||
readonly property real openFactor: Math.min(1, Math.max(0, Math.min(1, (view.contentY + view.originY + view.height*2 - root.closedPositionOffset*2) / (PlasmaCore.Units.gridUnit * 10))))
|
|
||||||
|
|
||||||
function open() {
|
|
||||||
if (root.status === AppDrawer.Status.Open) {
|
|
||||||
view.flick(0,1);
|
|
||||||
} else {
|
|
||||||
scrollAnim.to = 0
|
|
||||||
scrollAnim.restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
if (root.status !== AppDrawer.Status.Closed) {
|
|
||||||
scrollAnim.to = -view.height + closedPositionOffset;
|
|
||||||
scrollAnim.restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function snapDrawerStatus() {
|
|
||||||
if (root.status !== AppDrawer.Status.Peeking) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view.movementDirection === AppDrawer.MovementDirection.Up) {
|
|
||||||
if (view.contentY > 7 * -view.height / 8) { // over one eighth of the screen
|
|
||||||
open();
|
|
||||||
} else {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (view.contentY < -view.height / 8) { // over one eighth of the screen
|
|
||||||
close();
|
|
||||||
} else {
|
|
||||||
open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Drag.dragType: Drag.Automatic
|
|
||||||
|
|
||||||
onOffsetChanged: {
|
|
||||||
if (!view.moving) {
|
|
||||||
view.contentY = Math.max(0, offset) - view.originY - view.height*2 + closedPositionOffset*2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NumberAnimation {
|
|
||||||
id: scrollAnim
|
|
||||||
target: view
|
|
||||||
properties: "contentY"
|
|
||||||
duration: PlasmaCore.Units.longDuration * 2
|
|
||||||
easing.type: Easing.OutQuad
|
|
||||||
easing.amplitude: 2.0
|
|
||||||
}
|
|
||||||
|
|
||||||
PC3.Label {
|
|
||||||
id: metrics
|
|
||||||
text: "M\nM"
|
|
||||||
visible: false
|
|
||||||
font.pointSize: PlasmaCore.Theme.defaultFont.pointSize * 0.9
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenDrawerButton {
|
|
||||||
id: openDrawerButton
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
bottom: scrim.top
|
|
||||||
}
|
|
||||||
factor: root.openFactor
|
|
||||||
flickable: view
|
|
||||||
onOpenRequested: root.open();
|
|
||||||
onCloseRequested: root.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: scrim
|
|
||||||
anchors {
|
|
||||||
left: view.left
|
|
||||||
right: view.right
|
|
||||||
leftMargin: -1
|
|
||||||
rightMargin: -1
|
|
||||||
}
|
|
||||||
border.color: Qt.rgba(1, 1, 1, 0.5)
|
|
||||||
radius: PlasmaCore.Units.gridUnit
|
|
||||||
color: "black"
|
|
||||||
opacity: 0.4 * root.openFactor
|
|
||||||
height: root.height + radius * 2
|
|
||||||
y: Math.min(view.height, Math.max(-radius, -view.contentY - view.originY - root.height + root.topPadding + root.bottomPadding + root.closedPositionOffset))
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: closeTimer
|
|
||||||
interval: 1000
|
|
||||||
onTriggered: root.close();
|
|
||||||
}
|
|
||||||
GridView {
|
|
||||||
id: view
|
|
||||||
anchors {
|
|
||||||
fill: parent
|
|
||||||
leftMargin: root.leftPadding
|
|
||||||
topMargin: root.topPadding
|
|
||||||
rightMargin: root.rightPadding
|
|
||||||
bottomMargin: root.bottomPadding
|
|
||||||
}
|
|
||||||
|
|
||||||
opacity: {
|
|
||||||
if (root.status == AppDrawer.Status.Open) {
|
|
||||||
return 1;
|
|
||||||
} else if (root.status == AppDrawer.Status.Closed) {
|
|
||||||
return 0;
|
|
||||||
} else { // peeking
|
|
||||||
return root.openFactor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
visible: root.status !== AppDrawer.Status.Closed
|
|
||||||
cellWidth: view.width / Math.floor(view.width / ((root.availableCellHeight - root.reservedSpaceForLabel) + PlasmaCore.Units.smallSpacing*4))
|
|
||||||
cellHeight: root.availableCellHeight
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
cacheBuffer: contentHeight
|
|
||||||
|
|
||||||
property real oldContentY: contentY
|
|
||||||
property int movementDirection: AppDrawer.MovementDirection.None
|
|
||||||
onContentYChanged: {
|
|
||||||
if (contentY > oldContentY) {
|
|
||||||
movementDirection = AppDrawer.MovementDirection.Up;
|
|
||||||
} else {
|
|
||||||
movementDirection = AppDrawer.MovementDirection.Down;
|
|
||||||
}
|
|
||||||
|
|
||||||
oldContentY = contentY;
|
|
||||||
root.offset = contentY + view.originY + view.height*2 - root.closedPositionOffset*2
|
|
||||||
}
|
|
||||||
onMovementEnded: root.snapDrawerStatus()
|
|
||||||
onFlickEnded: movementEnded()
|
|
||||||
|
|
||||||
// boundsBehavior: Flickable.StopAtBounds
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: HomeScreenComponents.ApplicationListModel
|
|
||||||
onLaunchError: NanoShell.StartupFeedback.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
model: HomeScreenComponents.ApplicationListModel
|
|
||||||
|
|
||||||
header: Rectangle {
|
|
||||||
height: root.height - root.topPadding - root.bottomPadding - root.closedPositionOffset
|
|
||||||
property real oldHeight: height
|
|
||||||
onHeightChanged: {
|
|
||||||
if (root.status !== AppDrawer.Status.Open) {
|
|
||||||
view.contentY = -view.height + root.closedPositionOffset;
|
|
||||||
}
|
|
||||||
oldHeight = height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: DrawerDelegate {
|
|
||||||
id: delegate
|
|
||||||
width: view.cellWidth
|
|
||||||
height: view.cellHeight
|
|
||||||
reservedSpaceForLabel: root.reservedSpaceForLabel
|
|
||||||
|
|
||||||
onDragStarted: (imageSource, x, y, mimeData) => {
|
|
||||||
root.Drag.imageSource = imageSource;
|
|
||||||
root.Drag.hotSpot.x = x;
|
|
||||||
root.Drag.hotSpot.y = y;
|
|
||||||
root.Drag.mimeData = { "text/x-plasma-phone-homescreen-launcher": mimeData };
|
|
||||||
|
|
||||||
root.close()
|
|
||||||
|
|
||||||
root.dragStarted()
|
|
||||||
root.Drag.active = true;
|
|
||||||
}
|
|
||||||
onLaunch: (x, y, icon, title, storageId) => {
|
|
||||||
if (icon !== "") {
|
|
||||||
NanoShell.StartupFeedback.open(
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
HomeScreenComponents.ApplicationListModel.setMinimizedDelegate(index, delegate);
|
|
||||||
HomeScreenComponents.ApplicationListModel.runApplication(storageId);
|
|
||||||
root.launched();
|
|
||||||
closeTimer.restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PC3.ScrollBar.vertical: PC3.ScrollBar {
|
|
||||||
id: scrollabr
|
|
||||||
opacity: view.moving
|
|
||||||
interactive: false
|
|
||||||
enabled: false
|
|
||||||
Behavior on opacity {
|
|
||||||
OpacityAnimator {
|
|
||||||
duration: PlasmaCore.Units.longDuration * 2
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
implicitWidth: Math.round(PlasmaCore.Units.gridUnit/3)
|
|
||||||
contentItem: Rectangle {
|
|
||||||
radius: width/2
|
|
||||||
color: Qt.rgba(1, 1, 1, 0.3)
|
|
||||||
border.color: Qt.rgba(0, 0, 0, 0.4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
bottom: parent.bottom
|
|
||||||
leftMargin: PlasmaCore.Units.gridUnit + root.leftPadding
|
|
||||||
rightMargin: PlasmaCore.Units.gridUnit + root.rightPadding
|
|
||||||
bottomMargin: root.bottomPadding - height
|
|
||||||
}
|
|
||||||
height: 1
|
|
||||||
visible: root.bottomPadding > 0
|
|
||||||
gradient: Gradient {
|
|
||||||
orientation: Gradient.Horizontal
|
|
||||||
GradientStop { position: 0.0; color: Qt.rgba(1, 1, 1, 0) }
|
|
||||||
GradientStop { position: 0.15; color: Qt.rgba(1, 1, 1, 0.5) }
|
|
||||||
GradientStop { position: 0.5; color: Qt.rgba(1, 1, 1, 1) }
|
|
||||||
GradientStop { position: 0.85; color: Qt.rgba(1, 1, 1, 0.5) }
|
|
||||||
GradientStop { position: 1.0; color: Qt.rgba(1, 1, 1, 0) }
|
|
||||||
}
|
|
||||||
opacity: root.status !== AppDrawer.Status.Closed ? 0.6 : 0
|
|
||||||
Behavior on opacity {
|
|
||||||
OpacityAnimator {
|
|
||||||
duration: PlasmaCore.Units.longDuration * 2
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
103
components/mobilehomescreencomponents/qml/DrawerGridDelegate.qml
Normal file
103
components/mobilehomescreencomponents/qml/DrawerGridDelegate.qml
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.4
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Controls 2.3 as Controls
|
||||||
|
import QtGraphicalEffects 1.6
|
||||||
|
|
||||||
|
import org.kde.plasma.plasmoid 2.0
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||||
|
import org.kde.kquickcontrolsaddons 2.0
|
||||||
|
|
||||||
|
import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager
|
||||||
|
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: delegate
|
||||||
|
width: GridView.view.cellWidth
|
||||||
|
height: GridView.view.cellHeight
|
||||||
|
|
||||||
|
property int reservedSpaceForLabel
|
||||||
|
property alias iconItem: icon
|
||||||
|
|
||||||
|
signal launch(int x, int y, var source, string title, string storageId)
|
||||||
|
signal dragStarted(string imageSource, int x, int y, string mimeData)
|
||||||
|
|
||||||
|
onPressAndHold: {
|
||||||
|
delegate.grabToImage(function(result) {
|
||||||
|
delegate.Drag.imageSource = result.url
|
||||||
|
dragStarted(result.url, width/2, height/2, model.applicationStorageId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (model.applicationRunning) {
|
||||||
|
delegate.launch(0, 0, "", model.applicationName, model.applicationStorageId);
|
||||||
|
} else {
|
||||||
|
delegate.launch(delegate.x + (PlasmaCore.Units.smallSpacing * 2), delegate.y + (PlasmaCore.Units.smallSpacing * 2), icon.source, model.applicationName, model.applicationStorageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//preventStealing: true
|
||||||
|
ColumnLayout {
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
leftMargin: PlasmaCore.Units.smallSpacing * 2
|
||||||
|
topMargin: PlasmaCore.Units.smallSpacing * 2
|
||||||
|
rightMargin: PlasmaCore.Units.smallSpacing * 2
|
||||||
|
bottomMargin: PlasmaCore.Units.smallSpacing * 2
|
||||||
|
}
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
PlasmaCore.IconItem {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumHeight: parent.height - delegate.reservedSpaceForLabel
|
||||||
|
Layout.preferredHeight: Layout.minimumHeight
|
||||||
|
|
||||||
|
usesPlasmaTheme: false
|
||||||
|
source: model.applicationIcon
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
visible: model.applicationRunning
|
||||||
|
radius: width
|
||||||
|
width: PlasmaCore.Units.smallSpacing
|
||||||
|
height: width
|
||||||
|
color: theme.highlightColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlasmaComponents.Label {
|
||||||
|
id: label
|
||||||
|
visible: text.length > 0
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: delegate.reservedSpaceForLabel
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
Layout.leftMargin: -parent.anchors.leftMargin + PlasmaCore.Units.smallSpacing
|
||||||
|
Layout.rightMargin: -parent.anchors.rightMargin + PlasmaCore.Units.smallSpacing
|
||||||
|
maximumLineCount: 2
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignTop
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
text: model.applicationName
|
||||||
|
|
||||||
|
//FIXME: export smallestReadableFont
|
||||||
|
font.pointSize: theme.defaultFont.pointSize * 0.9
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
108
components/mobilehomescreencomponents/qml/DrawerListDelegate.qml
Normal file
108
components/mobilehomescreencomponents/qml/DrawerListDelegate.qml
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.4
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Controls 2.3 as Controls
|
||||||
|
import QtGraphicalEffects 1.6
|
||||||
|
|
||||||
|
import org.kde.plasma.plasmoid 2.0
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||||
|
import org.kde.kquickcontrolsaddons 2.0
|
||||||
|
|
||||||
|
import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager
|
||||||
|
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: delegate
|
||||||
|
property int reservedSpaceForLabel
|
||||||
|
property alias iconItem: icon
|
||||||
|
|
||||||
|
signal launch(int x, int y, var source, string title, string storageId)
|
||||||
|
signal dragStarted(string imageSource, int x, int y, string mimeData)
|
||||||
|
|
||||||
|
onPressAndHold: {
|
||||||
|
delegate.grabToImage(function(result) {
|
||||||
|
delegate.Drag.imageSource = result.url
|
||||||
|
dragStarted(result.url, width/2, height/2, model.applicationStorageId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (model.applicationRunning) {
|
||||||
|
delegate.launch(0, 0, "", model.applicationName, model.applicationStorageId);
|
||||||
|
} else {
|
||||||
|
delegate.launch(delegate.x + (PlasmaCore.Units.smallSpacing * 2), delegate.y + (PlasmaCore.Units.smallSpacing * 2), icon.source, model.applicationName, model.applicationStorageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: delegate.pressed ? Qt.rgba(255, 255, 255, 0.2) : (delegate.containsMouse ? Qt.rgba(255, 255, 255, 0.05) : "transparent")
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation { duration: PlasmaCore.Units.shortDuration }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
leftMargin: PlasmaCore.Units.smallSpacing * 2
|
||||||
|
topMargin: PlasmaCore.Units.smallSpacing
|
||||||
|
rightMargin: PlasmaCore.Units.smallSpacing * 2
|
||||||
|
bottomMargin: PlasmaCore.Units.smallSpacing
|
||||||
|
}
|
||||||
|
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: model.applicationIcon
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
visible: model.applicationRunning
|
||||||
|
radius: width
|
||||||
|
width: PlasmaCore.Units.smallSpacing
|
||||||
|
height: width
|
||||||
|
color: theme.highlightColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlasmaComponents.Label {
|
||||||
|
id: label
|
||||||
|
visible: text.length > 0
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
Layout.leftMargin: PlasmaCore.Units.smallSpacing * 2
|
||||||
|
Layout.rightMargin: PlasmaCore.Units.largeSpacing
|
||||||
|
maximumLineCount: 1
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
text: model.applicationName
|
||||||
|
|
||||||
|
//FIXME: export smallestReadableFont
|
||||||
|
font.pointSize: Math.round(theme.defaultFont.pointSize * 1.1)
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ import org.kde.plasma.private.mobilehomescreencomponents 0.1 as HomeScreenCompon
|
||||||
Flickable {
|
Flickable {
|
||||||
id: mainFlickable
|
id: mainFlickable
|
||||||
|
|
||||||
property AppDrawer appDrawer
|
property AbstractAppDrawer appDrawer
|
||||||
|
|
||||||
readonly property int totalPages: Math.ceil(contentWidth / width)
|
readonly property int totalPages: Math.ceil(contentWidth / width)
|
||||||
property int currentIndex: 0
|
property int currentIndex: 0
|
||||||
|
|
@ -35,9 +35,8 @@ Flickable {
|
||||||
property alias dragGestureEnabled: gestureHandler.enabled
|
property alias dragGestureEnabled: gestureHandler.enabled
|
||||||
opacity: appDrawer ? 1 - appDrawer.openFactor : 1
|
opacity: appDrawer ? 1 - appDrawer.openFactor : 1
|
||||||
transform: Translate {
|
transform: Translate {
|
||||||
y: appDrawer ? -mainFlickable.height/10 * appDrawer.openFactor : 0
|
y: appDrawer ? (-mainFlickable.height / 20) * appDrawer.openFactor : 0
|
||||||
}
|
}
|
||||||
scale: appDrawer ? (3 - appDrawer.openFactor) /3 : 1
|
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
property bool showAddPageIndicator: false
|
property bool showAddPageIndicator: false
|
||||||
|
|
|
||||||
120
components/mobilehomescreencomponents/qml/GridViewAppDrawer.qml
Normal file
120
components/mobilehomescreencomponents/qml/GridViewAppDrawer.qml
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Marco Martin <mart@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Controls 2.15 as Controls
|
||||||
|
|
||||||
|
import org.kde.plasma.plasmoid 2.0
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
import org.kde.plasma.components 3.0 as PC3
|
||||||
|
import org.kde.plasma.extras 2.0 as PlasmaExtra
|
||||||
|
import org.kde.kirigami 2.10 as Kirigami
|
||||||
|
|
||||||
|
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
|
||||||
|
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||||
|
|
||||||
|
import org.kde.plasma.private.mobilehomescreencomponents 0.1 as HomeScreenComponents
|
||||||
|
|
||||||
|
import "private"
|
||||||
|
|
||||||
|
AbstractAppDrawer {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
contentItem: GridView {
|
||||||
|
id: gridView
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
// start location of dragging
|
||||||
|
property real startDragContentY
|
||||||
|
onMovementStarted: {
|
||||||
|
oldContentY = contentY;
|
||||||
|
startDragContentY = contentY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move drawer down when at the top of the app list
|
||||||
|
property real oldContentY
|
||||||
|
property bool movingDrawerDown: false
|
||||||
|
onContentYChanged: {
|
||||||
|
let candidateContentY = root.flickable.contentY - (oldContentY - contentY);
|
||||||
|
if (dragging && startDragContentY <= 0 && oldContentY <= 0 && candidateContentY <= root.drawerTopMargin) {
|
||||||
|
root.flickable.contentY = candidateContentY;
|
||||||
|
contentY = 0;
|
||||||
|
movingDrawerDown = true;
|
||||||
|
}
|
||||||
|
oldContentY = contentY;
|
||||||
|
}
|
||||||
|
onMovementEnded: {
|
||||||
|
if (movingDrawerDown) {
|
||||||
|
root.snapDrawerStatus();
|
||||||
|
movingDrawerDown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cellWidth: root.contentWidth / Math.floor(root.contentWidth / ((root.availableCellHeight - root.reservedSpaceForLabel) + PlasmaCore.Units.smallSpacing*4))
|
||||||
|
cellHeight: root.availableCellHeight
|
||||||
|
|
||||||
|
property int columns: Math.floor(root.contentWidth / cellWidth)
|
||||||
|
property int rows: Math.ceil(model.count / columns)
|
||||||
|
cacheBuffer: rows * cellHeight
|
||||||
|
|
||||||
|
model: HomeScreenComponents.ApplicationListModel
|
||||||
|
|
||||||
|
delegate: DrawerGridDelegate {
|
||||||
|
id: delegate
|
||||||
|
|
||||||
|
width: gridView.cellWidth
|
||||||
|
height: gridView.cellHeight
|
||||||
|
reservedSpaceForLabel: root.reservedSpaceForLabel
|
||||||
|
|
||||||
|
onDragStarted: (imageSource, x, y, mimeData) => {
|
||||||
|
root.Drag.imageSource = imageSource;
|
||||||
|
root.Drag.hotSpot.x = x;
|
||||||
|
root.Drag.hotSpot.y = y;
|
||||||
|
root.Drag.mimeData = { "text/x-plasma-phone-homescreen-launcher": mimeData };
|
||||||
|
|
||||||
|
root.close()
|
||||||
|
|
||||||
|
root.dragStarted()
|
||||||
|
root.Drag.active = true;
|
||||||
|
}
|
||||||
|
onLaunch: (x, y, icon, title, storageId) => {
|
||||||
|
if (icon !== "") {
|
||||||
|
NanoShell.StartupFeedback.open(
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
HomeScreenComponents.ApplicationListModel.setMinimizedDelegate(index, delegate);
|
||||||
|
HomeScreenComponents.ApplicationListModel.runApplication(storageId);
|
||||||
|
root.launched();
|
||||||
|
closeTimer.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PC3.ScrollBar.vertical: PC3.ScrollBar {
|
||||||
|
id: scrollBar
|
||||||
|
interactive: true
|
||||||
|
enabled: true
|
||||||
|
Behavior on opacity {
|
||||||
|
OpacityAnimator {
|
||||||
|
duration: PlasmaCore.Units.longDuration * 2
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
implicitWidth: PlasmaCore.Units.smallSpacing
|
||||||
|
contentItem: Rectangle {
|
||||||
|
radius: width/2
|
||||||
|
color: Qt.rgba(1, 1, 1, 0.3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -160,7 +160,7 @@ DragDrop.DropArea {
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
target: mainFlickable
|
target: mainFlickable
|
||||||
enabled: appDrawer.status !== AppDrawer.Status.Open
|
enabled: appDrawer.status !== AbstractAppDrawer.Status.Open
|
||||||
onTapped: {
|
onTapped: {
|
||||||
//Hides icons close button
|
//Hides icons close button
|
||||||
appletsLayout.appletsLayoutInteracted();
|
appletsLayout.appletsLayoutInteracted();
|
||||||
|
|
|
||||||
116
components/mobilehomescreencomponents/qml/ListViewAppDrawer.qml
Normal file
116
components/mobilehomescreencomponents/qml/ListViewAppDrawer.qml
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Marco Martin <mart@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Controls 2.15 as Controls
|
||||||
|
|
||||||
|
import org.kde.plasma.plasmoid 2.0
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
import org.kde.plasma.components 3.0 as PC3
|
||||||
|
import org.kde.plasma.extras 2.0 as PlasmaExtra
|
||||||
|
import org.kde.kirigami 2.10 as Kirigami
|
||||||
|
|
||||||
|
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
|
||||||
|
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||||
|
|
||||||
|
import org.kde.plasma.private.mobilehomescreencomponents 0.1 as HomeScreenComponents
|
||||||
|
|
||||||
|
import "private"
|
||||||
|
|
||||||
|
AbstractAppDrawer {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
contentItem: ListView {
|
||||||
|
id: listView
|
||||||
|
clip: true
|
||||||
|
reuseItems: true
|
||||||
|
cacheBuffer: model.count * delegateHeight // delegate height
|
||||||
|
|
||||||
|
// start location of dragging
|
||||||
|
property real startDragContentY
|
||||||
|
onMovementStarted: {
|
||||||
|
oldContentY = contentY;
|
||||||
|
startDragContentY = contentY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move drawer down when at the top of the app list
|
||||||
|
property real oldContentY
|
||||||
|
property bool movingDrawerDown: false
|
||||||
|
onContentYChanged: {
|
||||||
|
let candidateContentY = root.flickable.contentY - (oldContentY - contentY);
|
||||||
|
if (dragging && startDragContentY <= 0 && oldContentY <= 0 && candidateContentY <= root.drawerTopMargin) {
|
||||||
|
root.flickable.contentY = candidateContentY;
|
||||||
|
contentY = 0;
|
||||||
|
movingDrawerDown = true;
|
||||||
|
}
|
||||||
|
oldContentY = contentY;
|
||||||
|
}
|
||||||
|
onMovementEnded: {
|
||||||
|
if (movingDrawerDown) {
|
||||||
|
root.snapDrawerStatus();
|
||||||
|
movingDrawerDown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property int delegateHeight: PlasmaCore.Units.gridUnit * 3
|
||||||
|
|
||||||
|
model: HomeScreenComponents.ApplicationListModel
|
||||||
|
|
||||||
|
delegate: DrawerListDelegate {
|
||||||
|
id: delegate
|
||||||
|
|
||||||
|
width: listView.width
|
||||||
|
height: listView.delegateHeight
|
||||||
|
reservedSpaceForLabel: root.reservedSpaceForLabel
|
||||||
|
|
||||||
|
onDragStarted: (imageSource, x, y, mimeData) => {
|
||||||
|
root.Drag.imageSource = imageSource;
|
||||||
|
root.Drag.hotSpot.x = x;
|
||||||
|
root.Drag.hotSpot.y = y;
|
||||||
|
root.Drag.mimeData = { "text/x-plasma-phone-homescreen-launcher": mimeData };
|
||||||
|
|
||||||
|
root.close()
|
||||||
|
|
||||||
|
root.dragStarted()
|
||||||
|
root.Drag.active = true;
|
||||||
|
}
|
||||||
|
onLaunch: (x, y, icon, title, storageId) => {
|
||||||
|
if (icon !== "") {
|
||||||
|
NanoShell.StartupFeedback.open(
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
HomeScreenComponents.ApplicationListModel.setMinimizedDelegate(index, delegate);
|
||||||
|
HomeScreenComponents.ApplicationListModel.runApplication(storageId);
|
||||||
|
root.launched();
|
||||||
|
closeTimer.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PC3.ScrollBar.vertical: PC3.ScrollBar {
|
||||||
|
id: scrollBar
|
||||||
|
interactive: true
|
||||||
|
enabled: true
|
||||||
|
Behavior on opacity {
|
||||||
|
OpacityAnimator {
|
||||||
|
duration: PlasmaCore.Units.longDuration * 2
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
implicitWidth: PlasmaCore.Units.smallSpacing
|
||||||
|
contentItem: Rectangle {
|
||||||
|
radius: width/2
|
||||||
|
color: Qt.rgba(1, 1, 1, 0.3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021 Marco Martin <mart@kde.org>
|
* SPDX-FileCopyrightText: 2021 Marco Martin <mart@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
@ -15,7 +16,7 @@ DragHandler {
|
||||||
yAxis.enabled: enabled
|
yAxis.enabled: enabled
|
||||||
xAxis.enabled: enabled
|
xAxis.enabled: enabled
|
||||||
property Flickable mainFlickable
|
property Flickable mainFlickable
|
||||||
property Launcher.AppDrawer appDrawer
|
property Launcher.AbstractAppDrawer appDrawer
|
||||||
signal snapPage
|
signal snapPage
|
||||||
signal snapNextPage
|
signal snapNextPage
|
||||||
signal snapPrevPage
|
signal snapPrevPage
|
||||||
|
|
@ -33,7 +34,7 @@ DragHandler {
|
||||||
if (active) {
|
if (active) {
|
||||||
if (root.appDrawer) {
|
if (root.appDrawer) {
|
||||||
if (__scrollDirection === DragGestureHandler.None) {
|
if (__scrollDirection === DragGestureHandler.None) {
|
||||||
if (root.appDrawer.offset > PlasmaCore.Units.gridUnit) {
|
if (root.appDrawer.flickable.contentY > PlasmaCore.Units.gridUnit * 2) {
|
||||||
|
|
||||||
__scrollDirection = DragGestureHandler.Vertical;
|
__scrollDirection = DragGestureHandler.Vertical;
|
||||||
snapPage();
|
snapPage();
|
||||||
|
|
@ -49,7 +50,7 @@ DragHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__scrollDirection !== DragGestureHandler.Left && __scrollDirection !== DragGestureHandler.Right) {
|
if (__scrollDirection !== DragGestureHandler.Left && __scrollDirection !== DragGestureHandler.Right) {
|
||||||
root.appDrawer.offset = -translation.y;
|
root.appDrawer.flickable.contentY = Math.min(root.appDrawer.drawerTopMargin, Math.max(0, -translation.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (__scrollDirection !== DragGestureHandler.Vertical) {
|
if (__scrollDirection !== DragGestureHandler.Vertical) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Marco Martin <mart@kde.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Behavior on opacity {
|
||||||
|
OpacityAnimator {
|
||||||
|
duration: PlasmaCore.Units.longDuration * 2
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
leftMargin: PlasmaCore.Units.gridUnit + root.leftPadding
|
||||||
|
rightMargin: PlasmaCore.Units.gridUnit + root.rightPadding
|
||||||
|
}
|
||||||
|
height: 1
|
||||||
|
gradient: Gradient {
|
||||||
|
orientation: Gradient.Horizontal
|
||||||
|
GradientStop { position: 0.0; color: Qt.rgba(1, 1, 1, 0) }
|
||||||
|
GradientStop { position: 0.15; color: Qt.rgba(1, 1, 1, 0.5) }
|
||||||
|
GradientStop { position: 0.5; color: Qt.rgba(1, 1, 1, 1) }
|
||||||
|
GradientStop { position: 0.85; color: Qt.rgba(1, 1, 1, 0.5) }
|
||||||
|
GradientStop { position: 1.0; color: Qt.rgba(1, 1, 1, 0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,23 +25,20 @@ MouseArea {
|
||||||
property Flickable flickable
|
property Flickable flickable
|
||||||
property real factor: 0
|
property real factor: 0
|
||||||
|
|
||||||
height: PlasmaCore.Units.iconSizes.medium
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
height: PlasmaCore.Units.iconSizes.smallMedium
|
||||||
signal openRequested
|
signal openRequested
|
||||||
signal closeRequested
|
signal closeRequested
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if ((arrowUpIcon.flickable.contentY + arrowUpIcon.flickable.originY + arrowUpIcon.flickable.height*2) >= arrowUpIcon.flickable.height/2) {
|
|
||||||
closeRequested();
|
|
||||||
} else {
|
|
||||||
openRequested();
|
openRequested();
|
||||||
}
|
|
||||||
scrollAnim.restart();
|
scrollAnim.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
width: PlasmaCore.Units.iconSizes.medium
|
width: PlasmaCore.Units.iconSizes.smallMedium
|
||||||
height: width
|
height: width
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -51,7 +48,7 @@ MouseArea {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
verticalCenterOffset: -arrowUpIcon.height/4 + (arrowUpIcon.height/4) * arrowUpIcon.factor
|
verticalCenterOffset: -arrowUpIcon.height/4 + (arrowUpIcon.height/4) * arrowUpIcon.factor
|
||||||
}
|
}
|
||||||
color: PlasmaCore.Theme.backgroundColor
|
color: "white"
|
||||||
transformOrigin: Item.Right
|
transformOrigin: Item.Right
|
||||||
rotation: -45 + 90 * arrowUpIcon.factor
|
rotation: -45 + 90 * arrowUpIcon.factor
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
|
|
@ -64,7 +61,7 @@ MouseArea {
|
||||||
right: parent.right
|
right: parent.right
|
||||||
verticalCenterOffset: -arrowUpIcon.height/4 + (arrowUpIcon.height/4) * arrowUpIcon.factor
|
verticalCenterOffset: -arrowUpIcon.height/4 + (arrowUpIcon.height/4) * arrowUpIcon.factor
|
||||||
}
|
}
|
||||||
color: PlasmaCore.Theme.backgroundColor
|
color: "white"
|
||||||
transformOrigin: Item.Left
|
transformOrigin: Item.Left
|
||||||
rotation: 45 - 90 * arrowUpIcon.factor
|
rotation: 45 - 90 * arrowUpIcon.factor
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@ module org.kde.plasma.private.mobilehomescreencomponents
|
||||||
|
|
||||||
plugin mobilehomescreencomponentsplugin
|
plugin mobilehomescreencomponentsplugin
|
||||||
|
|
||||||
AppDrawer 0.1 AppDrawer.qml
|
AbstractAppDrawer 0.1 AbstractAppDrawer.qml
|
||||||
DrawerDelegate 0.1 DrawerDelegate.qml
|
GridViewAppDrawer 0.1 GridViewAppDrawer.qml
|
||||||
|
ListViewAppDrawer 0.1 ListViewAppDrawer.qml
|
||||||
|
DrawerListDelegate 0.1 DrawerListDelegate.qml
|
||||||
|
DrawerGridDelegate 0.1 DrawerGridDelegate.qml
|
||||||
FavoriteStrip 0.1 FavoriteStrip.qml
|
FavoriteStrip 0.1 FavoriteStrip.qml
|
||||||
FlickablePages 0.1 FlickablePages.qml
|
FlickablePages 0.1 FlickablePages.qml
|
||||||
HomeDelegate 0.1 HomeDelegate.qml
|
HomeDelegate 0.1 HomeDelegate.qml
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import QtGraphicalEffects 1.0
|
||||||
import org.kde.plasma.plasmoid 2.0
|
import org.kde.plasma.plasmoid 2.0
|
||||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
import org.kde.plasma.components 3.0 as PlasmaComponents
|
import org.kde.plasma.components 3.0 as PlasmaComponents
|
||||||
|
import org.kde.plasma.extras 2.0 as PlasmaExtra
|
||||||
import org.kde.draganddrop 2.0 as DragDrop
|
import org.kde.draganddrop 2.0 as DragDrop
|
||||||
|
|
||||||
import org.kde.plasma.private.mobilehomescreencomponents 0.1 as HomeScreenComponents
|
import org.kde.plasma.private.mobilehomescreencomponents 0.1 as HomeScreenComponents
|
||||||
|
|
@ -53,6 +54,9 @@ FocusScope {
|
||||||
}
|
}
|
||||||
componentComplete = true;
|
componentComplete = true;
|
||||||
recalculateMaxFavoriteCount()
|
recalculateMaxFavoriteCount()
|
||||||
|
|
||||||
|
// ensure the gestures work immediately on load
|
||||||
|
forceActiveFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
Plasmoid.onScreenChanged: {
|
Plasmoid.onScreenChanged: {
|
||||||
|
|
@ -76,13 +80,13 @@ FocusScope {
|
||||||
}
|
}
|
||||||
function onSnapHomeScreenPosition() {
|
function onSnapHomeScreenPosition() {
|
||||||
if (lastRequestedPosition < 0) {
|
if (lastRequestedPosition < 0) {
|
||||||
appDrawer.open();
|
root.appDrawer.open();
|
||||||
} else {
|
} else {
|
||||||
appDrawer.close();
|
root.appDrawer.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function onRequestRelativeScroll(pos) {
|
function onRequestRelativeScroll(pos) {
|
||||||
appDrawer.offset -= pos.y;
|
root.appDrawer.offset -= pos.y;
|
||||||
lastRequestedPosition = pos.y;
|
lastRequestedPosition = pos.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,57 +100,25 @@ FocusScope {
|
||||||
bottomMargin: plasmoid.screenGeometry.height - plasmoid.availableScreenRect.height - plasmoid.availableScreenRect.y
|
bottomMargin: plasmoid.screenGeometry.height - plasmoid.availableScreenRect.height - plasmoid.availableScreenRect.y
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: favorite strip disappearing with everything else
|
|
||||||
footer: favoriteStrip
|
|
||||||
appletsLayout: homeScreenContents.appletsLayout
|
appletsLayout: homeScreenContents.appletsLayout
|
||||||
|
|
||||||
appDrawer: appDrawer
|
appDrawer: root.appDrawer
|
||||||
contentWidth: Math.max(width, width * Math.ceil(homeScreenContents.itemsBoundingRect.width/width)) + (homeScreenContents.launcherDragManager.active ? width : 0)
|
contentWidth: Math.max(width, width * Math.ceil(homeScreenContents.itemsBoundingRect.width/width)) + (homeScreenContents.launcherDragManager.active ? width : 0)
|
||||||
showAddPageIndicator: homeScreenContents.launcherDragManager.active
|
showAddPageIndicator: homeScreenContents.launcherDragManager.active
|
||||||
|
|
||||||
dragGestureEnabled: root.focus && appDrawer.status !== HomeScreenComponents.AppDrawer.Status.Open && !appletsLayout.editMode && !plasmoid.editMode && !homeScreenContents.launcherDragManager.active
|
dragGestureEnabled: root.focus && (!appDrawer || appDrawer.status !== HomeScreenComponents.AbstractAppDrawer.Status.Open) && !appletsLayout.editMode && !plasmoid.editMode && !homeScreenContents.launcherDragManager.active
|
||||||
|
|
||||||
HomeScreenComponents.HomeScreenContents {
|
HomeScreenComponents.HomeScreenContents {
|
||||||
id: homeScreenContents
|
id: homeScreenContents
|
||||||
width: mainFlickable.width * 100
|
width: mainFlickable.width * 100
|
||||||
favoriteStrip: favoriteStrip
|
favoriteStrip: favoriteStrip
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Plasmoid.onActivated: {
|
footer: HomeScreenComponents.FavoriteStrip {
|
||||||
console.log("Triggered!", plasmoid.nativeInterface.showingDesktop)
|
|
||||||
|
|
||||||
// there's a couple of steps:
|
|
||||||
// - minimize windows
|
|
||||||
// - open app drawer
|
|
||||||
// - restore windows
|
|
||||||
if (!plasmoid.nativeInterface.showingDesktop) {
|
|
||||||
plasmoid.nativeInterface.showingDesktop = true
|
|
||||||
} else if (appDrawer.status !== HomeScreenComponents.AppDrawer.Status.Open) {
|
|
||||||
mainFlickable.currentIndex = 0
|
|
||||||
appDrawer.open()
|
|
||||||
} else {
|
|
||||||
plasmoid.nativeInterface.showingDesktop = false
|
|
||||||
appDrawer.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HomeScreenComponents.AppDrawer {
|
|
||||||
id: appDrawer
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
topPadding: plasmoid.availableScreenRect.y
|
|
||||||
bottomPadding: plasmoid.screenGeometry.height - plasmoid.availableScreenRect.height - plasmoid.availableScreenRect.y
|
|
||||||
rightPadding: plasmoid.screenGeometry.width - plasmoid.availableScreenRect.width - plasmoid.availableScreenRect.x
|
|
||||||
closedPositionOffset: favoriteStrip.height
|
|
||||||
}
|
|
||||||
|
|
||||||
HomeScreenComponents.FavoriteStrip {
|
|
||||||
id: favoriteStrip
|
id: favoriteStrip
|
||||||
|
|
||||||
appletsLayout: homeScreenContents.appletsLayout
|
appletsLayout: homeScreenContents.appletsLayout
|
||||||
|
|
||||||
visible: flow.children.length > 0 || homeScreenContents.launcherDragManager.active || homeScreenContents.containsDrag
|
visible: flow.children.length > 0 || homeScreenContents.launcherDragManager.active || homeScreenContents.containsDrag
|
||||||
|
|
||||||
opacity: homeScreenContents.launcherDragManager.active && HomeScreenComponents.ApplicationListModel.favoriteCount >= HomeScreenComponents.ApplicationListModel.maxFavoriteCount ? 0.3 : 1
|
opacity: homeScreenContents.launcherDragManager.active && HomeScreenComponents.ApplicationListModel.favoriteCount >= HomeScreenComponents.ApplicationListModel.maxFavoriteCount ? 0.3 : 1
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
|
|
@ -162,3 +134,106 @@ FocusScope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// listview/gridview header
|
||||||
|
property int headerHeight: Math.round(PlasmaCore.Units.gridUnit * 3)
|
||||||
|
property string appDrawerType: "gridview" // gridview/listview
|
||||||
|
property alias appDrawer: appDrawerLoader.item
|
||||||
|
|
||||||
|
Plasmoid.onActivated: {
|
||||||
|
console.log("Triggered!", plasmoid.nativeInterface.showingDesktop)
|
||||||
|
|
||||||
|
// there's a couple of steps:
|
||||||
|
// - minimize windows
|
||||||
|
// - open app drawer
|
||||||
|
// - restore windows
|
||||||
|
if (!plasmoid.nativeInterface.showingDesktop) {
|
||||||
|
plasmoid.nativeInterface.showingDesktop = true
|
||||||
|
} else if (appDrawer.status !== HomeScreenComponents.AppDrawer.Status.Open) {
|
||||||
|
mainFlickable.currentIndex = 0
|
||||||
|
root.appDrawer.open()
|
||||||
|
} else {
|
||||||
|
plasmoid.nativeInterface.showingDesktop = false
|
||||||
|
root.appDrawer.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: headerComponent
|
||||||
|
PlasmaCore.ColorScope {
|
||||||
|
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.topMargin: PlasmaCore.Units.smallSpacing
|
||||||
|
anchors.leftMargin: PlasmaCore.Units.largeSpacing
|
||||||
|
anchors.rightMargin: PlasmaCore.Units.largeSpacing
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: PlasmaCore.Units.smallSpacing
|
||||||
|
|
||||||
|
PlasmaExtra.Heading {
|
||||||
|
color: "white"
|
||||||
|
level: 1
|
||||||
|
text: i18n("Applications")
|
||||||
|
}
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
PlasmaComponents.ToolButton {
|
||||||
|
icon.name: "view-list-symbolic"
|
||||||
|
implicitWidth: Math.round(PlasmaCore.Units.gridUnit * 2.1)
|
||||||
|
implicitHeight: Math.round(PlasmaCore.Units.gridUnit * 2.1)
|
||||||
|
onClicked: {
|
||||||
|
if (root.appDrawerType !== "listview") {
|
||||||
|
root.appDrawerType = "listview";
|
||||||
|
appDrawer.flickable.goToBeginning(); // jump to top
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PlasmaComponents.ToolButton {
|
||||||
|
icon.name: "view-grid-symbolic"
|
||||||
|
implicitWidth: Math.round(PlasmaCore.Units.gridUnit * 2.1)
|
||||||
|
implicitHeight: Math.round(PlasmaCore.Units.gridUnit * 2.1)
|
||||||
|
onClicked: {
|
||||||
|
if (root.appDrawerType !== "gridview") {
|
||||||
|
root.appDrawerType = "gridview";
|
||||||
|
appDrawer.flickable.goToBeginning(); // jump to top
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: listViewDrawer
|
||||||
|
HomeScreenComponents.ListViewAppDrawer {
|
||||||
|
anchors.fill: parent
|
||||||
|
topPadding: plasmoid.availableScreenRect.y
|
||||||
|
bottomPadding: plasmoid.screenGeometry.height - plasmoid.availableScreenRect.height - plasmoid.availableScreenRect.y
|
||||||
|
closedPositionOffset: favoriteStrip.height
|
||||||
|
|
||||||
|
headerItem: Loader {
|
||||||
|
sourceComponent: headerComponent
|
||||||
|
}
|
||||||
|
headerHeight: root.headerHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component {
|
||||||
|
id: gridViewDrawer
|
||||||
|
HomeScreenComponents.GridViewAppDrawer {
|
||||||
|
anchors.fill: parent
|
||||||
|
topPadding: plasmoid.availableScreenRect.y
|
||||||
|
bottomPadding: plasmoid.screenGeometry.height - plasmoid.availableScreenRect.height - plasmoid.availableScreenRect.y
|
||||||
|
closedPositionOffset: favoriteStrip.height
|
||||||
|
|
||||||
|
headerItem: Loader {
|
||||||
|
sourceComponent: headerComponent
|
||||||
|
}
|
||||||
|
headerHeight: root.headerHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: appDrawerLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
sourceComponent: appDrawerType === "gridview" ? gridViewDrawer : listViewDrawer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue