mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-27 14:33:08 +00:00
Having a global set margins and orientation (that were calculated from the panel containment) caused a lot of issues with the way bindings were evaluated across panels, and with high coupling. Now use properties from within containments to determine shell margins instead, which removes the dependency on other containments for measurements. This allows us to get rid of TaskPanelControls as well! Fixes: https://invent.kde.org/teams/plasma-mobile/issues/-/issues/198
283 lines
8.8 KiB
QML
283 lines
8.8 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 org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState
|
|
|
|
import "../components" as Components
|
|
|
|
/**
|
|
* Component that provides a task switcher.
|
|
*/
|
|
Item {
|
|
id: root
|
|
visible: false
|
|
opacity: 0
|
|
|
|
/**
|
|
* Margins for the content (taking shell panels into account).
|
|
*/
|
|
required property real topMargin
|
|
required property real bottomMargin
|
|
required property real leftMargin
|
|
required property real rightMargin
|
|
|
|
// state object
|
|
property var taskSwitcherState: TaskSwitcherState {
|
|
taskSwitcher: root
|
|
}
|
|
|
|
/**
|
|
* The task manager model to use for the tasks switcher.
|
|
*/
|
|
property TaskManager.TasksModel tasksModel
|
|
|
|
/**
|
|
* The number of tasks in the given task manager model.
|
|
*/
|
|
readonly property int tasksCount: tasksModel.count
|
|
|
|
/**
|
|
* The screen model to be used for moving windows between screens.
|
|
*/
|
|
property var displaysModel: MobileShell.DisplaysModel {}
|
|
|
|
/**
|
|
* Whether the window is active.
|
|
*/
|
|
property bool windowActive: Window.active
|
|
onWindowActiveChanged: {
|
|
// if a window has popped up in front, close the task switcher
|
|
if (visible && !windowActive) {
|
|
hide();
|
|
}
|
|
}
|
|
|
|
// update API property
|
|
onVisibleChanged: MobileShellState.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;
|
|
}
|
|
|
|
Timer {
|
|
id: reorderTimer
|
|
|
|
interval: 5000
|
|
|
|
onTriggered: tasksModel.taskReorderingEnabled = true
|
|
}
|
|
|
|
//BEGIN functions
|
|
|
|
function show(animation) {
|
|
// reset values
|
|
taskSwitcherState.cancelAnimations();
|
|
taskSwitcherState.yPosition = 0;
|
|
taskSwitcherState.xPosition = 0;
|
|
taskSwitcherState.wasInActiveTask = tasksModel.activeTask.row >= 0;
|
|
taskSwitcherState.currentlyBeingOpened = true;
|
|
|
|
reorderTimer.stop();
|
|
tasksModel.taskReorderingEnabled = false;
|
|
|
|
// skip to first active task
|
|
if (taskSwitcherState.wasInActiveTask) {
|
|
taskSwitcherState.goToTaskIndex(tasksModel.activeTask.row);
|
|
} else {
|
|
taskSwitcherState.goToTaskIndex(0);
|
|
}
|
|
|
|
// 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;
|
|
closeAllButton.closeRequested = 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();
|
|
|
|
if (taskSwitcherState.wasInActiveTask) {
|
|
reorderTimer.restart();
|
|
} else {
|
|
tasksModel.taskReorderingEnabled = true;
|
|
}
|
|
}
|
|
|
|
function minimizeAll() {
|
|
MobileShell.WindowUtil.unsetAllMinimizedGeometries(root);
|
|
MobileShell.WindowUtil.minimizeAll();
|
|
}
|
|
|
|
//END functions
|
|
|
|
NumberAnimation on opacity {
|
|
id: closeAnim
|
|
to: 0
|
|
duration: PlasmaCore.Units.shortDuration
|
|
easing.type: Easing.InOutQuad
|
|
|
|
onFinished: {
|
|
root.visible = false;
|
|
tasksModel.taskReorderingEnabled = true;
|
|
closeAllButton.closeRequested = false;
|
|
}
|
|
}
|
|
|
|
// background colour
|
|
Rectangle {
|
|
id: backgroundRect
|
|
anchors.fill: parent
|
|
|
|
color: {
|
|
// animate background colour only if we are *not* opening from the homescreen
|
|
if (taskSwitcherState.wasInActiveTask || !taskSwitcherState.currentlyBeingOpened) {
|
|
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: root.leftMargin
|
|
anchors.rightMargin: root.rightMargin
|
|
anchors.bottomMargin: root.bottomMargin
|
|
anchors.topMargin: root.topMargin
|
|
|
|
FlickContainer {
|
|
id: flickable
|
|
|
|
anchors.fill: parent
|
|
|
|
taskSwitcherState: root.taskSwitcherState
|
|
|
|
// the item is effectively anchored to the flickable bounds
|
|
TaskList {
|
|
id: taskList
|
|
shellTopMargin: root.topMargin
|
|
shellBottomMargin: root.bottomMargin
|
|
|
|
taskSwitcher: root
|
|
|
|
opacity: {
|
|
// animate opacity only if we are *not* opening from the homescreen
|
|
if (taskSwitcherState.wasInActiveTask || !taskSwitcherState.currentlyBeingOpened) {
|
|
return 1;
|
|
} else {
|
|
Math.min(1, taskSwitcherState.yPosition / taskSwitcherState.openedYPosition);
|
|
}
|
|
}
|
|
|
|
x: flickable.contentX
|
|
width: flickable.width
|
|
height: flickable.height
|
|
|
|
PlasmaComponents.ToolButton {
|
|
id: closeAllButton
|
|
|
|
property bool closeRequested: false
|
|
|
|
anchors {
|
|
bottom: parent.bottom
|
|
bottomMargin: taskList.taskY / 2
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
|
|
PlasmaCore.ColorScope.colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
|
PlasmaCore.ColorScope.inherit: false
|
|
|
|
opacity: taskSwitcherState.currentlyBeingOpened || taskSwitcherState.currentlyBeingClosed || !root.visible ? 0.0 : 1.0
|
|
|
|
Behavior on opacity {
|
|
NumberAnimation {
|
|
duration: PlasmaCore.Units.shortDuration
|
|
}
|
|
}
|
|
|
|
icon.name: "edit-clear-history"
|
|
font.bold: true
|
|
|
|
text: closeRequested ? "Confirm Close All" : "Close All"
|
|
|
|
onClicked: {
|
|
if (closeRequested) {
|
|
taskList.closeAll();
|
|
} else {
|
|
closeRequested = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|