Warning, /plasma/plasma-mobile/kwin/mobiletaskswitcher/qml/TaskSwitcherState.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
0002 // SPDX-License-Identifier: GPL-2.0-or-later
0003
0004 import QtQuick 2.15
0005
0006 import org.kde.kirigami 2.20 as Kirigami
0007
0008 import org.kde.kwin 3.0 as KWinComponents
0009
0010 /**
0011 * State object for the task switcher.
0012 */
0013 QtObject {
0014 id: root
0015
0016 // TaskSwitcher item component
0017 // We assume that the taskSwitcher the size of the entire screen.
0018 required property var taskSwitcher
0019
0020
0021 // ~~ positioning ~~
0022
0023 // Position of the list view:
0024 //
0025 // xPosition:
0026 // We start at 0, which is the position at which the first task in the task switcher is centered on the screen.
0027 // Decreasing xPosition results in the task switcher moving forward (to the second task, third task, etc), being the layout direction Right to Left.
0028 //
0029 // yPosition:
0030 // 0 - Start of swipe up gesture, if window was showing, the thumbnail is the size of it
0031 // Increasing yPosition results in the task switcher moving up (and thumbnails shrinking)
0032 property real xPosition: 0
0033 property real yPosition: 0
0034
0035 // direction of the movement
0036 property bool movingRight: false
0037 property bool movingUp: false
0038
0039 // used for calculating movement direction
0040 property real oldXPosition: 0
0041 property real oldYPosition: 0
0042 onXPositionChanged: {
0043 movingRight = xPosition < oldXPosition;
0044 oldXPosition = xPosition;
0045 }
0046 onYPositionChanged: {
0047 movingUp = yPosition > oldYPosition;
0048 oldYPosition = yPosition;
0049 }
0050
0051 // yPosition when the task switcher is completely open
0052 readonly property real openedYPosition: (taskSwitcher.height - taskHeight) / 2
0053
0054 // ~~ active state ~~
0055
0056 // whether the user was in an active task before the task switcher was opened
0057 property bool wasInActiveTask: false
0058
0059 // whether we are in a swipe up gesture to open the task switcher
0060 property bool currentlyBeingOpened: true // assume that task switcher is loaded on open
0061
0062 // whether the task switcher is being closed: an animation is running
0063 property bool currentlyBeingClosed: false
0064
0065 // whether we are in a swipe left/right gesture to walk through tasks
0066 property bool scrollingTasks: false
0067
0068 readonly property int currentTaskIndex: {
0069 let candidateIndex = Math.round(-xPosition / (taskSpacing + taskWidth));
0070 return Math.max(0, Math.min(taskSwitcher.tasksCount - 1, candidateIndex));
0071 }
0072
0073 // ~~ measurement constants ~~
0074
0075 // dimensions of a real window on the screen
0076 readonly property real windowHeight: taskSwitcher.height - taskSwitcher.topMargin - taskSwitcher.bottomMargin
0077 readonly property real windowWidth: taskSwitcher.width - taskSwitcher.leftMargin - taskSwitcher.rightMargin
0078
0079 // dimensions of the task previews
0080 readonly property real previewHeight: windowHeight * scalingFactor
0081 readonly property real previewWidth: windowWidth * scalingFactor
0082 readonly property real taskHeight: previewHeight + taskHeaderHeight
0083 readonly property real taskWidth: previewWidth
0084
0085 // spacing between each task preview
0086 readonly property real taskSpacing: Kirigami.Units.gridUnit
0087
0088 // height of the task preview header
0089 readonly property real taskHeaderHeight: Kirigami.Units.gridUnit * 2 + Kirigami.Units.smallSpacing * 2
0090
0091 // the scaling factor of the window preview compared to the actual window
0092 // we need to ensure that window previews always fit on screen
0093 readonly property real scalingFactor: {
0094 let candidateFactor = 0.6;
0095 let candidateTaskHeight = windowHeight * candidateFactor + taskHeaderHeight;
0096 let candidateTaskWidth = windowWidth * candidateFactor;
0097
0098 let candidateHeight = (candidateTaskWidth / windowWidth) * windowHeight;
0099 if (candidateHeight > windowHeight) {
0100 return candidateTaskHeight / windowHeight;
0101 } else {
0102 return candidateTaskWidth / windowWidth;
0103 }
0104 }
0105
0106 // scale of the task list (based on the progress of the swipe up gesture)
0107 readonly property real currentScale: {
0108 let maxScale = 1 / scalingFactor;
0109 let subtract = (maxScale - 1) * (yPosition / openedYPosition);
0110 let finalScale = Math.max(0, Math.min(maxScale, maxScale - subtract));
0111
0112 // animate scale only if we are *not* opening from the homescreen
0113 if ((wasInActiveTask || !currentlyBeingOpened) && !scrollingTasks) {
0114 return finalScale;
0115 }
0116 return scrollingTasks ? maxScale : 1;
0117 }
0118
0119 // ~~ signals and functions ~~
0120
0121 // cancel all animated moving, as another flick source is taking over
0122 signal cancelAnimations()
0123 onCancelAnimations: {
0124 openAnim.stop();
0125 openAppAnim.stop();
0126 closeAnim.stop();
0127 xAnim.stop();
0128 }
0129
0130 function open() {
0131 openAnim.restart();
0132 }
0133
0134 function close() {
0135 closeAnim.restart();
0136 }
0137
0138 function openApp(index, window) {
0139 animateGoToTaskIndex(index, Kirigami.Units.shortDuration);
0140 openAppAnim.restart();
0141 KWinComponents.Workspace.activeWindow = window
0142 }
0143
0144 // get the xPosition where the task will be centered on the screen
0145 function xPositionFromTaskIndex(index) {
0146 return -index * (taskWidth + taskSpacing);
0147 }
0148
0149 // instantly go to the task index
0150 function goToTaskIndex(index) {
0151 xPosition = xPositionFromTaskIndex(index);
0152 }
0153
0154 // go to the task index, animated
0155 function animateGoToTaskIndex(index, duration) {
0156 xAnim.duration = duration;
0157 xAnim.to = xPositionFromTaskIndex(index);
0158 xAnim.restart();
0159 }
0160
0161 // called after a user finishes an interaction (ex. lets go of the screen)
0162 function updateState() {
0163 cancelAnimations();
0164
0165 // update vertical state
0166 if ((movingUp || root.yPosition >= openedYPosition) && !scrollingTasks) {
0167 // open task switcher and stay
0168 openAnim.restart();
0169 } else {
0170 // close task switcher and return to app
0171 closeAnim.restart();
0172 }
0173
0174 // update horizontal state
0175 let duration = Kirigami.Units.longDuration * 2;
0176 if (currentlyBeingOpened) {
0177 animateGoToTaskIndex(currentTaskIndex, duration);
0178 } else {
0179 let currentTaskIndexPosition = xPositionFromTaskIndex(currentTaskIndex);
0180 if (xPosition > currentTaskIndexPosition) {
0181 if (movingRight) {
0182 animateGoToTaskIndex(currentTaskIndex, duration);
0183 } else {
0184 animateGoToTaskIndex(Math.max(0, currentTaskIndex - 1), duration);
0185 }
0186 } else {
0187 if (movingRight) {
0188 animateGoToTaskIndex(Math.min(taskSwitcher.tasksCount - 1, currentTaskIndex + 1), duration);
0189 } else {
0190 animateGoToTaskIndex(currentTaskIndex, duration);
0191 }
0192 }
0193 }
0194 }
0195
0196 // ~~ property animators ~~
0197
0198 property var xAnim: NumberAnimation {
0199 target: root
0200 property: "xPosition"
0201 easing.type: Easing.OutBack
0202 }
0203
0204 property var openAnim: NumberAnimation {
0205 target: root
0206 property: "yPosition"
0207 to: openedYPosition
0208 duration: 300
0209 easing.type: Easing.OutBack
0210
0211 onFinished: {
0212 root.currentlyBeingOpened = false;
0213 }
0214 }
0215
0216 property var closeAnim: NumberAnimation {
0217 target: root
0218 property: "yPosition"
0219 to: 0
0220 duration: Kirigami.Units.longDuration
0221 easing.type: Easing.InOutQuad
0222
0223 onStarted: root.currentlyBeingClosed = true
0224
0225 onFinished: {
0226 root.currentlyBeingClosed = false;
0227 root.currentlyBeingOpened = false;
0228 scrollingTasks = false;
0229 taskSwitcher.instantHide();
0230 }
0231 }
0232
0233 property var openAppAnim: NumberAnimation {
0234 target: root
0235 property: "yPosition"
0236 to: 0
0237 duration: 300
0238 easing.type: Easing.OutQuint
0239
0240 onStarted: root.currentlyBeingClosed = true
0241
0242 onFinished: {
0243 root.currentlyBeingClosed = false;
0244 root.currentlyBeingOpened = false;
0245 taskSwitcher.instantHide();
0246 }
0247 }
0248 }