mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-29 15:03:09 +00:00
Revamp task switcher
This commit is contained in:
parent
25e0f99f43
commit
90138d5442
6 changed files with 352 additions and 380 deletions
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Marco Martin <mart@kde.org>
|
||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
|
@ -15,6 +16,7 @@ QtObject {
|
|||
signal resetHomeScreenPosition()
|
||||
signal snapHomeScreenPosition()
|
||||
signal requestRelativeScroll(point pos)
|
||||
signal setHomeScreenOpacity(int opacity)
|
||||
property Item homeScreen
|
||||
property QtObject homeScreenWindow
|
||||
property bool homeScreenVisible: true
|
||||
|
|
|
|||
|
|
@ -60,6 +60,17 @@ FocusScope {
|
|||
lastRequestedPosition = pos.y;
|
||||
}
|
||||
}
|
||||
opacity: 1
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: PlasmaCore.Units.shortDuration }
|
||||
}
|
||||
Connections {
|
||||
target: MobileShell.HomeScreenControls
|
||||
function onSetHomeScreenOpacity(opacity) {
|
||||
root.opacity = opacity;
|
||||
}
|
||||
}
|
||||
|
||||
//END API implementation
|
||||
|
||||
property bool componentComplete: false
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls 2.2 as QQC2
|
||||
|
|
@ -15,32 +16,25 @@ import org.kde.plasma.components 3.0 as PlasmaComponents
|
|||
|
||||
Item {
|
||||
id: delegate
|
||||
width: window.width/2
|
||||
height: window.height/2
|
||||
|
||||
//Workaround
|
||||
required property var model
|
||||
property bool active: model.IsActive
|
||||
readonly property point taskScreenPoint: Qt.point(model.ScreenGeometry.x, model.ScreenGeometry.y)
|
||||
onActiveChanged: {
|
||||
//sometimes the task switcher window itself appears, screwing up the state
|
||||
if (model.IsActive) {
|
||||
// window.currentTaskIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
readonly property point taskScreenPoint: Qt.point(model.ScreenGeometry.x, model.ScreenGeometry.y)
|
||||
readonly property real dragOffset: -control.y
|
||||
|
||||
property bool active: model.IsActive
|
||||
|
||||
required property real previewHeight
|
||||
required property real previewWidth
|
||||
property real scale: 1
|
||||
|
||||
opacity: 1 - dragOffset / window.height
|
||||
|
||||
Component.onCompleted: syncDelegateGeometry();
|
||||
function syncDelegateGeometry() {
|
||||
let pos = pipeWireLoader.mapToItem(tasksView, 0, 0);
|
||||
if (window.visible) {
|
||||
tasksModel.requestPublishDelegateGeometry(tasksModel.index(model.index, 0), Qt.rect(pos.x, pos.y, pipeWireLoader.width, pipeWireLoader.height), pipeWireLoader);
|
||||
} else {
|
||||
// tasksModel.requestPublishDelegateGeometry(tasksModel.index(model.index, 0), Qt.rect(pos.x, pos.y, delegate.width, delegate.height), dummyWindowTask);
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: tasksView
|
||||
onContentYChanged: {
|
||||
syncDelegateGeometry();
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
|
|
@ -49,125 +43,140 @@ Item {
|
|||
syncDelegateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
function closeApp() {
|
||||
tasksModel.requestClose(tasksModel.index(model.index, 0));
|
||||
}
|
||||
|
||||
Component.onCompleted: syncDelegateGeometry();
|
||||
|
||||
Item {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: PlasmaCore.Units.smallSpacing
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: slideAnim
|
||||
property alias to: internalSlideAnim.to
|
||||
NumberAnimation {
|
||||
id: internalSlideAnim
|
||||
target: background
|
||||
properties: "x"
|
||||
duration: PlasmaCore.Units.longDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
QQC2.Control {
|
||||
id: control
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
// drag up gesture
|
||||
DragHandler {
|
||||
id: dragHandler
|
||||
target: parent
|
||||
yAxis.enabled: true
|
||||
xAxis.enabled: false
|
||||
yAxis.maximum: 0
|
||||
onActiveChanged: {
|
||||
yAnimator.stop();
|
||||
|
||||
if (parent.y < -PlasmaCore.Units.gridUnit * 2) {
|
||||
yAnimator.to = -window.height;
|
||||
} else {
|
||||
yAnimator.to = 0;
|
||||
}
|
||||
yAnimator.start();
|
||||
}
|
||||
ScriptAction {
|
||||
script: {
|
||||
if (background.x != 0) {
|
||||
tasksModel.requestClose(tasksModel.index(model.index, 0));
|
||||
}
|
||||
}
|
||||
|
||||
NumberAnimation on y {
|
||||
id: yAnimator
|
||||
running: !dragHandler.active
|
||||
duration: PlasmaCore.Units.longDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
to: 0
|
||||
onFinished: {
|
||||
if (to != 0) { // close app
|
||||
delegate.closeApp();
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: background
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
radius: PlasmaCore.Units.smallSpacing
|
||||
color: PlasmaCore.Theme.backgroundColor
|
||||
opacity: 1 * (1-Math.abs(x)/width)
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
drag {
|
||||
target: background
|
||||
axis: Drag.XAxis
|
||||
// application
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: PlasmaCore.Units.smallSpacing
|
||||
|
||||
RowLayout {
|
||||
id: appHeader
|
||||
z: 99
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
Layout.preferredHeight: PlasmaCore.Units.iconSizes.smallMedium
|
||||
Layout.preferredWidth: PlasmaCore.Units.iconSizes.smallMedium
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
usesPlasmaTheme: false
|
||||
source: model.decoration
|
||||
}
|
||||
onPressed: delegate.z = 10;
|
||||
onClicked: {
|
||||
window.setSingleActiveWindow(model.index, delegate);
|
||||
if (!model.IsMinimized) {
|
||||
window.visible = false;
|
||||
|
||||
PlasmaComponents.Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
text: model.AppName
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: rep
|
||||
model: plasmoid.nativeInterface.outputs
|
||||
delegate: PlasmaComponents.ToolButton {
|
||||
text: model.modelName
|
||||
visible: model.position !== delegate.taskScreenPoint
|
||||
display: rep.count < 3 ? QQC2.Button.IconOnly : QQC2.Button.TextBesideIcon
|
||||
icon.name: "tv" //TODO provide a more adequate icon
|
||||
|
||||
onClicked: {
|
||||
plasmoid.nativeInterface.sendWindowToOutput(delegate.model.WinIdList[0], model.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
onReleased: {
|
||||
delegate.z = 0;
|
||||
if (Math.abs(background.x) > background.width/2) {
|
||||
slideAnim.to = background.x > 0 ? background.width*2 : -background.width*2;
|
||||
slideAnim.running = true;
|
||||
} else {
|
||||
slideAnim.to = 0;
|
||||
slideAnim.running = true;
|
||||
}
|
||||
|
||||
PlasmaComponents.ToolButton {
|
||||
z: 99
|
||||
icon.name: "window-close"
|
||||
icon.width: PlasmaCore.Units.iconSizes.smallMedium
|
||||
icon.height: PlasmaCore.Units.iconSizes.smallMedium
|
||||
onClicked: delegate.closeApp()
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: PlasmaCore.Units.smallSpacing
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.Control {
|
||||
id: appView
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
||||
Layout.preferredWidth: delegate.previewWidth
|
||||
Layout.preferredHeight: delegate.previewHeight // keep same as window resolution
|
||||
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
|
||||
transform: Scale {
|
||||
origin.x: item.width / 2
|
||||
origin.y: item.height / 2
|
||||
xScale: delegate.scale
|
||||
yScale: delegate.scale
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: PlasmaCore.Theme.backgroundColor
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
id: item
|
||||
|
||||
RowLayout {
|
||||
z: 99
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumHeight: PlasmaCore.Units.gridUnit
|
||||
PlasmaCore.IconItem {
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: height
|
||||
usesPlasmaTheme: false
|
||||
source: model.decoration
|
||||
}
|
||||
PlasmaComponents.Label {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
text: model.AppName
|
||||
color: PlasmaCore.Theme.textColor
|
||||
}
|
||||
Repeater {
|
||||
id: rep
|
||||
model: plasmoid.nativeInterface.outputs
|
||||
delegate: PlasmaComponents.ToolButton {
|
||||
text: model.modelName
|
||||
visible: model.position !== delegate.taskScreenPoint
|
||||
display: rep.count < 3 ? QQC2.Button.IconOnly : QQC2.Button.TextBesideIcon
|
||||
icon.name: "tv" //TODO provide a more adequate icon
|
||||
|
||||
onClicked: {
|
||||
plasmoid.nativeInterface.sendWindowToOutput(delegate.model.WinIdList[0], model.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
PlasmaComponents.ToolButton {
|
||||
z: 99
|
||||
icon.name: "window-close"
|
||||
icon.width: PlasmaCore.Units.iconSizes.medium
|
||||
icon.height: PlasmaCore.Units.iconSizes.medium
|
||||
onClicked: {
|
||||
slideAnim.to = -background.width*2;
|
||||
slideAnim.running = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: pipeWireLoader
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
source: Qt.resolvedUrl("./Thumbnail.qml")
|
||||
anchors.fill: parent
|
||||
source: /*Qt.resolvedUrl("./TaskIcon.qml");*/ Qt.resolvedUrl("./Thumbnail.qml")
|
||||
onStatusChanged: {
|
||||
if (status === Loader.Error) {
|
||||
source = Qt.resolvedUrl("./TaskIcon.qml");
|
||||
}
|
||||
}
|
||||
}
|
||||
TapHandler {
|
||||
onTapped: {
|
||||
window.setSingleActiveWindow(model.index, delegate);
|
||||
window.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import org.kde.plasma.core 2.0 as PlasmaCore
|
|||
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
implicitWidth: PlasmaCore.Units.iconSizes.medium
|
||||
implicitHeight: PlasmaCore.Units.iconSizes.medium
|
||||
usesPlasmaTheme: false
|
||||
source: model.decoration
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
|
@ -19,18 +20,31 @@ NanoShell.FullScreenOverlay {
|
|||
visible: false
|
||||
width: Screen.width
|
||||
height: Screen.height
|
||||
property int offset: 0
|
||||
property int overShoot: PlasmaCore.Units.gridUnit * 2
|
||||
|
||||
required property bool gestureDragging
|
||||
required property real panelHeight // height of task panel, provided by main.qml
|
||||
|
||||
property int tasksCount: window.model.count
|
||||
property int currentTaskIndex: -1
|
||||
property int currentTaskIndex: tasksView.contentX / (tasksView.width + tasksView.spacing)
|
||||
property TaskManager.TasksModel model
|
||||
|
||||
property real offset: 0
|
||||
|
||||
Component.onCompleted: plasmoid.nativeInterface.panel = window;
|
||||
|
||||
enum MovementDirection {
|
||||
None = 0,
|
||||
Up,
|
||||
Down
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
window.contentItem.opacity = 1;
|
||||
}
|
||||
// hide homescreen elements to make use of wallpaper
|
||||
MobileShell.HomeScreenControls.setHomeScreenOpacity(visible ? 0 : 1);
|
||||
MobileShell.HomeScreenControls.taskSwitcherVisible = visible;
|
||||
}
|
||||
|
||||
onTasksCountChanged: {
|
||||
|
|
@ -38,38 +52,35 @@ NanoShell.FullScreenOverlay {
|
|||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
color: "transparent"
|
||||
// More controllable than the color property
|
||||
|
||||
Rectangle {
|
||||
id: backgroundRect
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(0, 0, 0, 0.6)
|
||||
opacity: Math.min(
|
||||
(Math.min(tasksView.contentY, tasksView.height) / tasksView.height),
|
||||
((tasksView.contentHeight - tasksView.contentY - window.height) / tasksView.height))
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: hide()
|
||||
}
|
||||
}
|
||||
|
||||
function show() {
|
||||
if (window.model.count == 0) {
|
||||
return;
|
||||
window.offset = 0;
|
||||
// skip to first active task
|
||||
if (window.model.activeTask.row >= 0) {
|
||||
tasksView.contentX = window.model.activeTask.row * (tasksView.width + tasksView.spacing);
|
||||
}
|
||||
|
||||
visible = true;
|
||||
scrollAnim.from = tasksView.contentY;
|
||||
scrollAnim.to = window.height;
|
||||
scrollAnim.restart();
|
||||
|
||||
root.minimizeAll();
|
||||
window.visible = true;
|
||||
}
|
||||
function hide() {
|
||||
if (!window.visible) {
|
||||
return;
|
||||
}
|
||||
scrollAnim.from = tasksView.contentY;
|
||||
|
||||
if (tasksView.contentY + window.height <= tasksView.contentHeight - tasksView.contentY) {
|
||||
scrollAnim.to = 0;
|
||||
} else {
|
||||
scrollAnim.to = tasksView.contentHeight - window.height;
|
||||
}
|
||||
scrollAnim.restart();
|
||||
window.visible = false;
|
||||
}
|
||||
|
||||
function setSingleActiveWindow(id, delegate) {
|
||||
|
|
@ -91,232 +102,179 @@ NanoShell.FullScreenOverlay {
|
|||
}
|
||||
}
|
||||
}
|
||||
activateAnim.delegate = delegate;
|
||||
activateAnim.restart();
|
||||
|
||||
window.visible = false;
|
||||
}
|
||||
|
||||
onOffsetChanged: tasksView.contentY = offset + grid.y
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
tasksView.contentY = 0;
|
||||
moveTransition.enabled = false;
|
||||
scrollAnim.running = false;
|
||||
activateAnim.running = false;
|
||||
window.contentItem.opacity = 1;
|
||||
if (activateAnim.delegate) {
|
||||
activateAnim.delegate.z = 0;
|
||||
activateAnim.delegate.scale = 1;
|
||||
|
||||
//Rectangle {
|
||||
//id: liveAppShrink
|
||||
//anchors.fill: parent
|
||||
//anchors.topMargin: MobileShell.TopPanelControls.panelHeight
|
||||
//anchors.bottomMargin: window.panelHeight
|
||||
|
||||
//// visible: window.gestureDragging
|
||||
//z: tasksView.z + 1
|
||||
//color: Qt.rgba(255, 255, 255, 0.1)
|
||||
|
||||
//transform: Scale {
|
||||
//origin.x: window.width / 2
|
||||
//origin.y: MobileShell.TopPanelControls.panelHeight + liveAppShrink.height / 2
|
||||
//xScale: {
|
||||
//let minScale = tasksView.scalingFactor;
|
||||
//let travelDist = window.height - tasksView.height;
|
||||
//let subtract = (1 - minScale) * (window.offset / travelDist);
|
||||
//return Math.min(1, Math.max(minScale, 1 - subtract));
|
||||
//}
|
||||
//yScale: xScale
|
||||
//}
|
||||
|
||||
//Loader {
|
||||
//id: pipeWireLoader
|
||||
//anchors.fill: parent
|
||||
|
||||
//z: tasksView.z + 1
|
||||
//source: Qt.resolvedUrl("./Thumbnail.qml")
|
||||
//onStatusChanged: {
|
||||
//if (status === Loader.Error) {
|
||||
//visible = false;
|
||||
//}
|
||||
//}
|
||||
|
||||
//function syncDelegateGeometry() {
|
||||
//window.model.requestPublishDelegateGeometry(window.model.activeTask, Qt.rect(parent.x, parent.y, pipeWireLoader.width, pipeWireLoader.height), pipeWireLoader);
|
||||
//}
|
||||
//Component.onCompleted: syncDelegateGeometry();
|
||||
//Connections {
|
||||
//target: window.model
|
||||
//function onActiveTaskChanged() {
|
||||
//pipeWireLoader.syncDelegateGeometry();
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
ListView {
|
||||
id: tasksView
|
||||
z: 100
|
||||
|
||||
property real horizontalMargin: PlasmaCore.Units.gridUnit * 3
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: window.width - horizontalMargin * 2
|
||||
height: window.height - (MobileShell.TopPanelControls.panelHeight + window.panelHeight + footerButtons.height
|
||||
+ PlasmaCore.Units.gridUnit * 2 + PlasmaCore.Units.largeSpacing * 2)
|
||||
|
||||
// ensure that window previews are exactly to the scale of the device screen
|
||||
property real windowHeight: window.height - window.panelHeight - MobileShell.TopPanelControls.panelHeight
|
||||
property real scalingFactor: {
|
||||
let candidateWidth = tasksView.width;
|
||||
let candidateHeight = (tasksView.width / window.width) * windowHeight;
|
||||
|
||||
if (candidateHeight > tasksView.height) {
|
||||
return tasksView.height / windowHeight;
|
||||
} else {
|
||||
return tasksView.width / window.width;
|
||||
}
|
||||
}
|
||||
MobileShell.HomeScreenControls.taskSwitcherVisible = visible;
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: scrollAnim
|
||||
property alias to: internalAnim.to
|
||||
property alias from: internalAnim.from
|
||||
ScriptAction {
|
||||
script: window.showFullScreen();
|
||||
|
||||
model: window.model
|
||||
snapMode: ListView.SnapToItem
|
||||
orientation: ListView.Horizontal
|
||||
spacing: PlasmaCore.Units.largeSpacing
|
||||
displayMarginBeginning: 2 * (width + spacing)
|
||||
displayMarginEnd: 2 * (width + spacing)
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation { properties: "x,y"; duration: PlasmaCore.Units.longDuration; easing.type: Easing.InOutQuad }
|
||||
}
|
||||
NumberAnimation {
|
||||
id: internalAnim
|
||||
target: tasksView
|
||||
properties: "contentY"
|
||||
duration: PlasmaCore.Units.longDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
ScriptAction {
|
||||
script: {
|
||||
if (tasksView.contentY <= 0 || tasksView.contentY >= tasksView.contentHeight - window.height) {
|
||||
window.visible = false;
|
||||
setSingleActiveWindow(currentTaskIndex);
|
||||
} else {
|
||||
moveTransition.enabled = true;
|
||||
|
||||
property real offset: 0
|
||||
property real currentIndexInView: indexAt(contentX, contentY)
|
||||
|
||||
MouseArea {
|
||||
z: -1
|
||||
anchors.fill: parent
|
||||
visible: tasksView.count === 0
|
||||
enabled: visible
|
||||
onClicked: { // close window on tap if there are no delegates
|
||||
if (tasksView.count === 0) {
|
||||
window.hide()
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
anchors.centerIn: parent
|
||||
text: i18n("No applications are open")
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Task {
|
||||
id: task
|
||||
property int curIndex: model.index
|
||||
width: tasksView.width
|
||||
height: tasksView.height
|
||||
|
||||
// ensure that window previews are exactly to the scale of the device screen
|
||||
previewWidth: tasksView.scalingFactor * window.width
|
||||
previewHeight: tasksView.scalingFactor * tasksView.windowHeight
|
||||
|
||||
scale: {
|
||||
if (task.curIndex === window.currentTaskIndex) {
|
||||
let maxScale = 1 / tasksView.scalingFactor;
|
||||
let travelDist = window.height - tasksView.height;
|
||||
let subtract = (maxScale - 1) * (window.offset / travelDist);
|
||||
let finalScale = Math.max(1, Math.min(maxScale, maxScale - subtract));
|
||||
|
||||
return finalScale;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
onDragOffsetChanged: tasksView.offset = dragOffset
|
||||
|
||||
// TODO slide right animation
|
||||
//transform: Translate {
|
||||
//x: task.curIndex < tasksView.currentIndexInView ? Math.min(task.width + tasksView.spacing, tasksView.offset / 2) : 0
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: activateAnim
|
||||
property Item delegate
|
||||
ScriptAction {
|
||||
script: {
|
||||
activateAnim.delegate.z = 2;
|
||||
let pos = tasksView.mapFromItem(activateAnim.delegate, 0, 0);
|
||||
if (pos.x < tasksView.width / 2 && pos.y < tasksView.height / 2) {
|
||||
activateAnim.delegate.transformOrigin = Item.TopLeft;
|
||||
} else if (pos.x < tasksView.width / 2 && pos.y >= tasksView.height / 2) {
|
||||
activateAnim.delegate.transformOrigin = Item.BottomLeft;
|
||||
} else if (pos.x >= tasksView.width / 2 && pos.y < tasksView.height / 2) {
|
||||
activateAnim.delegate.transformOrigin = Item.TopRight;
|
||||
} else {
|
||||
activateAnim.delegate.transformOrigin = Item.BottomRight;
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
id: footerButtons
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: PlasmaCore.Units.largeSpacing + window.panelHeight
|
||||
anchors.topMargin: PlasmaCore.Units.largeSpacing
|
||||
|
||||
spacing: PlasmaCore.Units.largeSpacing
|
||||
|
||||
PlasmaComponents.ToolButton {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
icon.width: PlasmaCore.Units.iconSizes.medium
|
||||
icon.height: PlasmaCore.Units.iconSizes.medium
|
||||
icon.name: "view-list-symbolic" // "view-grid-symbolic"
|
||||
text: i18n("Switch to list view")
|
||||
display: PlasmaComponents.ToolButton.IconOnly
|
||||
}
|
||||
ParallelAnimation {
|
||||
OpacityAnimator {
|
||||
target: window.contentItem
|
||||
from: 1
|
||||
to: 0
|
||||
duration: PlasmaCore.Units.longDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
ScaleAnimator {
|
||||
target: activateAnim.delegate
|
||||
from: 1
|
||||
to: 2
|
||||
// To try tosync up with kwin animation
|
||||
duration: PlasmaCore.Units.longDuration * 0.85
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
|
||||
PlasmaComponents.ToolButton {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
icon.width: PlasmaCore.Units.iconSizes.medium
|
||||
icon.height: PlasmaCore.Units.iconSizes.medium
|
||||
icon.name: "trash-empty"
|
||||
text: i18n("Clear All")
|
||||
display: PlasmaComponents.ToolButton.IconOnly
|
||||
}
|
||||
ScriptAction {
|
||||
script: {
|
||||
window.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: tasksView
|
||||
width: window.width
|
||||
height: window.height
|
||||
contentWidth: width
|
||||
contentHeight: mainArea.implicitHeight
|
||||
// topMargin: flickingVertically ? -height : 0
|
||||
// bottomMargin: flickingVertically ? -height : 0
|
||||
property int flickState: TaskSwitcher.MovementDirection.None
|
||||
|
||||
readonly property int movementDirection: {
|
||||
if (flickState != TaskSwitcher.MovementDirection.None) {
|
||||
return flickState;
|
||||
} else if (verticalVelocity < 0) {
|
||||
return TaskSwitcher.MovementDirection.Up;
|
||||
} else if (verticalVelocity > 0) {
|
||||
return TaskSwitcher.MovementDirection.Down;
|
||||
} else {
|
||||
return TaskSwitcher.MovementDirection.None;
|
||||
}
|
||||
}
|
||||
|
||||
onFlickingVerticallyChanged: {
|
||||
if (flickingVertically) {
|
||||
flickState = verticalVelocity < 0 ? TaskSwitcher.MovementDirection.Up : TaskSwitcher.MovementDirection.Down;
|
||||
} else if (/*!draggingVertically &&*/ !flickingVertically) {
|
||||
flickState = TaskSwitcher.MovementDirection.None
|
||||
}
|
||||
Qt.callLater(function() {
|
||||
tasksView.topMargin = flickingVertically && !scrollAnim.running ? -tasksView.height : 0;
|
||||
tasksView.bottomMargin = tasksView.topMargin;
|
||||
});
|
||||
}
|
||||
|
||||
onDraggingVerticallyChanged: {
|
||||
if (draggingVertically) {
|
||||
return;
|
||||
}
|
||||
|
||||
let beforeBeginning = contentY < window.height;
|
||||
let afterEnd = contentY > contentHeight - window.height * 2;
|
||||
|
||||
let topCloseCondition = contentY < window.height / 10 * 9;
|
||||
let bottomClosecondition = contentY > contentHeight - window.height * 2 - window.height / 10;
|
||||
|
||||
switch (movementDirection) {
|
||||
case TaskSwitcher.MovementDirection.Up: {
|
||||
if (topCloseCondition) {
|
||||
hide();
|
||||
} else if (beforeBeginning) {
|
||||
show();
|
||||
} else if (afterEnd) {
|
||||
scrollAnim.from = tasksView.contentY;
|
||||
scrollAnim.to = tasksView.contentHeight - window.height * 2;
|
||||
scrollAnim.restart();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TaskSwitcher.MovementDirection.Down: {
|
||||
if (bottomClosecondition) {
|
||||
hide();
|
||||
} else if (beforeBeginning) {
|
||||
show();
|
||||
} else if (afterEnd) {
|
||||
scrollAnim.from = tasksView.contentY;
|
||||
scrollAnim.to = tasksView.contentHeight - window.height * 2;
|
||||
scrollAnim.restart();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TaskSwitcher.MovementDirection.None:
|
||||
default:
|
||||
if (beforeBeginning) {
|
||||
show();
|
||||
} else if (afterEnd) {
|
||||
scrollAnim.from = tasksView.contentY;
|
||||
scrollAnim.to = tasksView.contentHeight - window.height * 2;
|
||||
scrollAnim.restart();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mainArea
|
||||
parent: tasksView.contentItem
|
||||
width: tasksView.width
|
||||
implicitHeight: window.height * 2 + Math.max(window.height, grid.implicitHeight)
|
||||
onClicked: window.hide()
|
||||
|
||||
Grid {
|
||||
id: grid
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
columns: 2
|
||||
y: parent.height - height - window.height
|
||||
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: PlasmaCore.Units.longDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
Repeater {
|
||||
model: window.model
|
||||
delegate: Task {}
|
||||
}
|
||||
|
||||
move: Transition {
|
||||
id: moveTransition
|
||||
enabled: false
|
||||
NumberAnimation {
|
||||
properties: "x,y"
|
||||
duration: PlasmaCore.Units.longDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PlasmaComponents.RoundButton {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
bottom: parent.bottom
|
||||
}
|
||||
icon.name: "start-here-kde"
|
||||
icon.width: PlasmaCore.Units.iconSizes.medium
|
||||
icon.height: PlasmaCore.Units.iconSizes.medium
|
||||
onClicked: {
|
||||
currentTaskIndex = -1;
|
||||
window.hide();
|
||||
//plasmoid.nativeInterface.showDesktop = true;
|
||||
|
||||
root.minimizeAll();
|
||||
|
||||
PlasmaComponents.ToolButton {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
icon.width: PlasmaCore.Units.iconSizes.medium
|
||||
icon.height: PlasmaCore.Units.iconSizes.medium
|
||||
icon.name: "system-search"
|
||||
text: i18n("Search")
|
||||
display: PlasmaComponents.ToolButton.IconOnly
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
|
||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
|
@ -46,7 +47,7 @@ PlasmaCore.ColorScope {
|
|||
running: true
|
||||
interval: 200
|
||||
onTriggered: {
|
||||
taskSwitcherLoader.setSource(Qt.resolvedUrl("TaskSwitcher.qml"), {"model": tasksModel});
|
||||
taskSwitcherLoader.setSource(Qt.resolvedUrl("TaskSwitcher.qml"), {"model": tasksModel, "panelHeight": root.height, "gestureDragging": mainMouseArea.pressed});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,8 +78,6 @@ PlasmaCore.ColorScope {
|
|||
|
||||
virtualDesktop: virtualDesktopInfo.currentDesktop
|
||||
activity: activityInfo.currentActivity
|
||||
//FIXME: workaround
|
||||
Component.onCompleted: tasksModel.countChanged();
|
||||
}
|
||||
|
||||
TaskManager.VirtualDesktopInfo {
|
||||
|
|
@ -104,7 +103,6 @@ PlasmaCore.ColorScope {
|
|||
onPressed: {
|
||||
startMouseX = oldMouseX = mouse.y;
|
||||
startMouseY = oldMouseY = mouse.y;
|
||||
taskSwitcher.offset = -taskSwitcher.height;
|
||||
activeButton = icons.childAt(mouse.x, mouse.y);
|
||||
}
|
||||
onPositionChanged: {
|
||||
|
|
@ -119,18 +117,18 @@ PlasmaCore.ColorScope {
|
|||
isDragging = true;
|
||||
}
|
||||
|
||||
taskSwitcher.offset = taskSwitcher.offset - (mouse.y - oldMouseY);
|
||||
taskSwitcher.offset = Math.max(0, taskSwitcher.offset - (mouse.y - oldMouseY));
|
||||
opening = oldMouseY > mouse.y;
|
||||
|
||||
if (taskSwitcher.visibility == Window.Hidden && taskSwitcher.offset > -taskSwitcher.height + units.gridUnit && taskSwitcher.tasksCount) {
|
||||
if (taskSwitcher.visibility == Window.Hidden && Math.abs(startMouseY - mouse.y) > PlasmaCore.Units.gridUnit && taskSwitcher.tasksCount) {
|
||||
activeButton = null;
|
||||
taskSwitcher.showFullScreen();
|
||||
//no tasks, let's scroll up the homescreen instead
|
||||
taskSwitcher.show();
|
||||
} else if (taskSwitcher.tasksCount === 0) {
|
||||
//no tasks, let's scroll up the homescreen instead
|
||||
MobileShell.HomeScreenControls.requestRelativeScroll(Qt.point(mouse.x - oldMouseX, mouse.y - oldMouseY));
|
||||
}
|
||||
oldMouseY = mouse.y;
|
||||
oldMouseY = mouse.y;
|
||||
oldMouseX = mouse.x;
|
||||
}
|
||||
onReleased: {
|
||||
if (taskSwitcher.visibility == Window.Hidden) {
|
||||
|
|
@ -172,19 +170,11 @@ PlasmaCore.ColorScope {
|
|||
|
||||
visible: plasmoid.configuration.PanelButtonsVisible
|
||||
property real buttonLength: 0
|
||||
|
||||
|
||||
// background colour
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0
|
||||
color: showingApp ? root.backgroundColor : "transparent"
|
||||
}
|
||||
GradientStop {
|
||||
position: 1
|
||||
color: showingApp ? root.backgroundColor : Qt.rgba(0, 0, 0, 0.1)
|
||||
}
|
||||
}
|
||||
color: showingApp ? root.backgroundColor : "transparent"
|
||||
}
|
||||
|
||||
Button {
|
||||
|
|
@ -213,6 +203,7 @@ PlasmaCore.ColorScope {
|
|||
}
|
||||
root.minimizeAll();
|
||||
MobileShell.HomeScreenControls.resetHomeScreenPosition();
|
||||
MobileShell.HomeScreenControls.setHomeScreenOpacity(1);
|
||||
plasmoid.nativeInterface.allMinimizedChanged();
|
||||
}
|
||||
iconSizeFactor: 1
|
||||
|
|
@ -253,7 +244,6 @@ PlasmaCore.ColorScope {
|
|||
return;
|
||||
|
||||
Window.window.offset = Qt.binding(() => {
|
||||
// FIXME: find a more precise way to determine the top panel height
|
||||
return plasmoid.formFactor === PlasmaCore.Types.Vertical ? MobileShell.TopPanelControls.panelHeight : 0
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue