mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-10-30 09:30:47 +03:00
parent
c2eb2f7ad1
commit
fa0c14b846
16 changed files with 251 additions and 6 deletions
|
@ -594,8 +594,8 @@ if(USE_BUNDLED_MTXCLIENT)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
MatrixClient
|
MatrixClient
|
||||||
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
GIT_TAG 7155cbb8ed3289f2cc7269da7607b0dd012f471b
|
GIT_TAG 13285437739413587a22272865d1e684e1959579
|
||||||
)
|
)
|
||||||
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
||||||
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
||||||
|
|
|
@ -182,7 +182,7 @@ modules:
|
||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
name: mtxclient
|
name: mtxclient
|
||||||
sources:
|
sources:
|
||||||
- commit: 7155cbb8ed3289f2cc7269da7607b0dd012f471b
|
- commit: 13285437739413587a22272865d1e684e1959579
|
||||||
#tag: v0.8.2
|
#tag: v0.8.2
|
||||||
type: git
|
type: git
|
||||||
url: https://github.com/Nheko-Reborn/mtxclient.git
|
url: https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
|
|
BIN
resources/confettiparticle.png
Normal file
BIN
resources/confettiparticle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
49
resources/confettiparticle.svg
Normal file
49
resources/confettiparticle.svg
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
version="1.0"
|
||||||
|
width="32.000000pt"
|
||||||
|
height="10.000000pt"
|
||||||
|
viewBox="0 0 32.000000 10.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="confettiparticle.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview6"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="pt"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="17.7"
|
||||||
|
inkscape:cx="7.1751412"
|
||||||
|
inkscape:cy="0.64971751"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1015"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<g
|
||||||
|
transform="translate(0.000000,10.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000"
|
||||||
|
stroke="none"
|
||||||
|
id="g2" />
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;stroke-width:0.75"
|
||||||
|
id="rect307"
|
||||||
|
width="32.033897"
|
||||||
|
height="10"
|
||||||
|
x="0"
|
||||||
|
y="0" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -59,7 +59,6 @@ Item {
|
||||||
onCountChanged: {
|
onCountChanged: {
|
||||||
// Mark timeline as read
|
// Mark timeline as read
|
||||||
if (atYEnd && room) model.currentIndex = 0;
|
if (atYEnd && room) model.currentIndex = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollBar.vertical: scrollbar
|
ScrollBar.vertical: scrollbar
|
||||||
|
|
|
@ -13,6 +13,7 @@ import Qt.labs.platform 1.1 as Platform
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
import QtQuick.Controls 2.5
|
import QtQuick.Controls 2.5
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Particles 2.15
|
||||||
import QtQuick.Window 2.13
|
import QtQuick.Window 2.13
|
||||||
import im.nheko 1.0
|
import im.nheko 1.0
|
||||||
import im.nheko.EmojiModel 1.0
|
import im.nheko.EmojiModel 1.0
|
||||||
|
@ -25,6 +26,8 @@ Item {
|
||||||
property bool showBackButton: false
|
property bool showBackButton: false
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
|
onRoomChanged: if (room != null) room.triggerSpecialEffects()
|
||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: StandardKey.Close
|
sequence: StandardKey.Close
|
||||||
onActivated: Rooms.resetCurrentRoom()
|
onActivated: Rooms.resetCurrentRoom()
|
||||||
|
@ -298,6 +301,58 @@ Item {
|
||||||
onClicked: Rooms.resetCurrentRoom()
|
onClicked: Rooms.resetCurrentRoom()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParticleSystem { id: confettiParticleSystem }
|
||||||
|
|
||||||
|
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
|
||||||
|
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: 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 {
|
NhekoDropArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
roomid: room ? room.roomId : ""
|
roomid: room ? room.roomId : ""
|
||||||
|
@ -321,6 +376,15 @@ Item {
|
||||||
timelineRoot.destroyOnClose(dialog);
|
timelineRoot.destroyOnClose(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onConfetti()
|
||||||
|
{
|
||||||
|
if (!Settings.fancyEffects)
|
||||||
|
return
|
||||||
|
|
||||||
|
confettiEmitter.pulse(parent.height * 2)
|
||||||
|
room.markSpecialEffectsDone()
|
||||||
|
}
|
||||||
|
|
||||||
target: room
|
target: room
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,20 @@ Item {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.ConfettiMessage
|
||||||
|
|
||||||
|
TextMessage {
|
||||||
|
formatted: d.formattedBody
|
||||||
|
body: d.body
|
||||||
|
isOnlyEmoji: d.isOnlyEmoji
|
||||||
|
isReply: d.isReply
|
||||||
|
keepFullText: d.keepFullText
|
||||||
|
metadataWidth: d.metadataWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: MtxEvent.NoticeMessage
|
roleValue: MtxEvent.NoticeMessage
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,7 @@
|
||||||
<file>qml/voip/PlaceCall.qml</file>
|
<file>qml/voip/PlaceCall.qml</file>
|
||||||
<file>qml/voip/ScreenShare.qml</file>
|
<file>qml/voip/ScreenShare.qml</file>
|
||||||
<file>qml/voip/VideoCall.qml</file>
|
<file>qml/voip/VideoCall.qml</file>
|
||||||
|
<file>confettiparticle.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/media">
|
<qresource prefix="/media">
|
||||||
<file>media/ring.ogg</file>
|
<file>media/ring.ogg</file>
|
||||||
|
|
|
@ -82,6 +82,10 @@ CommandCompleter::data(const QModelIndex &index, int role) const
|
||||||
return QString("/notice ");
|
return QString("/notice ");
|
||||||
case RainbowNotice:
|
case RainbowNotice:
|
||||||
return QString("/rainbownotice ");
|
return QString("/rainbownotice ");
|
||||||
|
case Confetti:
|
||||||
|
return QString("/confetti ");
|
||||||
|
case RainbowConfetti:
|
||||||
|
return QString("/rainbowconfetti ");
|
||||||
case Goto:
|
case Goto:
|
||||||
return QString("/goto ");
|
return QString("/goto ");
|
||||||
case ConvertToDm:
|
case ConvertToDm:
|
||||||
|
@ -145,6 +149,10 @@ CommandCompleter::data(const QModelIndex &index, int role) const
|
||||||
return tr("/notice [message]");
|
return tr("/notice [message]");
|
||||||
case RainbowNotice:
|
case RainbowNotice:
|
||||||
return tr("/rainbownotice [message]");
|
return tr("/rainbownotice [message]");
|
||||||
|
case Confetti:
|
||||||
|
return tr("/confetti [message]");
|
||||||
|
case RainbowConfetti:
|
||||||
|
return tr("/rainbowconfetti [message]");
|
||||||
case Goto:
|
case Goto:
|
||||||
return tr("/goto ($eventid|message index|matrix:r/room/e/event)");
|
return tr("/goto ($eventid|message index|matrix:r/room/e/event)");
|
||||||
case ConvertToDm:
|
case ConvertToDm:
|
||||||
|
@ -207,6 +215,10 @@ CommandCompleter::data(const QModelIndex &index, int role) const
|
||||||
return tr("Send a bot message.");
|
return tr("Send a bot message.");
|
||||||
case RainbowNotice:
|
case RainbowNotice:
|
||||||
return tr("Send a bot message in rainbow colors.");
|
return tr("Send a bot message in rainbow colors.");
|
||||||
|
case Confetti:
|
||||||
|
return tr("Send a message with confetti.");
|
||||||
|
case RainbowConfetti:
|
||||||
|
return tr("Send a message in rainbow colors with confetti.");
|
||||||
case Goto:
|
case Goto:
|
||||||
return tr("Go to this event or link.");
|
return tr("Go to this event or link.");
|
||||||
case ConvertToDm:
|
case ConvertToDm:
|
||||||
|
|
|
@ -44,6 +44,8 @@ public:
|
||||||
RainbowMe,
|
RainbowMe,
|
||||||
Notice,
|
Notice,
|
||||||
RainbowNotice,
|
RainbowNotice,
|
||||||
|
Confetti,
|
||||||
|
RainbowConfetti,
|
||||||
Goto,
|
Goto,
|
||||||
ConvertToDm,
|
ConvertToDm,
|
||||||
ConvertToRoom,
|
ConvertToRoom,
|
||||||
|
|
|
@ -92,6 +92,7 @@ UserSettings::load(std::optional<QString> profile)
|
||||||
decryptNotifications_ =
|
decryptNotifications_ =
|
||||||
settings.value(QStringLiteral("user/decrypt_notifications"), true).toBool();
|
settings.value(QStringLiteral("user/decrypt_notifications"), true).toBool();
|
||||||
spaceNotifications_ = settings.value(QStringLiteral("user/space_notifications"), true).toBool();
|
spaceNotifications_ = settings.value(QStringLiteral("user/space_notifications"), true).toBool();
|
||||||
|
fancyEffects_ = settings.value(QStringLiteral("user/fancy_effects"), true).toBool();
|
||||||
privacyScreen_ = settings.value(QStringLiteral("user/privacy_screen"), false).toBool();
|
privacyScreen_ = settings.value(QStringLiteral("user/privacy_screen"), false).toBool();
|
||||||
privacyScreenTimeout_ =
|
privacyScreenTimeout_ =
|
||||||
settings.value(QStringLiteral("user/privacy_screen_timeout"), 0).toInt();
|
settings.value(QStringLiteral("user/privacy_screen_timeout"), 0).toInt();
|
||||||
|
@ -459,6 +460,16 @@ UserSettings::setSpaceNotifications(bool state)
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setFancyEffects(bool state)
|
||||||
|
{
|
||||||
|
if (state == fancyEffects_)
|
||||||
|
return;
|
||||||
|
fancyEffects_ = state;
|
||||||
|
emit fancyEffectsChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UserSettings::setPrivacyScreen(bool state)
|
UserSettings::setPrivacyScreen(bool state)
|
||||||
{
|
{
|
||||||
|
@ -822,6 +833,7 @@ UserSettings::save()
|
||||||
settings.setValue(QStringLiteral("decrypt_sidebar"), decryptSidebar_);
|
settings.setValue(QStringLiteral("decrypt_sidebar"), decryptSidebar_);
|
||||||
settings.setValue(QStringLiteral("decrypt_notificatons"), decryptNotifications_);
|
settings.setValue(QStringLiteral("decrypt_notificatons"), decryptNotifications_);
|
||||||
settings.setValue(QStringLiteral("space_notifications"), spaceNotifications_);
|
settings.setValue(QStringLiteral("space_notifications"), spaceNotifications_);
|
||||||
|
settings.setValue(QStringLiteral("fancy_effects"), fancyEffects_);
|
||||||
settings.setValue(QStringLiteral("privacy_screen"), privacyScreen_);
|
settings.setValue(QStringLiteral("privacy_screen"), privacyScreen_);
|
||||||
settings.setValue(QStringLiteral("privacy_screen_timeout"), privacyScreenTimeout_);
|
settings.setValue(QStringLiteral("privacy_screen_timeout"), privacyScreenTimeout_);
|
||||||
settings.setValue(QStringLiteral("mobile_mode"), mobileMode_);
|
settings.setValue(QStringLiteral("mobile_mode"), mobileMode_);
|
||||||
|
@ -976,6 +988,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
||||||
return tr("Decrypt notifications");
|
return tr("Decrypt notifications");
|
||||||
case SpaceNotifications:
|
case SpaceNotifications:
|
||||||
return tr("Show message counts for communities and tags");
|
return tr("Show message counts for communities and tags");
|
||||||
|
case FancyEffects:
|
||||||
|
return tr("Display fancy effects such as confetti");
|
||||||
case PrivacyScreen:
|
case PrivacyScreen:
|
||||||
return tr("Privacy Screen");
|
return tr("Privacy Screen");
|
||||||
case PrivacyScreenTimeout:
|
case PrivacyScreenTimeout:
|
||||||
|
@ -1112,6 +1126,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
||||||
return i->decryptNotifications();
|
return i->decryptNotifications();
|
||||||
case SpaceNotifications:
|
case SpaceNotifications:
|
||||||
return i->spaceNotifications();
|
return i->spaceNotifications();
|
||||||
|
case FancyEffects:
|
||||||
|
return i->fancyEffects();
|
||||||
case PrivacyScreen:
|
case PrivacyScreen:
|
||||||
return i->privacyScreen();
|
return i->privacyScreen();
|
||||||
case PrivacyScreenTimeout:
|
case PrivacyScreenTimeout:
|
||||||
|
@ -1276,6 +1292,9 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
||||||
case SpaceNotifications:
|
case SpaceNotifications:
|
||||||
return tr("Choose where to show the total number of notifications contained within a "
|
return tr("Choose where to show the total number of notifications contained within a "
|
||||||
"community or tag.");
|
"community or tag.");
|
||||||
|
case FancyEffects:
|
||||||
|
return tr("Some messages can be sent with fancy effects. For example, messages sent "
|
||||||
|
"with '/confetti' will show confetti on screen.");
|
||||||
case PrivacyScreen:
|
case PrivacyScreen:
|
||||||
return tr("When the window loses focus, the timeline will\nbe blurred.");
|
return tr("When the window loses focus, the timeline will\nbe blurred.");
|
||||||
case MobileMode:
|
case MobileMode:
|
||||||
|
@ -1388,6 +1407,7 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
|
||||||
case UseOnlineKeyBackup:
|
case UseOnlineKeyBackup:
|
||||||
case ExposeDBusApi:
|
case ExposeDBusApi:
|
||||||
case SpaceNotifications:
|
case SpaceNotifications:
|
||||||
|
case FancyEffects:
|
||||||
return Toggle;
|
return Toggle;
|
||||||
case Profile:
|
case Profile:
|
||||||
case UserId:
|
case UserId:
|
||||||
|
@ -1716,6 +1736,13 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
case FancyEffects: {
|
||||||
|
if (value.userType() == QMetaType::Bool) {
|
||||||
|
i->setFancyEffects(value.toBool());
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
case PrivacyScreen: {
|
case PrivacyScreen: {
|
||||||
if (value.userType() == QMetaType::Bool) {
|
if (value.userType() == QMetaType::Bool) {
|
||||||
i->setPrivacyScreen(value.toBool());
|
i->setPrivacyScreen(value.toBool());
|
||||||
|
@ -2037,6 +2064,9 @@ UserSettingsModel::UserSettingsModel(QObject *p)
|
||||||
connect(s.get(), &UserSettings::spaceNotificationsChanged, this, [this]() {
|
connect(s.get(), &UserSettings::spaceNotificationsChanged, this, [this]() {
|
||||||
emit dataChanged(index(SpaceNotifications), index(SpaceNotifications), {Value});
|
emit dataChanged(index(SpaceNotifications), index(SpaceNotifications), {Value});
|
||||||
});
|
});
|
||||||
|
connect(s.get(), &UserSettings::fancyEffectsChanged, this, [this]() {
|
||||||
|
emit dataChanged(index(FancyEffects), index(FancyEffects), {Value});
|
||||||
|
});
|
||||||
connect(s.get(), &UserSettings::trayChanged, this, [this]() {
|
connect(s.get(), &UserSettings::trayChanged, this, [this]() {
|
||||||
emit dataChanged(index(Tray), index(Tray), {Value});
|
emit dataChanged(index(Tray), index(Tray), {Value});
|
||||||
emit dataChanged(index(StartInTray), index(StartInTray), {Enabled});
|
emit dataChanged(index(StartInTray), index(StartInTray), {Enabled});
|
||||||
|
|
|
@ -64,6 +64,7 @@ class UserSettings final : public QObject
|
||||||
NOTIFY decryptNotificationsChanged)
|
NOTIFY decryptNotificationsChanged)
|
||||||
Q_PROPERTY(bool spaceNotifications READ spaceNotifications WRITE setSpaceNotifications NOTIFY
|
Q_PROPERTY(bool spaceNotifications READ spaceNotifications WRITE setSpaceNotifications NOTIFY
|
||||||
spaceNotificationsChanged)
|
spaceNotificationsChanged)
|
||||||
|
Q_PROPERTY(bool fancyEffects READ fancyEffects WRITE setFancyEffects NOTIFY fancyEffectsChanged)
|
||||||
Q_PROPERTY(
|
Q_PROPERTY(
|
||||||
bool privacyScreen READ privacyScreen WRITE setPrivacyScreen NOTIFY privacyScreenChanged)
|
bool privacyScreen READ privacyScreen WRITE setPrivacyScreen NOTIFY privacyScreenChanged)
|
||||||
Q_PROPERTY(int privacyScreenTimeout READ privacyScreenTimeout WRITE setPrivacyScreenTimeout
|
Q_PROPERTY(int privacyScreenTimeout READ privacyScreenTimeout WRITE setPrivacyScreenTimeout
|
||||||
|
@ -171,6 +172,7 @@ public:
|
||||||
void setDecryptSidebar(bool state);
|
void setDecryptSidebar(bool state);
|
||||||
void setDecryptNotifications(bool state);
|
void setDecryptNotifications(bool state);
|
||||||
void setSpaceNotifications(bool state);
|
void setSpaceNotifications(bool state);
|
||||||
|
void setFancyEffects(bool state);
|
||||||
void setPrivacyScreen(bool state);
|
void setPrivacyScreen(bool state);
|
||||||
void setPrivacyScreenTimeout(int state);
|
void setPrivacyScreenTimeout(int state);
|
||||||
void setPresence(Presence state);
|
void setPresence(Presence state);
|
||||||
|
@ -214,6 +216,7 @@ public:
|
||||||
bool decryptSidebar() const { return decryptSidebar_; }
|
bool decryptSidebar() const { return decryptSidebar_; }
|
||||||
bool decryptNotifications() const { return decryptNotifications_; }
|
bool decryptNotifications() const { return decryptNotifications_; }
|
||||||
bool spaceNotifications() const { return spaceNotifications_; }
|
bool spaceNotifications() const { return spaceNotifications_; }
|
||||||
|
bool fancyEffects() const { return fancyEffects_; }
|
||||||
bool privacyScreen() const { return privacyScreen_; }
|
bool privacyScreen() const { return privacyScreen_; }
|
||||||
int privacyScreenTimeout() const { return privacyScreenTimeout_; }
|
int privacyScreenTimeout() const { return privacyScreenTimeout_; }
|
||||||
bool markdown() const { return markdown_; }
|
bool markdown() const { return markdown_; }
|
||||||
|
@ -295,6 +298,7 @@ signals:
|
||||||
void decryptSidebarChanged(bool state);
|
void decryptSidebarChanged(bool state);
|
||||||
void decryptNotificationsChanged(bool state);
|
void decryptNotificationsChanged(bool state);
|
||||||
void spaceNotificationsChanged(bool state);
|
void spaceNotificationsChanged(bool state);
|
||||||
|
void fancyEffectsChanged(bool state);
|
||||||
void privacyScreenChanged(bool state);
|
void privacyScreenChanged(bool state);
|
||||||
void privacyScreenTimeoutChanged(int state);
|
void privacyScreenTimeoutChanged(int state);
|
||||||
void timelineMaxWidthChanged(int state);
|
void timelineMaxWidthChanged(int state);
|
||||||
|
@ -360,6 +364,7 @@ private:
|
||||||
bool decryptSidebar_;
|
bool decryptSidebar_;
|
||||||
bool decryptNotifications_;
|
bool decryptNotifications_;
|
||||||
bool spaceNotifications_;
|
bool spaceNotifications_;
|
||||||
|
bool fancyEffects_;
|
||||||
bool privacyScreen_;
|
bool privacyScreen_;
|
||||||
int privacyScreenTimeout_;
|
int privacyScreenTimeout_;
|
||||||
bool shareKeysWithTrustedUsers_;
|
bool shareKeysWithTrustedUsers_;
|
||||||
|
@ -442,6 +447,8 @@ class UserSettingsModel final : public QAbstractListModel
|
||||||
InvertEnterKey,
|
InvertEnterKey,
|
||||||
Bubbles,
|
Bubbles,
|
||||||
SmallAvatars,
|
SmallAvatars,
|
||||||
|
FancyEffects,
|
||||||
|
|
||||||
SidebarSection,
|
SidebarSection,
|
||||||
GroupView,
|
GroupView,
|
||||||
SortByImportance,
|
SortByImportance,
|
||||||
|
|
|
@ -534,6 +534,27 @@ InputBar::notice(const QString &msg, bool rainbowify)
|
||||||
room->sendMessageEvent(notice, mtx::events::EventType::RoomMessage);
|
room->sendMessageEvent(notice, mtx::events::EventType::RoomMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputBar::confetti(const QString &body, bool rainbowify)
|
||||||
|
{
|
||||||
|
auto html = utils::markdownToHtml(body, rainbowify);
|
||||||
|
|
||||||
|
mtx::events::msg::Confetti confetti;
|
||||||
|
confetti.body = body.trimmed().toStdString();
|
||||||
|
|
||||||
|
if (html != body.trimmed().toHtmlEscaped() &&
|
||||||
|
ChatPage::instance()->userSettings()->markdown()) {
|
||||||
|
confetti.formatted_body = html.toStdString();
|
||||||
|
confetti.format = "org.matrix.custom.html";
|
||||||
|
// Remove markdown links by completer
|
||||||
|
confetti.body = replaceMatrixToMarkdownLink(body.trimmed()).toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
confetti.relations = generateRelations();
|
||||||
|
|
||||||
|
room->sendMessageEvent(confetti, mtx::events::EventType::RoomMessage);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
InputBar::image(const QString &filename,
|
InputBar::image(const QString &filename,
|
||||||
const std::optional<mtx::crypto::EncryptedFile> &file,
|
const std::optional<mtx::crypto::EncryptedFile> &file,
|
||||||
|
@ -777,6 +798,10 @@ InputBar::command(const QString &command, QString args)
|
||||||
notice(args, false);
|
notice(args, false);
|
||||||
} else if (command == QLatin1String("rainbownotice")) {
|
} else if (command == QLatin1String("rainbownotice")) {
|
||||||
notice(args, true);
|
notice(args, true);
|
||||||
|
} else if (command == QLatin1String("confetti")) {
|
||||||
|
confetti(args, false);
|
||||||
|
} else if (command == QLatin1String("rainbowconfetti")) {
|
||||||
|
confetti(args, true);
|
||||||
} else if (command == QLatin1String("goto")) {
|
} else if (command == QLatin1String("goto")) {
|
||||||
// Goto has three different modes:
|
// Goto has three different modes:
|
||||||
// 1 - Going directly to a given event ID
|
// 1 - Going directly to a given event ID
|
||||||
|
|
|
@ -230,6 +230,7 @@ signals:
|
||||||
private:
|
private:
|
||||||
void emote(const QString &body, bool rainbowify);
|
void emote(const QString &body, bool rainbowify);
|
||||||
void notice(const QString &body, bool rainbowify);
|
void notice(const QString &body, bool rainbowify);
|
||||||
|
void confetti(const QString &body, bool rainbowify);
|
||||||
void command(const QString &name, QString args);
|
void command(const QString &name, QString args);
|
||||||
void image(const QString &filename,
|
void image(const QString &filename,
|
||||||
const std::optional<mtx::crypto::EncryptedFile> &file,
|
const std::optional<mtx::crypto::EncryptedFile> &file,
|
||||||
|
|
|
@ -53,6 +53,10 @@ struct RoomEventType
|
||||||
{
|
{
|
||||||
return qml_mtx_events::EventType::AudioMessage;
|
return qml_mtx_events::EventType::AudioMessage;
|
||||||
}
|
}
|
||||||
|
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Confetti> &)
|
||||||
|
{
|
||||||
|
return qml_mtx_events::EventType::ConfettiMessage;
|
||||||
|
}
|
||||||
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Emote> &)
|
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Emote> &)
|
||||||
{
|
{
|
||||||
return qml_mtx_events::EventType::EmoteMessage;
|
return qml_mtx_events::EventType::EmoteMessage;
|
||||||
|
@ -346,6 +350,7 @@ qml_mtx_events::fromRoomEventType(qml_mtx_events::EventType t)
|
||||||
return mtx::events::EventType::SpaceChild;
|
return mtx::events::EventType::SpaceChild;
|
||||||
/// m.room.message
|
/// m.room.message
|
||||||
case qml_mtx_events::AudioMessage:
|
case qml_mtx_events::AudioMessage:
|
||||||
|
case qml_mtx_events::ConfettiMessage:
|
||||||
case qml_mtx_events::EmoteMessage:
|
case qml_mtx_events::EmoteMessage:
|
||||||
case qml_mtx_events::FileMessage:
|
case qml_mtx_events::FileMessage:
|
||||||
case qml_mtx_events::ImageMessage:
|
case qml_mtx_events::ImageMessage:
|
||||||
|
@ -1025,9 +1030,18 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
|
||||||
} else if (std::holds_alternative<StateEvent<state::space::Parent>>(e)) {
|
} else if (std::holds_alternative<StateEvent<state::space::Parent>>(e)) {
|
||||||
this->parentChecked = false;
|
this->parentChecked = false;
|
||||||
emit parentSpaceChanged();
|
emit parentSpaceChanged();
|
||||||
}
|
} else if (std::holds_alternative<RoomEvent<mtx::events::msg::Text>>(e)) {
|
||||||
|
if (auto msg = QString::fromStdString(
|
||||||
|
std::get<RoomEvent<mtx::events::msg::Text>>(e).content.body);
|
||||||
|
msg.contains("🎉") || msg.contains("🎊"))
|
||||||
|
needsSpecialEffects_ = true;
|
||||||
|
} else if (std::holds_alternative<RoomEvent<mtx::events::msg::Confetti>>(e))
|
||||||
|
needsSpecialEffects_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needsSpecialEffects_)
|
||||||
|
emit confetti();
|
||||||
|
|
||||||
updateLastMessage();
|
updateLastMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1957,6 +1971,22 @@ TimelineModel::copyLinkToEvent(const QString &eventId) const
|
||||||
QGuiApplication::clipboard()->setText(link);
|
QGuiApplication::clipboard()->setText(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineModel::triggerSpecialEffects()
|
||||||
|
{
|
||||||
|
if (needsSpecialEffects_) {
|
||||||
|
// Note (Loren): Without the timer, this apparently emits before QML is ready
|
||||||
|
QTimer::singleShot(1, this, [this] { emit confetti(); });
|
||||||
|
needsSpecialEffects_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineModel::markSpecialEffectsDone()
|
||||||
|
{
|
||||||
|
needsSpecialEffects_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
TimelineModel::formatTypingUsers(const std::vector<QString> &users, const QColor &bg)
|
TimelineModel::formatTypingUsers(const std::vector<QString> &users, const QColor &bg)
|
||||||
{
|
{
|
||||||
|
@ -2790,7 +2820,8 @@ TimelineModel::setEdit(const QString &newEdit)
|
||||||
auto msgType = mtx::accessors::msg_type(e);
|
auto msgType = mtx::accessors::msg_type(e);
|
||||||
if (msgType == mtx::events::MessageType::Text ||
|
if (msgType == mtx::events::MessageType::Text ||
|
||||||
msgType == mtx::events::MessageType::Notice ||
|
msgType == mtx::events::MessageType::Notice ||
|
||||||
msgType == mtx::events::MessageType::Emote) {
|
msgType == mtx::events::MessageType::Emote ||
|
||||||
|
msgType == mtx::events::MessageType::Confetti) {
|
||||||
auto relInfo = relatedInfo(newEdit);
|
auto relInfo = relatedInfo(newEdit);
|
||||||
auto editText = relInfo.quoted_body;
|
auto editText = relInfo.quoted_body;
|
||||||
|
|
||||||
|
@ -2811,6 +2842,8 @@ TimelineModel::setEdit(const QString &newEdit)
|
||||||
|
|
||||||
if (msgType == mtx::events::MessageType::Emote)
|
if (msgType == mtx::events::MessageType::Emote)
|
||||||
input()->setText("/me " + editText);
|
input()->setText("/me " + editText);
|
||||||
|
else if (msgType == mtx::events::MessageType::Confetti)
|
||||||
|
input()->setText("/confetti" + editText);
|
||||||
else
|
else
|
||||||
input()->setText(editText);
|
input()->setText(editText);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -100,6 +100,7 @@ enum EventType
|
||||||
Widget,
|
Widget,
|
||||||
/// m.room.message
|
/// m.room.message
|
||||||
AudioMessage,
|
AudioMessage,
|
||||||
|
ConfettiMessage,
|
||||||
EmoteMessage,
|
EmoteMessage,
|
||||||
FileMessage,
|
FileMessage,
|
||||||
ImageMessage,
|
ImageMessage,
|
||||||
|
@ -419,6 +420,9 @@ public slots:
|
||||||
|
|
||||||
QString scrollTarget() const;
|
QString scrollTarget() const;
|
||||||
|
|
||||||
|
void triggerSpecialEffects();
|
||||||
|
void markSpecialEffectsDone();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void addPendingMessage(mtx::events::collections::TimelineEvents event);
|
void addPendingMessage(mtx::events::collections::TimelineEvents event);
|
||||||
void scrollTimerEvent();
|
void scrollTimerEvent();
|
||||||
|
@ -438,6 +442,7 @@ signals:
|
||||||
void paginationInProgressChanged(const bool);
|
void paginationInProgressChanged(const bool);
|
||||||
void newCallEvent(const mtx::events::collections::TimelineEvents &event);
|
void newCallEvent(const mtx::events::collections::TimelineEvents &event);
|
||||||
void scrollToIndex(int index);
|
void scrollToIndex(int index);
|
||||||
|
void confetti();
|
||||||
|
|
||||||
void lastMessageChanged();
|
void lastMessageChanged();
|
||||||
void notificationsChanged();
|
void notificationsChanged();
|
||||||
|
@ -509,6 +514,9 @@ private:
|
||||||
std::string last_event_id;
|
std::string last_event_id;
|
||||||
std::string fullyReadEventId_;
|
std::string fullyReadEventId_;
|
||||||
|
|
||||||
|
// TODO (Loren): This should hopefully handle more than just confetti in the future
|
||||||
|
bool needsSpecialEffects_ = false;
|
||||||
|
|
||||||
std::unique_ptr<RoomSummary, DeleteLaterDeleter> parentSummary = nullptr;
|
std::unique_ptr<RoomSummary, DeleteLaterDeleter> parentSummary = nullptr;
|
||||||
bool parentChecked = false;
|
bool parentChecked = false;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue