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 }