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 @@ Failed to kick %1 from %2: %3 - 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; -};