mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-07-26 06:14:45 +00:00
lockscreen: Refactor and lazy load notifications
This commit is contained in:
parent
c4472ca39a
commit
2a779900f3
5 changed files with 310 additions and 294 deletions
|
|
@ -12,80 +12,75 @@ import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||||
|
|
||||||
import org.kde.notificationmanager 1.0 as NotificationManager
|
import org.kde.notificationmanager 1.0 as NotificationManager
|
||||||
|
|
||||||
Loader {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property real openFactor
|
required property real openFactor
|
||||||
|
required property real statusBarHeight
|
||||||
readonly property real statusBarHeight: PlasmaCore.Units.gridUnit * 1.25
|
|
||||||
|
|
||||||
property var notificationsModel: []
|
property var notificationsModel: []
|
||||||
|
|
||||||
signal passwordRequested()
|
signal passwordRequested()
|
||||||
|
|
||||||
asynchronous: true
|
// top status bar
|
||||||
|
MobileShell.StatusBar {
|
||||||
sourceComponent: Item {
|
id: statusBar
|
||||||
// top status bar
|
|
||||||
MobileShell.StatusBar {
|
anchors.top: parent.top
|
||||||
id: statusBar
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
height: root.statusBarHeight
|
||||||
anchors.right: parent.right
|
|
||||||
|
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
||||||
height: root.statusBarHeight
|
backgroundColor: "transparent"
|
||||||
|
|
||||||
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
showSecondRow: false
|
||||||
backgroundColor: "transparent"
|
showDropShadow: true
|
||||||
|
showTime: false
|
||||||
showSecondRow: false
|
disableSystemTray: true // prevent SIGABRT, since loading the system tray on the lockscreen leads to bad... things
|
||||||
showDropShadow: true
|
}
|
||||||
showTime: false
|
|
||||||
disableSystemTray: true // prevent SIGABRT, since loading the system tray on the lockscreen leads to bad... things
|
// drag down gesture to open action drawer
|
||||||
|
MobileShell.ActionDrawerOpenSurface {
|
||||||
|
id: swipeArea
|
||||||
|
actionDrawer: drawer
|
||||||
|
anchors.fill: statusBar
|
||||||
|
}
|
||||||
|
|
||||||
|
// action drawer component
|
||||||
|
MobileShell.ActionDrawer {
|
||||||
|
id: drawer
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
visible: offset !== 0
|
||||||
|
restrictedPermissions: true
|
||||||
|
|
||||||
|
notificationSettings: NotificationManager.Settings {}
|
||||||
|
notificationModel: root.notificationsModel
|
||||||
|
notificationModelType: MobileShell.NotificationsModelType.WatchedNotificationsModel
|
||||||
|
|
||||||
|
property bool requestNotificationAction: false
|
||||||
|
|
||||||
|
// notification button clicked, requesting auth
|
||||||
|
onPermissionsRequested: {
|
||||||
|
requestNotificationAction = true;
|
||||||
|
drawer.close();
|
||||||
|
root.passwordRequested();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// drag down gesture to open action drawer
|
|
||||||
MobileShell.ActionDrawerOpenSurface {
|
// listen to authentication events
|
||||||
id: swipeArea
|
Connections {
|
||||||
actionDrawer: drawer
|
target: authenticator
|
||||||
anchors.fill: statusBar
|
function onSucceeded() {
|
||||||
}
|
// run pending action if successfully unlocked
|
||||||
|
if (drawer.requestNotificationAction) {
|
||||||
// action drawer component
|
drawer.runPendingAction();
|
||||||
MobileShell.ActionDrawer {
|
|
||||||
id: drawer
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
restrictedPermissions: true
|
|
||||||
|
|
||||||
notificationSettings: NotificationManager.Settings {}
|
|
||||||
notificationModel: root.notificationsModel
|
|
||||||
notificationModelType: MobileShell.NotificationsModelType.WatchedNotificationsModel
|
|
||||||
|
|
||||||
property bool requestNotificationAction: false
|
|
||||||
|
|
||||||
// notification button clicked, requesting auth
|
|
||||||
onPermissionsRequested: {
|
|
||||||
requestNotificationAction = true;
|
|
||||||
drawer.close();
|
|
||||||
root.passwordRequested();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// listen to authentication events
|
|
||||||
Connections {
|
|
||||||
target: authenticator
|
|
||||||
function onSucceeded() {
|
|
||||||
// run pending action if successfully unlocked
|
|
||||||
if (drawer.requestNotificationAction) {
|
|
||||||
drawer.runPendingAction();
|
|
||||||
drawer.requestNotificationAction = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function onFailed() {
|
|
||||||
drawer.requestNotificationAction = false;
|
drawer.requestNotificationAction = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function onFailed() {
|
||||||
|
drawer.requestNotificationAction = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2019 Nicolas Fella <nicolas.fella@gmx.de>
|
* SPDX-FileCopyrightText: 2019 Nicolas Fella <nicolas.fella@gmx.de>
|
||||||
* SPDX-FileCopyrightText: 2021-2022 Devin Lin <espidev@gmail.com>
|
* SPDX-FileCopyrightText: 2021-2022 Devin Lin <espidev@gmail.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -17,25 +17,22 @@ import org.kde.kirigami 2.12 as Kirigami
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lockscreen component that is loaded after the device is locked.
|
* Lockscreen component that is loaded after the device is locked.
|
||||||
*
|
*
|
||||||
* Special attention must be paid to ensuring the GUI loads as fast as possible.
|
* Special attention must be paid to ensuring the GUI loads as fast as possible.
|
||||||
*/
|
*/
|
||||||
PlasmaCore.ColorScope {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var lockScreenState: LockScreenState {}
|
property var lockScreenState: LockScreenState {}
|
||||||
property var notifModel: Notifications.WatchedNotificationsModel {}
|
property var notifModel: Notifications.WatchedNotificationsModel {}
|
||||||
|
|
||||||
// only show widescreen mode for short height devices (ex. phone landscape)
|
// only show widescreen mode for short height devices (ex. phone landscape)
|
||||||
property bool isWidescreen: root.height < 720 && (root.height < root.width * 0.75)
|
property bool isWidescreen: root.height < 720 && (root.height < root.width * 0.75)
|
||||||
property bool notificationsShown: false
|
property bool notificationsShown: false
|
||||||
|
|
||||||
readonly property bool drawerOpen: flickable.openFactor >= 1
|
readonly property bool drawerOpen: flickable.openFactor >= 1
|
||||||
property var passwordBar: keypadLoader.item.passwordBar
|
property var passwordBar: keypadLoader.item.passwordBar
|
||||||
|
|
||||||
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
// listen for keyboard events, and focus on input area
|
// listen for keyboard events, and focus on input area
|
||||||
Component.onCompleted: forceActiveFocus();
|
Component.onCompleted: forceActiveFocus();
|
||||||
Keys.onPressed: {
|
Keys.onPressed: {
|
||||||
|
|
@ -43,7 +40,7 @@ PlasmaCore.ColorScope {
|
||||||
flickable.goToOpenPosition();
|
flickable.goToOpenPosition();
|
||||||
passwordBar.textField.forceActiveFocus();
|
passwordBar.textField.forceActiveFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK: kscreenlocker doesn't draw the wallpaper (shows up as black)
|
// HACK: kscreenlocker doesn't draw the wallpaper (shows up as black)
|
||||||
Loader {
|
Loader {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -55,8 +52,8 @@ PlasmaCore.ColorScope {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wallpaper blur
|
// wallpaper blur
|
||||||
Loader {
|
Loader {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
|
|
@ -65,181 +62,192 @@ PlasmaCore.ColorScope {
|
||||||
blur: root.notificationsShown || root.drawerOpen // only blur once animation finished for performance
|
blur: root.notificationsShown || root.drawerOpen // only blur once animation finished for performance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// header bar and action drawer
|
|
||||||
HeaderComponent {
|
|
||||||
id: headerBar
|
|
||||||
z: 1 // on top of flick area
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
openFactor: flickable.openFactor
|
|
||||||
notificationsModel: root.notifModel
|
|
||||||
onPasswordRequested: root.askPassword()
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root.lockScreenState
|
target: root.lockScreenState
|
||||||
|
|
||||||
// ensure keypad is opened when password is updated (ex. keyboard)
|
// ensure keypad is opened when password is updated (ex. keyboard)
|
||||||
function onPasswordChanged() {
|
function onPasswordChanged() {
|
||||||
flickable.goToOpenPosition()
|
flickable.goToOpenPosition()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickContainer {
|
PlasmaCore.ColorScope {
|
||||||
id: flickable
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
||||||
property real openFactor: position / keypadHeight
|
|
||||||
|
// header bar and action drawer
|
||||||
onOpened: {
|
Loader {
|
||||||
if (root.lockScreenState.passwordless) {
|
id: headerBarLoader
|
||||||
// try unlocking if flicked to the top, and we have passwordless login
|
z: 1 // on top of flick area
|
||||||
root.lockScreenState.tryPassword();
|
readonly property real statusBarHeight: PlasmaCore.Units.gridUnit * 1.25
|
||||||
}
|
|
||||||
}
|
anchors.fill: parent
|
||||||
|
asynchronous: true
|
||||||
keypadHeight: PlasmaCore.Units.gridUnit * 20
|
|
||||||
|
sourceComponent: HeaderComponent {
|
||||||
// go to closed position when loaded
|
statusBarHeight: headerBarLoader.statusBarHeight
|
||||||
Component.onCompleted: {
|
openFactor: flickable.openFactor
|
||||||
flickable.position = 0;
|
|
||||||
flickable.goToClosePosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
// update position, and cap it at the keypad height
|
|
||||||
onPositionChanged: {
|
|
||||||
if (position > keypadHeight) {
|
|
||||||
position = keypadHeight;
|
|
||||||
} else if (position < 0) {
|
|
||||||
position = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: flickable.width
|
|
||||||
height: flickable.height
|
|
||||||
y: flickable.contentY // effectively anchored to the screen
|
|
||||||
|
|
||||||
LockScreenNarrowContent {
|
|
||||||
id: phoneComponent
|
|
||||||
|
|
||||||
visible: !isWidescreen
|
|
||||||
active: visible
|
|
||||||
opacity: 1 - flickable.openFactor
|
|
||||||
|
|
||||||
fullHeight: root.height
|
|
||||||
|
|
||||||
lockScreenState: root.lockScreenState
|
|
||||||
notificationsModel: root.notifModel
|
notificationsModel: root.notifModel
|
||||||
onNotificationsShownChanged: root.notificationsShown = notificationsShown
|
onPasswordRequested: root.askPassword()
|
||||||
|
|
||||||
onPasswordRequested: flickable.goToOpenPosition()
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: scrollUpIconLoader.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
// move while swiping up
|
|
||||||
transform: Translate { y: Math.round((1 - phoneComponent.opacity) * (-root.height / 6)) }
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
LockScreenWideScreenContent {
|
|
||||||
id: tabletComponent
|
FlickContainer {
|
||||||
|
id: flickable
|
||||||
visible: isWidescreen
|
anchors.fill: parent
|
||||||
active: visible
|
|
||||||
opacity: 1 - flickable.openFactor
|
property real openFactor: position / keypadHeight
|
||||||
|
|
||||||
lockScreenState: root.lockScreenState
|
onOpened: {
|
||||||
notificationsModel: root.notifModel
|
if (root.lockScreenState.passwordless) {
|
||||||
onNotificationsShownChanged: root.notificationsShown = notificationsShown
|
// try unlocking if flicked to the top, and we have passwordless login
|
||||||
|
root.lockScreenState.tryPassword();
|
||||||
onPasswordRequested: flickable.goToOpenPosition()
|
|
||||||
|
|
||||||
anchors.topMargin: headerBar.statusBarHeight
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: scrollUpIconLoader.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
// move while swiping up
|
|
||||||
transform: Translate { y: Math.round((1 - phoneComponent.opacity) * (-root.height / 6)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// scroll up icon
|
|
||||||
Loader {
|
|
||||||
id: scrollUpIconLoader
|
|
||||||
asynchronous: true
|
|
||||||
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.bottomMargin: PlasmaCore.Units.gridUnit + flickable.position * 0.5
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
|
|
||||||
sourceComponent: PlasmaCore.IconItem {
|
|
||||||
id: scrollUpIcon
|
|
||||||
implicitWidth: PlasmaCore.Units.iconSizes.smallMedium
|
|
||||||
implicitHeight: PlasmaCore.Units.iconSizes.smallMedium
|
|
||||||
opacity: 1 - flickable.openFactor
|
|
||||||
|
|
||||||
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
|
||||||
source: "arrow-up"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// password keypad
|
keypadHeight: PlasmaCore.Units.gridUnit * 20
|
||||||
Loader {
|
|
||||||
id: keypadLoader
|
// go to closed position when loaded
|
||||||
width: parent.width
|
Component.onCompleted: {
|
||||||
asynchronous: true
|
flickable.position = 0;
|
||||||
active: !root.lockScreenState.passwordless // only load keypad if not passwordless
|
flickable.goToClosePosition();
|
||||||
|
}
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
|
// update position, and cap it at the keypad height
|
||||||
sourceComponent: ColumnLayout {
|
onPositionChanged: {
|
||||||
property alias passwordBar: keypad.passwordBar
|
if (position > keypadHeight) {
|
||||||
|
position = keypadHeight;
|
||||||
transform: Translate { y: flickable.keypadHeight - flickable.position }
|
} else if (position < 0) {
|
||||||
spacing: 0
|
position = 0;
|
||||||
|
}
|
||||||
// info notification text
|
}
|
||||||
Label {
|
|
||||||
Layout.fillWidth: true
|
Item {
|
||||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
width: flickable.width
|
||||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
height: flickable.height
|
||||||
Layout.bottomMargin: PlasmaCore.Units.smallSpacing * 2
|
y: flickable.contentY // effectively anchored to the screen
|
||||||
font.pointSize: 9
|
|
||||||
|
LockScreenNarrowContent {
|
||||||
elide: Text.ElideRight
|
id: phoneComponent
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
text: root.lockScreenState.info
|
visible: !isWidescreen
|
||||||
opacity: (root.lockScreenState.info.length === 0 || flickable.openFactor < 1) ? 0 : 1
|
active: visible
|
||||||
color: 'white'
|
opacity: 1 - flickable.openFactor
|
||||||
|
|
||||||
Behavior on opacity {
|
fullHeight: root.height
|
||||||
NumberAnimation { duration: 200 }
|
|
||||||
}
|
lockScreenState: root.lockScreenState
|
||||||
}
|
notificationsModel: root.notifModel
|
||||||
|
onNotificationsShownChanged: root.notificationsShown = notificationsShown
|
||||||
// scroll down icon
|
|
||||||
PlasmaCore.IconItem {
|
onPasswordRequested: flickable.goToOpenPosition()
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
Layout.bottomMargin: PlasmaCore.Units.gridUnit
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: scrollUpIconLoader.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
// move while swiping up
|
||||||
|
transform: Translate { y: Math.round((1 - phoneComponent.opacity) * (-root.height / 6)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
LockScreenWideScreenContent {
|
||||||
|
id: tabletComponent
|
||||||
|
|
||||||
|
visible: isWidescreen
|
||||||
|
active: visible
|
||||||
|
opacity: 1 - flickable.openFactor
|
||||||
|
|
||||||
|
lockScreenState: root.lockScreenState
|
||||||
|
notificationsModel: root.notifModel
|
||||||
|
onNotificationsShownChanged: root.notificationsShown = notificationsShown
|
||||||
|
|
||||||
|
onPasswordRequested: flickable.goToOpenPosition()
|
||||||
|
|
||||||
|
anchors.topMargin: headerBarLoader.statusBarHeight
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: scrollUpIconLoader.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
// move while swiping up
|
||||||
|
transform: Translate { y: Math.round((1 - phoneComponent.opacity) * (-root.height / 6)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll up icon
|
||||||
|
Loader {
|
||||||
|
id: scrollUpIconLoader
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: PlasmaCore.Units.gridUnit + flickable.position * 0.5
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
sourceComponent: PlasmaCore.IconItem {
|
||||||
|
id: scrollUpIcon
|
||||||
implicitWidth: PlasmaCore.Units.iconSizes.smallMedium
|
implicitWidth: PlasmaCore.Units.iconSizes.smallMedium
|
||||||
implicitHeight: PlasmaCore.Units.iconSizes.smallMedium
|
implicitHeight: PlasmaCore.Units.iconSizes.smallMedium
|
||||||
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
opacity: 1 - flickable.openFactor
|
||||||
source: "arrow-down"
|
|
||||||
opacity: Math.sin((Math.PI / 2) * flickable.openFactor + 1.5 * Math.PI) + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Keypad {
|
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
||||||
id: keypad
|
source: "arrow-up"
|
||||||
Layout.fillWidth: true
|
}
|
||||||
focus: true
|
}
|
||||||
|
|
||||||
lockScreenState: root.lockScreenState
|
// password keypad
|
||||||
swipeProgress: flickable.openFactor
|
Loader {
|
||||||
|
id: keypadLoader
|
||||||
|
width: parent.width
|
||||||
|
asynchronous: true
|
||||||
|
active: !root.lockScreenState.passwordless // only load keypad if not passwordless
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
sourceComponent: ColumnLayout {
|
||||||
|
property alias passwordBar: keypad.passwordBar
|
||||||
|
|
||||||
|
transform: Translate { y: flickable.keypadHeight - flickable.position }
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
// info notification text
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||||
|
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||||
|
Layout.bottomMargin: PlasmaCore.Units.smallSpacing * 2
|
||||||
|
font.pointSize: 9
|
||||||
|
|
||||||
|
elide: Text.ElideRight
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: root.lockScreenState.info
|
||||||
|
opacity: (root.lockScreenState.info.length === 0 || flickable.openFactor < 1) ? 0 : 1
|
||||||
|
color: 'white'
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: 200 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll down icon
|
||||||
|
PlasmaCore.IconItem {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.bottomMargin: PlasmaCore.Units.gridUnit
|
||||||
|
implicitWidth: PlasmaCore.Units.iconSizes.smallMedium
|
||||||
|
implicitHeight: PlasmaCore.Units.iconSizes.smallMedium
|
||||||
|
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
||||||
|
source: "arrow-down"
|
||||||
|
opacity: Math.sin((Math.PI / 2) * flickable.openFactor + 1.5 * Math.PI) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Keypad {
|
||||||
|
id: keypad
|
||||||
|
Layout.fillWidth: true
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
lockScreenState: root.lockScreenState
|
||||||
|
swipeProgress: flickable.openFactor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,51 +13,51 @@ import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property var lockScreenState
|
|
||||||
property var notificationsModel: []
|
|
||||||
|
|
||||||
|
required property var lockScreenState
|
||||||
|
|
||||||
|
property var notificationsModel: []
|
||||||
property bool notificationsShown: false
|
property bool notificationsShown: false
|
||||||
|
|
||||||
property real fullHeight
|
property real fullHeight
|
||||||
|
|
||||||
signal passwordRequested()
|
signal passwordRequested()
|
||||||
|
|
||||||
// avoid topMargin animation when item is being loaded
|
// avoid topMargin animation when item is being loaded
|
||||||
onLoaded: loadTimer.restart();
|
onLoaded: loadTimer.restart();
|
||||||
Timer {
|
Timer {
|
||||||
id: loadTimer
|
id: loadTimer
|
||||||
interval: PlasmaCore.Units.longDuration
|
interval: 200
|
||||||
}
|
}
|
||||||
|
|
||||||
// move while swiping up
|
// move while swiping up
|
||||||
transform: Translate { y: Math.round((1 - phoneComponent.opacity) * (-root.height / 6)) }
|
transform: Translate { y: Math.round((1 - root.opacity) * (-root.height / 6)) }
|
||||||
|
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
sourceComponent: Item {
|
sourceComponent: Item {
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: column
|
id: column
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
// center clock when no notifications are shown, otherwise move the clock upward
|
// center clock when no notifications are shown, otherwise move the clock upward
|
||||||
anchors.topMargin: !root.notificationsShown ? Math.round(root.fullHeight / 2 - (column.implicitHeight / 2)) : PlasmaCore.Units.gridUnit * 5
|
anchors.topMargin: !root.notificationsShown ? Math.round(root.fullHeight / 2 - (column.implicitHeight / 2)) : PlasmaCore.Units.gridUnit * 5
|
||||||
anchors.bottomMargin: PlasmaCore.Units.gridUnit
|
anchors.bottomMargin: PlasmaCore.Units.gridUnit
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
// animate
|
// animate
|
||||||
Behavior on anchors.topMargin {
|
Behavior on anchors.topMargin {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: loadTimer.running ? 0 : PlasmaCore.Units.longDuration
|
duration: loadTimer.running ? 0 : PlasmaCore.Units.veryLongDuration
|
||||||
easing.type: Easing.InOutQuad
|
easing.type: Easing.InOutExpo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Clock {
|
Clock {
|
||||||
layoutAlignment: Qt.AlignHCenter
|
layoutAlignment: Qt.AlignHCenter
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
Layout.bottomMargin: PlasmaCore.Units.gridUnit * 2 // keep spacing even if media controls are gone
|
Layout.bottomMargin: PlasmaCore.Units.gridUnit * 2 // keep spacing even if media controls are gone
|
||||||
}
|
}
|
||||||
|
|
||||||
MobileShell.MediaControlsWidget {
|
MobileShell.MediaControlsWidget {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -65,18 +65,18 @@ Loader {
|
||||||
Layout.leftMargin: PlasmaCore.Units.gridUnit
|
Layout.leftMargin: PlasmaCore.Units.gridUnit
|
||||||
Layout.rightMargin: PlasmaCore.Units.gridUnit
|
Layout.rightMargin: PlasmaCore.Units.gridUnit
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationsComponent {
|
NotificationsComponent {
|
||||||
id: notificationComponent
|
id: notificationComponent
|
||||||
lockScreenState: root.lockScreenState
|
lockScreenState: root.lockScreenState
|
||||||
notificationsModel: root.notificationsModel
|
notificationsModel: root.notificationsModel
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.maximumWidth: PlasmaCore.Units.gridUnit * (25 + 2) // clip margins
|
Layout.maximumWidth: PlasmaCore.Units.gridUnit * (25 + 2) // clip margins
|
||||||
topMargin: PlasmaCore.Units.gridUnit
|
topMargin: PlasmaCore.Units.gridUnit
|
||||||
|
|
||||||
onPasswordRequested: root.passwordRequested()
|
onPasswordRequested: root.passwordRequested()
|
||||||
onNotificationsShownChanged: root.notificationsShown = notificationsShown
|
onNotificationsShownChanged: root.notificationsShown = notificationsShown
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ Loader {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property var lockScreenState
|
required property var lockScreenState
|
||||||
property var notificationsModel: []
|
|
||||||
|
|
||||||
|
property var notificationsModel: []
|
||||||
property bool notificationsShown: false
|
property bool notificationsShown: false
|
||||||
|
|
||||||
signal passwordRequested()
|
signal passwordRequested()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022 Devin Lin <espidev@gmail.com>
|
* SPDX-FileCopyrightText: 2022 Devin Lin <espidev@gmail.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -14,27 +14,34 @@ import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||||
|
|
||||||
import org.kde.notificationmanager 1.0 as NotificationManager
|
import org.kde.notificationmanager 1.0 as NotificationManager
|
||||||
|
|
||||||
Rectangle {
|
Loader {
|
||||||
id: root
|
id: root
|
||||||
required property var lockScreenState
|
required property var lockScreenState
|
||||||
|
|
||||||
property var notificationsModel: []
|
property var notificationsModel: []
|
||||||
property var notificationSettings: NotificationManager.Settings {}
|
property var notificationSettings: NotificationManager.Settings {}
|
||||||
|
|
||||||
readonly property bool notificationsShown: notificationsList.hasNotifications
|
|
||||||
|
|
||||||
signal passwordRequested()
|
|
||||||
|
|
||||||
property real leftMargin: 0
|
property real leftMargin: 0
|
||||||
property real rightMargin: 0
|
property real rightMargin: 0
|
||||||
property real topMargin: 0
|
property real topMargin: 0
|
||||||
property real bottomMargin: 0
|
property real bottomMargin: 0
|
||||||
|
readonly property bool notificationsShown: item && item.notificationsList.hasNotifications
|
||||||
color: "transparent"
|
|
||||||
clip: true
|
property var notificationsList: item ? item.notificationsList : null
|
||||||
|
|
||||||
|
signal passwordRequested()
|
||||||
|
|
||||||
|
// perform delayed loading of notifications
|
||||||
|
active: false
|
||||||
|
Timer {
|
||||||
|
interval: 500
|
||||||
|
running: true
|
||||||
|
onTriggered: root.active = true
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: lockScreenState
|
target: lockScreenState
|
||||||
|
|
||||||
function onUnlockSucceeded() {
|
function onUnlockSucceeded() {
|
||||||
// run pending action if successfully unlocked
|
// run pending action if successfully unlocked
|
||||||
if (notificationsList.requestNotificationAction) {
|
if (notificationsList.requestNotificationAction) {
|
||||||
|
|
@ -42,34 +49,40 @@ Rectangle {
|
||||||
notificationsList.requestNotificationAction = false;
|
notificationsList.requestNotificationAction = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUnlockFailed() {
|
function onUnlockFailed() {
|
||||||
notificationsList.requestNotificationAction = false;
|
notificationsList.requestNotificationAction = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PlasmaCore.ColorScope {
|
sourceComponent: Item {
|
||||||
anchors.fill: parent
|
clip: true
|
||||||
anchors.topMargin: root.topMargin
|
|
||||||
anchors.bottomMargin: root.bottomMargin
|
property alias notificationsList: notificationsList
|
||||||
anchors.leftMargin: root.leftMargin
|
|
||||||
anchors.rightMargin: root.rightMargin
|
PlasmaCore.ColorScope {
|
||||||
colorGroup: PlasmaCore.Theme.NormalColorGroup
|
|
||||||
|
|
||||||
MobileShell.NotificationsWidget {
|
|
||||||
id: notificationsList
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: root.topMargin
|
||||||
historyModelType: MobileShell.NotificationsModelType.WatchedNotificationsModel
|
anchors.bottomMargin: root.bottomMargin
|
||||||
actionsRequireUnlock: true
|
anchors.leftMargin: root.leftMargin
|
||||||
historyModel: root.notificationsModel
|
anchors.rightMargin: root.rightMargin
|
||||||
notificationSettings: root.notificationSettings
|
colorGroup: PlasmaCore.Theme.NormalColorGroup
|
||||||
|
|
||||||
property bool requestNotificationAction: false
|
MobileShell.NotificationsWidget {
|
||||||
|
id: notificationsList
|
||||||
onUnlockRequested: {
|
anchors.fill: parent
|
||||||
requestNotificationAction = true;
|
|
||||||
root.passwordRequested();
|
historyModelType: MobileShell.NotificationsModelType.WatchedNotificationsModel
|
||||||
|
actionsRequireUnlock: true
|
||||||
|
historyModel: root.notificationsModel
|
||||||
|
notificationSettings: root.notificationSettings
|
||||||
|
|
||||||
|
property bool requestNotificationAction: false
|
||||||
|
|
||||||
|
onUnlockRequested: {
|
||||||
|
requestNotificationAction = true;
|
||||||
|
root.passwordRequested();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue