mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-06-11 00:47:22 +00:00
Use the unused lower-left convergence space for KDE's MonthView\ninstead of leaving wallpaper exposed below the notification list.
351 lines
14 KiB
QML
351 lines
14 KiB
QML
// SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
|
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
|
|
import QtQuick 2.15
|
|
import QtQuick.Controls 2.15
|
|
import QtQuick.Window 2.2
|
|
import QtQuick.Layouts
|
|
|
|
import org.kde.plasma.clock
|
|
import org.kde.plasma.components 3.0 as PlasmaComponents
|
|
import org.kde.plasma.private.mobileshell as MobileShell
|
|
import org.kde.plasma.components 3.0 as PC3
|
|
import org.kde.kirigami as Kirigami
|
|
import org.kde.plasma.workspace.calendar as PlasmaCalendar
|
|
import org.kde.plasma.private.mobileshell.quicksettingsplugin as QS
|
|
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
|
|
|
|
/**
|
|
* Root element that contains all the ActionDrawer's contents, and is anchored to the screen.
|
|
*/
|
|
Item {
|
|
id: root
|
|
|
|
required property var actionDrawer
|
|
required property QS.QuickSettingsModel quickSettingsModel
|
|
|
|
readonly property real minimizedQuickSettingsOffset: contentContainerLoader.minimizedQuickSettingsOffset
|
|
readonly property real maximizedQuickSettingsOffset: contentContainerLoader.maximizedQuickSettingsOffset
|
|
|
|
readonly property bool swipeAreaMoving: swipeAreaBase.moving || swipeAreaPortrait.moving
|
|
readonly property bool isConvergence: ShellSettings.Settings.convergenceModeEnabled
|
|
readonly property real convergenceFrameThickness: MobileShell.Constants.convergenceWorkspaceFrameThickness
|
|
readonly property real convergenceSurfaceTopInset: MobileShell.Constants.topPanelHeight + convergenceFrameThickness
|
|
readonly property real convergenceSurfaceBottomInset: MobileShell.Constants.convergenceDockHeight + convergenceFrameThickness
|
|
readonly property real convergenceSurfaceSideInset: 0
|
|
readonly property real convergenceSurfaceWidth: Math.max(0, width - convergenceSurfaceSideInset * 2)
|
|
readonly property real convergenceSurfaceHeight: Math.max(0, height - convergenceSurfaceTopInset - convergenceSurfaceBottomInset)
|
|
readonly property real convergenceNotificationRightMargin: Math.max(convergenceSurfaceSideInset, width - (convergenceSurfaceSideInset + convergenceSurfaceWidth * 0.5))
|
|
|
|
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
|
Kirigami.Theme.inherit: false
|
|
|
|
readonly property alias brightnessPressedValue: quickSettings.brightnessPressedValue
|
|
|
|
function applyMinMax(val) {
|
|
return Math.max(0, Math.min(1, val));
|
|
}
|
|
|
|
function startSwipe() {
|
|
actionDrawer.cancelAnimations();
|
|
actionDrawer.dragging = true;
|
|
// Immediately open action drawer if we interact with it and it's already open
|
|
// This allows us to have 2 quick flicks from minimized -> expanded
|
|
if (actionDrawer.visible && !actionDrawer.opened) {
|
|
actionDrawer.opened = true;
|
|
}
|
|
}
|
|
|
|
function endSwipe() {
|
|
actionDrawer.dragging = false;
|
|
actionDrawer.updateState();
|
|
}
|
|
|
|
function moveSwipe(totalDeltaX, totalDeltaY, deltaX, deltaY) {
|
|
actionDrawer.offset += deltaY;
|
|
}
|
|
|
|
// Background color
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: Qt.rgba(Kirigami.Theme.backgroundColor.r,
|
|
Kirigami.Theme.backgroundColor.g,
|
|
Kirigami.Theme.backgroundColor.b,
|
|
0.9)
|
|
Behavior on color { MobileShell.MotionColorAnimation { type: MobileShell.Motion.StandardDecel } }
|
|
opacity: {
|
|
let base = Math.max(0, Math.min(brightnessPressedValue, actionDrawer.offset / root.minimizedQuickSettingsOffset));
|
|
return ShellSettings.Settings.convergenceModeEnabled ? base * 0.3 : base;
|
|
}
|
|
}
|
|
|
|
// The base swipe area.
|
|
// Used to cover the full surface of the drawer to allow dismissing or expanding it.
|
|
MobileShell.SwipeArea {
|
|
id: swipeAreaBase
|
|
mode: MobileShell.SwipeArea.VerticalOnly
|
|
anchors.fill: parent
|
|
|
|
onSwipeStarted: root.startSwipe()
|
|
onSwipeEnded: root.endSwipe()
|
|
onSwipeMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => root.moveSwipe(totalDeltaX, totalDeltaY, deltaX, deltaY)
|
|
|
|
onTouchpadScrollStarted: root.startSwipe()
|
|
onTouchpadScrollEnded: root.endSwipe()
|
|
onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => root.moveSwipe(totalDeltaX, totalDeltaY, deltaX, deltaY)
|
|
|
|
// Proxy in the layout that switches between landscape and portrait mode.
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
visible: root.actionDrawer.mode != MobileShell.ActionDrawer.Portrait
|
|
LayoutItemProxy { target: contentContainerLoader }
|
|
}
|
|
|
|
// Mouse area for dismissing action drawer in portrait mode when background is clicked.
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
visible: root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait
|
|
|
|
// dismiss drawer when background is clicked
|
|
onClicked: root.actionDrawer.close();
|
|
}
|
|
|
|
// The clear all notification history button.
|
|
Item {
|
|
id: toolButtons
|
|
height: visible ? spacer.height + toolLayout.height + toolLayout.anchors.topMargin + toolLayout.anchors.bottomMargin : 0
|
|
|
|
visible: actionDrawer.intendedToBeVisible
|
|
opacity: Math.max(0, Math.min(root.brightnessPressedValue, actionDrawer.offsetResistance / root.minimizedQuickSettingsOffset))
|
|
|
|
anchors {
|
|
topMargin: notificationDrawer.y + notificationDrawer.height + 1
|
|
leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (notificationDrawer.isConvergence ? root.convergenceSurfaceSideInset : 10)
|
|
rightMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (notificationDrawer.isConvergence ? root.convergenceNotificationRightMargin : notificationDrawer.notificationWidget.anchors.rightMargin + Kirigami.Units.gridUnit - notificationDrawer.anchors.leftMargin + 370)
|
|
top: parent.top
|
|
left: parent.left
|
|
right: parent.right
|
|
}
|
|
|
|
Rectangle {
|
|
id: spacer
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
|
|
visible: notificationDrawer.listOverflowing
|
|
height: 1
|
|
opacity: 0.25
|
|
color: Kirigami.Theme.textColor
|
|
}
|
|
|
|
RowLayout {
|
|
id: toolLayout
|
|
|
|
anchors {
|
|
top: spacer.bottom
|
|
right: parent.right
|
|
left: parent.left
|
|
leftMargin: Kirigami.Units.largeSpacing
|
|
rightMargin: Kirigami.Units.largeSpacing
|
|
topMargin: Kirigami.Units.largeSpacing
|
|
bottomMargin: Kirigami.Units.largeSpacing
|
|
}
|
|
|
|
PlasmaComponents.ToolButton {
|
|
id: clearButton
|
|
|
|
Layout.alignment: Qt.AlignCenter
|
|
|
|
visible: notificationDrawer.hasNotifications
|
|
|
|
font.bold: true
|
|
font.pointSize: Kirigami.Theme.smallFont.pointSize
|
|
|
|
icon.name: "edit-clear-history"
|
|
text: i18n("Clear All Notifications")
|
|
onClicked: notificationDrawer.notificationWidget.clearHistory()
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
id: convergenceCalendarPanel
|
|
|
|
visible: root.isConvergence && actionDrawer.mode != MobileShell.ActionDrawer.Portrait
|
|
opacity: Math.max(0, Math.min(root.brightnessPressedValue, actionDrawer.offsetResistance / root.minimizedQuickSettingsOffset))
|
|
clip: true
|
|
|
|
anchors {
|
|
top: parent.top
|
|
left: parent.left
|
|
right: parent.right
|
|
bottom: parent.bottom
|
|
topMargin: notificationDrawer.hasNotifications
|
|
? toolButtons.y + toolButtons.height + Kirigami.Units.smallSpacing
|
|
: notificationDrawer.y + notificationDrawer.height + Kirigami.Units.largeSpacing
|
|
leftMargin: root.convergenceSurfaceSideInset + Kirigami.Units.gridUnit
|
|
rightMargin: root.convergenceNotificationRightMargin + Kirigami.Units.gridUnit
|
|
bottomMargin: root.convergenceSurfaceBottomInset + Kirigami.Units.largeSpacing
|
|
}
|
|
|
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
|
Kirigami.Theme.inherit: false
|
|
|
|
MobileShell.PanelBackground {
|
|
anchors.fill: parent
|
|
panelType: MobileShell.PanelBackground.PanelType.Drawer
|
|
}
|
|
|
|
PlasmaCalendar.MonthView {
|
|
anchors.fill: parent
|
|
anchors.margins: Kirigami.Units.smallSpacing
|
|
|
|
borderOpacity: 0.25
|
|
today: calendarClock.dateTime
|
|
eventPluginsManager: eventPluginsManager
|
|
}
|
|
}
|
|
}
|
|
|
|
// notification drawer ui
|
|
// separated from the main drawer ui swipe area to prevent scrolling conflicts
|
|
NotificationDrawer {
|
|
id: notificationDrawer
|
|
|
|
readonly property bool isConvergence: root.isConvergence
|
|
swipeArea: swipeAreaPortrait
|
|
actionDrawer: root.actionDrawer
|
|
mediaControlsWidget: root.mediaControlsWidget
|
|
contentContainer: root
|
|
opacity: {
|
|
let base = Math.max(0, Math.min(root.brightnessPressedValue, actionDrawer.offsetResistance / root.minimizedQuickSettingsOffset));
|
|
return isConvergence ? Math.max(0, Math.min(1, actionDrawer.offset / root.minimizedQuickSettingsOffset)) : base;
|
|
}
|
|
|
|
anchors {
|
|
top: parent.top
|
|
left: parent.left
|
|
right: parent.right
|
|
topMargin: isConvergence ? root.convergenceSurfaceTopInset : 0
|
|
rightMargin: root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (isConvergence ? root.convergenceNotificationRightMargin : 360)
|
|
leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (isConvergence ? root.convergenceSurfaceSideInset : notificationDrawer.minWidthHeight * 0.06)
|
|
}
|
|
|
|
// In convergence, cap the height so it doesn't stretch full-screen
|
|
maximumHeight: isConvergence ? root.convergenceSurfaceHeight * 0.6 : -1
|
|
toolButtonsItem: toolButtons
|
|
}
|
|
|
|
// Secondary swipe area for uses in portrait.
|
|
// Covers the surface area of the quick settings panel to allow dismissing or expanding the drawer while also having it over top of the notification list.
|
|
MobileShell.SwipeArea {
|
|
id: swipeAreaPortrait
|
|
mode: MobileShell.SwipeArea.VerticalOnly
|
|
anchors {
|
|
top: parent.top
|
|
left: parent.left
|
|
right: parent.right
|
|
}
|
|
height: root.actionDrawer.mode === MobileShell.ActionDrawer.Portrait ? actionDrawer.offsetResistance : root.height
|
|
interactive: root.actionDrawer.mode === MobileShell.ActionDrawer.Portrait
|
|
|
|
onSwipeStarted: root.startSwipe()
|
|
onSwipeEnded: root.endSwipe()
|
|
onSwipeMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => root.moveSwipe(totalDeltaX, totalDeltaY, deltaX, deltaY)
|
|
|
|
onTouchpadScrollStarted: root.startSwipe()
|
|
onTouchpadScrollEnded: root.endSwipe()
|
|
onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => root.moveSwipe(totalDeltaX, totalDeltaY, deltaX, deltaY)
|
|
|
|
// Proxy in the layout that switches between landscape and portrait mode.
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
visible: root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait
|
|
LayoutItemProxy { target: contentContainerLoader }
|
|
}
|
|
}
|
|
|
|
// Layout that switches between landscape and portrait mode
|
|
Loader {
|
|
id: contentContainerLoader
|
|
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
readonly property real minimizedQuickSettingsOffset: item ? item.minimizedQuickSettingsOffset : 0
|
|
readonly property real maximizedQuickSettingsOffset: item ? item.maximizedQuickSettingsOffset : 0
|
|
|
|
readonly property real offsetDist: root.actionDrawer.offset - minimizedQuickSettingsOffset
|
|
readonly property real totalOffsetDist: maximizedQuickSettingsOffset - minimizedQuickSettingsOffset
|
|
readonly property real minimizedToFullProgress: root.actionDrawer.openToPinnedMode ? (root.actionDrawer.opened ? applyMinMax(offsetDist / totalOffsetDist) : 0) : 1
|
|
|
|
asynchronous: true
|
|
sourceComponent: root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? portraitContentContainer : landscapeContentContainer
|
|
}
|
|
|
|
// The portrait content container.
|
|
Component {
|
|
id: portraitContentContainer
|
|
PortraitContentContainer {
|
|
actionDrawer: root.actionDrawer
|
|
width: root.width
|
|
height: root.height
|
|
|
|
quickSettings: root.quickSettings
|
|
statusBar: root.statusBar
|
|
mediaControlsWidget: root.mediaControlsWidget
|
|
}
|
|
}
|
|
|
|
// The landscape content container.
|
|
Component {
|
|
id: landscapeContentContainer
|
|
LandscapeContentContainer {
|
|
actionDrawer: root.actionDrawer
|
|
width: root.width
|
|
height: root.height
|
|
|
|
quickSettings: root.quickSettings
|
|
statusBar: root.statusBar
|
|
}
|
|
}
|
|
|
|
// Components shared between the two layouts.
|
|
// This allows us to avoid having to reload the components every time the screen size changes.
|
|
|
|
property QuickSettings quickSettings: QuickSettings {
|
|
id: quickSettings
|
|
actionDrawer: root.actionDrawer
|
|
quickSettingsModel: root.quickSettingsModel
|
|
fullViewProgress: (root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait) ? contentContainerLoader.minimizedToFullProgress : 1.0
|
|
}
|
|
|
|
property MobileShell.StatusBar statusBar: MobileShell.StatusBar {
|
|
id: statusBar
|
|
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
|
Kirigami.Theme.inherit: false
|
|
|
|
backgroundColor: "transparent"
|
|
showSecondRow: root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait
|
|
showDropShadow: false
|
|
showTime: root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait
|
|
|
|
// Disable system tray on lockscreen to prevent SIGABRT
|
|
disableSystemTray: root.actionDrawer.restrictedPermissions
|
|
|
|
opacity: brightnessPressedValue
|
|
}
|
|
|
|
property MobileShell.MediaControlsWidget mediaControlsWidget: MobileShell.MediaControlsWidget {
|
|
id: mediaWidget
|
|
opacity: brightnessPressedValue
|
|
}
|
|
|
|
Clock {
|
|
id: calendarClock
|
|
}
|
|
|
|
PlasmaCalendar.EventPluginsManager {
|
|
id: eventPluginsManager
|
|
}
|
|
}
|