mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-06-24 23:27:43 +00:00
Compare commits
3 commits
d1cd5f09d8
...
8f3a94b104
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f3a94b104 | |||
| 86283b526d | |||
| c2b864d8b4 |
13 changed files with 102 additions and 32 deletions
|
|
@ -11,6 +11,7 @@ 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
|
||||
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
|
||||
|
||||
/**
|
||||
* Root element that contains all the ActionDrawer's contents, and is anchored to the screen.
|
||||
|
|
@ -62,7 +63,10 @@ Item {
|
|||
Kirigami.Theme.backgroundColor.b,
|
||||
0.9)
|
||||
Behavior on color { ColorAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.OutQuad } }
|
||||
opacity: Math.max(0, Math.min(brightnessPressedValue, actionDrawer.offset / root.minimizedQuickSettingsOffset))
|
||||
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.
|
||||
|
|
@ -106,8 +110,8 @@ Item {
|
|||
|
||||
anchors {
|
||||
topMargin: notificationDrawer.height + 1
|
||||
leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : 10
|
||||
rightMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : notificationDrawer.notificationWidget.anchors.rightMargin + Kirigami.Units.gridUnit - notificationDrawer.anchors.leftMargin + 370
|
||||
leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (notificationDrawer.isConvergence ? Kirigami.Units.smallSpacing : 10)
|
||||
rightMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (notificationDrawer.isConvergence ? parent.width * 0.5 : notificationDrawer.notificationWidget.anchors.rightMargin + Kirigami.Units.gridUnit - notificationDrawer.anchors.leftMargin + 370)
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
|
|
@ -160,19 +164,28 @@ Item {
|
|||
NotificationDrawer {
|
||||
id: notificationDrawer
|
||||
|
||||
readonly property bool isConvergence: ShellSettings.Settings.convergenceModeEnabled
|
||||
|
||||
swipeArea: swipeAreaPortrait
|
||||
actionDrawer: root.actionDrawer
|
||||
mediaControlsWidget: root.mediaControlsWidget
|
||||
contentContainer: root
|
||||
opacity: Math.max(0, Math.min(root.brightnessPressedValue, actionDrawer.offsetResistance / root.minimizedQuickSettingsOffset))
|
||||
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
|
||||
rightMargin: root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : 360
|
||||
leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : notificationDrawer.minWidthHeight * 0.06
|
||||
topMargin: isConvergence ? Kirigami.Units.smallSpacing : 0
|
||||
rightMargin: root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (isConvergence ? parent.width * 0.5 : 360)
|
||||
leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (isConvergence ? Kirigami.Units.smallSpacing : notificationDrawer.minWidthHeight * 0.06)
|
||||
}
|
||||
|
||||
// In convergence, cap the height so it doesn't stretch full-screen
|
||||
maximumHeight: isConvergence ? root.height * 0.6 : -1
|
||||
}
|
||||
|
||||
// Secondary swipe area for uses in portrait.
|
||||
|
|
|
|||
|
|
@ -56,10 +56,14 @@ Item {
|
|||
: ShellSettings.Settings.quickSettingsColumns
|
||||
readonly property real intendedWidth: (columnWidth * effectiveColumns) + Kirigami.Units.gridUnit
|
||||
|
||||
property real offsetRatio: quickSettingsPanel.height / root.height
|
||||
anchors.topMargin: Math.min(root.actionDrawer.offsetResistance * offsetRatio - quickSettingsPanel.height, 0)
|
||||
readonly property bool isConvergence: ShellSettings.Settings.convergenceModeEnabled
|
||||
property real offsetRatio: (quickSettingsPanel.height + restingTopMargin) / root.height
|
||||
readonly property real restingTopMargin: isConvergence ? Kirigami.Units.smallSpacing : 0
|
||||
anchors.topMargin: isConvergence ? restingTopMargin : Math.min(root.actionDrawer.offsetResistance * offsetRatio - quickSettingsPanel.height, 0)
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: isConvergence ? Kirigami.Units.smallSpacing : 0
|
||||
opacity: isConvergence ? Math.max(0, Math.min(1, root.actionDrawer.offset / root.minimizedQuickSettingsOffset)) : 1
|
||||
|
||||
actionDrawer: root.actionDrawer
|
||||
fullScreenHeight: root.height
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import QtQuick.Layouts 1.1
|
|||
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.private.mobileshell.shellsettingsplugin as ShellSettings
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
Item {
|
||||
|
|
@ -24,14 +25,26 @@ Item {
|
|||
property alias notificationWidget: notificationWidget
|
||||
property real contentY: notificationWidget.listView.contentY
|
||||
|
||||
property real topPadding: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? Kirigami.Units.largeSpacing : date.y + date.height + Kirigami.Units.smallSpacing * 6
|
||||
property real topPadding: {
|
||||
if (actionDrawer.mode == MobileShell.ActionDrawer.Portrait)
|
||||
return Kirigami.Units.largeSpacing;
|
||||
if (ShellSettings.Settings.convergenceModeEnabled)
|
||||
return Kirigami.Units.largeSpacing;
|
||||
return date.y + date.height + Kirigami.Units.smallSpacing * 6;
|
||||
}
|
||||
property real topMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? actionDrawer.offsetResistance + 1 : 0
|
||||
|
||||
readonly property real minWidthHeight: Math.min(actionDrawer.width, actionDrawer.height)
|
||||
readonly property bool hasNotifications: notificationWidget.hasNotifications
|
||||
readonly property bool listOverflowing: notificationWidget.listView.listOverflowing
|
||||
|
||||
height: Math.min(actionDrawer.height - toolButtons.height, notificationWidget.listView.contentHeight + 10 + topMargin)
|
||||
// External cap for convergence mode; -1 means uncapped.
|
||||
property real maximumHeight: -1
|
||||
|
||||
height: {
|
||||
let h = Math.min(actionDrawer.height - toolButtons.height, notificationWidget.listView.contentHeight + 10 + topMargin);
|
||||
return maximumHeight > 0 ? Math.min(h, maximumHeight) : h;
|
||||
}
|
||||
|
||||
// time source for the time and date whenin landscape mode
|
||||
Clock {
|
||||
|
|
@ -155,6 +168,7 @@ Item {
|
|||
id: landscapeModeHeader
|
||||
anchors.fill: parent
|
||||
visible: actionDrawer.mode != MobileShell.ActionDrawer.Portrait
|
||||
&& !ShellSettings.Settings.convergenceModeEnabled
|
||||
|
||||
transform: [
|
||||
Translate {
|
||||
|
|
|
|||
|
|
@ -73,9 +73,11 @@ MobileShell.BaseItem {
|
|||
id: statusBarProxy
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
// Hide status bar in convergence — already visible in the top panel
|
||||
visible: !ShellSettings.Settings.convergenceModeEnabled
|
||||
// Align these to double pixels to aid vertical alignment and sharper icon rendering
|
||||
Layout.preferredHeight: Math.round(Kirigami.Units.gridUnit * 1.5 * ShellSettings.Settings.statusBarScaleFactor / 2) * 2
|
||||
Layout.maximumHeight: Math.round(Kirigami.Units.gridUnit * 1.5 * ShellSettings.Settings.statusBarScaleFactor / 2) * 2
|
||||
Layout.preferredHeight: visible ? Math.round(Kirigami.Units.gridUnit * 1.5 * ShellSettings.Settings.statusBarScaleFactor / 2) * 2 : 0
|
||||
Layout.maximumHeight: visible ? Math.round(Kirigami.Units.gridUnit * 1.5 * ShellSettings.Settings.statusBarScaleFactor / 2) * 2 : 0
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||
Kirigami.Theme.inherit: false
|
||||
|
|
|
|||
|
|
@ -27,6 +27,15 @@ Item {
|
|||
// 'popupWidth' and 'openOffset' is set by the 'notificationPopupManager'
|
||||
property int popupWidth
|
||||
property real openOffset
|
||||
property bool isConvergence: false
|
||||
|
||||
// In convergence the popup enters from the bottom-right corner
|
||||
readonly property real effectiveOpenOffset: isConvergence
|
||||
? (Screen.height - openOffset - popupHeight)
|
||||
: openOffset
|
||||
readonly property real effectiveClosedOffset: isConvergence
|
||||
? (Screen.height + Kirigami.Units.smallSpacing)
|
||||
: closedOffset
|
||||
|
||||
// calculate the position needed to at when the expanded drawer is active
|
||||
readonly property real fullOpenOffset: popupDrawerOpened ? aboveNotificationFullOffset + aboveNotificationHeight + Kirigami.Units.largeSpacing : 0
|
||||
|
|
@ -244,7 +253,7 @@ Item {
|
|||
waiting = false;
|
||||
inPopupDrawer = true;
|
||||
if (notificationPopup.popupDrawerOpened && notificationItem.state != "inDrawerClosed" && notificationItem.state != "open") {
|
||||
notificationItem.offset = openOffset;
|
||||
notificationItem.offset = effectiveOpenOffset;
|
||||
notificationItem.scale = 0.75;
|
||||
notificationItem.popupOpacity = 0.0;
|
||||
}
|
||||
|
|
@ -255,7 +264,7 @@ Item {
|
|||
|
||||
function openPopup() {
|
||||
if (notificationPopup.popupDrawerOpened && notificationItem.state != "open" && notificationItem.state != "inDrawerClosed") {
|
||||
notificationItem.offset = openOffset;
|
||||
notificationItem.offset = effectiveOpenOffset;
|
||||
notificationItem.scale = 0.75;
|
||||
notificationItem.popupOpacity = 0.0;
|
||||
}
|
||||
|
|
@ -343,7 +352,7 @@ Item {
|
|||
|
||||
onDismissRequested: closePopup(popupIndex)
|
||||
|
||||
property real offset: closedOffset
|
||||
property real offset: notificationPopup.effectiveClosedOffset
|
||||
property real scale: 1.0
|
||||
property real popupOpacity: 1.0 // controls the opacity of the notification popup when outside the popup drawer
|
||||
property real drawerScale: {
|
||||
|
|
@ -365,6 +374,9 @@ Item {
|
|||
return Kirigami.Units.gridUnit * 0.5 * indexClamped;
|
||||
}
|
||||
property real drawerOpacity: {
|
||||
if (notificationPopup.isConvergence && notificationPopup.inPopupDrawer) {
|
||||
return 0;
|
||||
}
|
||||
let index = notificationPopup.popupIndex - popupNotifications.currentPopupIndex;
|
||||
if (index > 2 && !notificationPopup.popupDrawerOpened) {
|
||||
return 0; // make this popup invisible if it is below 3 other popups
|
||||
|
|
@ -399,7 +411,7 @@ Item {
|
|||
State {
|
||||
name: "open"
|
||||
PropertyChanges {
|
||||
target: notificationItem; offset: notificationPopup.openOffset
|
||||
target: notificationItem; offset: notificationPopup.effectiveOpenOffset
|
||||
}
|
||||
PropertyChanges {
|
||||
target: notificationItem; scale: 1.0
|
||||
|
|
@ -411,7 +423,7 @@ Item {
|
|||
State {
|
||||
name: "closeWithMove"
|
||||
PropertyChanges {
|
||||
target: notificationItem; offset: notificationPopup.closedOffset
|
||||
target: notificationItem; offset: notificationPopup.effectiveClosedOffset
|
||||
}
|
||||
PropertyChanges {
|
||||
target: notificationItem; scale: 1.0
|
||||
|
|
@ -423,7 +435,7 @@ Item {
|
|||
State {
|
||||
name: "closeWithScale"
|
||||
PropertyChanges {
|
||||
target: notificationItem; offset: notificationPopup.openOffset
|
||||
target: notificationItem; offset: notificationPopup.effectiveOpenOffset
|
||||
}
|
||||
PropertyChanges {
|
||||
target: notificationItem; scale: 0.75
|
||||
|
|
@ -435,7 +447,7 @@ Item {
|
|||
State {
|
||||
name: "inDrawerClosed"
|
||||
PropertyChanges {
|
||||
target: notificationItem; offset: notificationPopup.openOffset
|
||||
target: notificationItem; offset: notificationPopup.effectiveOpenOffset
|
||||
}
|
||||
PropertyChanges {
|
||||
target: notificationItem; scale: 1
|
||||
|
|
@ -556,15 +568,29 @@ Item {
|
|||
startActive = false;
|
||||
}
|
||||
lastOffset = notificationPopup.dragOffset;
|
||||
notificationPopup.dragOffset = calculateResistance(startDragOffset + (translation.y - startPosition), 0);
|
||||
let rawOffset = startDragOffset + (translation.y - startPosition);
|
||||
if (notificationPopup.isConvergence) {
|
||||
notificationPopup.dragOffset = -calculateResistance(-rawOffset, 0);
|
||||
} else {
|
||||
notificationPopup.dragOffset = calculateResistance(rawOffset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
startActive = active;
|
||||
notificationPopup.preventDismissTimeout = true;
|
||||
if (!active && !(notificationItem.state == "closeWithScale" || notificationItem.state == "closeWithMove")) {
|
||||
if ((lastOffset - notificationPopup.dragOffset > 1.0 && notificationPopup.dragOffset < 0) || (-(notificationPopup.openOffset - notificationPopup.closedOffset) / 4 > notificationPopup.dragOffset)) {
|
||||
// this code is called when the notification is swiped or dragged to the top.
|
||||
let dominated = false;
|
||||
if (notificationPopup.isConvergence) {
|
||||
// convergence: dismiss on swipe down
|
||||
dominated = (notificationPopup.dragOffset - lastOffset > 1.0 && notificationPopup.dragOffset > 0)
|
||||
|| (notificationPopup.dragOffset > (notificationPopup.effectiveClosedOffset - notificationPopup.effectiveOpenOffset) / 4);
|
||||
} else {
|
||||
// mobile: dismiss on swipe up
|
||||
dominated = (lastOffset - notificationPopup.dragOffset > 1.0 && notificationPopup.dragOffset < 0)
|
||||
|| (-(notificationPopup.openOffset - notificationPopup.closedOffset) / 4 > notificationPopup.dragOffset);
|
||||
}
|
||||
if (dominated) {
|
||||
notificationPopup.closedWithSwipe = true;
|
||||
notificationPopup.closePopup(popupIndex);
|
||||
return;
|
||||
|
|
@ -589,7 +615,7 @@ Item {
|
|||
|
||||
height: Kirigami.Units.gridUnit * 2
|
||||
|
||||
enabled: !notificationPopup.popupDrawerOpened && (notificationPopup.popupCount - popupNotifications.currentPopupIndex > 1)
|
||||
enabled: !notificationPopup.isConvergence && !notificationPopup.popupDrawerOpened && (notificationPopup.popupCount - popupNotifications.currentPopupIndex > 1)
|
||||
|
||||
onReleased: {
|
||||
notificationPopup.openPopupDrawer();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import QtQuick.Window
|
|||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.plasma.private.mobileshell as MobileShell
|
||||
import org.kde.plasma.private.mobileshell.state as MobileShellState
|
||||
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
|
||||
|
||||
import org.kde.layershell 1.0 as LayerShell
|
||||
|
||||
|
|
@ -31,6 +32,7 @@ Window {
|
|||
readonly property int popupWidth: Math.min(Kirigami.Units.gridUnit * 20, Screen.width - Kirigami.Units.gridUnit * 2)
|
||||
readonly property real openOffset: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 3
|
||||
readonly property int longestLength: Math.max(Screen.width, Screen.height)
|
||||
readonly property bool isConvergence: ShellSettings.Settings.convergenceModeEnabled
|
||||
property var keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
||||
|
||||
LayerShell.Window.scope: "notification"
|
||||
|
|
@ -97,9 +99,15 @@ Window {
|
|||
console.warn("popupNotification: could not retrieve current popup height - falling back to a default value")
|
||||
}
|
||||
|
||||
if (isConvergence) {
|
||||
let regionX = notificationPopupManager.width - notificationPopupManager.popupWidth - Kirigami.Units.gridUnit * 4;
|
||||
let regionY = Screen.height - openOffset - popupHeight - Kirigami.Units.gridUnit;
|
||||
ShellUtil.setInputRegion(notificationPopupManager, Qt.rect(regionX, regionY, notificationPopupManager.popupWidth + Kirigami.Units.gridUnit * 2, popupHeight + Kirigami.Units.gridUnit * 2));
|
||||
} else {
|
||||
ShellUtil.setInputRegion(notificationPopupManager, Qt.rect((notificationPopupManager.width - notificationPopupManager.popupWidth - Kirigami.Units.gridUnit) / 2, openOffset - Kirigami.Units.gridUnit / 2, notificationPopupManager.popupWidth + Kirigami.Units.gridUnit, popupHeight + Kirigami.Units.gridUnit * ((notifications.count - notifications.currentPopupIndex > 1) ? 4 : 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parent the popup notifications inside a Flickable so that they can be scrollable when the drawer state is active
|
||||
Flickable {
|
||||
|
|
@ -194,9 +202,12 @@ Window {
|
|||
delegate: NotificationPopup {
|
||||
id: popup
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
x: notificationPopupManager.isConvergence
|
||||
? (parent.width - width - Kirigami.Units.gridUnit * 2)
|
||||
: (parent.width - width) / 2
|
||||
z: notifications.count - index
|
||||
|
||||
isConvergence: notificationPopupManager.isConvergence
|
||||
popupWidth: notificationPopupManager.popupWidth
|
||||
openOffset: notificationPopupManager.openOffset
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ QMap<QString, QMap<QString, QVariant>> getKwinrcSettings(KSharedConfig::Ptr m_mo
|
|||
{
|
||||
{"blurEnabled", false}, // disable blur for performance reasons, we could reconsider in the future for more powerful devices
|
||||
{"convergentwindowsEnabled", true}, // enable our convergent window plugin
|
||||
{"mobiletaskswitcherEnabled", true}, // ensure the mobile task switcher plugin is enabled
|
||||
{"mobiletaskswitcherEnabled", !convergenceModeEnabled}, // mobile task switcher on phone only; convergence uses standard Alt-Tab tabbox
|
||||
{"overviewEnabled", convergenceModeEnabled}, // enable KWin Overview effect in convergence mode for desktop-style task switching
|
||||
{"screenedgeEnabled", convergenceModeEnabled} // enable screen edge visual feedback in convergence mode (mouse hot corners)
|
||||
}},
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
SPDX-FileCopyrightText: 2025 Marco A.
|
||||
SPDX-FileCopyrightText: 2026 Marco Allegretti.
|
||||
SPDX-License-Identifier: EUPL-1.2
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
SPDX-FileCopyrightText: 2025 Marco A.
|
||||
SPDX-FileCopyrightText: 2026 Marco Allegretti.
|
||||
SPDX-License-Identifier: EUPL-1.2
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
SPDX-FileCopyrightText: 2025 Marco A.
|
||||
SPDX-FileCopyrightText: 2026 Marco Allegretti.
|
||||
SPDX-License-Identifier: EUPL-1.2
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
SPDX-FileCopyrightText: 2025 Marco A.
|
||||
SPDX-FileCopyrightText: 2026 Marco Allegretti.
|
||||
SPDX-License-Identifier: EUPL-1.2
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
SPDX-FileCopyrightText: 2025 Marco A.
|
||||
SPDX-FileCopyrightText: 2026 Marco Allegretti.
|
||||
SPDX-License-Identifier: EUPL-1.2
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
SPDX-FileCopyrightText: 2025 Marco A.
|
||||
SPDX-FileCopyrightText: 2026 Marco Allegretti.
|
||||
SPDX-License-Identifier: EUPL-1.2
|
||||
|
|
|
|||
Loading…
Reference in a new issue