diff --git a/app/icons/Close.svg b/app/icons/Close.svg
new file mode 100644
index 000000000..e33397dfc
--- /dev/null
+++ b/app/icons/Close.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/icons/icons.qrc b/app/icons/icons.qrc
index 7f82ade42..56ba3d5fa 100644
--- a/app/icons/icons.qrc
+++ b/app/icons/icons.qrc
@@ -14,5 +14,6 @@
CloseButton.svg
UploadImage.svg
ReachedDataLimitImage.svg
+ Close.svg
diff --git a/app/qmlV2/component/MMInput.qml b/app/qmlV2/component/MMInput.qml
index 85a810435..3b40627d0 100644
--- a/app/qmlV2/component/MMInput.qml
+++ b/app/qmlV2/component/MMInput.qml
@@ -15,7 +15,7 @@ import "../Style.js" as Style
Item {
id: control
- enum Type { Normal, Password, Search, Calendar, Scan, CopyButton }
+ enum Type { Normal, Password, Search, Calendar, Scan, CopyButton, SendButton }
property int type: MMInput.Type.Normal
property alias text: textField.text
@@ -23,6 +23,8 @@ Item {
property string warningMsg
property string errorMsg
+ signal sendButtonClicked
+
width: 280 * __dp
height: rect.height + messageItem.height
@@ -120,7 +122,7 @@ Item {
height: rect.height
visible: control.type === MMInput.Type.Password ||
control.type === MMInput.Type.Scan ||
- ((control.type !== MMInput.Type.CopyButton) && textField.activeFocus && textField.text.length>0)
+ ((control.type !== MMInput.Type.CopyButton || control.type !== MMInput.Type.SendButton) && textField.activeFocus && textField.text.length>0)
MouseArea {
anchors.fill: parent
@@ -140,13 +142,13 @@ Item {
Button {
id: button
- visible: control.type === MMInput.Type.CopyButton
+ visible: control.type === MMInput.Type.CopyButton || control.type === MMInput.Type.SendButton
anchors.verticalCenter: parent.verticalCenter
contentItem: Text {
anchors.centerIn: button
font: Qt.font(Style.t5)
- text: qsTr("Copy")
+ text: control.type === MMInput.Type.CopyButton ? qsTr("Copy") : qsTr("Send")
leftPadding: 2 * __dp
rightPadding: 2 * __dp
topPadding: 2 * __dp
@@ -163,9 +165,14 @@ Item {
}
onClicked: {
- textField.selectAll()
- textField.copy()
- textField.deselect()
+ if(control.type === MMInput.Type.CopyButton) {
+ textField.selectAll()
+ textField.copy()
+ textField.deselect()
+ }
+ else if(control.type === MMInput.Type.SendButton) {
+ sendButtonClicked()
+ }
}
}
diff --git a/app/qmlV2/component/MMNotification.qml b/app/qmlV2/component/MMNotification.qml
new file mode 100644
index 000000000..986775369
--- /dev/null
+++ b/app/qmlV2/component/MMNotification.qml
@@ -0,0 +1,91 @@
+/***************************************************************************
+ * *
+ * 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) any later version. *
+ * *
+ ***************************************************************************/
+
+import QtQuick
+import "../Style.js" as Style
+import notificationType 1.0
+
+Row {
+ id: notification
+
+ width: listView.width - 2 * Style.commonSpacing
+ height: Style.notificationHeight
+ anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
+
+ readonly property int innerSpacing: 5 * __dp
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ color: Style.forest
+ radius: Style.notificationRadius
+
+ Rectangle {
+ id: borderRect
+
+ anchors.centerIn: parent
+ width: parent.width - notification.innerSpacing
+ height: parent.height - notification.innerSpacing
+ radius: Style.notificationRadius
+ color: Style.transparent
+ border.width: __dp
+ border.color: {
+ switch( type ) {
+ case NotificationType.Information: return Style.sky
+ case NotificationType.Warning: return Style.warning
+ case NotificationType.Error: return Style.negative
+ default: return Style.positive
+ }
+ }
+ }
+
+ Rectangle {
+ id: icon
+
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: Style.commonSpacing
+ width: 18 * __dp
+ height: 18 * __dp
+ color: borderRect.border.color
+ radius: width/2
+ }
+
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: icon.right
+ width: parent.width - 3 * Style.commonSpacing - closeButton.width - icon.width
+ text: message
+ color: Style.white
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignLeft
+ leftPadding: Style.commonSpacing - notification.innerSpacing
+ font: Qt.font(Style.t3)
+ clip: true
+ }
+
+ Image {
+ id: closeButton
+
+ anchors.right: parent.right
+ anchors.rightMargin: Style.commonSpacing
+ anchors.verticalCenter: parent.verticalCenter
+ scale: maRemove.containsMouse ? 1.2 : 1
+ source: Style.closeIcon
+
+ MouseArea {
+ id: maRemove
+
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: notificationModel.remove(id)
+ }
+ }
+ }
+}
diff --git a/app/qmlV2/component/MMNotificationView.qml b/app/qmlV2/component/MMNotificationView.qml
new file mode 100644
index 000000000..8211d8498
--- /dev/null
+++ b/app/qmlV2/component/MMNotificationView.qml
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * *
+ * 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) any later version. *
+ * *
+ ***************************************************************************/
+
+import QtQuick
+import "../Style.js" as Style
+
+Item {
+ id: control
+
+ anchors.top: parent.top
+ anchors.topMargin: Style.commonSpacing
+ width: parent.width
+ height: parent.height
+
+ // just for information - will be removed in release version
+ Rectangle {
+ anchors.bottom: parent.bottom
+ width: control.width
+ height: 20
+ color: Style.white
+
+ Text {
+ text: listView.count
+ anchors.centerIn: parent
+ color: Style.forest
+ }
+ }
+
+ ListView {
+ id: listView
+
+ anchors.top: parent.top
+ width: parent.width
+ height: Style.notificationHeight * listView.count + spacing * (listView.count - 1)
+ spacing: Style.notificationSpace
+ clip: true
+ model: notificationModel
+ delegate: MMNotification {
+
+ }
+
+ add: Transition {
+ NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 200 }
+ NumberAnimation { property: "scale"; easing.type: Easing.OutCubic; from: 0; to: 1.0; duration: 200 }
+ }
+
+ }
+}
diff --git a/gallery/CMakeLists.txt b/gallery/CMakeLists.txt
index d0f19d73b..634927f10 100644
--- a/gallery/CMakeLists.txt
+++ b/gallery/CMakeLists.txt
@@ -29,9 +29,9 @@ find_package(
qt_standard_project_setup()
qt_policy(SET QTP0001 NEW)
-set(GALLERY_HDRS helper.h)
+set(GALLERY_HDRS helper.h notificationmodel.h)
-set(GALLERY_SRCS helper.cpp)
+set(GALLERY_SRCS helper.cpp notificationmodel.cpp)
if (IOS OR ANDROID)
add_compile_definitions(MOBILE_OS)
diff --git a/gallery/main.cpp b/gallery/main.cpp
index 0055d1efa..1d33f5b93 100644
--- a/gallery/main.cpp
+++ b/gallery/main.cpp
@@ -16,6 +16,7 @@
#include "helper.h"
#include
#include
+#include "notificationmodel.h"
int main( int argc, char *argv[] )
{
@@ -30,6 +31,9 @@ int main( int argc, char *argv[] )
engine.rootContext()->setContextProperty( "_hotReload", &hotReload );
#endif
+ NotificationModel notificationModel;
+ engine.rootContext()->setContextProperty("notificationModel", ¬ificationModel);
+
// path to local wrapper pages
engine.rootContext()->setContextProperty( "_qmlWrapperPath", QGuiApplication::applicationDirPath() + "/HotReload/qml/pages/" );
engine.rootContext()->setContextProperty( "__dp", Helper::calculateDpRatio() );
diff --git a/gallery/notificationmodel.cpp b/gallery/notificationmodel.cpp
new file mode 100644
index 000000000..cf53a5228
--- /dev/null
+++ b/gallery/notificationmodel.cpp
@@ -0,0 +1,108 @@
+/***************************************************************************
+ * *
+ * 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) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "notificationmodel.h"
+#include
+
+Notification::Notification(uint id, const QString &message, uint interval, NotificationType::MessageType type = NotificationType::Information)
+{
+ mId = id;
+ mMessage = message;
+ mInterval = interval;
+ mType = type;
+}
+
+NotificationModel::NotificationModel(QObject *parent) : QAbstractListModel{parent}
+{
+ qmlRegisterUncreatableType("notificationType", 1, 0, "NotificationType", "Not creatable as it is an enum type");
+
+ mTimer = new QTimer(this);
+ connect(mTimer, &QTimer::timeout, this, &NotificationModel::timerFired);
+ mTimer->start(1000);
+
+ // Initial data
+ mNotifications << Notification{ nextId(), "Ahoj", 10, NotificationType::Information };
+ mNotifications << Notification{ nextId(), "Hello all", 5, NotificationType::Information };
+}
+
+NotificationModel::~NotificationModel()
+{
+ mTimer->stop();
+ delete mTimer;
+}
+
+QHash NotificationModel::roleNames() const
+{
+ return {
+ { IdRole, "id" },
+ { MessageRole, "message" },
+ { TypeRole, "type" }
+ };
+}
+
+int NotificationModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return mNotifications.size();
+}
+
+QVariant NotificationModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(), index.parent()))
+ return {};
+
+ Notification notification = mNotifications.at(index.row());
+ if (role == IdRole) return notification.id();
+ if (role == MessageRole) return notification.message();
+ if (role == TypeRole) return notification.type();
+
+ return {};
+}
+
+// remove item by message
+void NotificationModel::remove(uint id)
+{
+ for(int i=0; i
+#include
+
+class NotificationType
+{
+ Q_GADGET
+ public:
+
+ enum MessageType {
+ Information,
+ Warning,
+ Error
+ };
+ Q_ENUM(MessageType)
+
+ private:
+ explicit NotificationType();
+};
+
+class Notification
+{
+ Q_GADGET
+
+ public:
+ Notification(uint id, const QString &message, uint interval, NotificationType::MessageType type);
+ uint id() { return mId; }
+ QString message() { return mMessage; }
+ NotificationType::MessageType type() { return mType; }
+ bool canBeRemoved() { return (mInterval-- == 0); }
+
+ private:
+ uint mId;
+ QString mMessage;
+ uint mInterval; // [seconds]
+ NotificationType::MessageType mType;
+};
+
+class NotificationModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ public:
+ enum MyRoles {
+ IdRole = Qt::UserRole + 1, MessageRole, TypeRole
+ };
+ Q_ENUM(MyRoles)
+
+ NotificationModel(QObject *parent = nullptr);
+ ~NotificationModel();
+
+ QHash roleNames() const override;
+ int rowCount(const QModelIndex & parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
+
+ Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged);
+ Q_INVOKABLE void remove(uint id);
+ Q_INVOKABLE void add(const QString &message, uint interval, NotificationType::MessageType type);
+
+ private:
+ uint nextId() { static uint id = 0; return id++; }
+ void timerFired();
+
+ signals:
+ void rowCountChanged();
+
+ private:
+ QList mNotifications;
+ QTimer *mTimer;
+};
+
+#endif // NOTIFICATIONMODEL_H
diff --git a/gallery/qml.qrc b/gallery/qml.qrc
index 3e165441a..0a15b2f06 100644
--- a/gallery/qml.qrc
+++ b/gallery/qml.qrc
@@ -19,6 +19,9 @@
../app/qmlV2/component/MMCheckBox.qml
../app/qmlV2/component/MMRadioButton.qml
../app/qmlV2/component/MMSwitch.qml
+ qml/pages/NotificationPage.qml
+ ../app/qmlV2/component/MMNotification.qml
+ ../app/qmlV2/component/MMNotificationView.qml
../app/qmlV2/component/MMDrawer.qml
qml/pages/DrawerPage.qml
qml/pages/ChecksPage.qml
diff --git a/gallery/qml/Main.qml b/gallery/qml/Main.qml
index 1859be814..11866cd69 100644
--- a/gallery/qml/Main.qml
+++ b/gallery/qml/Main.qml
@@ -124,6 +124,10 @@ ApplicationWindow {
title: "Checks"
source: "ChecksPage.qml"
}
+ ListElement {
+ title: "Notifications"
+ source: "NotificationPage.qml"
+ }
ListElement {
title: "Drawers"
source: "DrawerPage.qml"
diff --git a/gallery/qml/pages/NotificationPage.qml b/gallery/qml/pages/NotificationPage.qml
new file mode 100644
index 000000000..11417ddb2
--- /dev/null
+++ b/gallery/qml/pages/NotificationPage.qml
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * *
+ * 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) any later version. *
+ * *
+ ***************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Basic
+
+import "../../app/qmlV2/component"
+import notificationType 1.0
+
+Page {
+ id: pane
+
+ Rectangle {
+ anchors.fill: parent
+ color: "white"
+ }
+
+ Column {
+ width: parent.width
+ spacing: 20
+ anchors.centerIn: parent
+
+ MMInput {
+ type: MMInput.Type.SendButton
+ anchors.horizontalCenter: parent.horizontalCenter
+ placeholderText: "Write an informative message"
+ onSendButtonClicked: { notificationModel.add(text, 100, NotificationType.Information); text = "" }
+ }
+ MMInput {
+ type: MMInput.Type.SendButton
+ anchors.horizontalCenter: parent.horizontalCenter
+ placeholderText: "Write a warning message"
+ onSendButtonClicked: { notificationModel.add(text, 100, NotificationType.Warning); text = "" }
+ }
+ MMInput {
+ type: MMInput.Type.SendButton
+ anchors.horizontalCenter: parent.horizontalCenter
+ placeholderText: "Write an error message"
+ onSendButtonClicked: { notificationModel.add(text, 100, NotificationType.Error); text = "" }
+ }
+ Text {
+ text: "Note: Notification will be removed in 10s"
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: "green"
+ }
+ }
+
+ MMNotificationView {}
+}