mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
Move from a C++ library + QML plugin to a QML plugin only for simplicity, since the homescreen switching architecture will be done from Plasma, and so use of the shell library only needs to be from QML.
188 lines
5.7 KiB
QML
188 lines
5.7 KiB
QML
/*
|
|
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
|
* SPDX-FileCopyrightText: 2021-2022 Devin Lin <devin@kde.org>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
import QtQuick 2.15
|
|
import QtQuick.Controls 2.15 as QQC2
|
|
import QtQuick.Layouts 1.1
|
|
import QtQuick.Window 2.15
|
|
|
|
import org.kde.taskmanager 0.1 as TaskManager
|
|
import org.kde.plasma.core 2.1 as PlasmaCore
|
|
import org.kde.plasma.components 3.0 as PlasmaComponents
|
|
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
|
|
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
|
|
|
import "../components" as Components
|
|
|
|
Item {
|
|
id: root
|
|
visible: false
|
|
opacity: 0
|
|
|
|
// state object
|
|
property var taskSwitcherState: TaskSwitcherState {
|
|
taskSwitcher: root
|
|
}
|
|
|
|
// task list model
|
|
property TaskManager.TasksModel tasksModel
|
|
readonly property int tasksCount: tasksModel.count
|
|
|
|
property var displaysModel: MobileShell.DisplaysModel {}
|
|
|
|
// if a window has popped up in front, close the task switcher
|
|
property bool windowActive: Window.active
|
|
onWindowActiveChanged: {
|
|
if (visible && !windowActive) {
|
|
hide();
|
|
}
|
|
}
|
|
|
|
// update API property
|
|
onVisibleChanged: MobileShell.HomeScreenControls.taskSwitcherVisible = visible;
|
|
|
|
// keep track of task list events
|
|
property int oldTasksCount: tasksCount
|
|
onTasksCountChanged: {
|
|
if (tasksCount == 0) {
|
|
hide();
|
|
} else if (tasksCount < oldTasksCount && taskSwitcherState.currentTaskIndex >= tasksCount - 1) {
|
|
// if the user is on the last task, and it is closed, scroll left
|
|
taskSwitcherState.animateGoToTaskIndex(tasksCount - 1, PlasmaCore.Units.longDuration);
|
|
}
|
|
|
|
oldTasksCount = tasksCount;
|
|
}
|
|
|
|
//BEGIN functions
|
|
|
|
function show(animation) {
|
|
// reset values
|
|
taskSwitcherState.cancelAnimations();
|
|
taskSwitcherState.yPosition = 0;
|
|
taskSwitcherState.xPosition = 0;
|
|
taskSwitcherState.wasInActiveTask = tasksModel.activeTask.row >= 0;
|
|
taskSwitcherState.currentlyBeingOpened = true;
|
|
|
|
// skip to first active task
|
|
if (taskSwitcherState.wasInActiveTask) {
|
|
taskSwitcherState.goToTaskIndex(tasksModel.activeTask.row);
|
|
}
|
|
|
|
// show task switcher, hide all running apps
|
|
visible = true;
|
|
opacity = 1;
|
|
minimizeAll();
|
|
|
|
// fully open the panel (if this is a button press, not gesture)
|
|
if (animation) {
|
|
taskSwitcherState.open();
|
|
}
|
|
}
|
|
|
|
function instantHide() {
|
|
opacity = 0;
|
|
visible = false;
|
|
}
|
|
|
|
function hide() {
|
|
closeAnim.restart();
|
|
}
|
|
|
|
// scroll to delegate index, and activate it
|
|
function activateWindow(id) {
|
|
taskSwitcherState.openApp(id);
|
|
}
|
|
|
|
function setSingleActiveWindow(id) {
|
|
if (id < 0) {
|
|
return;
|
|
}
|
|
|
|
var newActiveIdx = tasksModel.index(id, 0)
|
|
var newActiveGeo = tasksModel.data(newActiveIdx, TaskManager.AbstractTasksModel.ScreenGeometry)
|
|
for (var i = 0 ; i < tasksModel.count; i++) {
|
|
var idx = tasksModel.index(i, 0)
|
|
if (i == id) {
|
|
tasksModel.requestActivate(idx);
|
|
// ensure the window is in maximized state
|
|
if (!tasksModel.data(idx, TaskManager.AbstractTasksModel.IsMaximized)) {
|
|
tasksModel.requestToggleMaximized(idx);
|
|
}
|
|
} else if (!tasksModel.data(idx, TaskManager.AbstractTasksModel.IsMinimized)) {
|
|
var geo = tasksModel.data(idx, TaskManager.AbstractTasksModel.ScreenGeometry)
|
|
// only minimize the other windows in the same screen
|
|
if (geo === newActiveGeo) {
|
|
tasksModel.requestToggleMinimized(idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
instantHide();
|
|
}
|
|
|
|
function minimizeAll() {
|
|
for (var i = 0 ; i < tasksModel.count; i++) {
|
|
var idx = tasksModel.makeModelIndex(i);
|
|
if (!tasksModel.data(idx, TaskManager.AbstractTasksModel.IsMinimized)) {
|
|
tasksModel.requestToggleMinimized(idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
//END functions
|
|
|
|
NumberAnimation on opacity {
|
|
id: closeAnim
|
|
to: 0
|
|
duration: PlasmaCore.Units.shortDuration
|
|
easing.type: Easing.InOutQuad
|
|
onFinished: {
|
|
root.visible = false;
|
|
}
|
|
}
|
|
|
|
// background colour
|
|
Rectangle {
|
|
id: backgroundRect
|
|
anchors.fill: parent
|
|
|
|
color: {
|
|
// animate background colour only if opening from the homescreen
|
|
if (taskSwitcherState.wasInActiveTask) {
|
|
return Qt.rgba(0, 0, 0, 0.6);
|
|
} else {
|
|
return Qt.rgba(0, 0, 0, 0.6 * Math.min(1, taskSwitcherState.yPosition / taskSwitcherState.openedYPosition));
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
id: container
|
|
|
|
// provide shell margins
|
|
anchors.fill: parent
|
|
anchors.leftMargin: MobileShell.Shell.leftMargin
|
|
anchors.rightMargin: MobileShell.Shell.rightMargin
|
|
anchors.bottomMargin: MobileShell.Shell.bottomMargin
|
|
anchors.topMargin: MobileShell.Shell.topMargin
|
|
|
|
FlickContainer {
|
|
id: flickable
|
|
anchors.fill: parent
|
|
taskSwitcherState: root.taskSwitcherState
|
|
|
|
// the item is effectively anchored to the flickable bounds
|
|
TaskList {
|
|
taskSwitcher: root
|
|
x: flickable.contentX
|
|
width: flickable.width
|
|
height: flickable.height
|
|
}
|
|
}
|
|
}
|
|
}
|