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 @@
<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 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 @@
<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>
|