diff --git a/CMakeLists.txt b/CMakeLists.txt index d2d975f9059be7b5da02c34ddc0987336280d3c4..7dd4d2450cb244fe4723951fa0c68e63c4d8dd6e 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 29a043554cd9de205c6ea9613ab7a5f4d047529d..c499874b1fb77a27e2ee3c4bb3983fb7039e1075 100644 --- a/resources/langs/nheko_de.ts +++ b/resources/langs/nheko_de.ts @@ -319,7 +319,7 @@ <message> <location line="+66"/> <source>Failed to kick %1 from %2: %3</source> - <translation>Kontte %1 nicht aus %2 entfernen: %3</translation> + <translation>Konnte %1 nicht aus %2 entfernen: %3</translation> </message> </context> <context> diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml index e3be440d12c1654eefcd8ca807292e2b7c3a7d95..88d3e7c6f1dd5d58ed5df4cf4eb5f0b22618a9bd 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 0000000000000000000000000000000000000000..80c0d88860a0aa181216c807d6b7039665413929 --- /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 5b49d596b671a2f6a39baf9aead4bbbbe8284db4..2fba5f4cc0c5caa20d8533b5241c4c1703eec0ff 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -157,6 +157,7 @@ <file>qml/ui/NhekoSlider.qml</file> <file>qml/ui/Ripple.qml</file> <file>qml/ui/Spinner.qml</file> + <file>qml/ui/Snackbar.qml</file> <file>qml/ui/animations/BlinkAnimation.qml</file> <file>qml/ui/media/MediaControls.qml</file> <file>qml/voip/ActiveCallBar.qml</file> diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 6458707580602178848c3e4b5f2304dc8c5ca4c9..83504d866a4bc3e11c58a022a8f14e3893a73af7 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 80ade988d00f5799e8f2f314e6d87f5f89b6d3d1..7bc94328bc535aaaeb655ef2b298eb2cd8a134fa 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 b755a44cfe456392613dbb136fb6fb354a2aea7e..0000000000000000000000000000000000000000 --- 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 <QPainter> -#include <QStyleOption> - -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 19ad0cc6a9dbedb1bf1f796fadfeaf67479b5d7a..0000000000000000000000000000000000000000 --- 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 <QEvent> -#include <QWidget> - -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; -};