diff --git a/CMakeLists.txt b/CMakeLists.txt
index 06af4bbe..20fcb029 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -602,7 +602,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare(
MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
- GIT_TAG c8849cd033bb59bee39f3fb2eaca953853731eb2
+ GIT_TAG dd2bdbd104ae8f70f82da9ff7b4b60007fc105c3
)
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
diff --git a/io.github.NhekoReborn.Nheko.yaml b/io.github.NhekoReborn.Nheko.yaml
index 3bcfdf52..97d0b770 100644
--- a/io.github.NhekoReborn.Nheko.yaml
+++ b/io.github.NhekoReborn.Nheko.yaml
@@ -213,7 +213,7 @@ modules:
buildsystem: cmake-ninja
name: mtxclient
sources:
- - commit: c8849cd033bb59bee39f3fb2eaca953853731eb2
+ - commit: dd2bdbd104ae8f70f82da9ff7b4b60007fc105c3
#tag: v0.9.2
type: git
url: https://github.com/Nheko-Reborn/mtxclient.git
diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index a146a991..30ad9292 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -364,60 +364,10 @@ Item {
onClicked: Rooms.resetCurrentRoom()
}
- ParticleSystem { id: confettiParticleSystem
- Component.onCompleted: pause();
- paused: !shouldEffectsRun
- }
-
- Emitter {
- id: confettiEmitter
-
- width: parent.width * 3/4
- enabled: false
- anchors.horizontalCenter: parent.horizontalCenter
- y: parent.height
- emitRate: Math.min(400 * Math.sqrt(parent.width * parent.height) / 870, 1000)
- lifeSpan: 15000
- system: confettiParticleSystem
- maximumEmitted: 500
- velocityFromMovement: 8
- size: 16
- sizeVariation: 4
- velocity: PointDirection {
- x: 0
- y: -Math.min(450 * parent.height / 700, 1000)
- xVariation: Math.min(4 * parent.width / 7, 450)
- yVariation: 250
- }
- }
+ TimelineEffects {
+ id: timelineEffects
- ImageParticle {
- system: confettiParticleSystem
- source: "qrc:/confettiparticle.svg"
- rotationVelocity: 0
- rotationVelocityVariation: 360
- colorVariation: 1
- color: "white"
- entryEffect: ImageParticle.None
- xVector: PointDirection {
- x: 1
- y: 0
- xVariation: 0.2
- yVariation: 0.2
- }
- yVector: PointDirection {
- x: 0
- y: 0.5
- xVariation: 0.2
- yVariation: 0.2
- }
- }
-
- Gravity {
- system: confettiParticleSystem
anchors.fill: parent
- magnitude: 350
- angle: 90
}
NhekoDropArea {
@@ -428,7 +378,7 @@ Item {
Timer {
id: effectsTimer
onTriggered: shouldEffectsRun = false;
- interval: confettiEmitter.lifeSpan
+ interval: timelineEffects.maxLifespan
repeat: false
running: false
}
@@ -462,7 +412,7 @@ Item {
return
shouldEffectsRun = true;
- confettiEmitter.pulse(parent.height * 2)
+ timelineEffects.pulseConfetti()
room.markSpecialEffectsDone()
}
@@ -471,7 +421,25 @@ Item {
if (!Settings.fancyEffects)
return
- effectsTimer.start();
+ effectsTimer.restart();
+ }
+
+ function onRainfall()
+ {
+ if (!Settings.fancyEffects)
+ return
+
+ shouldEffectsRun = true;
+ timelineEffects.pulseRainfall()
+ room.markSpecialEffectsDone()
+ }
+
+ function onRainfallDone()
+ {
+ if (!Settings.fancyEffects)
+ return
+
+ effectsTimer.restart();
}
target: room
diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml
index d298fa4e..c0bcec0d 100644
--- a/resources/qml/delegates/MessageDelegate.qml
+++ b/resources/qml/delegates/MessageDelegate.qml
@@ -51,7 +51,7 @@ Item {
width: parent.width? parent.width: 0 // this should get rid of "cannot read property 'width' of null"
DelegateChoice {
- roleValue: MtxEvent.UnknownMessage
+ roleValue: MtxEvent.UnknownEvent
Placeholder {
typeString: d.typeString
@@ -102,7 +102,21 @@ Item {
}
DelegateChoice {
- roleValue: MtxEvent.ConfettiMessage
+ roleValue: MtxEvent.UnknownMessage
+
+ TextMessage {
+ formatted: d.formattedBody
+ body: d.body
+ isOnlyEmoji: d.isOnlyEmoji
+ isReply: d.isReply
+ keepFullText: d.keepFullText
+ metadataWidth: d.metadataWidth
+ }
+
+ }
+
+ DelegateChoice {
+ roleValue: MtxEvent.ElementEffectMessage
TextMessage {
formatted: d.formattedBody
diff --git a/resources/qml/ui/TimelineEffects.qml b/resources/qml/ui/TimelineEffects.qml
new file mode 100644
index 00000000..aaff04a0
--- /dev/null
+++ b/resources/qml/ui/TimelineEffects.qml
@@ -0,0 +1,112 @@
+// SPDX-FileCopyrightText: Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick 2.15
+import QtQuick.Particles 2.15
+
+Item {
+ readonly property int maxLifespan: Math.max(confettiEmitter.lifeSpan, rainfallEmitter.lifeSpan)
+
+ function pulseConfetti()
+ {
+ confettiEmitter.pulse(parent.height * 2)
+ }
+
+ function pulseRainfall()
+ {
+ rainfallEmitter.pulse(parent.height * 3.3)
+ }
+
+ ParticleSystem {
+ id: particleSystem
+
+ Component.onCompleted: pause();
+ paused: !shouldEffectsRun
+ }
+
+ Emitter {
+ id: confettiEmitter
+
+ group: "confetti"
+ width: parent.width * 3/4
+ enabled: false
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: parent.height
+ emitRate: Math.min(400 * Math.sqrt(parent.width * parent.height) / 870, 1000)
+ lifeSpan: 15000
+ system: particleSystem
+ maximumEmitted: 500
+ velocityFromMovement: 8
+ size: 16
+ sizeVariation: 4
+ velocity: PointDirection {
+ x: 0
+ y: -Math.min(450 * parent.height / 700, 1000)
+ xVariation: Math.min(4 * parent.width / 7, 450)
+ yVariation: 250
+ }
+ }
+
+ ImageParticle {
+ system: particleSystem
+ groups: ["confetti"]
+ source: "qrc:/confettiparticle.svg"
+ rotationVelocity: 0
+ rotationVelocityVariation: 360
+ colorVariation: 1
+ color: "white"
+ entryEffect: ImageParticle.None
+ xVector: PointDirection {
+ x: 1
+ y: 0
+ xVariation: 0.2
+ yVariation: 0.2
+ }
+ yVector: PointDirection {
+ x: 0
+ y: 0.5
+ xVariation: 0.2
+ yVariation: 0.2
+ }
+ }
+
+ Gravity {
+ system: particleSystem
+ groups: ["confetti"]
+ anchors.fill: parent
+ magnitude: 350
+ angle: 90
+ }
+
+ Emitter {
+ id: rainfallEmitter
+
+ group: "rain"
+ width: parent.width
+ enabled: false
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: -60
+ emitRate: parent.width / 50
+ lifeSpan: 10000
+ system: particleSystem
+ velocity: PointDirection {
+ x: 0
+ y: 300
+ xVariation: 0
+ yVariation: 75
+ }
+
+ ItemParticle {
+ system: particleSystem
+ groups: ["rain"]
+ fade: false
+ delegate: Rectangle {
+ width: 2
+ height: 30 + 30 * Math.random()
+ radius: 2
+ color: "#0099ff"
+ }
+ }
+ }
+}
diff --git a/resources/res.qrc b/resources/res.qrc
index faa90495..3f1b2b65 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -197,6 +197,7 @@
qml/voip/VideoCall.qml
confettiparticle.svg
qml/delegates/EncryptionEnabled.qml
+ qml/ui/TimelineEffects.qml
media/ring.ogg
diff --git a/src/CommandCompleter.cpp b/src/CommandCompleter.cpp
index 2ec427d6..8123b8e6 100644
--- a/src/CommandCompleter.cpp
+++ b/src/CommandCompleter.cpp
@@ -87,6 +87,10 @@ CommandCompleter::data(const QModelIndex &index, int role) const
return QStringLiteral("/confetti ");
case RainbowConfetti:
return QStringLiteral("/rainbowconfetti ");
+ case Rainfall:
+ return QStringLiteral("/rainfall ");
+ case Msgtype:
+ return QStringLiteral("/msgtype ");
case Goto:
return QStringLiteral("/goto ");
case ConvertToDm:
@@ -156,6 +160,10 @@ CommandCompleter::data(const QModelIndex &index, int role) const
return tr("/confetti [message]");
case RainbowConfetti:
return tr("/rainbowconfetti [message]");
+ case Rainfall:
+ return tr("/rainfall [message]");
+ case Msgtype:
+ return tr("/msgtype [message]");
case Goto:
return tr("/goto ");
case ConvertToDm:
@@ -225,6 +233,10 @@ CommandCompleter::data(const QModelIndex &index, int role) const
return tr("Send a message with confetti.");
case RainbowConfetti:
return tr("Send a message in rainbow colors with confetti.");
+ case Rainfall:
+ return tr("Send a message with rain.");
+ case Msgtype:
+ return tr("Send a message with a custom message type.");
case Goto:
return tr("Go to a specific message using an event id, index or matrix: link");
case ConvertToDm:
diff --git a/src/CommandCompleter.h b/src/CommandCompleter.h
index fcbbe3e5..4f27fe29 100644
--- a/src/CommandCompleter.h
+++ b/src/CommandCompleter.h
@@ -46,6 +46,8 @@ public:
RainbowNotice,
Confetti,
RainbowConfetti,
+ Rainfall,
+ Msgtype,
Goto,
ConvertToDm,
ConvertToRoom,
diff --git a/src/Utils.cpp b/src/Utils.cpp
index c5b2abd1..2bf8eb3b 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -215,19 +215,20 @@ utils::getMessageDescription(const TimelineEvent &event,
const QString &localUser,
const QString &displayName)
{
- using Audio = mtx::events::RoomEvent;
- using Emote = mtx::events::RoomEvent;
- using File = mtx::events::RoomEvent;
- using Image = mtx::events::RoomEvent;
- using Notice = mtx::events::RoomEvent;
- using Text = mtx::events::RoomEvent;
- using Video = mtx::events::RoomEvent;
- using Confetti = mtx::events::RoomEvent;
- using CallInvite = mtx::events::RoomEvent;
- using CallAnswer = mtx::events::RoomEvent;
- using CallHangUp = mtx::events::RoomEvent;
- using CallReject = mtx::events::RoomEvent;
- using Encrypted = mtx::events::EncryptedEvent;
+ using Audio = mtx::events::RoomEvent;
+ using Emote = mtx::events::RoomEvent;
+ using File = mtx::events::RoomEvent;
+ using Image = mtx::events::RoomEvent;
+ using Notice = mtx::events::RoomEvent;
+ using Text = mtx::events::RoomEvent;
+ using Unknown = mtx::events::RoomEvent;
+ using Video = mtx::events::RoomEvent;
+ using ElementEffect = mtx::events::RoomEvent;
+ using CallInvite = mtx::events::RoomEvent;
+ using CallAnswer = mtx::events::RoomEvent;
+ using CallHangUp = mtx::events::RoomEvent;
+ using CallReject = mtx::events::RoomEvent;
+ using Encrypted = mtx::events::EncryptedEvent;
if (std::holds_alternative