diff --git a/CMakeLists.txt b/CMakeLists.txt
index d2d975f9..7dd4d245 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -336,7 +336,6 @@ set(SRC_FILES
src/ui/NhekoCursorShape.cpp
src/ui/NhekoDropArea.cpp
src/ui/NhekoGlobalObject.cpp
- src/ui/OverlayWidget.cpp
src/ui/RoomSettings.cpp
src/ui/TextField.cpp
src/ui/Theme.cpp
@@ -532,7 +531,6 @@ qt5_wrap_cpp(MOC_HEADERS
src/ui/NhekoCursorShape.h
src/ui/NhekoDropArea.h
src/ui/NhekoGlobalObject.h
- src/ui/OverlayWidget.h
src/ui/RoomSettings.h
src/ui/TextField.h
src/ui/Theme.h
diff --git a/resources/langs/nheko_de.ts b/resources/langs/nheko_de.ts
index 29a04355..c499874b 100644
--- a/resources/langs/nheko_de.ts
+++ b/resources/langs/nheko_de.ts
@@ -319,7 +319,7 @@
- Kontte %1 nicht aus %2 entfernen: %3
+ Konnte %1 nicht aus %2 entfernen: %3
diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml
index e3be440d..88d3e7c6 100644
--- a/resources/qml/Root.qml
+++ b/resources/qml/Root.qml
@@ -9,6 +9,7 @@ import "./dialogs"
import "./emoji"
import "./pages"
import "./voip"
+import "./ui"
import Qt.labs.platform 1.1 as Platform
import QtQuick 2.15
import QtQuick.Controls 2.15
@@ -402,6 +403,8 @@ Pane {
}
}
+ Snackbar { id: snackbar }
+
Connections {
function onSwitchToChatPage() {
mainWindow.replace(null, chatPage);
@@ -409,6 +412,10 @@ Pane {
function onSwitchToLoginPage(error) {
mainWindow.replace(welcomePage, {}, loginPage, {"error": error}, StackView.PopTransition);
}
+ function onShowNotification(msg) {
+ snackbar.showNotification(msg);
+ console.log("New snack: " + msg);
+ }
target: MainWindow
}
diff --git a/resources/qml/ui/Snackbar.qml b/resources/qml/ui/Snackbar.qml
new file mode 100644
index 00000000..80c0d888
--- /dev/null
+++ b/resources/qml/ui/Snackbar.qml
@@ -0,0 +1,98 @@
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import im.nheko 1.0
+
+Popup {
+ id: snackbar
+
+ property var messages: []
+ property string currentMessage: ""
+
+ function showNotification(msg) {
+ messages.push(msg);
+ currentMessage = messages[0];
+ if (!visible) {
+ open();
+ dismissTimer.start();
+ }
+ }
+
+ Timer {
+ id: dismissTimer
+ interval: 10000
+ onTriggered: snackbar.close()
+ }
+
+ onAboutToHide: {
+ messages.shift();
+ }
+ onClosed: {
+ if (messages.length > 0) {
+ currentMessage = messages[0];
+ open();
+ dismissTimer.restart();
+ }
+ }
+
+ parent: Overlay.overlay
+ opacity: 0
+ y: -100
+ x: (parent.width - width)/2
+ padding: Nheko.paddingLarge
+
+ contentItem: Label {
+ color: Nheko.colors.light
+ width: Math.max(Overlay.overlay? Overlay.overlay.width/2 : 0, 400)
+ text: snackbar.currentMessage
+ font.bold: true
+ }
+
+ background: Rectangle {
+ radius: Nheko.paddingLarge
+ color: Nheko.colors.dark
+ opacity: 0.8
+ }
+
+ enter: Transition {
+ NumberAnimation {
+ target: snackbar
+ property: "opacity"
+ from: 0.0
+ to: 1.0
+ duration: 200
+ easing.type: Easing.OutCubic
+ }
+ NumberAnimation {
+ target: snackbar
+ properties: "y"
+ from: -100
+ to: 100
+ duration: 1000
+ easing.type: Easing.OutCubic
+ }
+ }
+ exit: Transition {
+ NumberAnimation {
+ target: snackbar
+ property: "opacity"
+ from: 1.0
+ to: 0.0
+ duration: 300
+ easing.type: Easing.InCubic
+ }
+ NumberAnimation {
+ target: snackbar
+ properties: "y"
+ to: -100
+ from: 100
+ duration: 300
+ easing.type: Easing.InCubic
+ }
+ }
+}
+
+
diff --git a/resources/res.qrc b/resources/res.qrc
index 5b49d596..2fba5f4c 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -157,6 +157,7 @@
qml/ui/NhekoSlider.qml
qml/ui/Ripple.qml
qml/ui/Spinner.qml
+ qml/ui/Snackbar.qml
qml/ui/animations/BlinkAnimation.qml
qml/ui/media/MediaControls.qml
qml/voip/ActiveCallBar.qml
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index 64587075..83504d86 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -84,9 +84,8 @@ MainWindow::MainWindow(QWindow *parent)
connect(chat_page_, &ChatPage::closing, this, [this] { switchToLoginPage(""); });
connect(chat_page_, &ChatPage::unreadMessages, this, &MainWindow::setWindowTitle);
connect(chat_page_, SIGNAL(unreadMessages(int)), trayIcon_, SLOT(setUnreadCount(int)));
- connect(chat_page_, &ChatPage::showLoginPage, this, [this](const QString &msg) {
- switchToLoginPage(msg);
- });
+ connect(chat_page_, &ChatPage::showLoginPage, this, &MainWindow::switchToLoginPage);
+ connect(chat_page_, &ChatPage::showNotification, this, &MainWindow::showNotification);
connect(userSettings_.get(), &UserSettings::trayChanged, trayIcon_, &TrayIcon::setVisible);
connect(trayIcon_,
diff --git a/src/MainWindow.h b/src/MainWindow.h
index 80ade988..7bc94328 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -70,6 +70,8 @@ signals:
void reload();
void secretsChanged();
+ void showNotification(QString msg);
+
void switchToChatPage();
void switchToWelcomePage();
void switchToLoginPage(QString error);
diff --git a/src/ui/OverlayWidget.cpp b/src/ui/OverlayWidget.cpp
deleted file mode 100644
index b755a44c..00000000
--- a/src/ui/OverlayWidget.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-// SPDX-FileCopyrightText: 2022 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "OverlayWidget.h"
-
-#include
-#include
-
-OverlayWidget::OverlayWidget(QWidget *parent)
- : QWidget(parent)
-{
- if (parent) {
- parent->installEventFilter(this);
- setGeometry(overlayGeometry());
- raise();
- }
-}
-
-bool
-OverlayWidget::event(QEvent *event)
-{
- if (!parent())
- return QWidget::event(event);
-
- switch (event->type()) {
- case QEvent::ParentChange: {
- parent()->installEventFilter(this);
- setGeometry(overlayGeometry());
- break;
- }
- case QEvent::ParentAboutToChange: {
- parent()->removeEventFilter(this);
- break;
- }
- default:
- break;
- }
-
- return QWidget::event(event);
-}
-
-bool
-OverlayWidget::eventFilter(QObject *obj, QEvent *event)
-{
- switch (event->type()) {
- case QEvent::Move:
- case QEvent::Resize:
- setGeometry(overlayGeometry());
- break;
- default:
- break;
- }
-
- return QWidget::eventFilter(obj, event);
-}
-
-QRect
-OverlayWidget::overlayGeometry() const
-{
- QWidget *widget = parentWidget();
-
- if (!widget)
- return QRect();
-
- return widget->rect();
-}
-
-void
-OverlayWidget::paintEvent(QPaintEvent *event)
-{
- Q_UNUSED(event);
-
- QStyleOption opt;
- opt.initFrom(this);
- QPainter p(this);
- style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
-}
diff --git a/src/ui/OverlayWidget.h b/src/ui/OverlayWidget.h
deleted file mode 100644
index 19ad0cc6..00000000
--- a/src/ui/OverlayWidget.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-// SPDX-FileCopyrightText: 2022 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include
-#include
-
-class QPainter;
-
-class OverlayWidget : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit OverlayWidget(QWidget *parent = nullptr);
-
-protected:
- bool event(QEvent *event) override;
- bool eventFilter(QObject *obj, QEvent *event) override;
-
- QRect overlayGeometry() const;
- void paintEvent(QPaintEvent *event) override;
-};