diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index c936c638edf4900b95680355e02b1feb6b747a9f..16c92ebf55e9d0cb271a38b26342b8dafe6fd47f 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -4,6 +4,8 @@ import "./delegates" import "./emoji" +import "./ui" + import Qt.labs.platform 1.1 as Platform import QtGraphicalEffects 1.0 import QtQuick 2.12 @@ -404,14 +406,13 @@ ScrollView { } - footer: BusyIndicator { + footer: Spinner { anchors.horizontalCenter: parent.horizontalCenter running: chat.model && chat.model.paginationInProgress - height: 50 - width: 50 + foreground: Nheko.colors.mid + visible: chat.model && chat.model.paginationInProgress z: 3 } - } Platform.Menu { diff --git a/resources/qml/RoomSettings.qml b/resources/qml/RoomSettings.qml index 1f7fe5dea06f509180eca7ff89244aa53fc1f4b1..d6e6c6a527076733f28b24108150ee75af202f7a 100644 --- a/resources/qml/RoomSettings.qml +++ b/resources/qml/RoomSettings.qml @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +import "./ui" import Qt.labs.platform 1.1 as Platform import QtQuick 2.9 import QtQuick.Controls 2.3 @@ -49,10 +50,11 @@ ApplicationWindow { } } - BusyIndicator { + Spinner { Layout.alignment: Qt.AlignHCenter - running: roomSettings.isLoading visible: roomSettings.isLoading + foreground: Nheko.colors.mid + running: roomSettings.isLoading } Text { diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 2c7c943abc5cdad9e063a64569e9ea8886e0ee3a..0209054df041f2b1f4abdb852b3ea20a69cfc8cb 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -6,6 +6,8 @@ import "./delegates" import "./device-verification" import "./emoji" import "./voip" +import "./ui" + import Qt.labs.platform 1.1 as Platform import QtGraphicalEffects 1.0 import QtQuick 2.9 @@ -29,12 +31,13 @@ Item { color: Nheko.colors.text } - BusyIndicator { - visible: running + Spinner { + visible: TimelineManager.isInitialSync anchors.centerIn: parent + foreground: Nheko.colors.mid running: TimelineManager.isInitialSync - height: 200 - width: 200 + // height is somewhat arbitrary here... don't set width because width scales w/ height + height: parent.height / 16 z: 3 } diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index 21f34f1577294e60a6d7b356288787af1cdb6f34..826d3165de6c7648c5264076c9d7ae8e5d8c6488 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -3,6 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later import "./device-verification" +import "./ui" import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.2 @@ -47,10 +48,11 @@ ApplicationWindow { onClicked: profile.isSelf ? profile.changeAvatar() : TimelineManager.openImageOverlay(profile.avatarUrl, "") } - BusyIndicator { + Spinner { Layout.alignment: Qt.AlignHCenter running: profile.isLoading visible: profile.isLoading + foreground: Nheko.colors.mid } Text { diff --git a/resources/qml/device-verification/AwaitingVerificationConfirmation.qml b/resources/qml/device-verification/AwaitingVerificationConfirmation.qml index a6a7f0277602e8ece4fe83a974be0c69b3656038..91306140429160297743eb706b83f60e62e839fb 100644 --- a/resources/qml/device-verification/AwaitingVerificationConfirmation.qml +++ b/resources/qml/device-verification/AwaitingVerificationConfirmation.qml @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +import "../ui" import QtQuick 2.3 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.10 @@ -25,8 +26,9 @@ Pane { verticalAlignment: Text.AlignVCenter } - BusyIndicator { + Spinner { Layout.alignment: Qt.AlignHCenter + foreground: Nheko.colors.mid } RowLayout { diff --git a/resources/qml/device-verification/Waiting.qml b/resources/qml/device-verification/Waiting.qml index c521503b5ee337492022ce6c95c0868393520c75..e1401a47d8f52b9e787e28c969985153efd5ba53 100644 --- a/resources/qml/device-verification/Waiting.qml +++ b/resources/qml/device-verification/Waiting.qml @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +import "../ui" import QtQuick 2.3 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.10 @@ -34,9 +35,9 @@ Pane { verticalAlignment: Text.AlignVCenter } - BusyIndicator { + Spinner { Layout.alignment: Qt.AlignHCenter - palette: Nheko.colors + foreground: Nheko.colors.mid } RowLayout { diff --git a/resources/qml/ui/Spinner.qml b/resources/qml/ui/Spinner.qml new file mode 100644 index 0000000000000000000000000000000000000000..a1a09a6abfe512719ca1a688e98a67a284a92746 --- /dev/null +++ b/resources/qml/ui/Spinner.qml @@ -0,0 +1,161 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.12 +import QtGraphicalEffects 1.12 + +import "./animations" + +Item { + id: spinner + + property int spacing: 0 + property bool running: true + property var foreground: "#333" + readonly property int barCount: 6 + readonly property real a: Math.PI / 6 + readonly property var colors: ["#c0def5", "#87aade", "white"] + readonly property var anims: [anim1, anim2, anim3, anim4, anim5, anim6] + readonly property int pauseDuration: barCount * 150 + readonly property int glowDuration: 300 + + height: 40 + width: barCount * (height * 0.375) + + Row { + id: row + + Rectangle { + id: rect1 + + width: ((spinner.width / spinner.barCount) - (spinner.spacing)) * 1.5 + height: spinner.height / 3.5 + color: "white" + } + + Rectangle { + id: rect2 + + width: (spinner.width / spinner.barCount) - spinner.spacing + height: spinner.height + color: spinner.colors[0] + } + + Rectangle { + id: rect3 + + width: (spinner.width / spinner.barCount) - spinner.spacing + height: spinner.height + color: spinner.colors[1] + } + + Rectangle { + id: rect4 + + width: (spinner.width / spinner.barCount) - spinner.spacing + height: spinner.height + color: spinner.colors[2] + } + + Rectangle { + id: rect5 + + width: (spinner.width / (spinner.barCount + 1)) - spinner.spacing + height: spinner.height / 3.5 + color: "white" + } + + Rectangle { + id: rect6 + + width: (spinner.width / spinner.barCount) - spinner.spacing + height: spinner.height + color: "white" + } + + BlinkAnimation { + id: anim1 + target: rect1 + pauseDuration: spinner.pauseDuration + glowDuration: spinner.glowDuration + + loops: Animation.Infinite + } + + BlinkAnimation { + id: anim2 + target: rect2 + pauseDuration: spinner.pauseDuration + glowDuration: spinner.glowDuration + } + + BlinkAnimation { + id: anim3 + target: rect3 + pauseDuration: spinner.pauseDuration + glowDuration: spinner.glowDuration + + } + + BlinkAnimation { + id: anim4 + target: rect4 + pauseDuration: spinner.pauseDuration + glowDuration: spinner.glowDuration + + } + + BlinkAnimation { + id: anim5 + target: rect5 + pauseDuration: spinner.pauseDuration + glowDuration: spinner.glowDuration + } + + BlinkAnimation { + id: anim6 + target: rect6 + pauseDuration: spinner.pauseDuration + glowDuration: spinner.glowDuration + } + + transform: Matrix4x4 { + matrix: Qt.matrix4x4(Math.cos(spinner.a), -Math.sin(spinner.a), 0, 0, 0, Math.cos(spinner.a), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) + } + + } + + Timer { + // ----- Private Properties ----- // + property int _barIndex: 0 + + interval: 80 + repeat: true + running: spinner.running + onTriggered: { + if (_barIndex === spinner.barCount) { + _barIndex = 0; + stop(); + } else { + anims[_barIndex].start(); + _barIndex++; + } + } + Component.onCompleted: start() + } + + Glow { + anchors.fill: row + radius: 14 + samples: 17 + color: spinner.foreground + source: row + + transform: Matrix4x4 { + matrix: Qt.matrix4x4(Math.cos(spinner.a), -Math.sin(spinner.a), 0, 0, 0, Math.cos(spinner.a), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) + } + + } + +} diff --git a/resources/qml/ui/animations/BlinkAnimation.qml b/resources/qml/ui/animations/BlinkAnimation.qml new file mode 100644 index 0000000000000000000000000000000000000000..73991a1fd4a067408e072f66a4e2b520757935a1 --- /dev/null +++ b/resources/qml/ui/animations/BlinkAnimation.qml @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.12 +import QtGraphicalEffects 1.12 + +SequentialAnimation { + property alias target: numberAnimation.target + property alias glowDuration: numberAnimation.duration + property alias pauseDuration: pauseAnimation.duration + + loops: Animation.Infinite + + NumberAnimation { + id: numberAnimation + property: "opacity" + from: 0 + to: 1 + } + + PauseAnimation { + id: pauseAnimation + } + +} \ No newline at end of file diff --git a/resources/qml/ui/animations/qmldir b/resources/qml/ui/animations/qmldir new file mode 100644 index 0000000000000000000000000000000000000000..14f9ad868288b8f48f0a50381fe4f5e68040afa9 --- /dev/null +++ b/resources/qml/ui/animations/qmldir @@ -0,0 +1,2 @@ +module im.nheko.UI.Animations +BlinkAnimation 1.0 BlinkAnimation.qml diff --git a/resources/qml/ui/qmldir b/resources/qml/ui/qmldir index a8466a103e1d5ee8bc291cd848e1589fee01f04c..831a723dca42e74db49ea007efd23cdf01acb6a5 100644 --- a/resources/qml/ui/qmldir +++ b/resources/qml/ui/qmldir @@ -1,2 +1,3 @@ module im.nheko.UI -Ripple 1.0 Ripple.qml \ No newline at end of file +Ripple 1.0 Ripple.qml +Spinner 1.0 Spinner.qml \ No newline at end of file diff --git a/resources/res.qrc b/resources/res.qrc index 53c74ae3844fe30b723d58547ce9bc70a3f5e468..9bb8ae2e4f7b18f24cd57e2662157bfaabda4475 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -171,6 +171,8 @@ <file>qml/device-verification/Success.qml</file> <file>qml/dialogs/InputDialog.qml</file> <file>qml/ui/Ripple.qml</file> + <file>qml/ui/Spinner.qml</file> + <file>qml/ui/animations/BlinkAnimation.qml</file> <file>qml/voip/ActiveCallBar.qml</file> <file>qml/voip/CallDevices.qml</file> <file>qml/voip/CallInvite.qml</file>