Commit 73993512 authored by Marco Martin's avatar Marco Martin
Browse files

Notification applet on the phone

Summary:
some optimizations for tablet mode (touch first, but also on
transformable laptops flipped to tablet)
and some for specifically the mobile case (mobile phone)

* hide the top toolbar in phone mode
* in tablet mode (and therefore on phone mode too) don't select text but drag the item laterally to dismiss it

Test Plan:
* on phone form factor for the new behavior
* on touch laptop in tablet mode
* on desktop for its behavior not changing at all

Reviewers: #plasma, broulik

Reviewed By: #plasma, broulik

Subscribers: nicolasfella, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D24765
parent 5db30d88
/*
* Copyright 2019 Marco Martin <mart@kde.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
import QtQuick 2.10
import org.kde.kirigami 2.11 as Kirigami
MouseArea {
id: delegate
property Item contentItem
property bool draggable: false
signal dismissRequested
implicitWidth: contentItem ? contentItem.implicitWidth : 0
implicitHeight: contentItem ? contentItem.implicitHeight : 0
opacity: 1 - Math.min(1, 1.5 * Math.abs(x) / width)
drag {
filterChildren: draggable
axis: Drag.XAxis
target: draggable && Kirigami.Settings.tabletMode ? this : null
}
onReleased: {
if (Math.abs(x) > width / 2) {
delegate.dismissRequested();
} else {
slideAnim.restart();
}
}
NumberAnimation {
id: slideAnim
target: delegate
property:"x"
to: 0
duration: units.longDuration
}
}
......@@ -107,104 +107,114 @@ PlasmaCore.Dialog {
}
}
mainItem: MouseArea {
id: area
mainItem: Item {
width: notificationPopup.popupWidth
height: notificationItem.implicitHeight + notificationItem.y
hoverEnabled: true
cursorShape: hasDefaultAction ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: hasDefaultAction ? Qt.LeftButton : Qt.NoButton
onClicked: notificationPopup.defaultActionInvoked()
onEntered: notificationPopup.hoverEntered()
onExited: notificationPopup.hoverExited()
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true
Timer {
id: timer
interval: notificationPopup.effectiveTimeout
running: notificationPopup.visible && !area.containsMouse && interval > 0
&& !notificationItem.dragging && !notificationItem.menuOpen
onTriggered: {
if (notificationPopup.dismissTimeout) {
notificationPopup.dismissClicked();
} else {
notificationPopup.expired();
}
}
}
DraggableDelegate {
id: area
width: parent.width
height: parent.height
hoverEnabled: true
draggable: notificationItem.notificationType != NotificationManager.Notifications.JobType
onDismissRequested: popupNotificationsModel.close(popupNotificationsModel.index(index, 0))
Timer {
id: timeoutIndicatorDelayTimer
// only show indicator for the last ten seconds of timeout
readonly property int remainingTimeout: 10000
interval: Math.max(0, timer.interval - remainingTimeout)
running: interval > 0 && timer.running
}
cursorShape: hasDefaultAction ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: hasDefaultAction || draggable ? Qt.LeftButton : Qt.NoButton
Rectangle {
id: timeoutIndicatorRect
anchors {
right: parent.right
rightMargin: -notificationPopup.margins.right
bottom: parent.bottom
bottomMargin: -notificationPopup.margins.bottom
onClicked: {
if (hasDefaultAction) {
notificationPopup.defaultActionInvoked();
}
}
width: units.devicePixelRatio * 3
color: theme.highlightColor
opacity: timeoutIndicatorAnimation.running ? 0.6 : 0
visible: units.longDuration > 1
Behavior on opacity {
NumberAnimation {
duration: units.longDuration
onEntered: notificationPopup.hoverEntered()
onExited: notificationPopup.hoverExited()
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true
Timer {
id: timer
interval: notificationPopup.effectiveTimeout
running: notificationPopup.visible && !area.containsMouse && interval > 0
&& !notificationItem.dragging && !notificationItem.menuOpen
onTriggered: {
if (notificationPopup.dismissTimeout) {
notificationPopup.dismissClicked();
} else {
notificationPopup.expired();
}
}
}
NumberAnimation {
id: timeoutIndicatorAnimation
target: timeoutIndicatorRect
property: "height"
from: area.height + notificationPopup.margins.top + notificationPopup.margins.bottom
to: 0
duration: Math.min(timer.interval, timeoutIndicatorDelayTimer.remainingTimeout)
running: timer.running && !timeoutIndicatorDelayTimer.running && units.longDuration > 1
Timer {
id: timeoutIndicatorDelayTimer
// only show indicator for the last ten seconds of timeout
readonly property int remainingTimeout: 10000
interval: Math.max(0, timer.interval - remainingTimeout)
running: interval > 0 && timer.running
}
}
NotificationItem {
id: notificationItem
// let the item bleed into the dialog margins so the close button margins cancel out
y: closable || dismissable || configurable ? -notificationPopup.margins.top : 0
headingRightPadding: -notificationPopup.margins.right
width: parent.width
hovered: area.containsMouse
maximumLineCount: 8
bodyCursorShape: notificationPopup.hasDefaultAction ? Qt.PointingHandCursor : 0
thumbnailLeftPadding: -notificationPopup.margins.left
thumbnailRightPadding: -notificationPopup.margins.right
thumbnailTopPadding: -notificationPopup.margins.top
thumbnailBottomPadding: -notificationPopup.margins.bottom
closable: true
onBodyClicked: {
if (area.acceptedButtons & mouse.button) {
area.clicked(null /*mouse*/);
Rectangle {
id: timeoutIndicatorRect
anchors {
right: parent.right
rightMargin: -notificationPopup.margins.right
bottom: parent.bottom
bottomMargin: -notificationPopup.margins.bottom
}
width: units.devicePixelRatio * 3
color: theme.highlightColor
opacity: timeoutIndicatorAnimation.running ? 0.6 : 0
visible: units.longDuration > 1
Behavior on opacity {
NumberAnimation {
duration: units.longDuration
}
}
NumberAnimation {
id: timeoutIndicatorAnimation
target: timeoutIndicatorRect
property: "height"
from: area.height + notificationPopup.margins.top + notificationPopup.margins.bottom
to: 0
duration: Math.min(timer.interval, timeoutIndicatorDelayTimer.remainingTimeout)
running: timer.running && !timeoutIndicatorDelayTimer.running && units.longDuration > 1
}
}
NotificationItem {
id: notificationItem
// let the item bleed into the dialog margins so the close button margins cancel out
y: closable || dismissable || configurable ? -notificationPopup.margins.top : 0
headingRightPadding: -notificationPopup.margins.right
width: parent.width
hovered: area.containsMouse
maximumLineCount: 8
bodyCursorShape: notificationPopup.hasDefaultAction ? Qt.PointingHandCursor : 0
thumbnailLeftPadding: -notificationPopup.margins.left
thumbnailRightPadding: -notificationPopup.margins.right
thumbnailTopPadding: -notificationPopup.margins.top
thumbnailBottomPadding: -notificationPopup.margins.bottom
closable: true
onBodyClicked: {
if (area.acceptedButtons & mouse.button) {
area.clicked(null /*mouse*/);
}
}
onCloseClicked: notificationPopup.closeClicked()
onDismissClicked: notificationPopup.dismissClicked()
onConfigureClicked: notificationPopup.configureClicked()
onActionInvoked: notificationPopup.actionInvoked(actionName)
onOpenUrl: notificationPopup.openUrl(url)
onFileActionInvoked: notificationPopup.fileActionInvoked()
onSuspendJobClicked: notificationPopup.suspendJobClicked()
onResumeJobClicked: notificationPopup.resumeJobClicked()
onKillJobClicked: notificationPopup.killJobClicked()
}
onCloseClicked: notificationPopup.closeClicked()
onDismissClicked: notificationPopup.dismissClicked()
onConfigureClicked: notificationPopup.configureClicked()
onActionInvoked: notificationPopup.actionInvoked(actionName)
onOpenUrl: notificationPopup.openUrl(url)
onFileActionInvoked: notificationPopup.fileActionInvoked()
onSuspendJobClicked: notificationPopup.suspendJobClicked()
onResumeJobClicked: notificationPopup.resumeJobClicked()
onKillJobClicked: notificationPopup.killJobClicked()
}
}
}
......@@ -26,6 +26,7 @@ import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.11 as Kirigami
// NOTE This wrapper item is needed for QQC ScrollView to work
// In NotificationItem we just do SelectableLabel {} and then it gets confused
......@@ -46,6 +47,7 @@ Item {
implicitWidth: bodyText.paintedWidth
implicitHeight: bodyText.paintedHeight
PlasmaExtras.ScrollArea {
id: bodyTextScrollArea
......@@ -60,7 +62,7 @@ Item {
width: bodyTextScrollArea.width
// TODO check that this doesn't causes infinite loops when it starts adding and removing the scrollbar
//width: bodyTextScrollArea.viewport.width
//enabled: !Settings.isMobile
enabled: !Kirigami.Settings.isMobile
color: PlasmaCore.ColorScope.textColor
selectedTextColor: theme.viewBackgroundColor
......@@ -77,7 +79,9 @@ Item {
// Work around Qt bug where NativeRendering breaks for non-integer scale factors
// https://bugreports.qt.io/browse/QTBUG-67007
renderType: Screen.devicePixelRatio % 1 !== 0 ? Text.QtRendering : Text.NativeRendering
selectByMouse: true
// Selectable only when we are in desktop mode
selectByMouse: !Kirigami.Settings.tabletMode
readOnly: true
wrapMode: Text.Wrap
textFormat: TextEdit.RichText
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment