Warning, /plasma/plasma-mobile/kwin/mobiletaskswitcher/qml/TaskSwitcher.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com> 0002 // SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org> 0003 // SPDX-License-Identifier: GPL-2.0-or-later 0004 0005 import QtQuick 0006 import QtQuick.Layouts 0007 0008 import org.kde.kirigami 2.20 as Kirigami 0009 import org.kde.plasma.core as PlasmaCore 0010 import org.kde.plasma.components 3.0 as PlasmaComponents 0011 import org.kde.plasma.private.mobileshell as MobileShell 0012 import org.kde.plasma.private.mobileshell.state as MobileShellState 0013 import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings 0014 0015 import org.kde.kwin 3.0 as KWinComponents 0016 import org.kde.kwin.private.effects 1.0 0017 0018 /** 0019 * Component that provides a task switcher. 0020 */ 0021 FocusScope { 0022 id: root 0023 focus: true 0024 0025 readonly property QtObject effect: KWinComponents.SceneView.effect 0026 readonly property QtObject targetScreen: KWinComponents.SceneView.screen 0027 0028 readonly property bool inLandscape: width > height; 0029 readonly property bool isInLandscapeNavPanelMode: inLandscape && ShellSettings.Settings.navigationPanelEnabled 0030 0031 readonly property real topMargin: MobileShell.Constants.topPanelHeight 0032 readonly property real bottomMargin: isInLandscapeNavPanelMode ? 0 : MobileShell.Constants.bottomPanelHeight 0033 readonly property real leftMargin: 0 0034 readonly property real rightMargin: isInLandscapeNavPanelMode ? MobileShell.Constants.bottomPanelHeight : 0 0035 0036 property var taskSwitcherState: TaskSwitcherState { 0037 taskSwitcher: root 0038 } 0039 0040 KWinComponents.WindowModel { 0041 id: stackModel 0042 } 0043 0044 KWinComponents.VirtualDesktopModel { 0045 id: desktopModel 0046 } 0047 0048 property var tasksModel: KWinComponents.WindowFilterModel { 0049 activity: KWinComponents.Workspace.currentActivity 0050 desktop: KWinComponents.Workspace.currentDesktop 0051 screenName: root.targetScreen.name 0052 windowModel: stackModel 0053 minimizedWindows: true 0054 windowType: ~KWinComponents.WindowFilterModel.Dock & 0055 ~KWinComponents.WindowFilterModel.Desktop & 0056 ~KWinComponents.WindowFilterModel.Notification & 0057 ~KWinComponents.WindowFilterModel.CriticalNotification 0058 } 0059 0060 readonly property int tasksCount: taskList.count 0061 0062 // keep track of task list events 0063 property int oldTasksCount: tasksCount 0064 onTasksCountChanged: { 0065 if (tasksCount === 0 && oldTasksCount !== 0) { 0066 hide(); 0067 } else if (tasksCount < oldTasksCount && taskSwitcherState.currentTaskIndex >= tasksCount - 1) { 0068 // if the user is on the last task, and it is closed, scroll left 0069 taskSwitcherState.animateGoToTaskIndex(tasksCount - 1, Kirigami.Units.longDuration); 0070 } 0071 0072 oldTasksCount = tasksCount; 0073 } 0074 0075 Keys.onEscapePressed: hide(); 0076 0077 Component.onCompleted: { 0078 taskList.jumpToFirstVisibleWindow(); 0079 taskList.minimizeAll(); 0080 0081 // fully open the panel (if this is a button press, not gesture) 0082 if (!root.effect.gestureInProgress) { 0083 taskSwitcherState.open(); 0084 } 0085 } 0086 0087 // called by c++ plugin 0088 function hideAnimation() { 0089 closeAnim.restart(); 0090 } 0091 0092 function instantHide() { 0093 root.effect.deactivate(true); 0094 } 0095 0096 function hide() { 0097 root.effect.deactivate(false); 0098 } 0099 0100 // scroll to delegate index, and activate it 0101 function activateWindow(index, window) { 0102 KWinComponents.Workspace.activeWindow = window; 0103 taskSwitcherState.openApp(index, window); 0104 } 0105 0106 Connections { 0107 target: root.effect 0108 0109 function onPartialActivationFactorChanged() { 0110 taskSwitcherState.yPosition = taskSwitcherState.openedYPosition * root.effect.partialActivationFactor; 0111 } 0112 0113 function onGestureInProgressChanged() { 0114 if (!root.effect.gestureInProgress) { 0115 taskSwitcherState.updateState(); 0116 } 0117 } 0118 } 0119 0120 // view of the desktop background 0121 KWinComponents.DesktopBackground { 0122 id: backgroundItem 0123 activity: KWinComponents.Workspace.currentActivity 0124 desktop: KWinComponents.Workspace.currentDesktop 0125 outputName: targetScreen.name 0126 } 0127 0128 // background colour 0129 Rectangle { 0130 id: backgroundRect 0131 anchors.fill: parent 0132 0133 opacity: container.opacity 0134 color: { 0135 // animate background colour only if we are *not* opening from the homescreen 0136 if (taskSwitcherState.wasInActiveTask || !taskSwitcherState.currentlyBeingOpened) { 0137 return Qt.rgba(0, 0, 0, 0.6); 0138 } else { 0139 return Qt.rgba(0, 0, 0, 0.6 * Math.min(1, taskSwitcherState.yPosition / taskSwitcherState.openedYPosition)); 0140 } 0141 } 0142 } 0143 0144 // status bar 0145 // TODO: improve load times, it is quite slow 0146 // MobileShell.StatusBar { 0147 // id: statusBar 0148 // z: 1 0149 // colorGroup: Kirigami.Theme.ComplementaryColorGroup 0150 // backgroundColor: "transparent" 0151 // 0152 // height: root.topMargin 0153 // anchors.top: parent.top 0154 // anchors.left: parent.left 0155 // anchors.right: parent.right 0156 // } 0157 0158 // navigation panel 0159 MobileShell.NavigationPanel { 0160 id: navigationPanel 0161 z: 1 0162 visible: ShellSettings.Settings.navigationPanelEnabled 0163 backgroundColor: Qt.rgba(0, 0, 0, 0.1) 0164 foregroundColorGroup: Kirigami.Theme.Complementary 0165 shadow: false 0166 0167 isVertical: MobileShell.Constants.navigationPanelOnSide(root.width, root.height) 0168 0169 leftAction: MobileShell.NavigationPanelAction { 0170 enabled: true 0171 iconSource: "mobile-task-switcher" 0172 iconSizeFactor: 0.75 0173 0174 onTriggered: { 0175 if (taskList.count === 0) { 0176 root.hide(); 0177 } else { 0178 const currentIndex = taskSwitcherState.currentTaskIndex; 0179 taskSwitcherState.openApp(taskSwitcherState.currentTaskIndex, taskList.getTaskAt(currentIndex).window); 0180 } 0181 } 0182 } 0183 0184 // home button 0185 middleAction: MobileShell.NavigationPanelAction { 0186 enabled: true 0187 iconSource: "start-here-kde" 0188 iconSizeFactor: 1 0189 onTriggered: root.hide() 0190 } 0191 0192 // close app/keyboard button 0193 rightAction: MobileShell.NavigationPanelAction { 0194 enabled: true 0195 iconSource: "mobile-close-app" 0196 iconSizeFactor: 0.75 0197 0198 onTriggered: { 0199 taskList.getTaskAt(taskSwitcherState.currentTaskIndex).closeApp(); 0200 } 0201 } 0202 0203 rightCornerAction: MobileShell.NavigationPanelAction { 0204 visible: false 0205 } 0206 } 0207 0208 states: [ 0209 State { 0210 name: "landscape" 0211 when: MobileShell.Constants.navigationPanelOnSide(root.width, root.height) 0212 AnchorChanges { 0213 target: navigationPanel 0214 anchors { 0215 right: root.right 0216 top: root.top 0217 bottom: root.bottom 0218 } 0219 } 0220 PropertyChanges { 0221 target: navigationPanel 0222 width: root.rightMargin 0223 anchors.topMargin: root.topMargin 0224 } 0225 }, 0226 State { 0227 name: "portrait" 0228 when: !MobileShell.Constants.navigationPanelOnSide(root.width, root.height) 0229 AnchorChanges { 0230 target: navigationPanel 0231 anchors { 0232 right: root.right 0233 left: root.left 0234 bottom: root.bottom 0235 } 0236 } 0237 PropertyChanges { 0238 target: navigationPanel 0239 height: root.bottomMargin 0240 } 0241 } 0242 ] 0243 0244 // task list 0245 Item { 0246 id: container 0247 0248 // provide shell margins 0249 anchors.fill: parent 0250 anchors.leftMargin: root.leftMargin 0251 anchors.rightMargin: root.rightMargin 0252 anchors.bottomMargin: root.bottomMargin 0253 anchors.topMargin: root.topMargin 0254 0255 NumberAnimation on opacity { 0256 id: closeAnim 0257 running: false 0258 to: 0 0259 duration: 200 0260 easing.type: Easing.InOutQuad 0261 0262 onFinished: { 0263 closeAllButton.closeRequested = false; 0264 } 0265 } 0266 0267 // placeholder message 0268 ColumnLayout { 0269 id: placeholder 0270 spacing: Kirigami.Units.gridUnit 0271 opacity: (root.tasksCount === 0 && !taskSwitcherState.currentlyBeingClosed) ? 0.9 : 0 0272 Behavior on opacity { NumberAnimation { duration: 500 } } 0273 0274 anchors.centerIn: parent 0275 0276 Kirigami.Icon { 0277 id: icon 0278 Layout.alignment: Qt.AlignHCenter 0279 implicitWidth: Kirigami.Units.iconSizes.large 0280 implicitHeight: Kirigami.Units.iconSizes.large 0281 source: "window" 0282 color: "white" 0283 } 0284 0285 Kirigami.Heading { 0286 Layout.fillWidth: true 0287 Layout.maximumWidth: root.width * 0.75 0288 Layout.alignment: Qt.AlignHCenter 0289 color: "white" 0290 level: 3 0291 wrapMode: Text.Wrap 0292 horizontalAlignment: Text.AlignHCenter 0293 text: i18n("No applications are running.") 0294 } 0295 } 0296 0297 // flicking area for task switcher 0298 FlickContainer { 0299 id: flickable 0300 anchors.fill: parent 0301 0302 taskSwitcherState: root.taskSwitcherState 0303 0304 // don't allow FlickContainer to steal from swiping on tasks 0305 interactive: taskList.taskInteractingCount === 0 0306 0307 // the item is effectively anchored to the flickable bounds 0308 TaskList { 0309 id: taskList 0310 taskSwitcher: root 0311 shellTopMargin: root.topMargin 0312 shellBottomMargin: root.bottomMargin 0313 0314 opacity: { 0315 // animate opacity only if we are *not* opening from the homescreen 0316 if (taskSwitcherState.wasInActiveTask || !taskSwitcherState.currentlyBeingOpened) { 0317 return 1; 0318 } else { 0319 return Math.min(1, taskSwitcherState.yPosition / taskSwitcherState.openedYPosition); 0320 } 0321 } 0322 0323 x: flickable.contentX 0324 width: flickable.width 0325 height: flickable.height 0326 0327 PlasmaComponents.ToolButton { 0328 id: closeAllButton 0329 property bool closeRequested: false 0330 visible: root.tasksCount !== 0 0331 0332 anchors { 0333 bottom: parent.bottom 0334 bottomMargin: taskList.taskY / 2 0335 horizontalCenter: parent.horizontalCenter 0336 } 0337 0338 Kirigami.Theme.colorSet: Kirigami.Theme.Complementary 0339 Kirigami.Theme.inherit: false 0340 0341 opacity: (taskSwitcherState.currentlyBeingOpened || taskSwitcherState.currentlyBeingClosed) ? 0.0 : 1.0 0342 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration } } 0343 0344 icon.name: "edit-clear-history" 0345 font.bold: true 0346 0347 text: closeRequested ? i18n("Confirm Close All") : i18n("Close All") 0348 0349 onClicked: { 0350 if (closeRequested) { 0351 taskList.closeAll(); 0352 } else { 0353 closeRequested = true; 0354 } 0355 } 0356 } 0357 } 0358 } 0359 } 0360 } 0361