diff --git a/src/controls/AbstractApplicationItem.qml b/src/controls/AbstractApplicationItem.qml --- a/src/controls/AbstractApplicationItem.qml +++ b/src/controls/AbstractApplicationItem.qml @@ -132,7 +132,7 @@ */ function showPassiveNotification(message, timeout, actionText, callBack) { if (!internal.__passiveNotification) { - var component = Qt.createComponent("templates/private/PassiveNotification.qml"); + var component = Qt.createComponent("templates/PassiveNotification.qml"); internal.__passiveNotification = component.createObject(overlay.parent); } diff --git a/src/controls/AbstractApplicationWindow.qml b/src/controls/AbstractApplicationWindow.qml --- a/src/controls/AbstractApplicationWindow.qml +++ b/src/controls/AbstractApplicationWindow.qml @@ -91,8 +91,8 @@ */ function showPassiveNotification(message, timeout, actionText, callBack) { if (!internal.__passiveNotification) { - var component = Qt.createComponent("templates/private/PassiveNotification.qml"); - internal.__passiveNotification = component.createObject(overlay.parent); + internal.__passiveNotification = Qt.createQmlObject("import QtQuick 2.11;import org.kde.kirigami 2.12 as Kirigami;PassiveNotification{}", overlay.parent); + //internal.__passiveNotification = component.createObject(overlay.parent); } internal.__passiveNotification.showNotification(message, timeout, actionText, callBack); @@ -303,7 +303,7 @@ QtObject { id: internal - property Item __passiveNotification + property QtObject __passiveNotification } Shortcut { diff --git a/src/controls/PassiveNotification.qml b/src/controls/PassiveNotification.qml new file mode 100644 --- /dev/null +++ b/src/controls/PassiveNotification.qml @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2015 Marco Martin + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.5 +import org.kde.kirigami 2.12 as Kirigami +import "templates" as KT + +KT.PassiveNotification { + id: root + + x: parent.width/2 - width/2 + y: parent.height - height - Kirigami.Units.largeSpacing + + background: Kirigami.ShadowedRectangle { + Kirigami.Theme.colorSet: root.Kirigami.Theme.colorSet + shadow { + size: Kirigami.Units.gridUnit/2 + color: Qt.rgba(0, 0, 0, 0.4) + yOffset: 2 + } + radius: Kirigami.Units.smallSpacing * 2 + color: Kirigami.Theme.backgroundColor + opacity: 0.6 + } +} + diff --git a/src/controls/templates/PassiveNotification.qml b/src/controls/templates/PassiveNotification.qml new file mode 100644 --- /dev/null +++ b/src/controls/templates/PassiveNotification.qml @@ -0,0 +1,161 @@ +/* + * SPDX-FileCopyrightText: 2015 Marco Martin + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Controls 2.3 as Controls +import QtQuick.Templates 2.5 as T2 +import QtQuick.Layouts 1.2 +import QtQuick.Window 2.2 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.12 as Kirigami + +/** + * PassiveNotification is a type for small, passive and inline +notifications in the app. + * used to show messages of limited importance that make sense only when + * the user is using the application and wouldn't be suited as a global + * system-wide notification. + * This is not a full-fledged notification system. the applciation should + * use this with care and only one notification should be visible at once per app. +*/ +T2.Drawer { + id: root + + /** + * text: string + * The text to display in the notification + */ + property alias text: label.text + + /** + * actionText: string + * if present, the notification will have a button with this text + */ + property alias actionText: actionButton.text + + /** + * callBack: function + * A JavaScript function that will be called when the user presses the action button + */ + property var callBack + + x: parent.width/2 - width/2 + implicitWidth: Math.max(background ? background.implicitWidth : 0, + contentWidth + leftPadding + rightPadding) + leftInset + rightInset + implicitHeight: Math.max(background ? background.implicitHeight : 0 , + contentHeight + topPadding + bottomPadding)+ topInset + bottomInset + + topPadding: Kirigami.Units.smallSpacing + leftPadding: Kirigami.Units.smallSpacing + rightPadding: Kirigami.Units.smallSpacing + bottomPadding: Kirigami.Units.smallSpacing + + //TODO: top-right edge on desktop? + edge: Qt.BottomEdge + modal: false + closePolicy: T2.Popup.NoAutoClose + topInset: Kirigami.Units.smallSpacing + bottomInset: Kirigami.Units.smallSpacing + focus: false + + function showNotification(message, timeout, actionText, callBack) { + if (!message) { + return; + } + text = message; + root.actionText = actionText; + root.callBack = callBack; + + if (timeout == "short") { + timer.interval = 4000; + } else if (timeout == "long") { + timer.interval = 12000; + } else if (timeout > 0) { + timer.interval = timeout; + } else { + timer.interval = 7000; + } + + open(); + } + + Kirigami.Theme.colorSet: Kirigami.Theme.Complementary + + Timer { + id: timer + interval: 4000 + running: mainLayout.Window.active && root.visible && !hover.hovered + onTriggered: root.close() + } + + contentItem: RowLayout { + id: mainLayout + Kirigami.Theme.colorSet: root.Kirigami.Theme.colorSet + + HoverHandler { + id: hover + } + TapHandler { + acceptedButtons: Qt.LeftButton + onTapped: root.close() + } + Controls.Label { + id: label + } + + Controls.Button { + id: actionButton + visible: root.actionText.length > 0 + onClicked: { + root.close(); + if (root.callBack) { + root.callBack(); + } + } + } + } + + T2.Overlay.modal: Rectangle { + color: Qt.rgba(0, 0, 0, 0.4) + } + + T2.Overlay.modeless: Item {} + + enter: Transition { + ParallelAnimation{ + NumberAnimation { + target: root + property: "position" + easing.type: Easing.OutQuad + duration: Kirigami.Units.longDuration + } + NumberAnimation { + property: "opacity" + from: 0.0 + to: 1.0 + easing.type: Easing.OutQuad + duration: Kirigami.Units.longDuration + } + } + } + + exit: Transition { + NumberAnimation { + target: root + property: "position" + easing.type: Easing.OutQuad + duration: Kirigami.Units.longDuration + } + NumberAnimation { + property: "opacity" + from: 1.0 + to: 0.0 + easing.type: Easing.InQuad + duration: Kirigami.Units.longDuration + } + } +} + diff --git a/src/controls/templates/private/PassiveNotification.qml b/src/controls/templates/private/PassiveNotification.qml deleted file mode 100644 --- a/src/controls/templates/private/PassiveNotification.qml +++ /dev/null @@ -1,148 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015 Marco Martin - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -import QtQuick 2.5 -import QtQuick.Controls 2.0 as QQC2 -import QtQuick.Layouts 1.2 -import QtQuick.Window 2.2 -import QtGraphicalEffects 1.0 -import org.kde.kirigami 2.4 - -MouseArea { - id: root - z: 9999999 - width: background.width - height: background.height - opacity: 0 - enabled: appearAnimation.appear - - anchors { - horizontalCenter: parent.horizontalCenter - bottom: parent.bottom - bottomMargin: Units.gridUnit * 4 - } - function showNotification(message, timeout, actionText, callBack) { - if (!message) { - return; - } - appearAnimation.running = false; - appearAnimation.appear = true; - appearAnimation.running = true; - if (timeout == "short") { - timer.interval = 4000; - } else if (timeout == "long") { - timer.interval = 12000; - } else if (timeout > 0) { - timer.interval = timeout; - } else { - timer.interval = 7000; - } - messageLabel.text = message ? message : ""; - actionButton.text = actionText ? actionText : ""; - actionButton.callBack = callBack ? callBack : ""; - - timer.stop(); // stop first to ensure it always starts anew - - // Only start the timer when the window has focus, to ensure that - // messages don't get missed on the desktop where it's common to - //be working with multiple windows at once - timer.running = Qt.binding(function() { - return root.Window.active; - }); - } - - function hideNotification() { - appearAnimation.running = false; - appearAnimation.appear = false; - appearAnimation.running = true; - } - - - onClicked: { - appearAnimation.appear = false; - appearAnimation.running = true; - } - - transform: Translate { - id: transform - y: root.height - } - - Timer { - id: timer - interval: 4000 - onTriggered: { - appearAnimation.appear = false; - appearAnimation.running = true; - } - } - ParallelAnimation { - id: appearAnimation - property bool appear: true - NumberAnimation { - target: root - properties: "opacity" - to: appearAnimation.appear ? 1 : 0 - duration: Units.longDuration - easing.type: Easing.InOutQuad - } - NumberAnimation { - target: transform - properties: "y" - to: appearAnimation.appear ? 0 : background.height - duration: Units.longDuration - easing.type: appearAnimation.appear ? Easing.OutQuad : Easing.InQuad - } - } - - Item { - id: background - width: backgroundRect.width + Units.gridUnit - height: backgroundRect.height + Units.gridUnit - Rectangle { - id: backgroundRect - anchors.centerIn: parent - radius: Units.smallSpacing - color: Theme.textColor - opacity: 0.6 - width: mainLayout.width + Math.round((height - mainLayout.height)) - height: Math.max(mainLayout.height + Units.smallSpacing*2, Units.gridUnit*2) - } - RowLayout { - id: mainLayout - anchors.centerIn: parent - QQC2.Label { - id: messageLabel - Layout.maximumWidth: Math.min(root.parent.width - Units.largeSpacing*2, implicitWidth) - elide: Text.ElideRight - wrapMode: Text.WordWrap - maximumLineCount: 4 - color: Theme.backgroundColor - } - QQC2.Button { - id: actionButton - property var callBack - visible: text != "" - onClicked: { - appearAnimation.appear = false; - appearAnimation.running = true; - if (callBack) { - callBack(); - } - } - } - } - layer.enabled: true - layer.effect: DropShadow { - horizontalOffset: 0 - verticalOffset: 0 - radius: Units.gridUnit - samples: 32 - color: Qt.rgba(0, 0, 0, 0.5) - } - } -} - diff --git a/src/controls/templates/qmldir b/src/controls/templates/qmldir --- a/src/controls/templates/qmldir +++ b/src/controls/templates/qmldir @@ -7,4 +7,4 @@ ApplicationHeader 2.2 ApplicationHeader.qml AbstractApplicationHeader 2.2 AbstractApplicationHeader.qml OverlayDrawer 2.2 OverlayDrawer.qml - +PassiveNotification 2.12 PassiveNotification.qml diff --git a/src/kirigamiplugin.cpp b/src/kirigamiplugin.cpp --- a/src/kirigamiplugin.cpp +++ b/src/kirigamiplugin.cpp @@ -240,6 +240,7 @@ qmlRegisterType(uri, 2, 12, "ShadowedRectangle"); qmlRegisterUncreatableType(uri, 2, 12, "BorderGroup", QStringLiteral("Used as grouped property")); qmlRegisterUncreatableType(uri, 2, 12, "ShadowGroup", QStringLiteral("Used as grouped property")); + qmlRegisterType(componentUrl(QStringLiteral("PassiveNotification.qml")), uri, 2, 12, "PassiveNotification"); qmlProtectModule(uri, 2); } diff --git a/src/qmldir b/src/qmldir --- a/src/qmldir +++ b/src/qmldir @@ -51,3 +51,4 @@ SearchField 2.8 SearchField.qml PasswordField 2.8 PasswordField.qml ListSectionHeader 2.10 ListSectionHeader.qml +PassiveNotification 2.12 PassiveNotification.qml