diff --git a/resources/qml/Avatar.qml b/resources/qml/Avatar.qml
index aa873ffe..2801bd37 100644
--- a/resources/qml/Avatar.qml
+++ b/resources/qml/Avatar.qml
@@ -1,3 +1,4 @@
+import "./ui"
import QtGraphicalEffects 1.0
import QtQuick 2.6
import QtQuick.Controls 2.3
@@ -43,6 +44,12 @@ Rectangle {
anchors.fill: parent
onClicked: TimelineManager.openImageOverlay(TimelineManager.timeline.avatarUrl(userid), TimelineManager.timeline.data.id)
+
+ Ripple {
+ rippleTarget: mouseArea
+ color: Qt.rgba(colors.alternateBase.r, colors.alternateBase.g, colors.alternateBase.b, 0.5)
+ }
+
}
layer.effect: OpacityMask {
diff --git a/resources/qml/ImageButton.qml b/resources/qml/ImageButton.qml
index 4ebda680..b5a34b7b 100644
--- a/resources/qml/ImageButton.qml
+++ b/resources/qml/ImageButton.qml
@@ -1,3 +1,4 @@
+import "./ui"
import QtQuick 2.3
import QtQuick.Controls 2.3
@@ -28,4 +29,10 @@ AbstractButton {
cursorShape: Qt.PointingHandCursor
}
+ Ripple {
+ color: Qt.rgba(buttonTextColor.r, buttonTextColor.g, buttonTextColor.b, 0.5)
+ clip: false
+ rippleTarget: button
+ }
+
}
diff --git a/resources/qml/ui/Ripple.qml b/resources/qml/ui/Ripple.qml
new file mode 100644
index 00000000..9b404a68
--- /dev/null
+++ b/resources/qml/ui/Ripple.qml
@@ -0,0 +1,177 @@
+import QtGraphicalEffects 1.10
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+
+Item {
+ id: ripple
+
+ property alias clip: backgroundLayer.clip
+ property real radius: 0
+ property color color: "#22000000"
+ property real maxRadius: Math.max(width, height)
+ property real radiusAnimationRate: 0.05
+ property real radiusTailAnimationRate: 0.5
+ property real opacityAnimationDuration: 300
+ readonly property real diameter: radius * 2
+ property real centerX
+ property real centerY
+ property var rippleTarget: parent
+
+ function start() {
+ console.log("Starting ripple animation");
+ ripple.state = "ACTIVE";
+ }
+
+ function stop() {
+ console.log("Stopping ripple animation");
+ ripple.state = "NORMAL";
+ }
+
+ anchors.fill: parent
+ state: "NORMAL"
+ states: [
+ State {
+ name: "NORMAL"
+ },
+ State {
+ name: "ACTIVE"
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "NORMAL"
+ to: "ACTIVE"
+
+ SequentialAnimation {
+ ScriptAction {
+ script: {
+ ripple.opacity = 1;
+ ripple.visible = true;
+ }
+ }
+
+ NumberAnimation {
+ id: radius_animation
+
+ target: ripple
+ properties: "radius"
+ from: 0
+ to: ripple.maxRadius
+ duration: ripple.maxRadius / ripple.radiusAnimationRate
+
+ easing {
+ type: Easing.OutQuad
+ }
+
+ }
+
+ }
+
+ },
+ Transition {
+ from: "ACTIVE"
+ to: "NORMAL"
+
+ SequentialAnimation {
+ ParallelAnimation {
+ NumberAnimation {
+ id: radius_tail_animation
+
+ target: ripple
+ properties: "radius"
+ to: ripple.maxRadius
+ duration: ripple.maxRadius / ripple.radiusTailAnimationRate
+
+ easing {
+ type: Easing.Linear
+ }
+
+ }
+
+ NumberAnimation {
+ id: opacity_animation
+
+ target: ripple
+ properties: "opacity"
+ to: 0
+ duration: ripple.opacityAnimationDuration
+
+ easing {
+ type: Easing.InQuad
+ }
+
+ }
+
+ }
+
+ ScriptAction {
+ script: {
+ ripple.visible = false;
+ }
+ }
+
+ }
+
+ }
+ ]
+
+ Connections {
+ function onPressed(mouse) {
+ // Button
+ // Default to center
+
+ // MouseArea
+ if (mouse) {
+ ripple.centerX = mouse.x;
+ ripple.centerY = mouse.y;
+ } else if (rippleTarget.pressX) {
+ ripple.centerX = rippleTarget.pressX;
+ ripple.centerY = rippleTarget.pressY;
+ } else {
+ ripple.centerX = width / 2;
+ ripple.centerY = height / 2;
+ }
+ ripple.start();
+ }
+
+ function onReleased() {
+ ripple.stop();
+ }
+
+ function onExited() {
+ ripple.stop();
+ }
+
+ function onCanceled() {
+ ripple.stop();
+ }
+
+ function onClicked() {
+ ripple.stop();
+ }
+
+ target: rippleTarget
+ ignoreUnknownSignals: true
+ }
+
+ Rectangle {
+ id: backgroundLayer
+
+ anchors.fill: parent
+ color: "transparent"
+ clip: true
+
+ Rectangle {
+ id: circle
+
+ x: ripple.centerX - ripple.radius
+ y: ripple.centerY - ripple.radius
+ height: ripple.diameter
+ width: ripple.diameter
+ radius: ripple.radius
+ color: ripple.color
+ }
+
+ }
+
+}
diff --git a/resources/qml/ui/qmldir b/resources/qml/ui/qmldir
new file mode 100644
index 00000000..a8466a10
--- /dev/null
+++ b/resources/qml/ui/qmldir
@@ -0,0 +1,2 @@
+module im.nheko.UI
+Ripple 1.0 Ripple.qml
\ No newline at end of file
diff --git a/resources/res.qrc b/resources/res.qrc
index a01907ec..9b05575e 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -159,6 +159,7 @@
qml/device-verification/NewVerificationRequest.qml
qml/device-verification/Failed.qml
qml/device-verification/Success.qml
+ qml/ui/Ripple.qml
media/ring.ogg