mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
actiondrawer: Share components between portrait and landscape
This avoids having to completely load the quicksettings, status bar, media widget, and notifications list from scratch when the view changes. We now have a single instance of each component which is reparented to the new view (portrait/landscape). Fixes https://invent.kde.org/plasma/plasma-mobile/-/issues/406
This commit is contained in:
parent
6da6f3fd55
commit
76882f5b5d
11 changed files with 234 additions and 203 deletions
|
|
@ -19,7 +19,13 @@ import org.kde.plasma.private.mobileshell.quicksettingsplugin as QS
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
visible: false
|
/*
|
||||||
|
* The intended visiblity of the action drawer.
|
||||||
|
*
|
||||||
|
* This is separate from "visible" in order to avoid having to set
|
||||||
|
* item visiblity when its on its own window (wasteful since the window itself can be shown/hidden).
|
||||||
|
*/
|
||||||
|
property bool intendedToBeVisible: false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The model for the notification widget.
|
* The model for the notification widget.
|
||||||
|
|
@ -34,7 +40,7 @@ Item {
|
||||||
/**
|
/**
|
||||||
* The model for the quick settings.
|
* The model for the quick settings.
|
||||||
*/
|
*/
|
||||||
property var quickSettingsModel: QS.QuickSettingsModel {}
|
property QS.QuickSettingsModel quickSettingsModel: QS.QuickSettingsModel {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The notification settings object to be used in the notification widget.
|
* The notification settings object to be used in the notification widget.
|
||||||
|
|
@ -77,7 +83,7 @@ Item {
|
||||||
/**
|
/**
|
||||||
* The notifications widget being shown. May be null.
|
* The notifications widget being shown. May be null.
|
||||||
*/
|
*/
|
||||||
property var notificationsWidget: contentContainerLoader.item.notificationsWidget
|
property var notificationsWidget: contentContainer.notificationsWidget
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The mode of the action drawer (portrait or landscape).
|
* The mode of the action drawer (portrait or landscape).
|
||||||
|
|
@ -178,17 +184,17 @@ Item {
|
||||||
|
|
||||||
if (root.offset <= 0) {
|
if (root.offset <= 0) {
|
||||||
// close immediately, so that we don't have to wait Kirigami.Units.longDuration
|
// close immediately, so that we don't have to wait Kirigami.Units.longDuration
|
||||||
root.visible = false;
|
root.intendedToBeVisible = false;
|
||||||
close();
|
close();
|
||||||
} else if (root.direction === MobileShell.Direction.None || !root.opened) {
|
} else if (root.direction === MobileShell.Direction.None || !root.opened) {
|
||||||
|
|
||||||
// if the panel has not been opened yet, run open animation only if drag passed threshold
|
// if the panel has not been opened yet, run open animation only if drag passed threshold
|
||||||
(root.offset < openThreshold) ? close() : open();
|
(root.offset < openThreshold) ? close() : open();
|
||||||
|
|
||||||
} else if (root.offset > contentContainerLoader.maximizedQuickSettingsOffset) {
|
} else if (root.offset > contentContainer.maximizedQuickSettingsOffset) {
|
||||||
// if drag has gone past the fully expanded view
|
// if drag has gone past the fully expanded view
|
||||||
expand();
|
expand();
|
||||||
} else if (root.offset > contentContainerLoader.minimizedQuickSettingsOffset) {
|
} else if (root.offset > contentContainer.minimizedQuickSettingsOffset) {
|
||||||
// if drag is between pinned view and fully expanded view
|
// if drag is between pinned view and fully expanded view
|
||||||
if (root.direction === MobileShell.Direction.Down) {
|
if (root.direction === MobileShell.Direction.Down) {
|
||||||
expand();
|
expand();
|
||||||
|
|
@ -229,13 +235,13 @@ Item {
|
||||||
State {
|
State {
|
||||||
name: "open"
|
name: "open"
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: root; offset: contentContainerLoader.minimizedQuickSettingsOffset
|
target: root; offset: contentContainer.minimizedQuickSettingsOffset
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
name: "expand"
|
name: "expand"
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: root; offset: contentContainerLoader.maximizedQuickSettingsOffset
|
target: root; offset: contentContainer.maximizedQuickSettingsOffset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -250,7 +256,7 @@ Item {
|
||||||
script: {
|
script: {
|
||||||
if (root.state != "") {
|
if (root.state != "") {
|
||||||
if (root.offset <= 0) {
|
if (root.offset <= 0) {
|
||||||
root.visible = false;
|
root.intendedToBeVisible = false;
|
||||||
root.opened = false;
|
root.opened = false;
|
||||||
root.state = "";
|
root.state = "";
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -289,35 +295,12 @@ Item {
|
||||||
onTouchpadScrollEnded: endSwipe()
|
onTouchpadScrollEnded: endSwipe()
|
||||||
onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => moveSwipe(totalDeltaX, totalDeltaY, deltaX, deltaY)
|
onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => moveSwipe(totalDeltaX, totalDeltaY, deltaX, deltaY)
|
||||||
|
|
||||||
Loader {
|
ContentContainer {
|
||||||
id: contentContainerLoader
|
id: contentContainer
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
property real minimizedQuickSettingsOffset: item ? item.minimizedQuickSettingsOffset : 0
|
actionDrawer: root
|
||||||
property real maximizedQuickSettingsOffset: item ? item.maximizedQuickSettingsOffset : 0
|
quickSettingsModel: root.quickSettingsModel
|
||||||
|
|
||||||
asynchronous: true
|
|
||||||
sourceComponent: root.mode == ActionDrawer.Portrait ? portraitContentContainer : landscapeContentContainer
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: portraitContentContainer
|
|
||||||
PortraitContentContainer {
|
|
||||||
actionDrawer: root
|
|
||||||
width: root.width
|
|
||||||
height: root.height
|
|
||||||
quickSettingsModel: root.quickSettingsModel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: landscapeContentContainer
|
|
||||||
LandscapeContentContainer {
|
|
||||||
actionDrawer: root
|
|
||||||
width: root.width
|
|
||||||
height: root.height
|
|
||||||
quickSettingsModel: root.quickSettingsModel
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021-2022 Devin Lin <devin@kde.org>
|
* SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
@ -19,7 +19,7 @@ MobileShell.SwipeArea {
|
||||||
required property ActionDrawer actionDrawer
|
required property ActionDrawer actionDrawer
|
||||||
|
|
||||||
function startSwipe() {
|
function startSwipe() {
|
||||||
if (actionDrawer.visible) {
|
if (actionDrawer.intendedToBeVisible) {
|
||||||
// ensure the action drawer state is consistent
|
// ensure the action drawer state is consistent
|
||||||
actionDrawer.closeImmediately();
|
actionDrawer.closeImmediately();
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +30,7 @@ MobileShell.SwipeArea {
|
||||||
// must be after properties other are set, we cannot have actionDrawer.updateState() be called
|
// must be after properties other are set, we cannot have actionDrawer.updateState() be called
|
||||||
actionDrawer.offset = 0;
|
actionDrawer.offset = 0;
|
||||||
actionDrawer.oldOffset = 0;
|
actionDrawer.oldOffset = 0;
|
||||||
actionDrawer.visible = true;
|
actionDrawer.intendedToBeVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function startSwipeWithPoint(point) {
|
function startSwipeWithPoint(point) {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ NanoShell.FullScreenOverlay {
|
||||||
*/
|
*/
|
||||||
property alias actionDrawer: drawer
|
property alias actionDrawer: drawer
|
||||||
|
|
||||||
visible: drawer.visible
|
visible: drawer.intendedToBeVisible
|
||||||
width: Screen.width
|
width: Screen.width
|
||||||
height: Screen.height
|
height: Screen.height
|
||||||
|
|
||||||
|
|
|
||||||
130
components/mobileshell/qml/actiondrawer/ContentContainer.qml
Normal file
130
components/mobileshell/qml/actiondrawer/ContentContainer.qml
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
// 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.Layouts 1.1
|
||||||
|
import QtQuick.Window 2.2
|
||||||
|
|
||||||
|
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.private.mobileshell.quicksettingsplugin as QS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root element that contains all the ActionDrawer's contents, and is anchored to the screen.
|
||||||
|
*/
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var actionDrawer
|
||||||
|
required property QS.QuickSettingsModel quickSettingsModel
|
||||||
|
|
||||||
|
readonly property real minimizedQuickSettingsOffset: contentContainerLoader.minimizedQuickSettingsOffset
|
||||||
|
readonly property real maximizedQuickSettingsOffset: contentContainerLoader.maximizedQuickSettingsOffset
|
||||||
|
|
||||||
|
function applyMinMax(val) {
|
||||||
|
return Math.max(0, Math.min(1, val));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Background color
|
||||||
|
color: Qt.rgba(Kirigami.Theme.backgroundColor.r,
|
||||||
|
Kirigami.Theme.backgroundColor.g,
|
||||||
|
Kirigami.Theme.backgroundColor.b,
|
||||||
|
(root.actionDrawer.mode == ActionDrawer.Portrait || notificationWidget.hasNotifications) ? 0.95 : 0.9)
|
||||||
|
Behavior on color { ColorAnimation { duration: Kirigami.Units.longDuration } }
|
||||||
|
opacity: Math.max(0, Math.min(1, actionDrawer.offset / root.minimizedQuickSettingsOffset))
|
||||||
|
|
||||||
|
// Layout that switches between landscape and portrait mode
|
||||||
|
Loader {
|
||||||
|
id: contentContainerLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
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 == ActionDrawer.Portrait ? portraitContentContainer : landscapeContentContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: portraitContentContainer
|
||||||
|
PortraitContentContainer {
|
||||||
|
actionDrawer: root.actionDrawer
|
||||||
|
width: root.width
|
||||||
|
height: root.height
|
||||||
|
|
||||||
|
quickSettings: root.quickSettings
|
||||||
|
statusBar: root.statusBar
|
||||||
|
mediaControlsWidget: root.mediaControlsWidget
|
||||||
|
notificationsWidget: root.notificationsWidget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: landscapeContentContainer
|
||||||
|
LandscapeContentContainer {
|
||||||
|
actionDrawer: root.actionDrawer
|
||||||
|
width: root.width
|
||||||
|
height: root.height
|
||||||
|
|
||||||
|
quickSettings: root.quickSettings
|
||||||
|
statusBar: root.statusBar
|
||||||
|
mediaControlsWidget: root.mediaControlsWidget
|
||||||
|
notificationsWidget: root.notificationsWidget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Components shared between the two layouts.
|
||||||
|
// This allows us to avoid having to reload the components every time the screen size changes.
|
||||||
|
|
||||||
|
property MobileShell.QuickSettings quickSettings: MobileShell.QuickSettings {
|
||||||
|
id: quickSettings
|
||||||
|
actionDrawer: root.actionDrawer
|
||||||
|
quickSettingsModel: root.quickSettingsModel
|
||||||
|
fullViewProgress: (root.actionDrawer.mode == 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 == ActionDrawer.Portrait
|
||||||
|
showDropShadow: false
|
||||||
|
showTime: root.actionDrawer.mode == ActionDrawer.Portrait
|
||||||
|
|
||||||
|
// security reasons, system tray also doesn't work on lockscreen
|
||||||
|
disableSystemTray: root.actionDrawer.restrictedPermissions
|
||||||
|
}
|
||||||
|
|
||||||
|
property MobileShell.MediaControlsWidget mediaControlsWidget: MobileShell.MediaControlsWidget {
|
||||||
|
id: mediaWidget
|
||||||
|
inActionDrawer: true
|
||||||
|
}
|
||||||
|
|
||||||
|
property MobileShell.NotificationsWidget notificationsWidget: MobileShell.NotificationsWidget {
|
||||||
|
id: notificationWidget
|
||||||
|
historyModel: root.actionDrawer.notificationModel
|
||||||
|
historyModelType: root.actionDrawer.notificationModelType
|
||||||
|
notificationSettings: root.actionDrawer.notificationSettings
|
||||||
|
actionsRequireUnlock: root.actionDrawer.restrictedPermissions
|
||||||
|
onUnlockRequested: root.actionDrawer.permissionsRequested()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.actionDrawer
|
||||||
|
|
||||||
|
function onRunPendingNotificationAction() {
|
||||||
|
notificationWidget.runPendingAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onBackgroundClicked: root.actionDrawer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
/*
|
// SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
|
||||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls as QQC2
|
||||||
import QtQuick.Layouts 1.1
|
import QtQuick.Layouts
|
||||||
import QtQuick.Window 2.2
|
import QtQuick.Window
|
||||||
|
|
||||||
import org.kde.kirigami 2.12 as Kirigami
|
import org.kde.kirigami 2.12 as Kirigami
|
||||||
|
|
||||||
|
|
@ -24,32 +21,21 @@ Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property var actionDrawer
|
required property var actionDrawer
|
||||||
property QS.QuickSettingsModel quickSettingsModel
|
|
||||||
|
|
||||||
property alias notificationsWidget: notificationWidget
|
property alias quickSettings: quickSettingsPanel.quickSettings
|
||||||
|
property alias statusBar: quickSettingsPanel.statusBar
|
||||||
|
property alias mediaControlsWidget: mediaControlsWidgetProxy.contentItem
|
||||||
|
property alias notificationsWidget: notificationWidgetProxy.contentItem
|
||||||
|
|
||||||
readonly property real minimizedQuickSettingsOffset: height
|
readonly property real minimizedQuickSettingsOffset: height
|
||||||
readonly property real maximizedQuickSettingsOffset: height
|
readonly property real maximizedQuickSettingsOffset: height
|
||||||
readonly property bool isOnLargeScreen: width > quickSettings.width * 2.5
|
readonly property bool isOnLargeScreen: width > quickSettingsPanel.width * 2.5
|
||||||
readonly property real minWidthHeight: Math.min(root.width, root.height)
|
readonly property real minWidthHeight: Math.min(root.width, root.height)
|
||||||
readonly property real opacityValue: Math.max(0, Math.min(1, actionDrawer.offset / root.minimizedQuickSettingsOffset))
|
readonly property real opacityValue: Math.max(0, Math.min(1, actionDrawer.offset / root.minimizedQuickSettingsOffset))
|
||||||
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||||
Kirigami.Theme.inherit: false
|
Kirigami.Theme.inherit: false
|
||||||
|
|
||||||
// fullscreen background
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
// darken if there are notifications
|
|
||||||
color: Qt.rgba(Kirigami.Theme.backgroundColor.r,
|
|
||||||
Kirigami.Theme.backgroundColor.g,
|
|
||||||
Kirigami.Theme.backgroundColor.b,
|
|
||||||
notificationWidget.hasNotifications ? 0.95 : 0.9)
|
|
||||||
Behavior on color { ColorAnimation { duration: Kirigami.Units.longDuration } }
|
|
||||||
opacity: opacityValue
|
|
||||||
}
|
|
||||||
|
|
||||||
P5Support.DataSource {
|
P5Support.DataSource {
|
||||||
id: timeSource
|
id: timeSource
|
||||||
engine: "time"
|
engine: "time"
|
||||||
|
|
@ -71,32 +57,17 @@ Item {
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: mediaWidget.bottom
|
top: mediaControlsWidgetProxy.bottom
|
||||||
topMargin: 0
|
topMargin: 0
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
bottomMargin: 0
|
bottomMargin: 0
|
||||||
right: quickSettings.left
|
right: quickSettingsPanel.left
|
||||||
left: parent.left
|
left: parent.left
|
||||||
}
|
}
|
||||||
anchors.margins: minWidthHeight * 0.06
|
anchors.margins: minWidthHeight * 0.06
|
||||||
|
|
||||||
MobileShell.NotificationsWidget {
|
MobileShell.BaseItem {
|
||||||
id: notificationWidget
|
id: notificationWidgetProxy
|
||||||
historyModel: root.actionDrawer.notificationModel
|
|
||||||
historyModelType: root.actionDrawer.notificationModelType
|
|
||||||
notificationSettings: root.actionDrawer.notificationSettings
|
|
||||||
actionsRequireUnlock: root.actionDrawer.restrictedPermissions
|
|
||||||
onUnlockRequested: root.actionDrawer.permissionsRequested()
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: root.actionDrawer
|
|
||||||
|
|
||||||
function onRunPendingNotificationAction() {
|
|
||||||
notificationWidget.runPendingAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onBackgroundClicked: root.actionDrawer.close();
|
|
||||||
|
|
||||||
// don't allow notifications widget to get too wide
|
// don't allow notifications widget to get too wide
|
||||||
Layout.maximumWidth: Kirigami.Units.gridUnit * 25
|
Layout.maximumWidth: Kirigami.Units.gridUnit * 25
|
||||||
|
|
@ -134,7 +105,7 @@ Item {
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
top: clock.bottom
|
top: clock.bottom
|
||||||
bottom: isOnLargeScreen ? columnLayout.top : mediaWidget.top
|
bottom: isOnLargeScreen ? columnLayout.top : mediaControlsWidgetProxy.top
|
||||||
topMargin: Kirigami.Units.smallSpacing
|
topMargin: Kirigami.Units.smallSpacing
|
||||||
leftMargin: columnLayout.anchors.margins
|
leftMargin: columnLayout.anchors.margins
|
||||||
}
|
}
|
||||||
|
|
@ -143,38 +114,35 @@ Item {
|
||||||
font.weight: Font.Light
|
font.weight: Font.Light
|
||||||
}
|
}
|
||||||
|
|
||||||
MobileShell.MediaControlsWidget {
|
MobileShell.BaseItem {
|
||||||
id: mediaWidget
|
id: mediaControlsWidgetProxy
|
||||||
property real fullHeight: visible ? height + Kirigami.Units.smallSpacing * 6 : 0
|
property real fullHeight: visible ? height + Kirigami.Units.smallSpacing * 6 : 0
|
||||||
|
|
||||||
y: isOnLargeScreen ? date.y - height + date.implicitHeight : date.y + date.implicitHeight + columnLayout.anchors.margins / 2
|
y: isOnLargeScreen ? date.y - height + date.implicitHeight : date.y + date.implicitHeight + columnLayout.anchors.margins / 2
|
||||||
|
|
||||||
inActionDrawer: true
|
|
||||||
opacity: columnLayout.opacity
|
opacity: columnLayout.opacity
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
right: quickSettings.left
|
right: quickSettingsPanel.left
|
||||||
left: isOnLargeScreen ? date.right : parent.left
|
left: isOnLargeScreen ? date.right : parent.left
|
||||||
leftMargin: columnLayout.anchors.margins
|
leftMargin: columnLayout.anchors.margins
|
||||||
rightMargin: columnLayout.anchors.margins - quickSettings.leftPadding
|
rightMargin: columnLayout.anchors.margins - quickSettingsPanel.leftPadding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// right sidebar
|
// right sidebar
|
||||||
MobileShell.QuickSettingsPanel {
|
MobileShell.QuickSettingsPanel {
|
||||||
id: quickSettings
|
id: quickSettingsPanel
|
||||||
height: quickSettings.contentImplicitHeight + quickSettings.topPadding + quickSettings.bottomPadding
|
height: quickSettingsPanel.contentImplicitHeight + quickSettingsPanel.topPadding + quickSettingsPanel.bottomPadding
|
||||||
width: intendedWidth
|
width: intendedWidth
|
||||||
|
|
||||||
readonly property real intendedWidth: 360
|
readonly property real intendedWidth: 360
|
||||||
|
|
||||||
property real offsetRatio: quickSettings.height / root.height
|
property real offsetRatio: quickSettingsPanel.height / root.height
|
||||||
anchors.topMargin: Math.min(root.actionDrawer.offset * offsetRatio - quickSettings.height, 0)
|
anchors.topMargin: Math.min(root.actionDrawer.offset * offsetRatio - quickSettingsPanel.height, 0)
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
actionDrawer: root.actionDrawer
|
actionDrawer: root.actionDrawer
|
||||||
quickSettingsModel: root.quickSettingsModel
|
|
||||||
fullScreenHeight: root.height
|
fullScreenHeight: root.height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
/*
|
// SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
|
||||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
import QtQuick.Layouts 1.1
|
import QtQuick.Layouts
|
||||||
import QtQuick.Window 2.2
|
import QtQuick.Window 2.2
|
||||||
|
|
||||||
import org.kde.plasma.private.mobileshell as MobileShell
|
import org.kde.plasma.private.mobileshell as MobileShell
|
||||||
|
|
@ -21,15 +18,17 @@ Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property var actionDrawer
|
required property var actionDrawer
|
||||||
property QS.QuickSettingsModel quickSettingsModel
|
|
||||||
|
|
||||||
property alias notificationsWidget: notificationWidget
|
|
||||||
|
|
||||||
// pinned position (disabled when openToPinnedMode is false)
|
// pinned position (disabled when openToPinnedMode is false)
|
||||||
readonly property real minimizedQuickSettingsOffset: quickSettings.minimizedHeight
|
readonly property real minimizedQuickSettingsOffset: quickSettingsDrawer.minimizedHeight
|
||||||
|
|
||||||
// fully open position
|
// fully open position
|
||||||
readonly property real maximizedQuickSettingsOffset: minimizedQuickSettingsOffset + quickSettings.maxAddedHeight
|
readonly property real maximizedQuickSettingsOffset: minimizedQuickSettingsOffset + quickSettingsDrawer.maxAddedHeight
|
||||||
|
|
||||||
|
property alias quickSettings: quickSettingsDrawer.quickSettings
|
||||||
|
property alias statusBar: quickSettingsDrawer.statusBar
|
||||||
|
property alias mediaControlsWidget: quickSettingsDrawer.mediaControlsWidget
|
||||||
|
property alias notificationsWidget: notificationWidgetProxy.contentItem
|
||||||
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||||
Kirigami.Theme.inherit: false
|
Kirigami.Theme.inherit: false
|
||||||
|
|
@ -38,20 +37,8 @@ Item {
|
||||||
return Math.max(0, Math.min(1, val));
|
return Math.max(0, Math.min(1, val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// fullscreen background
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
// darken if there are notifications
|
|
||||||
color: Qt.rgba(Kirigami.Theme.backgroundColor.r,
|
|
||||||
Kirigami.Theme.backgroundColor.g,
|
|
||||||
Kirigami.Theme.backgroundColor.b,
|
|
||||||
0.95)
|
|
||||||
Behavior on color { ColorAnimation { duration: Kirigami.Units.longDuration } }
|
|
||||||
opacity: Math.max(0, Math.min(1, actionDrawer.offset / root.minimizedQuickSettingsOffset))
|
|
||||||
}
|
|
||||||
|
|
||||||
MobileShell.QuickSettingsDrawer {
|
MobileShell.QuickSettingsDrawer {
|
||||||
id: quickSettings
|
id: quickSettingsDrawer
|
||||||
z: 1 // ensure it's above notifications
|
z: 1 // ensure it's above notifications
|
||||||
|
|
||||||
// physically move the drawer when between closed <-> pinned mode
|
// physically move the drawer when between closed <-> pinned mode
|
||||||
|
|
@ -62,7 +49,6 @@ Item {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
actionDrawer: root.actionDrawer
|
actionDrawer: root.actionDrawer
|
||||||
quickSettingsModel: root.quickSettingsModel
|
|
||||||
|
|
||||||
// opacity and move animation (disabled when openToPinnedMode is false)
|
// opacity and move animation (disabled when openToPinnedMode is false)
|
||||||
property real offsetDist: actionDrawer.offset - minimizedQuickSettingsOffset
|
property real offsetDist: actionDrawer.offset - minimizedQuickSettingsOffset
|
||||||
|
|
@ -79,44 +65,29 @@ Item {
|
||||||
addedHeight: {
|
addedHeight: {
|
||||||
if (!actionDrawer.openToPinnedMode) {
|
if (!actionDrawer.openToPinnedMode) {
|
||||||
// if pinned mode disabled, just go to full height
|
// if pinned mode disabled, just go to full height
|
||||||
let progress = (root.actionDrawer.offset - maximizedQuickSettingsOffset) / (quickSettings.maxAddedHeight * 4);
|
let progress = (root.actionDrawer.offset - maximizedQuickSettingsOffset) / (quickSettingsDrawer.maxAddedHeight * 4);
|
||||||
let effectProgress = Math.atan(Math.max(0, progress));
|
let effectProgress = Math.atan(Math.max(0, progress));
|
||||||
return (quickSettings.maxAddedHeight * effectProgress) + quickSettings.maxAddedHeight;
|
return (quickSettingsDrawer.maxAddedHeight * effectProgress) + quickSettingsDrawer.maxAddedHeight;
|
||||||
} else if (!actionDrawer.opened) {
|
} else if (!actionDrawer.opened) {
|
||||||
// over-scroll effect for initial opening
|
// over-scroll effect for initial opening
|
||||||
let progress = (root.actionDrawer.offset - minimizedQuickSettingsOffset) / quickSettings.maxAddedHeight;
|
let progress = (root.actionDrawer.offset - minimizedQuickSettingsOffset) / quickSettingsDrawer.maxAddedHeight;
|
||||||
let effectProgress = Math.atan(Math.max(0, progress));
|
let effectProgress = Math.atan(Math.max(0, progress));
|
||||||
return quickSettings.maxAddedHeight * 0.25 * effectProgress;
|
return quickSettingsDrawer.maxAddedHeight * 0.25 * effectProgress;
|
||||||
} else {
|
} else {
|
||||||
// over-scroll effect for full drawer
|
// over-scroll effect for full drawer
|
||||||
let progress = (root.actionDrawer.offset - maximizedQuickSettingsOffset) / (quickSettings.maxAddedHeight * 4);
|
let progress = (root.actionDrawer.offset - maximizedQuickSettingsOffset) / (quickSettingsDrawer.maxAddedHeight * 4);
|
||||||
let effectProgress = Math.atan(Math.max(0, progress));
|
let effectProgress = Math.atan(Math.max(0, progress));
|
||||||
// as the drawer opens, add height to the rectangle, revealing content
|
// as the drawer opens, add height to the rectangle, revealing content
|
||||||
return (quickSettings.maxAddedHeight * effectProgress) + Math.max(0, Math.min(quickSettings.maxAddedHeight, root.actionDrawer.offset - minimizedQuickSettingsOffset));
|
return (quickSettingsDrawer.maxAddedHeight * effectProgress) + Math.max(0, Math.min(quickSettingsDrawer.maxAddedHeight, root.actionDrawer.offset - minimizedQuickSettingsOffset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MobileShell.NotificationsWidget {
|
MobileShell.BaseItem {
|
||||||
id: notificationWidget
|
id: notificationWidgetProxy
|
||||||
historyModel: root.actionDrawer.notificationModel
|
|
||||||
historyModelType: root.actionDrawer.notificationModelType
|
|
||||||
notificationSettings: root.actionDrawer.notificationSettings
|
|
||||||
actionsRequireUnlock: root.actionDrawer.restrictedPermissions
|
|
||||||
onUnlockRequested: root.actionDrawer.permissionsRequested()
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: root.actionDrawer
|
|
||||||
|
|
||||||
function onRunPendingNotificationAction() {
|
|
||||||
notificationWidget.runPendingAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onBackgroundClicked: root.actionDrawer.close();
|
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: quickSettings.bottom
|
top: quickSettingsDrawer.bottom
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
left: parent.left
|
left: parent.left
|
||||||
right: parent.right
|
right: parent.right
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,12 @@ import org.kde.kirigami 2.20 as Kirigami
|
||||||
*/
|
*/
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
layer.enabled: true
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
required property var actionDrawer
|
required property var actionDrawer
|
||||||
|
|
||||||
property QS.QuickSettingsModel quickSettingsModel
|
required property QS.QuickSettingsModel quickSettingsModel
|
||||||
|
|
||||||
readonly property real columns: Math.round(Math.min(6, Math.max(3, width / intendedColumnWidth)))
|
readonly property real columns: Math.round(Math.min(6, Math.max(3, width / intendedColumnWidth)))
|
||||||
readonly property real columnWidth: Math.floor(width / columns)
|
readonly property real columnWidth: Math.floor(width / columns)
|
||||||
|
|
@ -89,9 +90,10 @@ Item {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
id: repeater
|
||||||
model: QS.PaginateModel {
|
model: QS.PaginateModel {
|
||||||
sourceModel: quickSettingsModel
|
sourceModel: root.quickSettingsModel
|
||||||
pageSize: minimizedColumns
|
pageSize: Math.min(root.pageSize, root.minimizedColumns) // HACK: just root.minimizedColumns appears to end up with an empty model?
|
||||||
}
|
}
|
||||||
delegate: MobileShell.BaseItem {
|
delegate: MobileShell.BaseItem {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
/*
|
// SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
|
||||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
|
|
@ -24,8 +21,6 @@ MobileShell.BaseItem {
|
||||||
|
|
||||||
required property var actionDrawer
|
required property var actionDrawer
|
||||||
|
|
||||||
property QS.QuickSettingsModel quickSettingsModel
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount of height to add to the panel (increasing the height of the quick settings area).
|
* The amount of height to add to the panel (increasing the height of the quick settings area).
|
||||||
*/
|
*/
|
||||||
|
|
@ -39,7 +34,7 @@ MobileShell.BaseItem {
|
||||||
/**
|
/**
|
||||||
* Height of panel when in minimized mode.
|
* Height of panel when in minimized mode.
|
||||||
*/
|
*/
|
||||||
readonly property real minimizedHeight: bottomPadding + topPadding + statusBar.height + minimizedQuickSettingsHeight + mediaWidget.height + handle.fullHeight
|
readonly property real minimizedHeight: bottomPadding + topPadding + statusBarProxy.height + minimizedQuickSettingsHeight + mediaControlsWidgetProxy.height + handle.fullHeight
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Height of just the QuickSettings component in minimized mode.
|
* Height of just the QuickSettings component in minimized mode.
|
||||||
|
|
@ -51,6 +46,10 @@ MobileShell.BaseItem {
|
||||||
*/
|
*/
|
||||||
property real minimizedToFullProgress: 1
|
property real minimizedToFullProgress: 1
|
||||||
|
|
||||||
|
property alias quickSettings: quickSettingsProxy.contentItem
|
||||||
|
property alias statusBar: statusBarProxy.contentItem
|
||||||
|
property alias mediaControlsWidget: mediaControlsWidgetProxy.contentItem
|
||||||
|
|
||||||
// we need extra padding if the background side border is enabled
|
// we need extra padding if the background side border is enabled
|
||||||
topPadding: Kirigami.Units.smallSpacing
|
topPadding: Kirigami.Units.smallSpacing
|
||||||
leftPadding: Kirigami.Units.smallSpacing
|
leftPadding: Kirigami.Units.smallSpacing
|
||||||
|
|
@ -74,39 +73,25 @@ MobileShell.BaseItem {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
MobileShell.StatusBar {
|
MobileShell.BaseItem {
|
||||||
id: statusBar
|
id: statusBarProxy
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: MobileShell.Constants.topPanelHeight + Kirigami.Units.gridUnit * 0.8
|
Layout.preferredHeight: MobileShell.Constants.topPanelHeight + Kirigami.Units.gridUnit * 0.8
|
||||||
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
|
||||||
Kirigami.Theme.inherit: false
|
|
||||||
|
|
||||||
backgroundColor: "transparent"
|
|
||||||
showSecondRow: true
|
|
||||||
showDropShadow: false
|
|
||||||
|
|
||||||
// security reasons, system tray also doesn't work on lockscreen
|
|
||||||
disableSystemTray: actionDrawer.restrictedPermissions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MobileShell.QuickSettings {
|
MobileShell.BaseItem {
|
||||||
id: quickSettings
|
id: quickSettingsProxy
|
||||||
Layout.preferredHeight: root.minimizedQuickSettingsHeight + root.addedHeight
|
Layout.preferredHeight: root.minimizedQuickSettingsHeight + root.addedHeight
|
||||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
actionDrawer: root.actionDrawer
|
|
||||||
quickSettingsModel: root.quickSettingsModel
|
|
||||||
fullViewProgress: root.minimizedToFullProgress
|
|
||||||
height: root.minimizedQuickSettingsHeight + root.addedHeight
|
height: root.minimizedQuickSettingsHeight + root.addedHeight
|
||||||
width: parent.width
|
width: parent.width
|
||||||
}
|
}
|
||||||
|
|
||||||
MobileShell.MediaControlsWidget {
|
MobileShell.BaseItem {
|
||||||
id: mediaWidget
|
id: mediaControlsWidgetProxy
|
||||||
property real fullHeight: height + Layout.topMargin
|
property real fullHeight: height + Layout.topMargin
|
||||||
inActionDrawer: true
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
/*
|
// SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
|
||||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
|
|
@ -36,6 +33,9 @@ MobileShell.BaseItem {
|
||||||
*/
|
*/
|
||||||
readonly property real contentImplicitHeight: column.implicitHeight
|
readonly property real contentImplicitHeight: column.implicitHeight
|
||||||
|
|
||||||
|
property alias quickSettings: quickSettingsProxy.contentItem
|
||||||
|
property alias statusBar: statusBarProxy.contentItem
|
||||||
|
|
||||||
// we need extra padding since the background side border is enabled
|
// we need extra padding since the background side border is enabled
|
||||||
topPadding: Kirigami.Units.smallSpacing * 4
|
topPadding: Kirigami.Units.smallSpacing * 4
|
||||||
leftPadding: Kirigami.Units.smallSpacing * 4
|
leftPadding: Kirigami.Units.smallSpacing * 4
|
||||||
|
|
@ -59,8 +59,8 @@ MobileShell.BaseItem {
|
||||||
height: root.fullScreenHeight
|
height: root.fullScreenHeight
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
MobileShell.StatusBar {
|
MobileShell.BaseItem {
|
||||||
id: statusBar
|
id: statusBarProxy
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
// Align these to double pixels to aid vertical alignment and sharper icon rendering
|
// Align these to double pixels to aid vertical alignment and sharper icon rendering
|
||||||
|
|
@ -69,30 +69,17 @@ MobileShell.BaseItem {
|
||||||
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||||
Kirigami.Theme.inherit: false
|
Kirigami.Theme.inherit: false
|
||||||
|
|
||||||
backgroundColor: "transparent"
|
|
||||||
showSecondRow: false
|
|
||||||
showDropShadow: false
|
|
||||||
showTime: false
|
|
||||||
|
|
||||||
// security reasons, system tray also doesn't work on lockscreen
|
|
||||||
disableSystemTray: actionDrawer.restrictedPermissions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MobileShell.QuickSettings {
|
MobileShell.BaseItem {
|
||||||
id: quickSettings
|
id: quickSettingsProxy
|
||||||
|
|
||||||
quickSettingsModel: root.quickSettingsModel
|
|
||||||
width: column.width
|
width: column.width
|
||||||
implicitHeight: quickSettings.fullHeight
|
implicitHeight: quickSettings.fullHeight
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.maximumHeight: root.fullScreenHeight - root.topPadding - root.bottomPadding - statusBar.height - Kirigami.Units.smallSpacing
|
Layout.maximumHeight: root.fullScreenHeight - root.topPadding - root.bottomPadding - statusBarProxy.height - Kirigami.Units.smallSpacing
|
||||||
Layout.maximumWidth: column.width
|
Layout.maximumWidth: column.width
|
||||||
|
|
||||||
actionDrawer: root.actionDrawer
|
|
||||||
fullViewProgress: 1.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { Layout.fillHeight: true }
|
Item { Layout.fillHeight: true }
|
||||||
|
|
|
||||||
|
|
@ -31,13 +31,17 @@ Item {
|
||||||
implicitWidth: leftPadding + rightPadding + contentItem.implicitWidth
|
implicitWidth: leftPadding + rightPadding + contentItem.implicitWidth
|
||||||
|
|
||||||
onContentItemChanged: {
|
onContentItemChanged: {
|
||||||
contentItem.parent = contentItemLoader;
|
if (contentItem !== null && contentItem !== undefined) {
|
||||||
contentItem.anchors.fill = contentItemLoader;
|
contentItem.parent = contentItemLoader;
|
||||||
|
contentItem.anchors.fill = contentItemLoader;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onBackgroundChanged: {
|
onBackgroundChanged: {
|
||||||
background.parent = backgroundLoader;
|
if (background !== null && background !== undefined) {
|
||||||
background.anchors.fill = backgroundLoader;
|
background.parent = backgroundLoader;
|
||||||
|
background.anchors.fill = backgroundLoader;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ ApplicationWindow {
|
||||||
id: drawer
|
id: drawer
|
||||||
z: 1
|
z: 1
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
visible: offset !== 0
|
||||||
|
|
||||||
notificationSettings: NotificationManager.Settings {}
|
notificationSettings: NotificationManager.Settings {}
|
||||||
notificationModelType: MobileShell.NotificationsModelType.WatchedNotificationsModel
|
notificationModelType: MobileShell.NotificationsModelType.WatchedNotificationsModel
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue