Compare commits

..

1 Commits

Author SHA1 Message Date
Tobias Fella
fe3516b044 Explicitely set room for EmojiPicker 2023-08-07 22:47:23 +02:00
137 changed files with 11857 additions and 12128 deletions

View File

@@ -57,7 +57,6 @@ Dependencies:
- 'on': ['Linux/Qt6', 'FreeBSD/Qt6']
'require':
'frameworks/kdbusaddons': '@latest-kf6'
'frameworks/kstatusnotifieritem': '@latest-kf6'
- 'on': ['Linux/Qt6', 'Linux/Qt5']
'require':

View File

@@ -27,7 +27,7 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(KDE_COMPILERSETTINGS_LEVEL 5.105)
set(KDE_COMPILERSETTINGS_LEVEL 5.84)
include(FeatureSummary)
include(ECMSetupVersion)
@@ -93,10 +93,6 @@ set_package_properties(KF${QT_MAJOR_VERSION}Kirigami2 PROPERTIES
)
find_package(KF${QT_MAJOR_VERSION}KirigamiAddons 0.7.2 REQUIRED)
if(QT_MAJOR_VERSION STREQUAL "6")
find_package(KF6StatusNotifierItem ${KF_MIN_VERSION} REQUIRED)
endif()
if(ANDROID)
find_package(OpenSSL)
set_package_properties(OpenSSL PROPERTIES

View File

@@ -9,7 +9,7 @@
A Qt/QML based Matrix client.
<a href='https://matrix.org'><img src='https://matrix.org/docs/legacy/made-for-matrix.png' alt='Made for Matrix' height=64 target=_blank /></a>
<a href='https://matrix.org'><img src='https://matrix.org/docs/projects/images/made-for-matrix.png' alt='Made for Matrix' height=64 target=_blank /></a>
<a href='https://flathub.org/apps/details/org.kde.neochat'><img width='190px' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-i-en.png'/></a>
## Introduction

View File

@@ -604,13 +604,13 @@ void TextHandlerTest::linkPreviewsMatch_data()
QTest::addColumn<QString>("testInputString");
QTest::addColumn<QList<QUrl>>("testOutputLinks");
QTest::newRow("plainHttps") << QStringLiteral("https://kde.org") << QList<QUrl>({QUrl("https://kde.org"_ls)});
QTest::newRow("richHttps") << QStringLiteral("<a href=\"https://kde.org\">Rich Link</a>") << QList<QUrl>({QUrl("https://kde.org"_ls)});
QTest::newRow("plainWww") << QStringLiteral("www.example.org") << QList<QUrl>({QUrl("www.example.org"_ls)});
QTest::newRow("plainHttps") << QStringLiteral("https://kde.org") << QList<QUrl>({QUrl("https://kde.org")});
QTest::newRow("richHttps") << QStringLiteral("<a href=\"https://kde.org\">Rich Link</a>") << QList<QUrl>({QUrl("https://kde.org")});
QTest::newRow("plainWww") << QStringLiteral("www.example.org") << QList<QUrl>({QUrl("www.example.org")});
QTest::newRow("multipleHttps") << QStringLiteral("https://kde.org www.example.org")
<< QList<QUrl>({
QUrl("https://kde.org"_ls),
QUrl("www.example.org"_ls),
QUrl("https://kde.org"),
QUrl("www.example.org"),
});
}

View File

@@ -47,15 +47,11 @@
<name xml:lang="x-test">xxNeoChatxx</name>
<name xml:lang="zh-CN">NeoChat</name>
<summary>Chat with your friends on matrix</summary>
<summary xml:lang="ar">دردش مع أصدقائك على ماتركس</summary>
<summary xml:lang="ca">Xategeu amb els vostres amics a Matrix</summary>
<summary xml:lang="ca-valencia">Xategeu amb els vostres amics a Matrix</summary>
<summary xml:lang="eo">Babilu kun viaj amikoj sur matrix</summary>
<summary xml:lang="es">Charle con sus amigos en matrix</summary>
<summary xml:lang="eu">Berriketan jardun zure lagunekin «Matrix»en</summary>
<summary xml:lang="fr">Discuter avec vos ami(e)s sur le réseau Matrix</summary>
<summary xml:lang="gl">Charle coas súas amizades en Matrix.</summary>
<summary xml:lang="it">Conversa con i tuoi contatti su matrix</summary>
<summary xml:lang="ka">ესაუბრეთ მეგობრებს Matrix-ზე</summary>
<summary xml:lang="nl">Met uw vrienden chatten op matrix</summary>
<summary xml:lang="nn">Prat med vennar på Matrix</summary>
@@ -269,13 +265,11 @@ to provide a convergent experience across multiple platforms.</p>
<value key="KDE::windows_store::PromotionalArt16x9">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/promoimage-1920x1080.png</value>
<value key="KDE::windows_store::screenshots::1::image">https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</value>
<value key="KDE::windows_store::screenshots::1::caption">Main view with room list, chat, and room information</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="fi">Päänäkymä, jossa huoneluettelo, keskustelu ja huoneen tiedot</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</value>
@@ -292,13 +286,11 @@ to provide a convergent experience across multiple platforms.</p>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="x-test">xxMain view with room list, chat, and room informationxx</value>
<value key="KDE::windows_store::screenshots::2::image">https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Login.png</value>
<value key="KDE::windows_store::screenshots::2::caption">Login screen</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ar">شاشة الدخول</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ca">Pantalla d'inici de sessió</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ca-valencia">Pantalla d'inici de sessió</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="eo">Ensaluta ekrano</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="es">Pantalla de inicio de sesión</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="eu">Saio-hasteko pantaila</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="fi">Kirjautumisnäkymä</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="fr">Écran de connexion</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="gl">Pantalla de identificación.</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="it">Schermata di accesso</value>
@@ -327,7 +319,6 @@ to provide a convergent experience across multiple platforms.</p>
<content_attribute id="social-chat">intense</content_attribute>
</content_rating>
<releases>
<release version="23.08.0" date="2023-08-24"/>
<release version="23.04.3" date="2023-07-06"/>
<release version="23.04.2" date="2023-06-08"/>
<release version="23.04.1" date="2023-05-11"/>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: neochat\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2023-08-21 00:46+0000\n"
"PO-Revision-Date: 2023-08-10 18:43+0200\n"
"POT-Creation-Date: 2023-08-04 00:46+0000\n"
"PO-Revision-Date: 2023-08-03 19:40+0200\n"
"Last-Translator: Karl Ove Hufthammer <karl@huftis.org>\n"
"Language-Team: Norwegian Nynorsk <l10n-no@lister.huftis.org>\n"
"Language: nn\n"
@@ -124,95 +124,95 @@ msgstr "Mål"
msgid "Network Error"
msgstr "Nettverksfeil"
#: src/main.cpp:171
#: src/main.cpp:160
#, kde-format
msgid "NeoChat"
msgstr "NeoChat"
#: src/main.cpp:173
#: src/main.cpp:162
#, kde-format
msgid "Matrix client"
msgstr "Matrix-klient"
#: src/main.cpp:175
#: src/main.cpp:164
#, kde-format
msgid "© 2018-2020 Black Hat, 2020-2023 KDE Community"
msgstr "© 20182020 Black Hat, © 20202023 KDE-fellesskapet"
#: src/main.cpp:176
#: src/main.cpp:165
#, kde-format
msgid "Carl Schwan"
msgstr "Carl Schwan"
#: src/main.cpp:176 src/main.cpp:177 src/main.cpp:178
#: src/main.cpp:165 src/main.cpp:166 src/main.cpp:167
#, kde-format
msgid "Maintainer"
msgstr "Vedlikehaldar"
#: src/main.cpp:177
#: src/main.cpp:166
#, kde-format
msgid "Tobias Fella"
msgstr "Tobias Fella"
#: src/main.cpp:178
#: src/main.cpp:167
#, kde-format
msgid "James Graham"
msgstr "James Graham"
#: src/main.cpp:179
#: src/main.cpp:168
#, kde-format
msgid "Black Hat"
msgstr "Black Hat"
#: src/main.cpp:179
#: src/main.cpp:168
#, kde-format
msgid "Original author of Spectral"
msgstr "Opphavleg utviklar av Spectral"
#: src/main.cpp:180
#: src/main.cpp:169
#, kde-format
msgid "Alexey Rusakov"
msgstr "Alexey Rusakov"
#: src/main.cpp:180
#: src/main.cpp:169
#, kde-format
msgid "Maintainer of Quotient"
msgstr "Vedlikehaldar av Quotient"
#: src/main.cpp:181
#: src/main.cpp:170
#, kde-format
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "Karl Ove Hufthammer"
#: src/main.cpp:181
#: src/main.cpp:170
#, kde-format
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your emails"
msgstr "karl@huftis.org"
#: src/main.cpp:185
#: src/main.cpp:174
#, kde-format
msgid "A Qt5 library to write cross-platform clients for Matrix"
msgstr "Eit Qt5-bibliotek for utvikling av kryssplattform-klientar for Matrix"
#: src/main.cpp:187
#: src/main.cpp:176
#, kde-format
msgctxt "<version number> (built against <possibly different version number>)"
msgid "%1 (built against %2)"
msgstr "%1 (bygd mot %2)"
#: src/main.cpp:333
#: src/main.cpp:324
#, kde-format
msgid "Client for the matrix communication protocol"
msgstr "Lynmeldings­klient for Matrix-protokollen"
#: src/main.cpp:334
#: src/main.cpp:325
#, kde-format
msgid "Supports matrix: url scheme"
msgstr "Støttar «matrix:»-adresser"
#: src/main.cpp:335
#: src/main.cpp:326
#, kde-format
msgid "Ignore all SSL Errors, e.g., unsigned certificates."
msgstr "Ignorer alle SSL-feil, for eksempel usignerte sertifikat."
@@ -648,35 +648,35 @@ msgctxt "As in 'The user's own emojis"
msgid "Own Emojis"
msgstr "Eigne emojiar"
#: src/models/messageeventmodel.cpp:464 src/models/messageeventmodel.cpp:473
#: src/models/messageeventmodel.cpp:463 src/models/messageeventmodel.cpp:472
#, kde-format
msgid "<i>[This message was deleted]</i>"
msgstr "<i>[Denne meldinga er sletta]</i>"
#: src/models/messageeventmodel.cpp:465
#: src/models/messageeventmodel.cpp:464
#, kde-format
msgid "<i>[This message was deleted: %1]</i>"
msgstr "<i>[Denne meldinga er sletta: %1]</i>"
# Eller «SENSURERT»?
#: src/models/messageeventmodel.cpp:541
#: src/models/messageeventmodel.cpp:540
#, kde-format
msgid "[REDACTED]"
msgstr "[TREKT TILBAKE]"
#: src/models/messageeventmodel.cpp:541
#: src/models/messageeventmodel.cpp:540
#, kde-format
msgid "[REDACTED: %1]"
msgstr "[TREKT TILBAKE: %1]"
#: src/models/messageeventmodel.cpp:837
#: src/models/messageeventmodel.cpp:836
#, kde-format
msgid "1 user: "
msgid_plural "%1 users: "
msgstr[0] "1 brukar: "
msgstr[1] "%1 brukarar: "
#: src/models/messageeventmodel.cpp:840
#: src/models/messageeventmodel.cpp:839
#, kde-format
msgctxt "list separator"
msgid ", "
@@ -1084,55 +1084,55 @@ msgstr "starta ei avstemming"
msgid "Report sent successfully."
msgstr "Rapporten er no send."
#: src/neochatroom.cpp:1924 src/neochatroom.cpp:1932
#: src/neochatroom.cpp:1927 src/neochatroom.cpp:1935
#, kde-format
msgctxt "'Lat' and 'Lon' as in Latitude and Longitude"
msgid "Lat: %1, Lon: %2"
msgstr "Breiddegr.: %1  lengdegr.: %2"
#: src/notificationsmanager.cpp:128
#: src/notificationsmanager.cpp:130
#, kde-format
msgid "Encrypted Message"
msgstr "Kryptert melding"
#: src/notificationsmanager.cpp:201 src/qml/main.qml:253
#: src/notificationsmanager.cpp:203 src/qml/main.qml:258
#, kde-format
msgid "%1: %2"
msgstr "%1: %2"
#: src/notificationsmanager.cpp:207
#: src/notificationsmanager.cpp:209
#, kde-format
msgid "Open NeoChat in this room"
msgstr "Opna NeoChat i dette rommet"
#: src/notificationsmanager.cpp:220 src/qml/Component/HoverActions.qml:109
#: src/notificationsmanager.cpp:222 src/qml/Component/HoverActions.qml:103
#: src/qml/Menu/Timeline/FileDelegateContextMenu.qml:50
#: src/qml/Menu/Timeline/MessageDelegateContextMenu.qml:36
#, kde-format
msgid "Reply"
msgstr "Svar"
#: src/notificationsmanager.cpp:221
#: src/notificationsmanager.cpp:223
#, kde-format
msgid "Reply..."
msgstr "Svar …"
#: src/notificationsmanager.cpp:239
#: src/notificationsmanager.cpp:241
#, kde-format
msgid "%1 invited you to a room"
msgstr "%1 inviterte deg til eit rom"
#: src/notificationsmanager.cpp:243
#: src/notificationsmanager.cpp:245
#, kde-format
msgid "Open this invitation in NeoChat"
msgstr "Opna invitasjonen i NeoChat"
#: src/notificationsmanager.cpp:249
#: src/notificationsmanager.cpp:251
#, kde-format
msgid "Accept Invitation"
msgstr "Godta invitasjonen"
#: src/notificationsmanager.cpp:249
#: src/notificationsmanager.cpp:251
#, kde-format
msgid "Reject Invitation"
msgstr "Avvis invitasjonen"
@@ -1143,7 +1143,7 @@ msgid "Attachment:"
msgstr "Vedlegg:"
#: src/qml/Component/ChatBox/AttachmentPane.qml:38
#: src/qml/Component/HoverActions.qml:103
#: src/qml/Component/HoverActions.qml:97
#: src/qml/Menu/Timeline/MessageDelegateContextMenu.qml:27
#: src/qml/Page/ImageEditorPage.qml:21
#, kde-format
@@ -1155,58 +1155,57 @@ msgstr "Rediger"
msgid "Cancel sending attachment"
msgstr "Avbryt sending av vedlegg"
#: src/qml/Component/ChatBox/ChatBar.qml:64
#: src/qml/Component/ChatBox/ChatBar.qml:63
#, kde-format
msgid "Attach an image or file"
msgstr "Legg ved bilete eller fil"
#: src/qml/Component/ChatBox/ChatBar.qml:91
#: src/qml/Component/ChatBox/ChatBar.qml:89
#, kde-format
msgid "Emojis & Stickers"
msgstr "Emojiar og klistremerke"
#: src/qml/Component/ChatBox/ChatBar.qml:108
#: src/qml/Component/ChatBox/ChatBar.qml:105
#, kde-format
msgid "Send a Location"
msgstr "Send geografisk posisjon"
# Namn på «send»-knappen i skrivefeltet.
#: src/qml/Component/ChatBox/ChatBar.qml:122
#: src/qml/Component/ChatBox/ChatBar.qml:118
#, kde-format
msgid "Send message"
msgstr "Send meldinga"
#: src/qml/Component/ChatBox/ChatBar.qml:169
#: src/qml/Component/ChatBox/ChatBar.qml:165
#, kde-format
msgid ""
"This room is encrypted. Build libQuotient with encryption enabled to send "
"encrypted messages."
msgstr ""
"Dette rommet er kryptert. Bygg libQuotient med kryptering slått på for å "
"senda krypterte meldingar."
#: src/qml/Component/ChatBox/ChatBar.qml:165
#, kde-format
msgid "Send an encrypted message…"
msgstr "Send ei kryptert melding …"
#: src/qml/Component/ChatBox/ChatBar.qml:169
#: src/qml/Component/ChatBox/ChatBar.qml:165
#, kde-format
msgid "Set an attachment caption..."
msgstr "Vel vedleggstekst …"
#: src/qml/Component/ChatBox/ChatBar.qml:169
#: src/qml/Component/ChatBox/ChatBar.qml:165
#, kde-format
msgid "Send a message…"
msgstr "Send ei melding …"
#: src/qml/Component/ChatBox/ChatBar.qml:349
#: src/qml/Component/ChatBox/ChatBar.qml:346
#, kde-format
msgctxt "@action:button"
msgid "Cancel reply"
msgstr "Avbryt svar"
#: src/qml/Component/ChatBox/ChatBar.qml:555
#, kde-format
msgid "Choose local file"
msgstr "Vel lokal fil"
#: src/qml/Component/ChatBox/ChatBar.qml:583
#, kde-format
msgid "Clipboard image"
msgstr "Utklippstavle-bilete"
#: src/qml/Component/ChatBox/LocationChooser.qml:22
#, kde-format
msgid "Choose a Location"
@@ -1314,13 +1313,13 @@ msgstr "Ingen klistremerke"
msgid "No emojis"
msgstr "Ingen emojiar"
#: src/qml/Component/Emoji/EmojiPicker.qml:52
#: src/qml/Component/Emoji/EmojiPicker.qml:47
#: src/qml/Settings/EmoticonsPage.qml:16 src/qml/Settings/EmoticonsPage.qml:25
#, kde-format
msgid "Emojis"
msgstr "Emojiar"
#: src/qml/Component/Emoji/EmojiPicker.qml:59
#: src/qml/Component/Emoji/EmojiPicker.qml:54
#: src/qml/Settings/EmoticonsPage.qml:16 src/qml/Settings/EmoticonsPage.qml:32
#, kde-format
msgid "Stickers"
@@ -1336,12 +1335,12 @@ msgstr "Vis posisjon"
msgid "Close"
msgstr "Lukk"
#: src/qml/Component/HoverActions.qml:85
#: src/qml/Component/HoverActions.qml:79
#, kde-format
msgid "This message was sent from a verified device"
msgstr "Meldinga vart send frå ei stadfesta eining"
#: src/qml/Component/HoverActions.qml:98
#: src/qml/Component/HoverActions.qml:92
#, kde-format
msgid "React"
msgstr "Reager"
@@ -1608,22 +1607,32 @@ msgstr "Lydstyrke"
msgid "Maximize"
msgstr "Maksimer"
#: src/qml/Component/TimelineView.qml:153
#: src/qml/Component/TimelineView.qml:128
#, kde-format
msgid "Choose local file"
msgstr "Vel lokal fil"
#: src/qml/Component/TimelineView.qml:156
#, kde-format
msgid "Clipboard image"
msgstr "Utklippstavle-bilete"
#: src/qml/Component/TimelineView.qml:205
#, kde-format
msgid "Jump to first unread message"
msgstr "Gå til første ulesne melding"
#: src/qml/Component/TimelineView.qml:176
#: src/qml/Component/TimelineView.qml:228
#, kde-format
msgid "Jump to latest message"
msgstr "Gå til nyaste melding"
#: src/qml/Component/TimelineView.qml:202
#: src/qml/Component/TimelineView.qml:254
#, kde-format
msgid "Drag items here to share them"
msgstr "Dra element her for å dela dei"
#: src/qml/Component/TimelineView.qml:228
#: src/qml/Component/TimelineView.qml:280
#, kde-format
msgctxt "Message displayed when some users are typing"
msgid "%2 is typing"
@@ -1644,18 +1653,20 @@ msgid ""
msgstr "Det er ikkje mogleg å slå av krypteringa etter at ho er slått på."
#: src/qml/Dialog/ConfirmEncryptionDialog.qml:32
#: src/qml/Dialog/ConfirmLogout.qml:31 src/qml/Page/ImageEditorPage.qml:126
#: src/qml/Dialog/ConfirmLogout.qml:29 src/qml/Page/ImageEditorPage.qml:126
#: src/qml/Settings/AccountEditorPage.qml:211
#, kde-format
msgid "Cancel"
msgstr "Avbryt"
#: src/qml/Dialog/ConfirmLogout.qml:18 src/qml/Dialog/ConfirmLogout.qml:37
#: src/qml/Dialog/ConfirmLogout.qml:16 src/qml/Dialog/ConfirmLogout.qml:35
#: src/qml/Settings/AccountEditorPage.qml:255
#: src/qml/Settings/AccountEditorPage.qml:263
#, kde-format
msgid "Sign out"
msgstr "Logg ut"
#: src/qml/Dialog/ConfirmLogout.qml:21
#: src/qml/Dialog/ConfirmLogout.qml:19
#, kde-format
msgid "Are you sure you want to sign out?"
msgstr "Er du sikker på at du vil logga ut?"
@@ -1676,7 +1687,7 @@ msgstr "Namn på rommet:"
msgid "Room topic:"
msgstr "Emne for rommet:"
#: src/qml/Dialog/CreateRoomDialog.qml:34 src/qml/Page/JoinRoomPage.qml:168
#: src/qml/Dialog/CreateRoomDialog.qml:34 src/qml/Page/JoinRoomPage.qml:160
#, kde-format
msgctxt "@action:button"
msgid "Ok"
@@ -2018,18 +2029,18 @@ msgstr "Start privat prat"
msgid "Copy link"
msgstr "Kopier lenkje"
#: src/qml/main.qml:293
#: src/qml/main.qml:300
#, kde-format
msgctxt "@title:window"
msgid "Session Verification"
msgstr "Øktstadfesting"
#: src/qml/main.qml:305
#: src/qml/main.qml:312
#, kde-format
msgid "User consent"
msgstr "Brukar­samtykke"
#: src/qml/main.qml:310
#: src/qml/main.qml:317
#, kde-format
msgid ""
"Your homeserver requires you to agree to its terms and conditions before "
@@ -2038,17 +2049,17 @@ msgstr ""
"Heimetenaren krev at du godtek brukarvilkåra før du kan ta han i bruk. Trykk "
"på knappen nedanfor for å lesa vilkåra."
#: src/qml/main.qml:315
#: src/qml/main.qml:322
#, kde-format
msgid "Open"
msgstr "Opna"
#: src/qml/main.qml:350
#: src/qml/main.qml:357
#, kde-format
msgid "Start a chat"
msgstr "Start prat"
#: src/qml/main.qml:352
#: src/qml/main.qml:359
#, kde-format
msgid "Do you want to start a chat with %1?"
msgstr "Vil du starta ein prat med %1?"
@@ -2449,78 +2460,72 @@ msgstr "Brukaren er alt medlem eller invitert"
msgid "Explore Rooms"
msgstr "Utforsk rom"
#: src/qml/Page/JoinRoomPage.qml:45
#: src/qml/Page/JoinRoomPage.qml:37
#, kde-format
msgid "Find a room..."
msgstr "Finn eit rom …"
#: src/qml/Page/JoinRoomPage.qml:53
#: src/qml/Page/JoinRoomPage.qml:45
#, kde-format
msgid "View"
msgstr "Vis"
#: src/qml/Page/JoinRoomPage.qml:53
#: src/qml/Page/JoinRoomPage.qml:45
#, kde-format
msgid "Join"
msgstr "Vert med"
#: src/qml/Page/JoinRoomPage.qml:82
#: src/qml/Page/JoinRoomPage.qml:74
#, kde-format
msgid "Add New Server"
msgstr "Legg til ny tenar"
#: src/qml/Page/JoinRoomPage.qml:83
#: src/qml/Page/JoinRoomPage.qml:75
#, kde-format
msgid "Home Server"
msgstr "Heimetenar"
#: src/qml/Page/JoinRoomPage.qml:92
#: src/qml/Page/JoinRoomPage.qml:84
#, kde-format
msgid "Add new server"
msgstr "Legg til ny tenar"
#: src/qml/Page/JoinRoomPage.qml:123
#: src/qml/Page/JoinRoomPage.qml:115
#, kde-format
msgctxt "@title:window"
msgid "Add server"
msgstr "Legg tenar"
#: src/qml/Page/JoinRoomPage.qml:136
#: src/qml/Page/JoinRoomPage.qml:128
#, kde-format
msgid "Valid server entered"
msgstr "Gyldig tenar"
#: src/qml/Page/JoinRoomPage.qml:136
#: src/qml/Page/JoinRoomPage.qml:128
#, kde-format
msgid "This server cannot be resolved or has already been added"
msgstr "Fann ikkje adressa til tenaren, eller så er han alt lagd til"
#: src/qml/Page/JoinRoomPage.qml:136
#: src/qml/Page/JoinRoomPage.qml:128
#, kde-format
msgid "The entered text is not a valid url"
msgstr "Oppgjeven tekst er ikkje ei gyldig adresse"
#: src/qml/Page/JoinRoomPage.qml:136
#: src/qml/Page/JoinRoomPage.qml:128
#, kde-format
msgid "Enter server url e.g. kde.org"
msgstr "Skriv inn adressa til tenaren, eks. kde.org"
#: src/qml/Page/JoinRoomPage.qml:144
#: src/qml/Page/JoinRoomPage.qml:136
#, kde-format
msgid "Server URL"
msgstr "Tenaradresse"
#: src/qml/Page/JoinRoomPage.qml:245
#: src/qml/Page/JoinRoomPage.qml:228
#, kde-format
msgid "Joined"
msgstr "Vart med"
#: src/qml/Page/JoinRoomPage.qml:299
#, kde-format
msgctxt "@info:label"
msgid "No rooms found"
msgstr ""
#: src/qml/Page/RoomList/AccountMenu.qml:18
#: src/qml/Page/RoomList/UserInfo.qml:175
#, kde-format
@@ -2528,7 +2533,7 @@ msgid "Edit this account"
msgstr "Rediger kontoen"
#: src/qml/Page/RoomList/AccountMenu.qml:23
#: src/qml/Page/RoomList/UserInfo.qml:169 src/qml/Settings/AccountsPage.qml:42
#: src/qml/Page/RoomList/UserInfo.qml:169 src/qml/Settings/AccountsPage.qml:38
#, kde-format
msgid "Account editor"
msgstr "Konto­redigering"
@@ -2539,13 +2544,12 @@ msgid "Notification settings"
msgstr "Varslings­innstillingar"
#: src/qml/Page/RoomList/AccountMenu.qml:37 src/qml/Settings/DevicesPage.qml:15
#: src/qml/Settings/SettingsPage.qml:62
#: src/qml/Settings/SettingsPage.qml:61
#, kde-format
msgid "Devices"
msgstr "Einingar"
#: src/qml/Page/RoomList/AccountMenu.qml:47
#: src/qml/Settings/AccountsPage.qml:79
#, kde-format
msgid "Logout"
msgstr "Logg ut"
@@ -2593,7 +2597,7 @@ msgid "Copy user's Matrix ID to Clipboard"
msgstr "Kopier Matrix-ID-en til brukaren til utklippstavla"
#: src/qml/Page/RoomList/ContextMenu.qml:56
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:32
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:31
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Address to Clipboard"
@@ -2684,12 +2688,12 @@ msgctxt "Expand <section name"
msgid "Expand %1"
msgstr "Utvid %1"
#: src/qml/Page/RoomList/RoomDelegate.qml:97
#: src/qml/Page/RoomList/RoomDelegate.qml:96
#, kde-format
msgid "Muted room"
msgstr "Dempa rom"
#: src/qml/Page/RoomList/RoomDelegate.qml:129
#: src/qml/Page/RoomList/RoomDelegate.qml:128
#, kde-format
msgid "Configure room"
msgstr "Set opp rommet"
@@ -2705,26 +2709,26 @@ msgctxt "'Space' is a matrix space"
msgid "View Space"
msgstr "Vis område"
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:42
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:40
#, kde-format
msgctxt "'Space' is a matrix space"
msgid "Space Settings"
msgstr "Område­innstillingar"
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:44
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:102
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:41
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:98
#, kde-format
msgid "Space Settings"
msgstr "Område­innstillingar"
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:50
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:106
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:47
#: src/qml/Page/RoomList/SpaceListContextMenu.qml:102
#, kde-format
msgctxt "'Space' is a matrix space"
msgid "Leave Space"
msgstr "Forlat område"
#: src/qml/Page/RoomList/UserInfo.qml:42 src/qml/Settings/AccountsPage.qml:107
#: src/qml/Page/RoomList/UserInfo.qml:42 src/qml/Settings/AccountsPage.qml:85
#, kde-format
msgid "Add Account"
msgstr "Legg til konto"
@@ -2750,7 +2754,7 @@ msgstr "Byt brukar"
msgid "Open Settings"
msgstr "Opna innstillingar"
#: src/qml/Page/RoomPage.qml:42
#: src/qml/Page/RoomPage.qml:50
#, kde-format
msgid "NeoChat is offline. Please check your network connection."
msgstr "NeoChat er fråkopla. Sjå til at du er kopla til nettet."
@@ -2796,12 +2800,12 @@ msgstr "Velkommen til Matrix"
msgid "No name"
msgstr "Namnlaus"
#: src/qml/Panel/GroupChatDrawerHeader.qml:71
#: src/qml/Panel/GroupChatDrawerHeader.qml:70
#, kde-format
msgid "No Canonical Alias"
msgstr "Manglar kanonisk alias"
#: src/qml/Panel/GroupChatDrawerHeader.qml:81
#: src/qml/Panel/GroupChatDrawerHeader.qml:80
#, kde-format
msgid "No Topic"
msgstr "Manglar emne"
@@ -2886,23 +2890,23 @@ msgstr[1] "%1 medlemmar"
msgid "No member count"
msgstr "Manglar medlemstal"
#: src/qml/RoomSettings/Categories.qml:19 src/qml/RoomSettings/General.qml:21
#: src/qml/Settings/SettingsPage.qml:18
#: src/qml/RoomSettings/Categories.qml:18 src/qml/RoomSettings/General.qml:21
#: src/qml/Settings/SettingsPage.qml:17
#, kde-format
msgid "General"
msgstr "Generelt"
#: src/qml/RoomSettings/Categories.qml:30 src/qml/RoomSettings/Security.qml:19
#: src/qml/RoomSettings/Categories.qml:29 src/qml/RoomSettings/Security.qml:19
#, kde-format
msgid "Security"
msgstr "Tryggleik"
#: src/qml/RoomSettings/Categories.qml:41
#: src/qml/RoomSettings/Categories.qml:40
#, kde-format
msgid "Permissions"
msgstr "Løyve"
#: src/qml/RoomSettings/Categories.qml:52 src/qml/Settings/SettingsPage.qml:30
#: src/qml/RoomSettings/Categories.qml:51 src/qml/Settings/SettingsPage.qml:29
#, kde-format
msgid "Notifications"
msgstr "Varslingar"
@@ -3213,93 +3217,93 @@ msgctxt "@option:check"
msgid "Encryption"
msgstr "Kryptering"
#: src/qml/RoomSettings/Security.qml:35
#: src/qml/RoomSettings/Security.qml:36
#, kde-format
msgid "Enable encryption"
msgstr "Bruk kryptering"
#: src/qml/RoomSettings/Security.qml:36
#: src/qml/RoomSettings/Security.qml:37
#, kde-format
msgctxt "option:check"
msgid "Once enabled, encryption cannot be disabled."
msgstr "Når kryptering er slått på, kan du ikkje slå han av att."
#: src/qml/RoomSettings/Security.qml:49
#: src/qml/RoomSettings/Security.qml:50
#, kde-format
msgctxt "@option:check"
msgid "Access"
msgstr "Tilgang"
#: src/qml/RoomSettings/Security.qml:56
#: src/qml/RoomSettings/Security.qml:57
#, kde-format
msgctxt "@option:check"
msgid "Private (invite only)"
msgstr "Privat (berre ved invitasjon)"
#: src/qml/RoomSettings/Security.qml:57
#: src/qml/RoomSettings/Security.qml:58
#, kde-format
msgid "Only invited people can join."
msgstr "Berre inviterte gjestar kan verta med."
#: src/qml/RoomSettings/Security.qml:65
#: src/qml/RoomSettings/Security.qml:66
#, kde-format
msgctxt "@option:check"
msgid "Space members"
msgstr "Områdemedlemmar"
#: src/qml/RoomSettings/Security.qml:66
#: src/qml/RoomSettings/Security.qml:67
#, kde-format
msgid "Anyone in a space can find and join."
msgstr "Alle i området kan søkja opp rommet og verta med."
#: src/qml/RoomSettings/Security.qml:75
#: src/qml/RoomSettings/Security.qml:76
#, kde-format
msgctxt "@option:check"
msgid "Knock"
msgstr "Bank på"
#: src/qml/RoomSettings/Security.qml:76
#: src/qml/RoomSettings/Security.qml:77
#, kde-format
msgid "People not in the room need to request an invite to join the room."
msgstr "Personar utanfor rommet må be om å få verta med."
#: src/qml/RoomSettings/Security.qml:86
#: src/qml/RoomSettings/Security.qml:87
#, kde-format
msgctxt "@option:check"
msgid "Public"
msgstr "Offentleg"
#: src/qml/RoomSettings/Security.qml:87
#: src/qml/RoomSettings/Security.qml:88
#, kde-format
msgctxt "@option:check"
msgid "Anyone can find and join."
msgstr "Alle kan søkja opp rommet og verta med."
#: src/qml/RoomSettings/Security.qml:99
#: src/qml/RoomSettings/Security.qml:100
#, kde-format
msgctxt "@option:check"
msgid "Message history visibility"
msgstr "Vising av meldingsloggen"
#: src/qml/RoomSettings/Security.qml:106
#: src/qml/RoomSettings/Security.qml:107
#, kde-format
msgctxt "@option:check"
msgid "Anyone"
msgstr "Alle"
#: src/qml/RoomSettings/Security.qml:107
#: src/qml/RoomSettings/Security.qml:108
#, kde-format
msgctxt "@option:check"
msgid "Anyone, regardless of whether they have joined, can view history."
msgstr "Alle, òg dei som aldri har vore med i rommet, kan sjå meldingsloggen."
#: src/qml/RoomSettings/Security.qml:115
#: src/qml/RoomSettings/Security.qml:116
#, kde-format
msgctxt "@option:check"
msgid "Members only"
msgstr "Berre medlemmar"
#: src/qml/RoomSettings/Security.qml:116
#: src/qml/RoomSettings/Security.qml:117
#, kde-format
msgctxt "@option:check"
msgid ""
@@ -3308,13 +3312,13 @@ msgstr ""
"Alle medlemmar kan sjå heile meldingsloggen, òg meldingar frå før dei vart "
"med i rommet."
#: src/qml/RoomSettings/Security.qml:124
#: src/qml/RoomSettings/Security.qml:125
#, kde-format
msgctxt "@option:check"
msgid "Members only (since invite)"
msgstr "Berre medlemmar (frå invitasjonstidspunkt)"
#: src/qml/RoomSettings/Security.qml:125
#: src/qml/RoomSettings/Security.qml:126
#, kde-format
msgctxt "@option:check"
msgid ""
@@ -3324,13 +3328,13 @@ msgstr ""
"Nye medlemmar kan sjå dei meldingane i loggen som er skrivne etter at dei "
"vart inviterte."
#: src/qml/RoomSettings/Security.qml:133
#: src/qml/RoomSettings/Security.qml:134
#, kde-format
msgctxt "@option:check"
msgid "Members only (since joining)"
msgstr "Berre medlemmar (frå medlemstidspunkt)"
#: src/qml/RoomSettings/Security.qml:134
#: src/qml/RoomSettings/Security.qml:135
#, kde-format
msgctxt "@option:check"
msgid ""
@@ -3339,7 +3343,7 @@ msgstr ""
"Nye medlemmar kan sjå dei meldingane i loggen som er skrivne etter at dei "
"vart med i rommet."
#: src/qml/RoomSettings/Security.qml:153
#: src/qml/RoomSettings/Security.qml:154
#: src/qml/Settings/NetworkProxyPage.qml:119
#, kde-format
msgid "Apply"
@@ -3427,23 +3431,23 @@ msgstr "Tenarinformasjon"
msgid "Homeserver url"
msgstr "Adresse til heimetenar"
#: src/qml/Settings/AccountsPage.qml:20 src/qml/Settings/AccountsPage.qml:29
#: src/qml/Settings/SettingsPage.qml:36
#: src/qml/Settings/AccountsPage.qml:16 src/qml/Settings/AccountsPage.qml:25
#: src/qml/Settings/SettingsPage.qml:35
#, kde-format
msgid "Accounts"
msgstr "Kontoar"
#: src/qml/Settings/AccountsPage.qml:124
#: src/qml/Settings/AccountsPage.qml:102
#, kde-format
msgid "Password changed successfully"
msgstr "Passordet er no endra"
#: src/qml/Settings/AccountsPage.qml:126
#: src/qml/Settings/AccountsPage.qml:104
#, kde-format
msgid "Wrong password entered"
msgstr "Du skreiv inn feil passord"
#: src/qml/Settings/AccountsPage.qml:128
#: src/qml/Settings/AccountsPage.qml:106
#, kde-format
msgid "Unknown problem while trying to change password"
msgstr "Ukjent problem ved endring av passord"
@@ -3524,12 +3528,6 @@ msgstr "I sidestolpen"
msgid "Color theme"
msgstr "Fargetema"
#: src/qml/Settings/DeviceDelegate.qml:52
#, kde-format
msgctxt "@label"
msgid "%1, Last activity: %2"
msgstr "%1  siste aktivitet: %2"
#: src/qml/Settings/DeviceDelegate.qml:61
#, kde-format
msgid "New device name"
@@ -3799,7 +3797,7 @@ msgid "Invites"
msgstr "Invitasjonar"
#: src/qml/Settings/NetworkProxyPage.qml:25
#: src/qml/Settings/SettingsPage.qml:56
#: src/qml/Settings/SettingsPage.qml:55
#, kde-format
msgid "Network Proxy"
msgstr "Mellomtenar"
@@ -3880,27 +3878,27 @@ msgstr "Slå på framheving av meldingar"
msgid "Delete keyword"
msgstr "Slett nøkkelord"
#: src/qml/Settings/SettingsPage.qml:24
#: src/qml/Settings/SettingsPage.qml:23
#, kde-format
msgid "Appearance"
msgstr "Utsjånad"
#: src/qml/Settings/SettingsPage.qml:42
#: src/qml/Settings/SettingsPage.qml:41
#, kde-format
msgid "Stickers & Emojis"
msgstr "Klistremerke og emojiar"
#: src/qml/Settings/SettingsPage.qml:49
#: src/qml/Settings/SettingsPage.qml:48
#, kde-format
msgid "Spell Checking"
msgstr "Stavekontroll"
#: src/qml/Settings/SettingsPage.qml:73
#: src/qml/Settings/SettingsPage.qml:72
#, kde-format
msgid "About NeoChat"
msgstr "Om NeoChat"
#: src/qml/Settings/SettingsPage.qml:79
#: src/qml/Settings/SettingsPage.qml:78
#, kde-format
msgid "About KDE"
msgstr "Om KDE"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,122 +0,0 @@
<?xml version="1.0" ?>
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
<!ENTITY % Swedish "INCLUDE">
]>
<!--
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
SPDX-License-Identifier: CC-BY-SA-4.0
-->
<refentry lang="&language;">
<refentryinfo>
<title
>NeoChat användarmanual</title>
<author
><firstname
>Carl</firstname
><surname
>Schwan</surname
> <contrib
>NeoChat manualsida.</contrib
> <email
>carl@carlschwan.eu</email
></author>
<date
>2022-11-01</date>
<releaseinfo
>22.09</releaseinfo>
<productname
>NeoChat</productname>
</refentryinfo>
<refmeta>
<refentrytitle>
<command
>neochat</command>
</refentrytitle>
<manvolnum
>1</manvolnum>
</refmeta>
<refnamediv>
<refname
>neochat</refname>
<refpurpose
>Klient för att interagera med meddelandeprotokollet matrix</refpurpose>
</refnamediv>
<!-- body begins here -->
<refsynopsisdiv id='synopsis'>
<cmdsynopsis
><command
>neochat</command
> <arg choice="opt"
><replaceable
>URI</replaceable
></arg
> </cmdsynopsis>
</refsynopsisdiv>
<refsect1 id="description">
<title
>Beskrivning</title>
<para
><command
>neochat</command
> är ett chattprogram för protokollet matrix som fungerar både på skrivbord och mobil. </para>
</refsect1>
<refsect1 id="options"
><title
>Väljare</title>
<variablelist>
<varlistentry>
<term
><option
>URI</option
></term>
<listitem>
<para
>Matrix webbadress för en användare eller ett rum, t.ex. matrix:u/användare:exempel.org. Det gör att NeoChat försöker öppna det angivna rummet eller konversationen. </para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="bug">
<title
>Rapportera fel</title>
<para
>Rapportera fel och funktionsönskemål på <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&amp;component=General"
>https://bugs.kde.org/enter_bug.cgi?product=NeoChat&amp;component=General</ulink
></para>
</refsect1>
<refsect1>
<title
>Se också</title>
<simplelist>
<member
>En lista över vanliga frågor om Matrix <ulink url="https://matrix.org/faq/"
>https://matrix.org/faq/</ulink
> </member>
<member
>kf5options(7)</member>
<member
>qt5options(7)</member>
</simplelist>
</refsect1>
<refsect1 id="copyright"
><title
>Copyright</title>
<para
>Copyright &copy; 2020-2022 Tobias Fella </para>
<para
>Copyright &copy; 2020-2022 Carl Schwan </para>
<para
>Licens: GNU General Public Version 3 eller senare &lt;<ulink url="https://wwwgnuorg/licenses/gpl-html"
>http://www.gnu.org/licenses/gpl-3.0.html</ulink
>&gt;</para>
</refsect1>
</refentry>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -155,9 +155,6 @@ if(NOT ANDROID)
target_sources(neochat PRIVATE colorschemer.cpp colorschemer.h)
if (NOT WIN32 AND NOT APPLE)
target_sources(neochat PRIVATE trayicon_sni.cpp trayicon_sni.h)
if(QT_MAJOR_VERSION STREQUAL "6")
target_link_libraries(neochat PRIVATE KF6::StatusNotifierItem)
endif()
else()
target_sources(neochat PRIVATE trayicon.cpp trayicon.h)
endif()

View File

@@ -44,7 +44,7 @@ void ActionsHandler::handleNewMessage()
if (!m_room->chatBoxAttachmentPath().isEmpty()) {
QUrl url(m_room->chatBoxAttachmentPath());
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
m_room->uploadFile(QUrl(path), m_room->chatBoxText().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : m_room->chatBoxText());
m_room->uploadFile(path, m_room->chatBoxText().isEmpty() ? path.mid(path.lastIndexOf('/') + 1) : m_room->chatBoxText());
m_room->setChatBoxAttachmentPath({});
m_room->setChatBoxText({});
return;
@@ -97,7 +97,7 @@ QString ActionsHandler::handleMentions(QString handledText, const bool &isEdit)
void ActionsHandler::handleMessage(const QString &text, QString handledText, const bool &isEdit)
{
if (NeoChatConfig::allowQuickEdit()) {
QRegularExpression sed(QStringLiteral("^s/([^/]*)/([^/]*)(/g)?$"));
QRegularExpression sed("^s/([^/]*)/([^/]*)(/g)?$");
auto match = sed.match(text);
if (match.hasMatch()) {
const QString regex = match.captured(1);
@@ -113,13 +113,13 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, con
} else {
originalString = event->plainBody();
}
if (flags == "/g"_ls) {
m_room->postHtmlMessage(handledText, originalString.replace(regex, replacement), event->msgtype(), {}, event->id());
if (flags == "/g") {
m_room->postHtmlMessage(handledText, originalString.replace(regex, replacement), event->msgtype(), "", event->id());
} else {
m_room->postHtmlMessage(handledText,
originalString.replace(originalString.indexOf(regex), regex.size(), replacement),
event->msgtype(),
{},
"",
event->id());
}
return;
@@ -133,7 +133,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, con
if (handledText.startsWith(QLatin1Char('/'))) {
for (const auto &action : ActionsModel::instance().allActions()) {
if (handledText.indexOf(action.prefix) == 1
&& (handledText.indexOf(" "_ls) == action.prefix.length() + 1 || handledText.length() == action.prefix.length() + 1)) {
&& (handledText.indexOf(" ") == action.prefix.length() + 1 || handledText.length() == action.prefix.length() + 1)) {
handledText = action.handle(handledText.mid(action.prefix.length() + 1).trimmed(), m_room);
if (action.messageType.has_value()) {
messageType = *action.messageType;
@@ -152,30 +152,30 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, con
textHandler.setData(handledText);
handledText = textHandler.handleSendText();
if (handledText.count("<p>"_ls) == 1 && handledText.count("</p>"_ls) == 1) {
handledText.remove("<p>"_ls);
handledText.remove("</p>"_ls);
if (handledText.count("<p>") == 1 && handledText.count("</p>") == 1) {
handledText.remove("<p>");
handledText.remove("</p>");
}
if (handledText.length() == 0) {
return;
}
m_room->postMessage(text, handledText, messageType, m_room->chatBoxReplyId(), isEdit ? m_room->chatBoxEditId() : QString());
m_room->postMessage(text, handledText, messageType, m_room->chatBoxReplyId(), isEdit ? m_room->chatBoxEditId() : "");
}
void ActionsHandler::checkEffects(const QString &text)
{
std::optional<QString> effect = std::nullopt;
if (text.contains(QStringLiteral("\u2744"))) {
if (text.contains("\u2744")) {
effect = QLatin1String("snowflake");
} else if (text.contains(QStringLiteral("\u1F386"))) {
} else if (text.contains("\u1F386")) {
effect = QLatin1String("fireworks");
} else if (text.contains(QStringLiteral("\u2F387"))) {
} else if (text.contains("\u2F387")) {
effect = QLatin1String("fireworks");
} else if (text.contains(QStringLiteral("\u1F389"))) {
} else if (text.contains("\u1F389")) {
effect = QLatin1String("confetti");
} else if (text.contains(QStringLiteral("\u1F38A"))) {
} else if (text.contains("\u1F38A")) {
effect = QLatin1String("confetti");
}
if (effect.has_value()) {

View File

@@ -225,7 +225,7 @@ void ChatDocumentHandler::complete(int index)
QTextCursor cursor(document()->textDocument());
cursor.setPosition(at);
cursor.setPosition(cursorPosition(), QTextCursor::KeepAnchor);
cursor.insertText(name + QStringLiteral(" "));
cursor.insertText(name % " ");
cursor.setPosition(at);
cursor.setPosition(cursor.position() + name.size(), QTextCursor::KeepAnchor);
cursor.setKeepPositionOnInsert(true);
@@ -246,7 +246,7 @@ void ChatDocumentHandler::complete(int index)
QTextCursor cursor(document()->textDocument());
cursor.setPosition(at);
cursor.setPosition(cursorPosition(), QTextCursor::KeepAnchor);
cursor.insertText(alias + QStringLiteral(" "));
cursor.insertText(alias % " ");
cursor.setPosition(at);
cursor.setPosition(cursor.position() + alias.size(), QTextCursor::KeepAnchor);
cursor.setKeepPositionOnInsert(true);

View File

@@ -104,12 +104,12 @@ class ChatDocumentHandler : public QObject
/**
* @brief The color to highlight user mentions.
*/
Q_PROPERTY(QColor mentionColor READ mentionColor WRITE setMentionColor NOTIFY mentionColorChanged)
Q_PROPERTY(QColor mentionColor READ mentionColor WRITE setMentionColor NOTIFY mentionColorChanged);
/**
* @brief The color to highlight spelling errors.
*/
Q_PROPERTY(QColor errorColor READ errorColor WRITE setErrorColor NOTIFY errorColorChanged)
Q_PROPERTY(QColor errorColor READ errorColor WRITE setErrorColor NOTIFY errorColorChanged);
public:
explicit ChatDocumentHandler(QObject *parent = nullptr);

View File

@@ -124,21 +124,9 @@ Controller &Controller::instance()
return _instance;
}
void Controller::toggleWindow()
void Controller::showWindow()
{
auto &instance = WindowController::instance();
auto window = instance.window();
if (window->isVisible()) {
if (window->windowStates() & Qt::WindowMinimized) {
window->showNormal();
window->requestActivate();
} else {
window->close();
}
} else {
instance.showAndRaiseWindow({});
instance.window()->requestActivate();
}
WindowController::instance().showAndRaiseWindow(QString());
}
void Controller::logout(Connection *conn, bool serverSideLogout)
@@ -148,7 +136,7 @@ void Controller::logout(Connection *conn, bool serverSideLogout)
return;
}
SettingsGroup("Accounts"_ls).remove(conn->userId());
SettingsGroup("Accounts").remove(conn->userId());
QKeychain::DeletePasswordJob job(qAppName());
job.setAutoDelete(true);
@@ -212,7 +200,7 @@ void Controller::dropConnection(Connection *c)
void Controller::invokeLogin()
{
const auto accounts = SettingsGroup("Accounts"_ls).childGroups();
const auto accounts = SettingsGroup("Accounts").childGroups();
QString id = NeoChatConfig::self()->activeConnection();
for (const auto &accountId : accounts) {
AccountSettings account{accountId};
@@ -226,7 +214,7 @@ void Controller::invokeLogin()
AccountSettings account{accountId};
QString accessToken;
if (accessTokenLoadingJob->error() == QKeychain::Error::NoError) {
accessToken = QString::fromLatin1(accessTokenLoadingJob->binaryData());
accessToken = accessTokenLoadingJob->binaryData();
} else {
return;
}
@@ -241,10 +229,10 @@ void Controller::invokeLogin()
}
});
connect(connection, &Connection::loginError, this, [this, connection](const QString &error, const QString &) {
if (error == "Unrecognised access token"_ls) {
if (error == "Unrecognised access token") {
Q_EMIT errorOccured(i18n("Login Failed: Access Token invalid or revoked"));
logout(connection, false);
} else if (error == "Connection closed"_ls) {
} else if (error == "Connection closed") {
Q_EMIT errorOccured(i18n("Login Failed: %1", error));
// Failed due to network connection issue. This might happen when the homeserver is
// temporary down, or the user trying to re-launch NeoChat in a network that cannot
@@ -342,7 +330,7 @@ bool Controller::supportSystemTray() const
#ifdef Q_OS_ANDROID
return false;
#else
auto de = QString::fromLatin1(qgetenv("XDG_CURRENT_DESKTOP"));
QString de = getenv("XDG_CURRENT_DESKTOP");
return de != QStringLiteral("GNOME") && de != QStringLiteral("Pantheon");
#endif
}
@@ -354,18 +342,18 @@ void Controller::changePassword(Connection *connection, const QString &currentPa
if (job->error() == 103) {
QJsonObject replyData = job->jsonData();
QJsonObject authData;
authData["session"_ls] = replyData["session"_ls];
authData["password"_ls] = currentPassword;
authData["type"_ls] = "m.login.password"_ls;
authData["user"_ls] = connection->user()->id();
QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, connection->user()->id()}};
authData["identifier"_ls] = identifier;
authData["session"] = replyData["session"];
authData["password"] = currentPassword;
authData["type"] = "m.login.password";
authData["user"] = connection->user()->id();
QJsonObject identifier = {{"type", "m.id.user"}, {"user", connection->user()->id()}};
authData["identifier"] = identifier;
NeochatChangePasswordJob *innerJob = connection->callApi<NeochatChangePasswordJob>(newPassword, false, authData);
connect(innerJob, &BaseJob::success, this, [this]() {
Q_EMIT passwordStatus(PasswordStatus::Success);
});
connect(innerJob, &BaseJob::failure, this, [innerJob, this]() {
if (innerJob->jsonData()["errcode"_ls] == "M_FORBIDDEN"_ls) {
if (innerJob->jsonData()["errcode"] == "M_FORBIDDEN") {
Q_EMIT passwordStatus(PasswordStatus::Wrong);
} else {
Q_EMIT passwordStatus(PasswordStatus::Other);
@@ -411,10 +399,10 @@ void Controller::setQuitOnLastWindowClosed()
if (NeoChatConfig::self()->systemTray()) {
m_trayIcon = new TrayIcon(this);
m_trayIcon->show();
connect(m_trayIcon, &TrayIcon::toggleWindow, this, &Controller::toggleWindow);
connect(m_trayIcon, &TrayIcon::showWindow, this, &Controller::showWindow);
} else {
if (m_trayIcon) {
disconnect(m_trayIcon, &TrayIcon::toggleWindow, this, &Controller::toggleWindow);
disconnect(m_trayIcon, &TrayIcon::showWindow, this, &Controller::showWindow);
delete m_trayIcon;
m_trayIcon = nullptr;
}
@@ -460,7 +448,7 @@ void Controller::setActiveConnection(Connection *connection)
Q_EMIT isOnlineChanged(true);
});
connect(connection, &Connection::requestFailed, this, [](BaseJob *job) {
if (dynamic_cast<DownloadFileJob *>(job) && job->jsonData()["errcode"_ls].toString() == "M_TOO_LARGE"_ls) {
if (dynamic_cast<DownloadFileJob *>(job) && job->jsonData()["errcode"].toString() == "M_TOO_LARGE"_ls) {
RoomManager::instance().warning(i18n("File too large to download."), i18n("Contact your matrix server administrator for support."));
}
});
@@ -498,7 +486,7 @@ NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Om
void Controller::createRoom(const QString &name, const QString &topic)
{
auto createRoomJob = m_connection->createRoom(Connection::PublishRoom, QString(), name, topic, QStringList());
auto createRoomJob = m_connection->createRoom(Connection::PublishRoom, "", name, topic, QStringList());
connect(createRoomJob, &CreateRoomJob::failure, this, [this, createRoomJob] {
Q_EMIT errorOccured(i18n("Room creation failed: %1", createRoomJob->errorString()));
});
@@ -534,12 +522,12 @@ bool Controller::isOnline() const
// TODO: Remove in favor of RoomManager::joinRoom
void Controller::joinRoom(const QString &alias)
{
if (!alias.contains(":"_ls)) {
if (!alias.contains(":")) {
Q_EMIT errorOccured(i18n("The room id you are trying to join is not valid"));
return;
}
const auto knownServer = alias.mid(alias.indexOf(":"_ls) + 1);
const auto knownServer = alias.mid(alias.indexOf(":") + 1);
RoomManager::instance().joinRoom(m_connection, alias, QStringList{knownServer});
}
@@ -593,6 +581,11 @@ bool Controller::hasWindowSystem() const
#endif
}
bool Controller::encryptionSupported() const
{
return Quotient::encryptionSupported();
}
void Controller::forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item)
{
// HACK: Workaround bug QTBUG 93281
@@ -637,6 +630,12 @@ int Controller::activeConnectionIndex() const
return result - m_accountRegistry.accounts().begin();
}
int Controller::quotientMinorVersion() const
{
// TODO libQuotient 0.7: Replace with version function from libQuotient
return 7;
}
bool Controller::isFlatpak() const
{
#ifdef NEOCHAT_FLATPAK
@@ -652,9 +651,9 @@ void Controller::setActiveAccountLabel(const QString &label)
return;
}
QJsonObject json{
{"account_label"_ls, label},
{"account_label", label},
};
m_connection->setAccountData("org.kde.neochat.account_label"_ls, json);
m_connection->setAccountData("org.kde.neochat.account_label", json);
}
QString Controller::activeAccountLabel() const
@@ -662,7 +661,7 @@ QString Controller::activeAccountLabel() const
if (!m_connection) {
return {};
}
return m_connection->accountDataJson("org.kde.neochat.account_label"_ls)["account_label"_ls].toString();
return m_connection->accountDataJson("org.kde.neochat.account_label")["account_label"].toString();
}
QVariantList Controller::getSupportedRoomVersions(Quotient::Connection *connection)
@@ -672,9 +671,9 @@ QVariantList Controller::getSupportedRoomVersions(Quotient::Connection *connecti
QVariantList supportedRoomVersions;
for (const Quotient::Connection::SupportedRoomVersion &v : roomVersions) {
QVariantMap roomVersionMap;
roomVersionMap.insert("id"_ls, v.id);
roomVersionMap.insert("status"_ls, v.status);
roomVersionMap.insert("isStable"_ls, v.isStable());
roomVersionMap.insert("id", v.id);
roomVersionMap.insert("status", v.status);
roomVersionMap.insert("isStable", v.isStable());
supportedRoomVersions.append(roomVersionMap);
}

View File

@@ -87,6 +87,20 @@ class Controller : public QObject
*/
Q_PROPERTY(bool isOnline READ isOnline NOTIFY isOnlineChanged)
/**
* @brief Whether the ecryption support has been enabled.
*/
Q_PROPERTY(bool encryptionSupported READ encryptionSupported CONSTANT)
/**
* @brief The current minor version number of libQuotient being used.
*
* This is the only way to gate NeoChat features by libQuotient version in QML.
*
* @note No major version because libQuotient doesn't have any; All are 0.x.
*/
Q_PROPERTY(int quotientMinorVersion READ quotientMinorVersion CONSTANT)
/**
* @brief Whether NeoChat is running as a flatpak.
*
@@ -180,6 +194,8 @@ public:
bool isOnline() const;
bool encryptionSupported() const;
/**
* @brief Sets the QNetworkProxy for the application.
*
@@ -187,6 +203,8 @@ public:
*/
Q_INVOKABLE void setApplicationProxy();
int quotientMinorVersion() const;
bool isFlatpak() const;
/**
@@ -234,7 +252,7 @@ private:
private Q_SLOTS:
void invokeLogin();
void toggleWindow();
void showWindow();
void setQuitOnLastWindowClosed();
Q_SIGNALS:

File diff suppressed because it is too large Load Diff

View File

@@ -10,29 +10,29 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
{
if (json.contains(QStringLiteral("pack"))) {
pack = ImagePackEventContent::Pack{
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
fromJson<Omittable<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
fromJson<Omittable<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
fromJson<Omittable<QString>>(json["pack"].toObject()["display_name"]),
fromJson<Omittable<QUrl>>(json["pack"].toObject()["avatar_url"]),
fromJson<Omittable<QStringList>>(json["pack"].toObject()["usage"]),
fromJson<Omittable<QString>>(json["pack"].toObject()["attribution"]),
};
} else {
pack = none;
}
const auto &keys = json["images"_ls].toObject().keys();
const auto &keys = json["images"].toObject().keys();
for (const auto &k : keys) {
Omittable<EventContent::ImageInfo> info;
if (json["images"_ls][k].toObject().contains(QStringLiteral("info"))) {
info = EventContent::ImageInfo(QUrl(json["images"_ls][k]["url"_ls].toString()), json["images"_ls][k]["info"_ls].toObject(), k);
if (json["images"][k].toObject().contains(QStringLiteral("info"))) {
info = EventContent::ImageInfo(QUrl(json["images"][k]["url"].toString()), json["images"][k]["info"].toObject(), k);
} else {
info = none;
}
images += ImagePackImage{
k,
fromJson<QUrl>(json["images"_ls][k]["url"_ls].toString()),
fromJson<Omittable<QString>>(json["images"_ls][k]["body"_ls]),
fromJson<QUrl>(json["images"][k]["url"].toString()),
fromJson<Omittable<QString>>(json["images"][k]["body"]),
info,
fromJson<Omittable<QStringList>>(json["images"_ls][k]["usage"_ls]),
fromJson<Omittable<QStringList>>(json["images"][k]["usage"]),
};
}
}
@@ -42,20 +42,20 @@ void ImagePackEventContent::fillJson(QJsonObject *o) const
if (pack) {
QJsonObject packJson;
if (pack->displayName) {
packJson["display_name"_ls] = *pack->displayName;
packJson["display_name"] = *pack->displayName;
}
if (pack->usage) {
QJsonArray usageJson;
for (const auto &usage : *pack->usage) {
usageJson += usage;
}
packJson["usage"_ls] = usageJson;
packJson["usage"] = usageJson;
}
if (pack->avatarUrl) {
packJson["avatar_url"_ls] = pack->avatarUrl->toString();
packJson["avatar_url"] = pack->avatarUrl->toString();
}
if (pack->attribution) {
packJson["attribution"_ls] = *pack->attribution;
packJson["attribution"] = *pack->attribution;
}
(*o)["pack"_ls] = packJson;
}
@@ -63,16 +63,16 @@ void ImagePackEventContent::fillJson(QJsonObject *o) const
QJsonObject imagesJson;
for (const auto &image : images) {
QJsonObject imageJson;
imageJson["url"_ls] = image.url.toString();
imageJson["url"] = image.url.toString();
if (image.body) {
imageJson["body"_ls] = *image.body;
imageJson["body"] = *image.body;
}
if (image.usage) {
QJsonArray usageJson;
for (const auto &usage : *image.usage) {
usageJson += usage;
}
imageJson["usage"_ls] = usageJson;
imageJson["usage"] = usageJson;
}
imagesJson[image.shortcode] = imageJson;
}

View File

@@ -12,12 +12,12 @@ PollStartEvent::PollStartEvent(const QJsonObject &obj)
int PollStartEvent::maxSelections() const
{
return contentJson()["org.matrix.msc3381.poll.start"_ls]["max_selections"_ls].toInt();
return contentJson()["org.matrix.msc3381.poll.start"]["max_selections"].toInt();
}
QString PollStartEvent::question() const
{
return contentJson()["org.matrix.msc3381.poll.start"_ls]["question"_ls]["body"_ls].toString();
return contentJson()["org.matrix.msc3381.poll.start"]["question"]["body"].toString();
}
PollResponseEvent::PollResponseEvent(const QJsonObject &obj)
@@ -32,7 +32,7 @@ PollEndEvent::PollEndEvent(const QJsonObject &obj)
PollResponseEvent::PollResponseEvent(const QString &pollStartEventId, QStringList responses)
: RoomEvent(basicJson(TypeId,
{{"org.matrix.msc3381.poll.response"_ls, QJsonObject{{"answers"_ls, QJsonArray::fromStringList(responses)}}},
{"m.relates_to"_ls, QJsonObject{{"rel_type"_ls, "m.reference"_ls}, {"event_id"_ls, pollStartEventId}}}}))
{{"org.matrix.msc3381.poll.response", QJsonObject{{"answers", QJsonArray::fromStringList(responses)}}},
{"m.relates_to", QJsonObject{{"rel_type", "m.reference"}, {"event_id", pollStartEventId}}}}))
{
}

View File

@@ -62,14 +62,14 @@ void LinkPreviewer::loadUrlPreview()
Q_EMIT loadedChanged();
auto conn = m_currentRoom->connection();
GetUrlPreviewJob *job = conn->callApi<GetUrlPreviewJob>(m_url);
GetUrlPreviewJob *job = conn->callApi<GetUrlPreviewJob>(m_url.toString());
connect(job, &BaseJob::success, this, [this, job, conn]() {
const auto json = job->jsonData();
m_title = json["og:title"_ls].toString().trimmed();
m_description = json["og:description"_ls].toString().trimmed().replace("\n"_ls, " "_ls);
m_title = json["og:title"].toString().trimmed();
m_description = json["og:description"].toString().trimmed().replace("\n", " ");
auto imageUrl = QUrl(json["og:image"_ls].toString());
auto imageUrl = QUrl(json["og:image"].toString());
if (imageUrl.isValid() && imageUrl.scheme() == QStringLiteral("mxc")) {
m_imageSource = conn->makeMediaUrl(imageUrl);
} else {

View File

@@ -87,32 +87,32 @@ public:
QMutexLocker locker(&mutex);
QByteArray buf;
QTextStream str(&buf);
str << QDateTime::currentDateTime().toString(Qt::ISODate) << QStringLiteral(" [");
str << QDateTime::currentDateTime().toString(Qt::ISODate) << " [";
switch (type) {
case QtDebugMsg:
str << QStringLiteral("DEBUG");
str << "DEBUG";
break;
case QtInfoMsg:
str << QStringLiteral("INFO ");
str << "INFO ";
break;
case QtWarningMsg:
str << QStringLiteral("WARN ");
str << "WARN ";
break;
case QtFatalMsg:
str << QStringLiteral("FATAL");
str << "FATAL";
break;
case QtCriticalMsg:
str << QStringLiteral("CRITICAL");
str << "CRITICAL";
break;
}
str << QStringLiteral("] ") << context.category << QStringLiteral(": ");
str << "] " << context.category << ": ";
if (context.file && *context.file && context.line) {
str << context.file << QStringLiteral(":") << context.line << QStringLiteral(": ");
str << context.file << ":" << context.line << ": ";
}
if (context.function && *context.function) {
str << context.function << QStringLiteral(": ");
str << context.function << ": ";
}
str << message << QStringLiteral("\n");
str << message << "\n";
str.flush();
file.write(buf.constData(), buf.size());
file.flush();
@@ -129,18 +129,18 @@ public:
if (file.isOpen()) {
file.close();
}
const auto &filePath = QStringLiteral("%1%2%3").arg(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), QDir::separator(), appName);
auto filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QDir::separator() + appName;
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QDir::separator());
auto entryList = dir.entryList({appName + QStringLiteral(".*")});
std::sort(entryList.begin(), entryList.end(), [](const auto &left, const auto &right) {
auto leftIndex = left.split(QStringLiteral(".")).last().toInt();
auto rightIndex = right.split(QStringLiteral(".")).last().toInt();
auto leftIndex = left.split(".").last().toInt();
auto rightIndex = right.split(".").last().toInt();
return leftIndex > rightIndex;
});
for (const auto &entry : entryList) {
bool ok = false;
const auto index = entry.split(QStringLiteral(".")).last().toInt(&ok);
const auto index = entry.split(".").last().toInt(&ok);
if (!ok) {
continue;
}
@@ -151,8 +151,8 @@ public:
file.remove();
continue;
}
const auto &newName = QStringLiteral("%1.%2").arg(filePath, QString::number(index + 1));
const auto success = file.copy(newName);
const QString newName = filePath + QStringLiteral(".%1").arg(index + 1);
const bool success = file.copy(newName);
if (success) {
file.remove();
} else {
@@ -216,7 +216,7 @@ void initLogging()
oldCategoryFilter = QLoggingCategory::installFilter(filter);
oldHandler = qInstallMessageHandler(messageHandler);
sInstance->setOrigHandler(oldHandler);
sInstance->setName(QStringLiteral("neochat.log"));
sInstance->setName("neochat.log");
}
#include "logger.moc"

View File

@@ -33,12 +33,12 @@ void Login::init()
connect(this, &Login::matrixIdChanged, this, [this]() {
setHomeserverReachable(false);
QRegularExpression validator(QStringLiteral("^\\@?[a-zA-Z0-9\\._=\\-/]+\\:[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)*(\\:[0-9]+)?$"));
QRegularExpression validator("^\\@?[a-zA-Z0-9\\._=\\-/]+\\:[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)*(\\:[0-9]+)?$");
if (!validator.match(m_matrixId).hasMatch()) {
return;
}
if (m_matrixId == QLatin1Char('@')) {
if (m_matrixId == "@") {
return;
}
@@ -120,8 +120,8 @@ QString Login::matrixId() const
void Login::setMatrixId(const QString &matrixId)
{
m_matrixId = matrixId;
if (!m_matrixId.startsWith(QLatin1Char('@'))) {
m_matrixId.prepend(QLatin1Char('@'));
if (!m_matrixId.startsWith('@')) {
m_matrixId.prepend('@');
}
Q_EMIT matrixIdChanged();
}
@@ -155,7 +155,7 @@ void Login::login()
// Some servers do not have a .well_known file. So we login via the username part from the mxid,
// rather than with the full mxid, as that would lead to an invalid user.
auto username = m_matrixId.mid(1, m_matrixId.indexOf(QLatin1Char(':')) - 1);
auto username = m_matrixId.mid(1, m_matrixId.indexOf(":") - 1);
m_connection->loginWithPassword(username, m_password, m_deviceName, QString());
}

View File

@@ -3,7 +3,6 @@
#include <QCommandLineParser>
#include <QIcon>
#include <QNetworkDiskCache>
#include <QNetworkProxyFactory>
#include <QObject>
#include <QQmlApplicationEngine>
@@ -106,17 +105,7 @@ class NetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory
{
QNetworkAccessManager *create(QObject *) override
{
auto nam = NetworkAccessManager::instance();
nam->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
nam->enableStrictTransportSecurityStore(true, QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/hsts/"));
nam->setStrictTransportSecurityEnabled(true);
auto namDiskCache = new QNetworkDiskCache(nam);
namDiskCache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/nam/"));
nam->setCache(namDiskCache);
return nam;
return NetworkAccessManager::instance();
}
};
@@ -143,7 +132,7 @@ int main(int argc, char *argv[])
QGuiApplication app(argc, argv);
QQuickStyle::setStyle(QStringLiteral("org.kde.breeze"));
#else
QIcon::setFallbackThemeName("breeze"_ls);
QIcon::setFallbackThemeName("breeze");
QApplication app(argc, argv);
// Default to org.kde.desktop style unless the user forces another style
if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) {
@@ -165,7 +154,7 @@ int main(int argc, char *argv[])
#endif
KLocalizedString::setApplicationDomain("neochat");
QGuiApplication::setOrganizationName("KDE"_ls);
QGuiApplication::setOrganizationName("KDE");
KAboutData about(QStringLiteral("neochat"),
i18n("NeoChat"),
@@ -202,8 +191,7 @@ int main(int argc, char *argv[])
#ifdef NEOCHAT_FLATPAK
// Copy over the included FontConfig configuration to the
// app's config dir:
QFile::copy(QStringLiteral("/app/etc/fonts/conf.d/99-noto-mono-color-emoji.conf"),
QStringLiteral("/var/config/fontconfig/conf.d/99-noto-mono-color-emoji.conf"));
QFile::copy("/app/etc/fonts/conf.d/99-noto-mono-color-emoji.conf", "/var/config/fontconfig/conf.d/99-noto-mono-color-emoji.conf");
#endif
Clipboard clipboard;
@@ -265,12 +253,12 @@ int main(int argc, char *argv[])
qmlRegisterType<AccountEmoticonModel>("org.kde.neochat", 1, 0, "AccountEmoticonModel");
qmlRegisterType<EmoticonFilterModel>("org.kde.neochat", 1, 0, "EmoticonFilterModel");
qmlRegisterType<DelegateSizeHelper>("org.kde.neochat", 1, 0, "DelegateSizeHelper");
qmlRegisterUncreatableType<RoomMessageEvent>("org.kde.neochat", 1, 0, "RoomMessageEvent", "ENUM"_ls);
qmlRegisterUncreatableType<PushNotificationKind>("org.kde.neochat", 1, 0, "PushNotificationKind", "ENUM"_ls);
qmlRegisterUncreatableType<PushNotificationSection>("org.kde.neochat", 1, 0, "PushNotificationSection", "ENUM"_ls);
qmlRegisterUncreatableType<PushNotificationState>("org.kde.neochat", 1, 0, "PushNotificationState", "ENUM"_ls);
qmlRegisterUncreatableType<PushNotificationAction>("org.kde.neochat", 1, 0, "PushNotificationAction", "ENUM"_ls);
qmlRegisterUncreatableType<NeoChatRoomType>("org.kde.neochat", 1, 0, "NeoChatRoomType", "ENUM"_ls);
qmlRegisterUncreatableType<RoomMessageEvent>("org.kde.neochat", 1, 0, "RoomMessageEvent", "ENUM");
qmlRegisterUncreatableType<PushNotificationKind>("org.kde.neochat", 1, 0, "PushNotificationKind", "ENUM");
qmlRegisterUncreatableType<PushNotificationSection>("org.kde.neochat", 1, 0, "PushNotificationSection", "ENUM");
qmlRegisterUncreatableType<PushNotificationState>("org.kde.neochat", 1, 0, "PushNotificationState", "ENUM");
qmlRegisterUncreatableType<PushNotificationAction>("org.kde.neochat", 1, 0, "PushNotificationAction", "ENUM");
qmlRegisterUncreatableType<NeoChatRoomType>("org.kde.neochat", 1, 0, "NeoChatRoomType", "ENUM");
qmlRegisterUncreatableType<User>("org.kde.neochat", 1, 0, "User", {});
qmlRegisterUncreatableType<NeoChatRoom>("org.kde.neochat", 1, 0, "NeoChatRoom", {});
@@ -284,13 +272,15 @@ int main(int argc, char *argv[])
qRegisterMetaType<User *>("User*");
qRegisterMetaType<GetRoomEventsJob *>("GetRoomEventsJob*");
qRegisterMetaType<QMimeType>("QMimeType");
#ifdef Quotient_E2EE_ENABLED
qRegisterMetaType<KeyVerificationSession *>("KeyVerificationSession*");
qmlRegisterUncreatableType<KeyVerificationSession>("org.kde.neochat", 1, 0, "KeyVerificationSession", {});
qRegisterMetaType<QVector<EmojiEntry>>("QVector<EmojiEntry>");
#endif
qmlRegisterSingletonType("org.kde.neochat", 1, 0, "About", [](QQmlEngine *engine, QJSEngine *) -> QJSValue {
return engine->toScriptValue(KAboutData::applicationData());
});
qmlRegisterSingletonType(QUrl("qrc:/OsmLocationPlugin.qml"_ls), "org.kde.neochat", 1, 0, "OsmLocationPlugin");
qmlRegisterSingletonType(QUrl("qrc:/OsmLocationPlugin.qml"), "org.kde.neochat", 1, 0, "OsmLocationPlugin");
qmlRegisterSingletonType("org.kde.neochat", 1, 0, "LocationHelper", [](QQmlEngine *engine, QJSEngine *) -> QJSValue {
return engine->toScriptValue(LocationHelper());
});
@@ -333,13 +323,13 @@ int main(int argc, char *argv[])
QCommandLineParser parser;
parser.setApplicationDescription(i18n("Client for the matrix communication protocol"));
parser.addPositionalArgument(QStringLiteral("urls"), i18n("Supports matrix: url scheme"));
parser.addOption(QCommandLineOption("ignore-ssl-errors"_ls, i18n("Ignore all SSL Errors, e.g., unsigned certificates.")));
parser.addOption(QCommandLineOption("ignore-ssl-errors", i18n("Ignore all SSL Errors, e.g., unsigned certificates.")));
about.setupCommandLine(&parser);
parser.process(app);
about.processCommandLine(&parser);
if (parser.isSet("ignore-ssl-errors"_ls)) {
if (parser.isSet("ignore-ssl-errors")) {
QObject::connect(NetworkAccessManager::instance(), &QNetworkAccessManager::sslErrors, NetworkAccessManager::instance(), [](QNetworkReply *reply) {
reply->ignoreSslErrors();
});
@@ -359,7 +349,7 @@ int main(int argc, char *argv[])
#ifdef HAVE_RUNNER
Runner runner;
QDBusConnection::sessionBus().registerObject("/RoomRunner"_ls, &runner, QDBusConnection::ExportScriptableContents);
QDBusConnection::sessionBus().registerObject("/RoomRunner", &runner, QDBusConnection::ExportScriptableContents);
#endif
QWindow *window = windowFromEngine(&engine);

View File

@@ -25,13 +25,13 @@ ThumbnailResponse::ThumbnailResponse(QString id, QSize size)
mediaId,
QString::number(requestedSize.width()),
QString::number(requestedSize.height())))
, errorStr("Image request hasn't started"_ls)
, errorStr("Image request hasn't started")
{
if (requestedSize.isEmpty()) {
requestedSize.setHeight(100);
requestedSize.setWidth(100);
}
if (mediaId.count(QLatin1Char('/')) != 1) {
if (mediaId.count('/') != 1) {
if (mediaId.startsWith(QLatin1Char('/'))) {
mediaId = mediaId.mid(1);
} else {

View File

@@ -138,7 +138,7 @@ QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl sourc
if (job->error() != BaseJob::NoError) {
co_return;
}
m_images->images[index].url = job->contentUri();
m_images->images[index].url = job->contentUri().toString();
m_images->images[index].info = none;
QJsonObject data;
m_images->fillJson(&data);

View File

@@ -14,10 +14,9 @@
using Action = ActionsModel::Action;
using namespace Quotient;
QStringList rainbowColors{"#ff2b00"_ls, "#ff5500"_ls, "#ff8000"_ls, "#ffaa00"_ls, "#ffd500"_ls, "#ffff00"_ls, "#d4ff00"_ls, "#aaff00"_ls, "#80ff00"_ls,
"#55ff00"_ls, "#2bff00"_ls, "#00ff00"_ls, "#00ff2b"_ls, "#00ff55"_ls, "#00ff80"_ls, "#00ffaa"_ls, "#00ffd5"_ls, "#00ffff"_ls,
"#00d4ff"_ls, "#00aaff"_ls, "#007fff"_ls, "#0055ff"_ls, "#002bff"_ls, "#0000ff"_ls, "#2a00ff"_ls, "#5500ff"_ls, "#7f00ff"_ls,
"#aa00ff"_ls, "#d400ff"_ls, "#ff00ff"_ls, "#ff00d4"_ls, "#ff00aa"_ls, "#ff0080"_ls, "#ff0055"_ls, "#ff002b"_ls, "#ff0000"_ls};
QStringList rainbowColors{"#ff2b00", "#ff5500", "#ff8000", "#ffaa00", "#ffd500", "#ffff00", "#d4ff00", "#aaff00", "#80ff00", "#55ff00", "#2bff00", "#00ff00",
"#00ff2b", "#00ff55", "#00ff80", "#00ffaa", "#00ffd5", "#00ffff", "#00d4ff", "#00aaff", "#007fff", "#0055ff", "#002bff", "#0000ff",
"#2a00ff", "#5500ff", "#7f00ff", "#aa00ff", "#d400ff", "#ff00ff", "#ff00d4", "#ff00aa", "#ff0080", "#ff0055", "#ff002b", "#ff0000"};
auto leaveRoomLambda = [](const QString &text, NeoChatRoom *room) {
if (text.isEmpty()) {
@@ -261,7 +260,7 @@ QVector<ActionsModel::Action> actions{
}
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Knocking room <roomname>.", "Knocking room %1.", text));
auto connection = Controller::instance().activeConnection();
const auto knownServer = roomName.mid(roomName.indexOf(":"_ls) + 1);
const auto knownServer = roomName.mid(roomName.indexOf(":") + 1);
if (parts.length() >= 2) {
RoomManager::instance().knockRoom(connection, roomName, parts[1], QStringList{knownServer});
} else {
@@ -451,7 +450,7 @@ QVector<ActionsModel::Action> actions{
i18nc("You are not allowed to ban <username> from this room.", "You are not allowed to ban %1 from this room.", parts[0]));
return QString();
}
room->ban(parts[0], parts.size() > 1 ? parts.mid(1).join(QLatin1Char(' ')) : QString());
room->ban(parts[0], parts.size() > 1 ? parts.mid(1).join(" ") : QString());
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> was banned from this room.", "%1 was banned from this room.", parts[0]));
return QString();
},
@@ -528,7 +527,7 @@ QVector<ActionsModel::Action> actions{
i18nc("You are not allowed to kick <username> from this room", "You are not allowed to kick %1 from this room.", parts[0]));
return QString();
}
room->kickMember(parts[0], parts.size() > 1 ? parts.mid(1).join(QLatin1Char(' ')) : QString());
room->kickMember(parts[0], parts.size() > 1 ? parts.mid(1).join(" ") : QString());
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> was kicked from this room.", "%1 was kicked from this room.", parts[0]));
return QString();
},

View File

@@ -75,13 +75,13 @@ QString CollapseStateProxyModel::aggregateEventToString(int sourceRow) const
}
}
chunks.removeDuplicates();
QString text = QStringLiteral("<style>a {text-decoration: none;}</style>"); // There can be links in the event text so make sure all are styled.
QString text = "<style>a {text-decoration: none;}</style>"; // There can be links in the event text so make sure all are styled.
// The author text is either "n users" if > 1 user or the matrix.to link to a single user.
QString userText = uniqueAuthors.length() > 1 ? i18ncp("n users", " %1 user ", " %1 users ", uniqueAuthors.length())
: QStringLiteral("<a href=\"https://matrix.to/#/%1\" style=\"color: %2\">%3</a> ")
.arg(uniqueAuthors[0].toMap()[QStringLiteral("id")].toString(),
uniqueAuthors[0].toMap()[QStringLiteral("color")].toString(),
uniqueAuthors[0].toMap()[QStringLiteral("displayName")].toString().toHtmlEscaped());
.arg(uniqueAuthors[0].toMap()["id"].toString(),
uniqueAuthors[0].toMap()["color"].toString(),
uniqueAuthors[0].toMap()["displayName"].toString().toHtmlEscaped());
text += userText;
text += chunks.takeFirst();
@@ -104,9 +104,9 @@ QVariantList CollapseStateProxyModel::stateEventsList(int sourceRow) const
QVariantList stateEvents;
for (int i = sourceRow; i >= 0; i--) {
auto nextState = QVariantMap{
{QStringLiteral("author"), sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::AuthorRole)},
{QStringLiteral("authorDisplayName"), sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::AuthorDisplayNameRole).toString()},
{QStringLiteral("text"), sourceModel()->data(sourceModel()->index(i, 0), Qt::DisplayRole).toString()},
{"author", sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::AuthorRole)},
{"authorDisplayName", sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::AuthorDisplayNameRole).toString()},
{"text", sourceModel()->data(sourceModel()->index(i, 0), Qt::DisplayRole).toString()},
};
stateEvents.append(nextState);
if (i > 0

View File

@@ -66,8 +66,8 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
if (m_autoCompletionType == Command) {
if (role == DisplayNameRole) {
return QStringLiteral("%1 %2").arg(m_filterModel->data(filterIndex, ActionsModel::Prefix).toString(),
m_filterModel->data(filterIndex, ActionsModel::Parameters).toString());
return m_filterModel->data(filterIndex, ActionsModel::Prefix).toString() + QStringLiteral(" ")
+ m_filterModel->data(filterIndex, ActionsModel::Parameters).toString();
}
if (role == SubtitleRole) {
return m_filterModel->data(filterIndex, ActionsModel::Description);
@@ -87,8 +87,7 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
}
if (role == IconNameRole) {
return QStringLiteral("mxc://%1")
.arg(m_roomListModel->connection()->makeMediaUrl(m_filterModel->data(filterIndex, RoomListModel::AvatarRole).toUrl()).toString());
return m_filterModel->data(filterIndex, RoomListModel::AvatarRole);
}
}
if (m_autoCompletionType == Emoji) {

View File

@@ -40,12 +40,12 @@ class CompletionModel : public QAbstractListModel
*
* @sa AutoCompletionType
*/
Q_PROPERTY(AutoCompletionType autoCompletionType READ autoCompletionType NOTIFY autoCompletionTypeChanged)
Q_PROPERTY(AutoCompletionType autoCompletionType READ autoCompletionType NOTIFY autoCompletionTypeChanged);
/**
* @brief The RoomListModel to be used for room completions.
*/
Q_PROPERTY(RoomListModel *roomListModel READ roomListModel WRITE setRoomListModel NOTIFY roomListModelChanged)
Q_PROPERTY(RoomListModel *roomListModel READ roomListModel WRITE setRoomListModel NOTIFY roomListModelChanged);
public:
/**

View File

@@ -11,11 +11,6 @@ bool CompletionProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &so
if (m_filterText.isEmpty()) {
return false;
}
if (sourceModel()->data(sourceModel()->index(sourceRow, 0), filterRole()).toString().isEmpty()) {
return false;
}
return (sourceModel()->data(sourceModel()->index(sourceRow, 0), filterRole()).toString().startsWith(m_filterText, Qt::CaseInsensitive)
&& !m_fullText.startsWith(sourceModel()->data(sourceModel()->index(sourceRow, 0), filterRole()).toString()))
|| (m_secondaryFilterRole != -1

View File

@@ -21,14 +21,14 @@ void CustomEmojiModel::fetchEmojis()
return;
}
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes"_ls);
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes");
if (data == nullptr) {
return;
}
QJsonObject emojis = data->contentJson()["images"_ls].toObject();
QJsonObject emojis = data->contentJson()["images"].toObject();
// TODO: Remove with stable migration
const auto legacyEmojis = data->contentJson()["emoticons"_ls].toObject();
const auto legacyEmojis = data->contentJson()["emoticons"].toObject();
for (const auto &emoji : legacyEmojis.keys()) {
if (!emojis.contains(emoji)) {
emojis[emoji] = legacyEmojis[emoji];
@@ -41,9 +41,9 @@ void CustomEmojiModel::fetchEmojis()
for (const auto &emoji : emojis.keys()) {
const auto &data = emojis[emoji];
const auto e = emoji.startsWith(":"_ls) ? emoji : (QStringLiteral(":") + emoji + QStringLiteral(":"));
const auto e = emoji.startsWith(":") ? emoji : (QStringLiteral(":") + emoji + QStringLiteral(":"));
m_emojis << CustomEmoji{e, data.toObject()["url"_ls].toString(), QRegularExpression(e)};
m_emojis << CustomEmoji{e, data.toObject()["url"].toString(), QRegularExpression(e)};
}
endResetModel();
@@ -56,19 +56,19 @@ void CustomEmojiModel::addEmoji(const QString &name, const QUrl &location)
auto job = Controller::instance().activeConnection()->uploadFile(location.toLocalFile());
connect(job, &BaseJob::success, this, [name, location, job] {
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes"_ls);
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes");
auto json = data != nullptr ? data->contentJson() : QJsonObject();
auto emojiData = json["images"_ls].toObject();
auto emojiData = json["images"].toObject();
QString url;
url = job->contentUri().toString();
QImage image(location.toLocalFile());
QJsonObject imageInfo;
imageInfo["w"_ls] = image.width();
imageInfo["h"_ls] = image.height();
imageInfo["mimetype"_ls] = QMimeDatabase().mimeTypeForFile(location.toLocalFile()).name();
imageInfo["size"_ls] = image.sizeInBytes();
imageInfo["w"] = image.width();
imageInfo["h"] = image.height();
imageInfo["mimetype"] = QMimeDatabase().mimeTypeForFile(location.toLocalFile()).name();
imageInfo["size"] = image.sizeInBytes();
emojiData[QStringLiteral("%1").arg(name)] = QJsonObject({
{QStringLiteral("url"), url},
@@ -77,8 +77,8 @@ void CustomEmojiModel::addEmoji(const QString &name, const QUrl &location)
{"usage"_ls, "emoticon"_ls},
});
json["images"_ls] = emojiData;
Controller::instance().activeConnection()->setAccountData("im.ponies.user_emotes"_ls, json);
json["images"] = emojiData;
Controller::instance().activeConnection()->setAccountData("im.ponies.user_emotes", json);
});
}
@@ -86,30 +86,30 @@ void CustomEmojiModel::removeEmoji(const QString &name)
{
using namespace Quotient;
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes"_ls);
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes");
Q_ASSERT(data);
auto json = data->contentJson();
const QString _name = name.mid(1).chopped(1);
auto emojiData = json["images"_ls].toObject();
auto emojiData = json["images"].toObject();
if (emojiData.contains(name)) {
emojiData.remove(name);
json["images"_ls] = emojiData;
json["images"] = emojiData;
}
if (emojiData.contains(_name)) {
emojiData.remove(_name);
json["images"_ls] = emojiData;
json["images"] = emojiData;
}
emojiData = json["emoticons"_ls].toObject();
emojiData = json["emoticons"].toObject();
if (emojiData.contains(name)) {
emojiData.remove(name);
json["emoticons"_ls] = emojiData;
json["emoticons"] = emojiData;
}
if (emojiData.contains(_name)) {
emojiData.remove(_name);
json["emoticons"_ls] = emojiData;
json["emoticons"] = emojiData;
}
Controller::instance().activeConnection()->setAccountData("im.ponies.user_emotes"_ls, json);
Controller::instance().activeConnection()->setAccountData("im.ponies.user_emotes", json);
}
CustomEmojiModel::CustomEmojiModel(QObject *parent)
@@ -174,7 +174,7 @@ QHash<int, QByteArray> CustomEmojiModel::roleNames() const
QString CustomEmojiModel::preprocessText(const QString &text)
{
auto parts = text.split("```"_ls);
auto parts = text.split("```");
bool skip = true;
for (auto &part : parts) {
skip = !skip;
@@ -187,7 +187,7 @@ QString CustomEmojiModel::preprocessText(const QString &text)
QStringLiteral(R"(<img data-mx-emoticon="" src="%1" alt="%2" title="%2" height="32" vertical-align="middle" />)").arg(emoji.url, emoji.name));
}
}
return parts.join("```"_ls);
return parts.join("```");
}
QVariantList CustomEmojiModel::filterModel(const QString &filter)

View File

@@ -113,11 +113,11 @@ void DevicesModel::logout(const QString &deviceId, const QString &password)
if (job->error() != BaseJob::Success) {
QJsonObject replyData = job->jsonData();
QJsonObject authData;
authData["session"_ls] = replyData["session"_ls];
authData["password"_ls] = password;
authData["type"_ls] = "m.login.password"_ls;
QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, Controller::instance().activeConnection()->user()->id()}};
authData["identifier"_ls] = identifier;
authData["session"] = replyData["session"];
authData["password"] = password;
authData["type"] = "m.login.password";
QJsonObject identifier = {{"type", "m.id.user"}, {"user", Controller::instance().activeConnection()->user()->id()}};
authData["identifier"] = identifier;
auto *innerJob = Controller::instance().activeConnection()->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
connect(innerJob, &BaseJob::success, this, onSuccess);
} else {

View File

@@ -8,7 +8,7 @@
class DevicesProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(int type READ type WRITE setType NOTIFY typeChanged)
Q_PROPERTY(int type READ type WRITE setType NOTIFY typeChanged);
public:
DevicesProxyModel(QObject *parent = nullptr);

View File

@@ -63,7 +63,7 @@ QHash<int, QByteArray> EmojiModel::roleNames() const
QVariantList EmojiModel::history() const
{
return m_settings.value(QStringLiteral("Editor/emojis"), QVariantList()).toList();
return m_settings.value("Editor/emojis", QVariantList()).toList();
}
QVariantList EmojiModel::filterModel(const QString &filter, bool limit)
@@ -105,7 +105,7 @@ void EmojiModel::emojiUsed(const QVariant &modelData)
}
list.push_front(modelData);
m_settings.setValue(QStringLiteral("Editor/emojis"), list);
m_settings.setValue("Editor/emojis", list);
Q_EMIT historyChanged();
}
@@ -133,8 +133,8 @@ QVariantList EmojiModel::emojis(Category category) const
QVariantList EmojiModel::tones(const QString &baseEmoji) const
{
if (baseEmoji.endsWith(QStringLiteral("tone"))) {
return EmojiTones::_tones.values(baseEmoji.split(QStringLiteral(":"))[0]);
if (baseEmoji.endsWith("tone")) {
return EmojiTones::_tones.values(baseEmoji.split(":")[0]);
}
return EmojiTones::_tones.values(baseEmoji);
}
@@ -145,54 +145,54 @@ QVariantList EmojiModel::categories() const
{
return QVariantList{
{QVariantMap{
{QStringLiteral("category"), EmojiModel::HistoryNoCustom},
{QStringLiteral("name"), i18nc("Previously used emojis", "History")},
{QStringLiteral("emoji"), QStringLiteral("⌛️")},
{"category", EmojiModel::HistoryNoCustom},
{"name", i18nc("Previously used emojis", "History")},
{"emoji", QStringLiteral("⌛️")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Smileys},
{QStringLiteral("name"), i18nc("'Smileys' is a category of emoji", "Smileys")},
{QStringLiteral("emoji"), QStringLiteral("😏")},
{"category", EmojiModel::Smileys},
{"name", i18nc("'Smileys' is a category of emoji", "Smileys")},
{"emoji", QStringLiteral("😏")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::People},
{QStringLiteral("name"), i18nc("'People' is a category of emoji", "People")},
{QStringLiteral("emoji"), QStringLiteral("🙋‍♂️")},
{"category", EmojiModel::People},
{"name", i18nc("'People' is a category of emoji", "People")},
{"emoji", QStringLiteral("🙋‍♂️")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Nature},
{QStringLiteral("name"), i18nc("'Nature' is a category of emoji", "Nature")},
{QStringLiteral("emoji"), QStringLiteral("🌲")},
{"category", EmojiModel::Nature},
{"name", i18nc("'Nature' is a category of emoji", "Nature")},
{"emoji", QStringLiteral("🌲")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Food},
{QStringLiteral("name"), i18nc("'Food' is a category of emoji", "Food")},
{QStringLiteral("emoji"), QStringLiteral("🍛")},
{"category", EmojiModel::Food},
{"name", i18nc("'Food' is a category of emoji", "Food")},
{"emoji", QStringLiteral("🍛")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Activities},
{QStringLiteral("name"), i18nc("'Activities' is a category of emoji", "Activities")},
{QStringLiteral("emoji"), QStringLiteral("🚁")},
{"category", EmojiModel::Activities},
{"name", i18nc("'Activities' is a category of emoji", "Activities")},
{"emoji", QStringLiteral("🚁")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Travel},
{QStringLiteral("name"), i18nc("'Travel' is a category of emoji", "Travel")},
{QStringLiteral("emoji"), QStringLiteral("🚅")},
{"category", EmojiModel::Travel},
{"name", i18nc("'Travel' is a category of emoji", "Travel")},
{"emoji", QStringLiteral("🚅")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Objects},
{QStringLiteral("name"), i18nc("'Objects' is a category of emoji", "Objects")},
{QStringLiteral("emoji"), QStringLiteral("💡")},
{"category", EmojiModel::Objects},
{"name", i18nc("'Objects' is a category of emoji", "Objects")},
{"emoji", QStringLiteral("💡")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Symbols},
{QStringLiteral("name"), i18nc("'Symbols' is a category of emoji", "Symbols")},
{QStringLiteral("emoji"), QStringLiteral("🔣")},
{"category", EmojiModel::Symbols},
{"name", i18nc("'Symbols' is a category of emoji", "Symbols")},
{"emoji", QStringLiteral("🔣")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Flags},
{QStringLiteral("name"), i18nc("'Flags' is a category of emoji", "Flags")},
{QStringLiteral("emoji"), QStringLiteral("🏁")},
{"category", EmojiModel::Flags},
{"name", i18nc("'Flags' is a category of emoji", "Flags")},
{"emoji", QStringLiteral("🏁")},
}},
};
}
@@ -203,15 +203,15 @@ QVariantList EmojiModel::categoriesWithCustom() const
cats.removeAt(0);
cats.insert(0,
QVariantMap{
{QStringLiteral("category"), EmojiModel::History},
{QStringLiteral("name"), i18nc("Previously used emojis", "History")},
{QStringLiteral("emoji"), QStringLiteral("⌛️")},
{"category", EmojiModel::History},
{"name", i18nc("Previously used emojis", "History")},
{"emoji", QStringLiteral("⌛️")},
});
cats.insert(1,
QVariantMap{
{QStringLiteral("category"), EmojiModel::Custom},
{QStringLiteral("name"), i18nc("'Custom' is a category of emoji", "Custom")},
{QStringLiteral("emoji"), QStringLiteral("🖼️")},
{"category", EmojiModel::Custom},
{"name", i18nc("'Custom' is a category of emoji", "Custom")},
{"emoji", QStringLiteral("🖼️")},
});
;
return cats;

View File

@@ -33,7 +33,7 @@ struct Emoji {
{
arch >> object.unicode;
arch >> object.shortName;
object.isCustom = object.unicode.startsWith(QStringLiteral("image://"));
object.isCustom = object.unicode.startsWith("image://");
return arch;
}

View File

@@ -82,9 +82,8 @@ void ImagePacksModel::reloadImages()
// Load emoticons from the account data
if (m_room->connection()->hasAccountData("im.ponies.user_emotes"_ls)) {
auto json = m_room->connection()->accountData("im.ponies.user_emotes"_ls)->contentJson();
json["pack"_ls] = QJsonObject{
{"display_name"_ls,
m_showStickers ? i18nc("As in 'The user's own Stickers'", "Own Stickers") : i18nc("As in 'The user's own emojis", "Own Emojis")},
json["pack"] = QJsonObject{
{"display_name", m_showStickers ? i18nc("As in 'The user's own Stickers'", "Own Stickers") : i18nc("As in 'The user's own emojis", "Own Emojis")},
};
const auto &content = ImagePackEventContent(json);
if (!content.images.isEmpty()) {
@@ -105,8 +104,8 @@ void ImagePacksModel::reloadImages()
for (const auto &packKey : packs.keys()) {
if (const auto &pack = stickerRoom->currentState().get<ImagePackEvent>(packKey)) {
const auto packContent = pack->content();
if ((!packContent.pack || !packContent.pack->usage || (packContent.pack->usage->contains("emoticon"_ls) && showEmoticons())
|| (packContent.pack->usage->contains("sticker"_ls) && showStickers()))
if ((!packContent.pack || !packContent.pack->usage || (packContent.pack->usage->contains("emoticon") && showEmoticons())
|| (packContent.pack->usage->contains("sticker") && showStickers()))
&& !packContent.images.isEmpty()) {
m_events += packContent;
}
@@ -116,12 +115,12 @@ void ImagePacksModel::reloadImages()
}
// Load emoticons from the current room
auto events = m_room->currentState().eventsOfType("im.ponies.room_emotes"_ls);
auto events = m_room->currentState().eventsOfType("im.ponies.room_emotes");
for (const auto &event : events) {
auto packContent = eventCast<const ImagePackEvent>(event)->content();
if (packContent.pack.has_value()) {
if (!packContent.pack->usage || (packContent.pack->usage->contains("emoticon"_ls) && showEmoticons())
|| (packContent.pack->usage->contains("sticker"_ls) && showStickers())) {
if (!packContent.pack->usage || (packContent.pack->usage->contains("emoticon") && showEmoticons())
|| (packContent.pack->usage->contains("sticker") && showStickers())) {
m_events += packContent;
}
}

View File

@@ -78,7 +78,7 @@ QVariant LiveLocationsModel::data(const QModelIndex &index, int roleName) const
return longitude.toFloat();
}
case AssetRole:
return data.beaconInfo["org.matrix.msc3488.asset"_ls].toObject()["type"_ls].toString();
return data.beaconInfo["org.matrix.msc3488.asset"_ls].toObject()["type"].toString();
case AuthorRole:
return m_room->getUser(data.senderId);
case IsLiveRole: {
@@ -129,7 +129,7 @@ QRectF LiveLocationsModel::boundingBox() const
void LiveLocationsModel::addEvent(const Quotient::RoomEvent *event)
{
if (event->isStateEvent() && event->matrixType() == "org.matrix.msc3672.beacon_info"_ls) {
if (event->isStateEvent() && event->matrixType() == "org.matrix.msc3672.beacon_info") {
LiveLocationData data;
data.senderId = event->senderId();
data.beaconInfo = event->contentJson();

View File

@@ -15,7 +15,7 @@ LocationsModel::LocationsModel(QObject *parent)
if (!is<RoomMessageEvent>(*event)) {
continue;
}
if (event->contentJson()["msgtype"_ls] == "m.location"_ls) {
if (event->contentJson()["msgtype"] == "m.location") {
const auto &e = *event;
addLocation(eventCast<const RoomMessageEvent>(&e));
}
@@ -25,7 +25,7 @@ LocationsModel::LocationsModel(QObject *parent)
if (!is<RoomMessageEvent>(*event)) {
continue;
}
if (event->contentJson()["msgtype"_ls] == "m.location"_ls) {
if (event->contentJson()["msgtype"] == "m.location") {
const auto &e = *event;
addLocation(eventCast<const RoomMessageEvent>(&e));
}
@@ -36,7 +36,7 @@ LocationsModel::LocationsModel(QObject *parent)
if (!is<RoomMessageEvent>(*event)) {
continue;
}
if (event->contentJson()["msgtype"_ls] == "m.location"_ls) {
if (event->contentJson()["msgtype"] == "m.location") {
const auto &e = *event;
addLocation(eventCast<const RoomMessageEvent>(&e));
}
@@ -53,7 +53,7 @@ LocationsModel::LocationsModel(QObject *parent)
void LocationsModel::addLocation(const RoomMessageEvent *event)
{
const auto uri = event->contentJson()["org.matrix.msc3488.location"_ls]["uri"_ls].toString();
const auto uri = event->contentJson()["org.matrix.msc3488.location"]["uri"].toString();
const auto parts = uri.mid(4).split(QLatin1Char(','));
if (parts.size() < 2) {
qWarning() << "invalid geo: URI" << uri;

View File

@@ -25,7 +25,7 @@ QVariant MediaMessageFilterModel::data(const QModelIndex &index, int role) const
{
if (role == SourceRole) {
if (mapToSource(index).data(MessageEventModel::DelegateTypeRole).toInt() == MessageEventModel::DelegateType::Image) {
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QStringLiteral("source")].toUrl();
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()["source"].toUrl();
} else if (mapToSource(index).data(MessageEventModel::DelegateTypeRole).toInt() == MessageEventModel::DelegateType::Video) {
auto progressInfo = mapToSource(index).data(MessageEventModel::ProgressInfoRole).value<Quotient::FileTransferInfo>();
@@ -39,7 +39,7 @@ QVariant MediaMessageFilterModel::data(const QModelIndex &index, int role) const
}
}
if (role == TempSourceRole) {
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QStringLiteral("tempInfo")].toMap()[QStringLiteral("source")].toUrl();
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()["tempInfo"].toMap()["source"].toUrl();
}
if (role == TypeRole) {
if (mapToSource(index).data(MessageEventModel::DelegateTypeRole).toInt() == MessageEventModel::DelegateType::Image) {
@@ -52,10 +52,10 @@ QVariant MediaMessageFilterModel::data(const QModelIndex &index, int role) const
return mapToSource(index).data(Qt::DisplayRole);
}
if (role == SourceWidthRole) {
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QStringLiteral("width")].toFloat();
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()["width"].toFloat();
}
if (role == SourceHeightRole) {
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QStringLiteral("height")].toFloat();
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()["height"].toFloat();
}
return sourceModel()->data(mapToSource(index), role);

View File

@@ -20,7 +20,6 @@
#include <QDebug>
#include <QGuiApplication>
#include <QMovie>
#include <QTimeZone>
#include <KLocalizedString>
@@ -579,7 +578,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
if (isPending) {
// A pending event with an m.new_content key will be merged into the
// original event so don't show.
if (evt.contentJson().contains("m.new_content"_ls)) {
if (evt.contentJson().contains("m.new_content")) {
return EventStatus::Hidden;
}
return pendingIt->deliveryStatus();
@@ -668,11 +667,11 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
}
if (role == IsReplyRole) {
return !evt.contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString().isEmpty();
return !evt.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString().isEmpty();
}
if (role == ReplyIdRole) {
return evt.contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString();
return evt.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString();
}
if (role == ReplyAuthor) {
@@ -733,8 +732,8 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
}
return QVariantMap{
{"display"_ls, m_currentRoom->eventToString(*replyPtr, Qt::RichText)},
{"type"_ls, type},
{"display", m_currentRoom->eventToString(*replyPtr, Qt::RichText)},
{"type", type},
};
}
@@ -789,7 +788,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
}
if (role == AssetRole) {
const auto assetType = evt.contentJson()["org.matrix.msc3488.asset"_ls].toObject()["type"_ls].toString();
const auto assetType = evt.contentJson()["org.matrix.msc3488.asset"].toObject()["type"].toString();
if (assetType.isEmpty()) {
return {};
}
@@ -820,7 +819,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
userIds.remove(m_currentRoom->localUser()->id());
if (userIds.count() > 5) {
return QStringLiteral("+ %1").arg(userIds.count() - 5);
return QStringLiteral("+ ") + QString::number(userIds.count() - 5);
} else {
return QString();
}
@@ -866,11 +865,13 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
}
if (role == VerifiedRole) {
#ifdef Quotient_E2EE_ENABLED
if (evt.originalEvent()) {
auto encrypted = dynamic_cast<const EncryptedEvent *>(evt.originalEvent());
Q_ASSERT(encrypted);
return m_currentRoom->connection()->isVerifiedSession(encrypted->sessionId().toLatin1());
}
#endif
return false;
}
@@ -880,8 +881,8 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
}
if (role == AuthorDisplayNameRole) {
if (is<RoomMemberEvent>(evt) && !evt.unsignedJson()["prev_content"_ls]["displayname"_ls].isNull() && evt.stateKey() == evt.senderId()) {
auto previousDisplayName = evt.unsignedJson()["prev_content"_ls]["displayname"_ls].toString().toHtmlEscaped();
if (is<RoomMemberEvent>(evt) && !evt.unsignedJson()["prev_content"]["displayname"].isNull() && evt.stateKey() == evt.senderId()) {
auto previousDisplayName = evt.unsignedJson()["prev_content"]["displayname"].toString().toHtmlEscaped();
if (previousDisplayName.isEmpty()) {
previousDisplayName = evt.senderId();
}
@@ -943,79 +944,76 @@ QVariantMap MessageEventModel::getMediaInfoFromFileInfo(const EventContent::File
// Get the mxc URL for the media.
if (!fileInfo->url().isValid() || eventId.isEmpty()) {
mediaInfo["source"_ls] = QUrl();
mediaInfo["source"] = QUrl();
} else {
QUrl source = m_currentRoom->makeMediaUrl(eventId, fileInfo->url());
if (source.isValid() && source.scheme() == QStringLiteral("mxc")) {
mediaInfo["source"_ls] = source;
mediaInfo["source"] = source;
} else {
mediaInfo["source"_ls] = QUrl();
mediaInfo["source"] = QUrl();
}
}
auto mimeType = fileInfo->mimeType;
// Add the MIME type for the media if available.
mediaInfo["mimeType"_ls] = mimeType.name();
mediaInfo["mimeType"] = mimeType.name();
// Add the MIME type icon if available.
mediaInfo["mimeIcon"_ls] = mimeType.iconName();
mediaInfo["mimeIcon"] = mimeType.iconName();
// Add media size if available.
mediaInfo["size"_ls] = fileInfo->payloadSize;
mediaInfo["size"] = fileInfo->payloadSize;
// Add parameter depending on media type.
if (mimeType.name().contains(QStringLiteral("image"))) {
if (auto castInfo = static_cast<const EventContent::ImageContent *>(fileInfo)) {
mediaInfo["width"_ls] = castInfo->imageSize.width();
mediaInfo["height"_ls] = castInfo->imageSize.height();
// TODO: Images in certain formats (e.g. WebP) will be erroneously marked as animated, even if they are static.
mediaInfo["animated"_ls] = QMovie::supportedFormats().contains(mimeType.preferredSuffix().toUtf8());
mediaInfo["width"] = castInfo->imageSize.width();
mediaInfo["height"] = castInfo->imageSize.height();
if (!isThumbnail) {
QVariantMap tempInfo;
auto thumbnailInfo = getMediaInfoFromFileInfo(castInfo->thumbnailInfo(), eventId, true);
if (thumbnailInfo["source"_ls].toUrl().scheme() == "mxc"_ls) {
if (thumbnailInfo["source"].toUrl().scheme() == "mxc") {
tempInfo = thumbnailInfo;
} else {
QString blurhash = castInfo->originalInfoJson["xyz.amorgan.blurhash"_ls].toString();
QString blurhash = castInfo->originalInfoJson["xyz.amorgan.blurhash"].toString();
if (blurhash.isEmpty()) {
tempInfo["source"_ls] = QUrl();
tempInfo["source"] = QUrl();
} else {
tempInfo["source"_ls] = QUrl("image://blurhash/"_ls + blurhash);
tempInfo["source"] = QUrl("image://blurhash/" + blurhash);
}
}
mediaInfo["tempInfo"_ls] = tempInfo;
mediaInfo["tempInfo"] = tempInfo;
}
}
}
if (mimeType.name().contains(QStringLiteral("video"))) {
if (auto castInfo = static_cast<const EventContent::VideoContent *>(fileInfo)) {
mediaInfo["width"_ls] = castInfo->imageSize.width();
mediaInfo["height"_ls] = castInfo->imageSize.height();
mediaInfo["duration"_ls] = castInfo->duration;
mediaInfo["width"] = castInfo->imageSize.width();
mediaInfo["height"] = castInfo->imageSize.height();
mediaInfo["duration"] = castInfo->duration;
if (!isThumbnail) {
QVariantMap tempInfo;
auto thumbnailInfo = getMediaInfoFromFileInfo(castInfo->thumbnailInfo(), eventId, true);
if (thumbnailInfo["source"_ls].toUrl().scheme() == "mxc"_ls) {
if (thumbnailInfo["source"].toUrl().scheme() == "mxc") {
tempInfo = thumbnailInfo;
} else {
QString blurhash = castInfo->originalInfoJson["xyz.amorgan.blurhash"_ls].toString();
QString blurhash = castInfo->originalInfoJson["xyz.amorgan.blurhash"].toString();
if (blurhash.isEmpty()) {
tempInfo["source"_ls] = QUrl();
tempInfo["source"] = QUrl();
} else {
tempInfo["source"_ls] = QUrl("image://blurhash/"_ls + blurhash);
tempInfo["source"] = QUrl("image://blurhash/" + blurhash);
}
}
mediaInfo["tempInfo"_ls] = tempInfo;
mediaInfo["tempInfo"] = tempInfo;
}
}
}
if (mimeType.name().contains(QStringLiteral("audio"))) {
if (auto castInfo = static_cast<const EventContent::AudioContent *>(fileInfo)) {
mediaInfo["duration"_ls] = castInfo->duration;
mediaInfo["duration"] = castInfo->duration;
}
}

View File

@@ -25,7 +25,7 @@ void PublicRoomListModel::setConnection(Connection *conn)
beginResetModel();
nextBatch = QString();
nextBatch = "";
attempted = false;
rooms.clear();
m_server.clear();
@@ -41,7 +41,6 @@ void PublicRoomListModel::setConnection(Connection *conn)
if (job) {
job->abandon();
job = nullptr;
Q_EMIT loadingChanged();
}
if (m_connection) {
@@ -68,17 +67,15 @@ void PublicRoomListModel::setServer(const QString &value)
beginResetModel();
nextBatch = QString();
nextBatch = "";
attempted = false;
rooms.clear();
Q_EMIT loadingChanged();
endResetModel();
if (job) {
job->abandon();
job = nullptr;
Q_EMIT loadingChanged();
}
if (m_connection) {
@@ -104,7 +101,7 @@ void PublicRoomListModel::setKeyword(const QString &value)
beginResetModel();
nextBatch = QString();
nextBatch = "";
attempted = false;
rooms.clear();
@@ -113,7 +110,6 @@ void PublicRoomListModel::setKeyword(const QString &value)
if (job) {
job->abandon();
job = nullptr;
Q_EMIT loadingChanged();
}
if (m_connection) {
@@ -137,7 +133,6 @@ void PublicRoomListModel::next(int count)
}
job = m_connection->callApi<QueryPublicRoomsJob>(m_server, count, nextBatch, QueryPublicRoomsJob::Filter{m_keyword, {}});
Q_EMIT loadingChanged();
connect(job, &BaseJob::finished, this, [this] {
attempted = true;
@@ -155,7 +150,6 @@ void PublicRoomListModel::next(int count)
}
this->job = nullptr;
Q_EMIT loadingChanged();
});
}
@@ -192,7 +186,7 @@ QVariant PublicRoomListModel::data(const QModelIndex &index, int role) const
auto avatarUrl = room.avatarUrl;
if (avatarUrl.isEmpty()) {
return {};
return "";
}
return avatarUrl.url().remove(0, 6);
}
@@ -259,9 +253,4 @@ bool PublicRoomListModel::hasMore() const
return !(attempted && nextBatch.isEmpty());
}
bool PublicRoomListModel::loading() const
{
return job != nullptr;
}
#include "moc_publicroomlistmodel.cpp"

View File

@@ -48,11 +48,6 @@ class PublicRoomListModel : public QAbstractListModel
*/
Q_PROPERTY(bool hasMore READ hasMore NOTIFY hasMoreChanged)
/**
* @biref Whether the model is still loading.
*/
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
public:
/**
* @brief Defines the model roles.
@@ -103,8 +98,6 @@ public:
[[nodiscard]] bool hasMore() const;
[[nodiscard]] bool loading() const;
/**
* @brief Load the next set of rooms.
*
@@ -118,7 +111,6 @@ private:
QString m_keyword;
bool attempted = false;
bool m_loading = false;
QString nextBatch;
QVector<Quotient::PublicRoomsChunk> rooms;
@@ -130,5 +122,4 @@ Q_SIGNALS:
void serverChanged();
void keywordChanged();
void hasMoreChanged();
void loadingChanged();
};

View File

@@ -69,20 +69,18 @@ PushRuleModel::PushRuleModel(QObject *parent)
void PushRuleModel::controllerConnectionChanged()
{
if (Controller::instance().activeConnection()) {
connect(Controller::instance().activeConnection(), &Quotient::Connection::accountDataChanged, this, &PushRuleModel::updateNotificationRules);
updateNotificationRules(QStringLiteral("m.push_rules"));
}
connect(Controller::instance().activeConnection(), &Quotient::Connection::accountDataChanged, this, &PushRuleModel::updateNotificationRules);
updateNotificationRules("m.push_rules");
}
void PushRuleModel::updateNotificationRules(const QString &type)
{
if (type != QStringLiteral("m.push_rules")) {
if (type != "m.push_rules") {
return;
}
const QJsonObject ruleDataJson = Controller::instance().activeConnection()->accountDataJson(QStringLiteral("m.push_rules"));
const Quotient::PushRuleset ruleData = Quotient::fromJson<Quotient::PushRuleset>(ruleDataJson[QStringLiteral("global")].toObject());
const QJsonObject ruleDataJson = Controller::instance().activeConnection()->accountDataJson("m.push_rules");
const Quotient::PushRuleset ruleData = Quotient::fromJson<Quotient::PushRuleset>(ruleDataJson["global"].toObject());
beginResetModel();
m_rules.clear();
@@ -203,7 +201,7 @@ bool PushRuleModel::globalNotificationsEnabled() const
void PushRuleModel::setGlobalNotificationsEnabled(bool enabled)
{
setNotificationRuleEnabled(QStringLiteral("override"), QStringLiteral(".m.rule.master"), !enabled);
setNotificationRuleEnabled("override", ".m.rule.master", !enabled);
}
bool PushRuleModel::globalNotificationsSet() const
@@ -304,26 +302,26 @@ void PushRuleModel::addKeyword(const QString &keyword, const QString &roomId)
kind = PushNotificationKind::Override;
Quotient::PushCondition roomCondition;
roomCondition.kind = QStringLiteral("event_match");
roomCondition.key = QStringLiteral("room_id");
roomCondition.kind = "event_match";
roomCondition.key = "room_id";
roomCondition.pattern = roomId;
pushConditions.append(roomCondition);
Quotient::PushCondition keywordCondition;
keywordCondition.kind = QStringLiteral("event_match");
keywordCondition.key = QStringLiteral("content.body");
keywordCondition.kind = "event_match";
keywordCondition.key = "content.body";
keywordCondition.pattern = keyword;
pushConditions.append(keywordCondition);
}
auto job = Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleJob>(QLatin1String("global"),
auto job = Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleJob>("global",
PushNotificationKind::kindString(kind),
keyword,
actions,
QString(),
QString(),
QLatin1String(""),
QLatin1String(""),
pushConditions,
roomId.isEmpty() ? keyword : QString());
roomId.isEmpty() ? keyword : QLatin1String(""));
connect(job, &Quotient::BaseJob::failure, this, [job, keyword]() {
qWarning() << QLatin1String("Unable to set push rule for keyword %1: ").arg(keyword) << job->errorString();
});
@@ -342,7 +340,7 @@ void PushRuleModel::removeKeyword(const QString &keyword)
}
auto kind = PushNotificationKind::kindString(m_rules[index].kind);
auto job = Controller::instance().activeConnection()->callApi<Quotient::DeletePushRuleJob>(QStringLiteral("global"), kind, m_rules[index].id);
auto job = Controller::instance().activeConnection()->callApi<Quotient::DeletePushRuleJob>("global", kind, m_rules[index].id);
connect(job, &Quotient::BaseJob::failure, this, [this, job, index]() {
qWarning() << QLatin1String("Unable to remove push rule for keyword %1: ").arg(m_rules[index].id) << job->errorString();
});
@@ -350,10 +348,10 @@ void PushRuleModel::removeKeyword(const QString &keyword)
void PushRuleModel::setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled)
{
auto job = Controller::instance().activeConnection()->callApi<Quotient::IsPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId);
auto job = Controller::instance().activeConnection()->callApi<Quotient::IsPushRuleEnabledJob>("global", kind, ruleId);
connect(job, &Quotient::BaseJob::success, this, [job, kind, ruleId, enabled]() {
if (job->enabled() != enabled) {
Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId, enabled);
Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleEnabledJob>("global", kind, ruleId, enabled);
}
});
}
@@ -361,13 +359,13 @@ void PushRuleModel::setNotificationRuleEnabled(const QString &kind, const QStrin
void PushRuleModel::setNotificationRuleActions(const QString &kind, const QString &ruleId, PushNotificationAction::Action action)
{
QVector<QVariant> actions;
if (ruleId == QStringLiteral(".m.rule.call")) {
actions = actionToVariant(action, QStringLiteral("ring"));
if (ruleId == ".m.rule.call") {
actions = actionToVariant(action, "ring");
} else {
actions = actionToVariant(action);
}
Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleActionsJob>(QStringLiteral("global"), kind, ruleId, actions);
Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleActionsJob>("global", kind, ruleId, actions);
}
PushNotificationAction::Action PushRuleModel::variantToAction(const QVector<QVariant> &actions, bool enabled)
@@ -385,10 +383,10 @@ PushNotificationAction::Action PushRuleModel::variantToAction(const QVector<QVar
}
QJsonObject action = i.toJsonObject();
if (action[QStringLiteral("set_tweak")].toString() == QStringLiteral("sound")) {
if (action["set_tweak"].toString() == "sound") {
isNoisy = true;
} else if (action[QStringLiteral("set_tweak")].toString() == QStringLiteral("highlight")) {
if (action[QStringLiteral("value")].toString() != QStringLiteral("false")) {
} else if (action["set_tweak"].toString() == "highlight") {
if (action["value"].toString() != "false") {
highlightEnabled = true;
}
}
@@ -425,19 +423,19 @@ QVector<QVariant> PushRuleModel::actionToVariant(PushNotificationAction::Action
QVector<QVariant> actions;
if (action != PushNotificationAction::Off) {
actions.append(QStringLiteral("notify"));
actions.append("notify");
} else {
actions.append(QStringLiteral("dont_notify"));
actions.append("dont_notify");
}
if (action == PushNotificationAction::Noisy || action == PushNotificationAction::NoisyHighlight) {
QJsonObject soundTweak;
soundTweak.insert(QStringLiteral("set_tweak"), QStringLiteral("sound"));
soundTweak.insert(QStringLiteral("value"), sound);
soundTweak.insert("set_tweak", "sound");
soundTweak.insert("value", sound);
actions.append(soundTweak);
}
if (action == PushNotificationAction::Highlight || action == PushNotificationAction::NoisyHighlight) {
QJsonObject highlightTweak;
highlightTweak.insert(QStringLiteral("set_tweak"), QStringLiteral("highlight"));
highlightTweak.insert("set_tweak", "highlight");
actions.append(highlightTweak);
}

View File

@@ -236,6 +236,6 @@ private:
void setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled);
void setNotificationRuleActions(const QString &kind, const QString &ruleId, PushNotificationAction::Action action);
PushNotificationAction::Action variantToAction(const QVector<QVariant> &actions, bool enabled);
QVector<QVariant> actionToVariant(PushNotificationAction::Action action, const QString &sound = QStringLiteral("default"));
QVector<QVariant> actionToVariant(PushNotificationAction::Action action, const QString &sound = "default");
};
Q_DECLARE_METATYPE(PushRuleModel *)

View File

@@ -31,7 +31,7 @@ QVariant ReactionModel::data(const QModelIndex &index, int role) const
if (role == TextRole) {
if (reaction.authors.count() > 1) {
return QStringLiteral("%1 %2").arg(reaction.reaction, reaction.authors.count());
return reaction.reaction + QStringLiteral(" %1").arg(reaction.authors.count());
} else {
return reaction.reaction;
}
@@ -52,7 +52,7 @@ QVariant ReactionModel::data(const QModelIndex &index, int role) const
text += i18nc("Separate the usernames of users", " and ");
}
}
text += reaction.authors.at(i).toMap()[QStringLiteral("displayName")].toString();
text += reaction.authors.at(i).toMap()["displayName"].toString();
}
if (reaction.authors.count() > 3) {
@@ -74,7 +74,7 @@ QVariant ReactionModel::data(const QModelIndex &index, int role) const
if (role == HasLocalUser) {
for (auto author : reaction.authors) {
if (author.toMap()[QStringLiteral("id")] == m_localUser->id()) {
if (author.toMap()["id"] == m_localUser->id()) {
return true;
}
}

View File

@@ -40,19 +40,19 @@ RoomListModel::RoomListModel(QObject *parent)
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
#ifndef Q_OS_ANDROID
// copied from Telegram desktop
const auto launcherUrl = "application://org.kde.neochat.desktop"_ls;
const auto launcherUrl = "application://org.kde.neochat.desktop";
// Gnome requires that count is a 64bit integer
const qint64 counterSlice = std::min(m_notificationCount, 9999);
QVariantMap dbusUnityProperties;
if (counterSlice > 0) {
dbusUnityProperties["count"_ls] = counterSlice;
dbusUnityProperties["count-visible"_ls] = true;
dbusUnityProperties["count"] = counterSlice;
dbusUnityProperties["count-visible"] = true;
} else {
dbusUnityProperties["count-visible"_ls] = false;
dbusUnityProperties["count-visible"] = false;
}
auto signal = QDBusMessage::createSignal("/com/canonical/unity/launcherentry/neochat"_ls, "com.canonical.Unity.LauncherEntry"_ls, "Update"_ls);
auto signal = QDBusMessage::createSignal("/com/canonical/unity/launcherentry/neochat", "com.canonical.Unity.LauncherEntry", "Update");
signal.setArguments({launcherUrl, dbusUnityProperties});
@@ -297,9 +297,9 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const
return NeoChatRoomType::Normal;
}
QJsonObject contentJson = creationEvent->contentJson();
QJsonObject::const_iterator typeIter = contentJson.find("type"_ls);
QJsonObject::const_iterator typeIter = contentJson.find("type");
if (typeIter != contentJson.end()) {
if (typeIter.value().toString() == "m.space"_ls) {
if (typeIter.value().toString() == "m.space") {
return NeoChatRoomType::Space;
}
}
@@ -400,7 +400,7 @@ QString RoomListModel::categoryName(int category)
case NeoChatRoomType::Space:
return i18n("Spaces");
default:
return {};
return "Deadbeef";
}
}

View File

@@ -163,7 +163,7 @@ private:
QMap<int, bool> m_categoryVisibility;
int m_notificationCount = 0;
QString m_activeSpaceId;
QString m_activeSpaceId = "";
void connectRoomSignals(NeoChatRoom *room);

View File

@@ -57,7 +57,7 @@ void SearchModel::search()
.searchTerm = m_searchText,
.keys = {},
.filter = filter,
.orderBy = "recent"_ls,
.orderBy = "recent",
.eventContext = SearchJob::IncludeEventContext{3, 3, true},
.includeState = false,
.groupings = none,
@@ -157,8 +157,8 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const
}
return QVariantMap{
{"display"_ls, m_room->eventToString(*replyPtr, Qt::RichText)},
{"type"_ls, type},
{"display", m_room->eventToString(*replyPtr, Qt::RichText)},
{"type", type},
};
}
case IsPendingRole:
@@ -166,13 +166,13 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const
case ShowLinkPreviewRole:
return false;
case IsReplyRole:
return !event.contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString().isEmpty();
return !event.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString().isEmpty();
case HighlightRole:
return !m_room->isDirectChat() && m_room->isEventHighlighted(&event);
case EventIdRole:
return event.id();
case ReplyIdRole:
return event.contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString();
return event.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString();
}
return MessageEventModel::DelegateType::Message;
}
@@ -261,7 +261,7 @@ QString renderDate(const QDateTime &timestamp)
return i18n("The day before yesterday");
}
if (date > QDate::currentDate().addDays(-7)) {
return date.toString("dddd"_ls);
return date.toString("dddd");
}
return QLocale::system().toString(date, QLocale::ShortFormat);

View File

@@ -15,8 +15,8 @@
ServerListModel::ServerListModel(QObject *parent)
: QAbstractListModel(parent)
{
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
KConfig dataResource("data", KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup serverGroup(&dataResource, "Servers");
QString domain = Controller::instance().activeConnection()->domain();
@@ -91,8 +91,8 @@ int ServerListModel::rowCount(const QModelIndex &parent) const
void ServerListModel::checkServer(const QString &url)
{
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
KConfig dataResource("data", KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup serverGroup(&dataResource, "Servers");
if (!serverGroup.hasKey(url)) {
if (Quotient::isJobPending(m_checkServerJob)) {
@@ -108,8 +108,8 @@ void ServerListModel::checkServer(const QString &url)
void ServerListModel::addServer(const QString &url)
{
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
KConfig dataResource("data", KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup serverGroup(&dataResource, "Servers");
if (!serverGroup.hasKey(url)) {
Server newServer = Server{
@@ -129,8 +129,8 @@ void ServerListModel::addServer(const QString &url)
void ServerListModel::removeServerAtIndex(int row)
{
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
KConfig dataResource("data", KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup serverGroup(&dataResource, "Servers");
serverGroup.deleteEntry(data(index(row), UrlRole).toString());
beginRemoveRows(QModelIndex(), row, row);

View File

@@ -80,7 +80,7 @@ bool SortFilterRoomListModel::filterAcceptsRow(int source_row, const QModelIndex
bool acceptRoom =
sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::DisplayNameRole).toString().contains(m_filterText, Qt::CaseInsensitive)
&& sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::JoinStateRole).toString() != QStringLiteral("upgraded")
&& sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::JoinStateRole).toString() != "upgraded"
&& sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::IsSpaceRole).toBool() == false;
if (m_activeSpaceId.isEmpty()) {

View File

@@ -27,7 +27,7 @@ bool SortFilterSpaceListModel::filterAcceptsRow(int source_row, const QModelInde
{
Q_UNUSED(source_parent);
return sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::IsSpaceRole).toBool()
&& sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::JoinStateRole).toString() != QStringLiteral("upgraded")
&& sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::JoinStateRole).toString() != "upgraded"
&& !sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::IsChildSpaceRole).toBool();
}

View File

@@ -26,7 +26,8 @@ QVariant StateModel::data(const QModelIndex &index, int role) const
int StateModel::rowCount(const QModelIndex &parent) const
{
return !m_room || parent.isValid() ? 0 : m_room->currentState().events().size();
Q_UNUSED(parent);
return m_room->currentState().events().size();
}
NeoChatRoom *StateModel::room() const
@@ -36,12 +37,8 @@ NeoChatRoom *StateModel::room() const
void StateModel::setRoom(NeoChatRoom *room)
{
if (m_room == room) {
return;
}
m_room = room;
Q_EMIT roomChanged();
beginResetModel();
m_stateEvents.clear();
m_stateEvents = m_room->currentState().events().keys();

View File

@@ -112,10 +112,10 @@ void StickerModel::postSticker(int index)
const auto &body = image.body ? *image.body : QString();
QJsonObject infoJson;
if (image.info) {
infoJson["w"_ls] = image.info->imageSize.width();
infoJson["h"_ls] = image.info->imageSize.height();
infoJson["mimetype"_ls] = image.info->mimeType.name();
infoJson["size"_ls] = image.info->payloadSize;
infoJson["w"] = image.info->imageSize.width();
infoJson["h"] = image.info->imageSize.height();
infoJson["mimetype"] = image.info->mimeType.name();
infoJson["size"] = image.info->payloadSize;
// TODO thumbnail
}
QJsonObject content{
@@ -123,7 +123,7 @@ void StickerModel::postSticker(int index)
{"url"_ls, image.url.toString()},
{"info"_ls, infoJson},
};
m_room->postJson("m.sticker"_ls, content);
m_room->postJson("m.sticker", content);
}
#include "moc_stickermodel.cpp"

View File

@@ -138,7 +138,7 @@ QVariant UserDirectoryListModel::data(const QModelIndex &index, int role) const
return displayName;
}
return QStringLiteral("Unknown User");
return "Unknown User";
}
if (role == AvatarRole) {
auto avatarUrl = user.avatarUrl;

View File

@@ -163,19 +163,17 @@ void UserListModel::refreshAllUsers()
}
m_users.clear();
if (m_currentRoom != nullptr) {
m_users = m_currentRoom->users();
std::sort(m_users.begin(), m_users.end(), m_currentRoom->memberSorter());
m_users = m_currentRoom->users();
std::sort(m_users.begin(), m_users.end(), m_currentRoom->memberSorter());
for (User *user : std::as_const(m_users)) {
connect(user, &User::defaultAvatarChanged, this, [this, user]() {
refreshUser(user, {AvatarRole});
});
}
connect(m_currentRoom->connection(), &Connection::loggedOut, this, [this]() {
setRoom(nullptr);
for (User *user : std::as_const(m_users)) {
connect(user, &User::defaultAvatarChanged, this, [this, user]() {
refreshUser(user, {AvatarRole});
});
}
connect(m_currentRoom->connection(), &Connection::loggedOut, this, [this]() {
setRoom(nullptr);
});
endResetModel();
Q_EMIT usersRefreshed();
}

View File

@@ -62,7 +62,7 @@ void KWebShortcutModel::setSelectedText(const QString &selectedText)
}
QString searchText = selectedText;
searchText = searchText.replace(QLatin1Char('\n'), QLatin1Char(' ')).replace(QLatin1Char('\r'), QLatin1Char(' ')).simplified();
searchText = searchText.replace('\n', ' ').replace('\r', ' ').simplified();
if (searchText.isEmpty()) {
endResetModel();
return;
@@ -115,7 +115,7 @@ void KWebShortcutModel::trigger(const QString &data)
#ifdef HAVE_KIO
KUriFilterData filterData(data);
if (KUriFilter::self()->filterSearchUri(filterData, KUriFilter::WebShortcutFilter)) {
Q_EMIT openUrl(filterData.uri());
Q_EMIT openUrl(filterData.uri().url());
}
#else
Q_UNUSED(data);
@@ -125,7 +125,7 @@ void KWebShortcutModel::trigger(const QString &data)
void KWebShortcutModel::configureWebShortcuts()
{
#ifdef HAVE_KIO
auto job = new KIO::CommandLauncherJob(QStringLiteral("kcmshell5"), QStringList() << QStringLiteral("webshortcuts"), this);
auto job = new KIO::CommandLauncherJob("kcmshell5", QStringList() << "webshortcuts", this);
job->exec();
#endif
}

View File

@@ -70,8 +70,8 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
connect(this, &Room::aboutToAddHistoricalMessages, this, &NeoChatRoom::readMarkerLoadedChanged);
// Load cached event if available.
KConfig dataResource("data"_ls, KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup eventCacheGroup(&dataResource, "EventCache"_ls);
KConfig dataResource("data", KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup eventCacheGroup(&dataResource, "EventCache");
if (eventCacheGroup.hasKey(id())) {
auto eventJson = QJsonDocument::fromJson(eventCacheGroup.readEntry(id(), QByteArray())).object();
@@ -121,7 +121,7 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
Q_EMIT defaultUrlPreviewStateChanged();
});
connect(this, &Room::accountDataChanged, this, [this](QString type) {
if (type == "org.matrix.room.preview_urls"_ls) {
if (type == "org.matrix.room.preview_urls") {
Q_EMIT urlPreviewEnabledChanged();
}
});
@@ -167,15 +167,15 @@ QCoro::Task<void> NeoChatRoom::doUploadFile(QUrl url, QString body)
}
auto mime = QMimeDatabase().mimeTypeForUrl(url);
url.setScheme("file"_ls);
url.setScheme("file");
QFileInfo fileInfo(url.isLocalFile() ? url.toLocalFile() : url.toString());
EventContent::TypedBase *content;
if (mime.name().startsWith("image/"_ls)) {
if (mime.name().startsWith("image/")) {
QImage image(url.toLocalFile());
content = new EventContent::ImageContent(url, fileInfo.size(), mime, image.size(), fileInfo.fileName());
} else if (mime.name().startsWith("audio/"_ls)) {
} else if (mime.name().startsWith("audio/")) {
content = new EventContent::AudioContent(url, fileInfo.size(), mime, fileInfo.fileName());
} else if (mime.name().startsWith("video/"_ls)) {
} else if (mime.name().startsWith("video/")) {
QMediaPlayer player;
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
player.setSource(url);
@@ -238,10 +238,10 @@ QVariantList NeoChatRoom::getUsersTyping() const
QVariantList userVariants;
for (User *user : users) {
userVariants.append(QVariantMap{
{"id"_ls, user->id()},
{"avatarMediaId"_ls, user->avatarMediaId(this)},
{"displayName"_ls, user->displayname(this)},
{"display"_ls, user->name()},
{"id", user->id()},
{"avatarMediaId", user->avatarMediaId(this)},
{"displayName", user->displayname(this)},
{"display", user->name()},
});
}
return userVariants;
@@ -314,8 +314,8 @@ void NeoChatRoom::cacheLastEvent()
{
auto event = lastEvent();
if (event != nullptr) {
KConfig dataResource("data"_ls, KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup eventCacheGroup(&dataResource, "EventCache"_ls);
KConfig dataResource("data", KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
KConfigGroup eventCacheGroup(&dataResource, "EventCache");
auto eventJson = QJsonDocument(event->fullJson()).toJson();
eventCacheGroup.writeEntry(id(), eventJson);
@@ -332,9 +332,9 @@ bool NeoChatRoom::lastEventIsSpoiler() const
{
if (auto event = lastEvent()) {
if (auto e = eventCast<const RoomMessageEvent>(event)) {
if (e->hasTextContent() && e->content() && e->mimeType().name() == "text/html"_ls) {
if (e->hasTextContent() && e->content() && e->mimeType().name() == "text/html") {
auto htmlBody = static_cast<const Quotient::EventContent::TextContent *>(e->content())->body;
return htmlBody.contains("data-mx-spoiler"_ls);
return htmlBody.contains("data-mx-spoiler");
}
}
}
@@ -435,13 +435,13 @@ QVariantList NeoChatRoom::getUsers(const QString &keyword, int limit) const
// An empty user is useful for returning as a model value to avoid properties being undefined.
static const QVariantMap emptyUser = {
{"isLocalUser"_ls, false},
{"id"_ls, QString()},
{"displayName"_ls, QString()},
{"avatarSource"_ls, QUrl()},
{"avatarMediaId"_ls, QString()},
{"color"_ls, QColor()},
{"object"_ls, QVariant()},
{"isLocalUser", false},
{"id", QString()},
{"displayName", QString()},
{"avatarSource", QUrl()},
{"avatarMediaId", QString()},
{"color", QColor()},
{"object", QVariant()},
};
QVariantMap NeoChatRoom::getUser(const QString &userID) const
@@ -500,7 +500,7 @@ QString NeoChatRoom::eventToString(const RoomEvent &evt, Qt::TextFormat format,
if (fileCaption.isEmpty()) {
fileCaption = e.plainBody();
} else if (e.content()->fileInfo()->originalName != e.plainBody()) {
fileCaption = e.plainBody() + " | "_ls + fileCaption;
fileCaption = e.plainBody() + " | " + fileCaption;
}
textHandler.setData(fileCaption);
return !fileCaption.isEmpty() ? textHandler.handleRecievePlainText(Qt::PlainText, stripNewlines) : i18n("a file");
@@ -516,7 +516,7 @@ QString NeoChatRoom::eventToString(const RoomEvent &evt, Qt::TextFormat format,
textHandler.setData(body);
Qt::TextFormat inputFormat;
if (e.mimeType().name() == "text/plain"_ls) {
if (e.mimeType().name() == "text/plain") {
inputFormat = Qt::PlainText;
} else {
inputFormat = Qt::RichText;
@@ -644,8 +644,8 @@ QString NeoChatRoom::eventToString(const RoomEvent &evt, Qt::TextFormat format,
return i18n("activated End-to-End Encryption");
},
[](const RoomCreateEvent &e) {
return e.isUpgrade() ? i18n("upgraded the room to version %1", e.version().isEmpty() ? "1"_ls : e.version().toHtmlEscaped())
: i18n("created the room, version %1", e.version().isEmpty() ? "1"_ls : e.version().toHtmlEscaped());
return e.isUpgrade() ? i18n("upgraded the room to version %1", e.version().isEmpty() ? "1" : e.version().toHtmlEscaped())
: i18n("created the room, version %1", e.version().isEmpty() ? "1" : e.version().toHtmlEscaped());
},
[](const RoomPowerLevelsEvent &) {
return i18nc("'power level' means permission level", "changed the power levels for this room");
@@ -655,13 +655,13 @@ QString NeoChatRoom::eventToString(const RoomEvent &evt, Qt::TextFormat format,
return i18n("changed the server access control lists for this room");
}
if (e.matrixType() == QLatin1String("im.vector.modular.widgets")) {
if (e.fullJson()["unsigned"_ls]["prev_content"_ls].toObject().isEmpty()) {
return i18nc("[User] added <name> widget", "added %1 widget", e.contentJson()["name"_ls].toString());
if (e.fullJson()["unsigned"]["prev_content"].toObject().isEmpty()) {
return i18nc("[User] added <name> widget", "added %1 widget", e.contentJson()["name"].toString());
}
if (e.contentJson().isEmpty()) {
return i18nc("[User] removed <name> widget", "removed %1 widget", e.fullJson()["unsigned"_ls]["prev_content"_ls]["name"_ls].toString());
return i18nc("[User] removed <name> widget", "removed %1 widget", e.fullJson()["unsigned"]["prev_content"]["name"].toString());
}
return i18nc("[User] configured <name> widget", "configured %1 widget", e.contentJson()["name"_ls].toString());
return i18nc("[User] configured <name> widget", "configured %1 widget", e.contentJson()["name"].toString());
}
if (e.matrixType() == "org.matrix.msc3672.beacon_info"_ls) {
return e.contentJson()["description"_ls].toString();
@@ -778,7 +778,7 @@ QString NeoChatRoom::eventToGenericString(const RoomEvent &evt) const
return i18n("changed the server access control lists for this room");
}
if (e.matrixType() == QLatin1String("im.vector.modular.widgets")) {
if (e.fullJson()["unsigned"_ls]["prev_content"_ls].toObject().isEmpty()) {
if (e.fullJson()["unsigned"]["prev_content"].toObject().isEmpty()) {
return i18n("added a widget");
}
if (e.contentJson().isEmpty()) {
@@ -800,7 +800,7 @@ void NeoChatRoom::changeAvatar(const QUrl &localFile)
const auto job = connection()->uploadFile(localFile.toLocalFile());
if (isJobPending(job)) {
connect(job, &BaseJob::success, this, [this, job] {
connection()->callApi<SetRoomStateWithKeyJob>(id(), "m.room.avatar"_ls, QString(), QJsonObject{{"url"_ls, job->contentUri().toString()}});
connection()->callApi<SetRoomStateWithKeyJob>(id(), "m.room.avatar", QString(), QJsonObject{{"url", job->contentUri().toString()}});
});
}
}
@@ -809,23 +809,23 @@ QString msgTypeToString(MessageEventType msgType)
{
switch (msgType) {
case MessageEventType::Text:
return "m.text"_ls;
return "m.text";
case MessageEventType::File:
return "m.file"_ls;
return "m.file";
case MessageEventType::Audio:
return "m.audio"_ls;
return "m.audio";
case MessageEventType::Emote:
return "m.emote"_ls;
return "m.emote";
case MessageEventType::Image:
return "m.image"_ls;
return "m.image";
case MessageEventType::Video:
return "m.video"_ls;
return "m.video";
case MessageEventType::Notice:
return "m.notice"_ls;
return "m.notice";
case MessageEventType::Location:
return "m.location"_ls;
return "m.location";
default:
return "m.text"_ls;
return "m.text";
}
}
@@ -845,16 +845,15 @@ void NeoChatRoom::postHtmlMessage(const QString &text, const QString &html, Mess
if (isEdit) {
QJsonObject json{
{"type"_ls, "m.room.message"_ls},
{"msgtype"_ls, msgTypeToString(type)},
{"body"_ls, "* %1"_ls.arg(text)},
{"format"_ls, "org.matrix.custom.html"_ls},
{"formatted_body"_ls, html},
{"m.new_content"_ls,
QJsonObject{{"body"_ls, text}, {"msgtype"_ls, msgTypeToString(type)}, {"format"_ls, "org.matrix.custom.html"_ls}, {"formatted_body"_ls, html}}},
{"m.relates_to"_ls, QJsonObject{{"rel_type"_ls, "m.replace"_ls}, {"event_id"_ls, relateToEventId}}}};
{"type", "m.room.message"},
{"msgtype", msgTypeToString(type)},
{"body", "* " + text},
{"format", "org.matrix.custom.html"},
{"formatted_body", html},
{"m.new_content", QJsonObject{{"body", text}, {"msgtype", msgTypeToString(type)}, {"format", "org.matrix.custom.html"}, {"formatted_body", html}}},
{"m.relates_to", QJsonObject{{"rel_type", "m.replace"}, {"event_id", relateToEventId}}}};
postJson("m.room.message"_ls, json);
postJson("m.room.message", json);
return;
}
@@ -863,25 +862,31 @@ void NeoChatRoom::postHtmlMessage(const QString &text, const QString &html, Mess
// clang-format off
QJsonObject json{
{"msgtype"_ls, msgTypeToString(type)},
{"body"_ls, "> <%1> %2\n\n%3"_ls.arg(replyEvt.senderId(), eventToString(replyEvt), text)},
{"format"_ls, "org.matrix.custom.html"_ls},
{"m.relates_to"_ls,
{"msgtype", msgTypeToString(type)},
{"body", "> <" + replyEvt.senderId() + "> " + eventToString(replyEvt) + "\n\n" + text},
{"format", "org.matrix.custom.html"},
{"m.relates_to",
QJsonObject {
{"m.in_reply_to"_ls,
{"m.in_reply_to",
QJsonObject {
{"event_id"_ls, replyEventId}
{"event_id", replyEventId}
}
}
}
},
{"formatted_body"_ls,
"<mx-reply><blockquote><a href=\"https://matrix.to/#/%1/%2\">In reply to</a> <a href=\"https://matrix.to/#/%3\">%4</a><br>%5</blockquote></mx-reply>%6"_ls.arg(id(), replyEventId, replyEvt.senderId(), replyEvt.senderId(), eventToString(replyEvt, Qt::RichText), html)
{"formatted_body",
"<mx-reply><blockquote><a href=\"https://matrix.to/#/" +
id() + "/" +
replyEventId +
"\">In reply to</a> <a href=\"https://matrix.to/#/" +
replyEvt.senderId() + "\">" + replyEvt.senderId() +
"</a><br>" + eventToString(replyEvt, Qt::RichText) +
"</blockquote></mx-reply>" + html
}
};
// clang-format on
postJson("m.room.message"_ls, json);
postJson("m.room.message", json);
return;
}
@@ -999,37 +1004,37 @@ QString NeoChatRoom::joinRule() const
void NeoChatRoom::setJoinRule(const QString &joinRule)
{
if (!canSendState("m.room.join_rules"_ls)) {
if (!canSendState("m.room.join_rules")) {
qWarning() << "Power level too low to set join rules";
return;
}
setState("m.room.join_rules"_ls, {}, QJsonObject{{"join_rule"_ls, joinRule}});
setState("m.room.join_rules", "", QJsonObject{{"join_rule", joinRule}});
// Not emitting joinRuleChanged() here, since that would override the change in the UI with the *current* value, which is not the *new* value.
}
QString NeoChatRoom::historyVisibility() const
{
return currentState().get("m.room.history_visibility"_ls)->contentJson()["history_visibility"_ls].toString();
return currentState().get("m.room.history_visibility")->contentJson()["history_visibility"_ls].toString();
}
void NeoChatRoom::setHistoryVisibility(const QString &historyVisibilityRule)
{
if (!canSendState("m.room.history_visibility"_ls)) {
if (!canSendState("m.room.history_visibility")) {
qWarning() << "Power level too low to set history visibility";
return;
}
setState("m.room.history_visibility"_ls, {}, QJsonObject{{"history_visibility"_ls, historyVisibilityRule}});
setState("m.room.history_visibility", "", QJsonObject{{"history_visibility", historyVisibilityRule}});
// Not emitting historyVisibilityChanged() here, since that would override the change in the UI with the *current* value, which is not the *new* value.
}
bool NeoChatRoom::defaultUrlPreviewState() const
{
auto urlPreviewsDisabled = currentState().get("org.matrix.room.preview_urls"_ls);
auto urlPreviewsDisabled = currentState().get("org.matrix.room.preview_urls");
// Some rooms will not have this state event set so check for a nullptr return.
if (urlPreviewsDisabled != nullptr) {
return !urlPreviewsDisabled->contentJson()["disable"_ls].toBool();
return !urlPreviewsDisabled->contentJson()["disable"].toBool();
} else {
return false;
}
@@ -1037,7 +1042,7 @@ bool NeoChatRoom::defaultUrlPreviewState() const
void NeoChatRoom::setDefaultUrlPreviewState(const bool &defaultUrlPreviewState)
{
if (!canSendState("org.matrix.room.preview_urls"_ls)) {
if (!canSendState("org.matrix.room.preview_urls")) {
qWarning() << "Power level too low to set the default URL preview state for the room";
return;
}
@@ -1071,13 +1076,13 @@ void NeoChatRoom::setDefaultUrlPreviewState(const bool &defaultUrlPreviewState)
*
* You just have to set disable to true to disable URL previews by default.
*/
setState("org.matrix.room.preview_urls"_ls, {}, QJsonObject{{"disable"_ls, !defaultUrlPreviewState}});
setState("org.matrix.room.preview_urls", "", QJsonObject{{"disable", !defaultUrlPreviewState}});
}
bool NeoChatRoom::urlPreviewEnabled() const
{
if (hasAccountData("org.matrix.room.preview_urls"_ls)) {
return !accountData("org.matrix.room.preview_urls"_ls)->contentJson()["disable"_ls].toBool();
if (hasAccountData("org.matrix.room.preview_urls")) {
return !accountData("org.matrix.room.preview_urls")->contentJson()["disable"].toBool();
} else {
return defaultUrlPreviewState();
}
@@ -1096,10 +1101,7 @@ void NeoChatRoom::setUrlPreviewEnabled(const bool &urlPreviewEnabled)
* "type": "org.matrix.room.preview_urls",
* }
*/
connection()->callApi<SetAccountDataPerRoomJob>(localUser()->id(),
id(),
"org.matrix.room.preview_urls"_ls,
QJsonObject{{"disable"_ls, !urlPreviewEnabled}});
connection()->callApi<SetAccountDataPerRoomJob>(localUser()->id(), id(), "org.matrix.room.preview_urls", QJsonObject{{"disable", !urlPreviewEnabled}});
}
void NeoChatRoom::setUserPowerLevel(const QString &userID, const int &powerLevel)
@@ -1108,7 +1110,7 @@ void NeoChatRoom::setUserPowerLevel(const QString &userID, const int &powerLevel
qWarning() << "Cannot modify the power level of the only user";
return;
}
if (!canSendState("m.room.power_levels"_ls)) {
if (!canSendState("m.room.power_levels")) {
qWarning() << "Power level too low to set user power levels";
return;
}
@@ -1118,14 +1120,14 @@ void NeoChatRoom::setUserPowerLevel(const QString &userID, const int &powerLevel
}
int clampPowerLevel = std::clamp(powerLevel, 0, 100);
auto powerLevelContent = currentState().get("m.room.power_levels"_ls)->contentJson();
auto powerLevelUserOverrides = powerLevelContent["users"_ls].toObject();
auto powerLevelContent = currentState().get("m.room.power_levels")->contentJson();
auto powerLevelUserOverrides = powerLevelContent["users"].toObject();
if (powerLevelUserOverrides[userID] != clampPowerLevel) {
powerLevelUserOverrides[userID] = clampPowerLevel;
powerLevelContent["users"_ls] = powerLevelUserOverrides;
powerLevelContent["users"] = powerLevelUserOverrides;
setState("m.room.power_levels"_ls, {}, powerLevelContent);
setState("m.room.power_levels", "", powerLevelContent);
}
}
@@ -1141,19 +1143,19 @@ int NeoChatRoom::getUserPowerLevel(const QString &userId) const
int NeoChatRoom::powerLevel(const QString &eventName, const bool &isStateEvent) const
{
const auto powerLevelEvent = currentState().get<RoomPowerLevelsEvent>();
if (eventName == "ban"_ls) {
if (eventName == "ban") {
return powerLevelEvent->ban();
} else if (eventName == "kick"_ls) {
} else if (eventName == "kick") {
return powerLevelEvent->kick();
} else if (eventName == "invite"_ls) {
} else if (eventName == "invite") {
return powerLevelEvent->invite();
} else if (eventName == "redact"_ls) {
} else if (eventName == "redact") {
return powerLevelEvent->redact();
} else if (eventName == "users_default"_ls) {
} else if (eventName == "users_default") {
return powerLevelEvent->usersDefault();
} else if (eventName == "state_default"_ls) {
} else if (eventName == "state_default") {
return powerLevelEvent->stateDefault();
} else if (eventName == "events_default"_ls) {
} else if (eventName == "events_default") {
return powerLevelEvent->eventsDefault();
} else if (isStateEvent) {
return powerLevelEvent->powerLevelForState(eventName);
@@ -1164,7 +1166,7 @@ int NeoChatRoom::powerLevel(const QString &eventName, const bool &isStateEvent)
void NeoChatRoom::setPowerLevel(const QString &eventName, const int &newPowerLevel, const bool &isStateEvent)
{
auto powerLevelContent = currentState().get("m.room.power_levels"_ls)->contentJson();
auto powerLevelContent = currentState().get("m.room.power_levels")->contentJson();
int clampPowerLevel = std::clamp(newPowerLevel, 0, 100);
int powerLevel = 0;
@@ -1175,215 +1177,215 @@ void NeoChatRoom::setPowerLevel(const QString &eventName, const int &newPowerLev
powerLevelContent[eventName] = clampPowerLevel;
}
} else {
auto eventPowerLevels = powerLevelContent["events"_ls].toObject();
auto eventPowerLevels = powerLevelContent["events"].toObject();
if (eventPowerLevels.contains(eventName)) {
powerLevel = eventPowerLevels[eventName].toInt();
} else {
if (isStateEvent) {
powerLevel = powerLevelContent["state_default"_ls].toInt();
powerLevel = powerLevelContent["state_default"].toInt();
} else {
powerLevel = powerLevelContent["events_default"_ls].toInt();
powerLevel = powerLevelContent["events_default"].toInt();
}
}
if (powerLevel != clampPowerLevel) {
eventPowerLevels[eventName] = clampPowerLevel;
powerLevelContent["events"_ls] = eventPowerLevels;
powerLevelContent["events"] = eventPowerLevels;
}
}
setState("m.room.power_levels"_ls, {}, powerLevelContent);
setState("m.room.power_levels", "", powerLevelContent);
}
int NeoChatRoom::defaultUserPowerLevel() const
{
return powerLevel("users_default"_ls);
return powerLevel("users_default");
}
void NeoChatRoom::setDefaultUserPowerLevel(const int &newPowerLevel)
{
setPowerLevel("users_default"_ls, newPowerLevel);
setPowerLevel("users_default", newPowerLevel);
}
int NeoChatRoom::invitePowerLevel() const
{
return powerLevel("invite"_ls);
return powerLevel("invite");
}
void NeoChatRoom::setInvitePowerLevel(const int &newPowerLevel)
{
setPowerLevel("invite"_ls, newPowerLevel);
setPowerLevel("invite", newPowerLevel);
}
int NeoChatRoom::kickPowerLevel() const
{
return powerLevel("kick"_ls);
return powerLevel("kick");
}
void NeoChatRoom::setKickPowerLevel(const int &newPowerLevel)
{
setPowerLevel("kick"_ls, newPowerLevel);
setPowerLevel("kick", newPowerLevel);
}
int NeoChatRoom::banPowerLevel() const
{
return powerLevel("ban"_ls);
return powerLevel("ban");
}
void NeoChatRoom::setBanPowerLevel(const int &newPowerLevel)
{
setPowerLevel("ban"_ls, newPowerLevel);
setPowerLevel("ban", newPowerLevel);
}
int NeoChatRoom::redactPowerLevel() const
{
return powerLevel("redact"_ls);
return powerLevel("redact");
}
void NeoChatRoom::setRedactPowerLevel(const int &newPowerLevel)
{
setPowerLevel("redact"_ls, newPowerLevel);
setPowerLevel("redact", newPowerLevel);
}
int NeoChatRoom::statePowerLevel() const
{
return powerLevel("state_default"_ls);
return powerLevel("state_default");
}
void NeoChatRoom::setStatePowerLevel(const int &newPowerLevel)
{
setPowerLevel("state_default"_ls, newPowerLevel);
setPowerLevel("state_default", newPowerLevel);
}
int NeoChatRoom::defaultEventPowerLevel() const
{
return powerLevel("events_default"_ls);
return powerLevel("events_default");
}
void NeoChatRoom::setDefaultEventPowerLevel(const int &newPowerLevel)
{
setPowerLevel("events_default"_ls, newPowerLevel);
setPowerLevel("events_default", newPowerLevel);
}
int NeoChatRoom::powerLevelPowerLevel() const
{
return powerLevel("m.room.power_levels"_ls, true);
return powerLevel("m.room.power_levels", true);
}
void NeoChatRoom::setPowerLevelPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.power_levels"_ls, newPowerLevel, true);
setPowerLevel("m.room.power_levels", newPowerLevel, true);
}
int NeoChatRoom::namePowerLevel() const
{
return powerLevel("m.room.name"_ls, true);
return powerLevel("m.room.name", true);
}
void NeoChatRoom::setNamePowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.name"_ls, newPowerLevel, true);
setPowerLevel("m.room.name", newPowerLevel, true);
}
int NeoChatRoom::avatarPowerLevel() const
{
return powerLevel("m.room.avatar"_ls, true);
return powerLevel("m.room.avatar", true);
}
void NeoChatRoom::setAvatarPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.avatar"_ls, newPowerLevel, true);
setPowerLevel("m.room.avatar", newPowerLevel, true);
}
int NeoChatRoom::canonicalAliasPowerLevel() const
{
return powerLevel("m.room.canonical_alias"_ls, true);
return powerLevel("m.room.canonical_alias", true);
}
void NeoChatRoom::setCanonicalAliasPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.canonical_alias"_ls, newPowerLevel, true);
setPowerLevel("m.room.canonical_alias", newPowerLevel, true);
}
int NeoChatRoom::topicPowerLevel() const
{
return powerLevel("m.room.topic"_ls, true);
return powerLevel("m.room.topic", true);
}
void NeoChatRoom::setTopicPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.topic"_ls, newPowerLevel, true);
setPowerLevel("m.room.topic", newPowerLevel, true);
}
int NeoChatRoom::encryptionPowerLevel() const
{
return powerLevel("m.room.encryption"_ls, true);
return powerLevel("m.room.encryption", true);
}
void NeoChatRoom::setEncryptionPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.encryption"_ls, newPowerLevel, true);
setPowerLevel("m.room.encryption", newPowerLevel, true);
}
int NeoChatRoom::historyVisibilityPowerLevel() const
{
return powerLevel("m.room.history_visibility"_ls, true);
return powerLevel("m.room.history_visibility", true);
}
void NeoChatRoom::setHistoryVisibilityPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.history_visibility"_ls, newPowerLevel, true);
setPowerLevel("m.room.history_visibility", newPowerLevel, true);
}
int NeoChatRoom::pinnedEventsPowerLevel() const
{
return powerLevel("m.room.pinned_events"_ls, true);
return powerLevel("m.room.pinned_events", true);
}
void NeoChatRoom::setPinnedEventsPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.pinned_events"_ls, newPowerLevel, true);
setPowerLevel("m.room.pinned_events", newPowerLevel, true);
}
int NeoChatRoom::tombstonePowerLevel() const
{
return powerLevel("m.room.tombstone"_ls, true);
return powerLevel("m.room.tombstone", true);
}
void NeoChatRoom::setTombstonePowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.tombstone"_ls, newPowerLevel, true);
setPowerLevel("m.room.tombstone", newPowerLevel, true);
}
int NeoChatRoom::serverAclPowerLevel() const
{
return powerLevel("m.room.server_acl"_ls, true);
return powerLevel("m.room.server_acl", true);
}
void NeoChatRoom::setServerAclPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.server_acl"_ls, newPowerLevel, true);
setPowerLevel("m.room.server_acl", newPowerLevel, true);
}
int NeoChatRoom::spaceChildPowerLevel() const
{
return powerLevel("m.space.child"_ls, true);
return powerLevel("m.space.child", true);
}
void NeoChatRoom::setSpaceChildPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.space.child"_ls, newPowerLevel, true);
setPowerLevel("m.space.child", newPowerLevel, true);
}
int NeoChatRoom::spaceParentPowerLevel() const
{
return powerLevel("m.space.parent"_ls, true);
return powerLevel("m.space.parent", true);
}
void NeoChatRoom::setSpaceParentPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.space.parent"_ls, newPowerLevel, true);
setPowerLevel("m.space.parent", newPowerLevel, true);
}
QCoro::Task<void> NeoChatRoom::doDeleteMessagesByUser(const QString &user, QString reason)
@@ -1395,7 +1397,7 @@ QCoro::Task<void> NeoChatRoom::doDeleteMessagesByUser(const QString &user, QStri
}
}
for (const auto &e : events) {
auto job = connection()->callApi<RedactEventJob>(id(), QString::fromLatin1(QUrl::toPercentEncoding(e)), connection()->generateTxnId(), reason);
auto job = connection()->callApi<RedactEventJob>(id(), QUrl::toPercentEncoding(e), connection()->generateTxnId(), reason);
co_await qCoro(job, &BaseJob::finished);
if (job->error() != BaseJob::Success) {
qWarning() << "Error: \"" << job->error() << "\" while deleting messages. Aborting";
@@ -1446,26 +1448,26 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
* Note to prevent race conditions any rule that is going ot be overridden later is not removed.
* If the default push notification state is chosen any exisiting rule needs to be removed.
*/
QJsonObject accountData = connection()->accountDataJson("m.push_rules"_ls);
QJsonObject accountData = connection()->accountDataJson("m.push_rules");
// For default and mute check for a room rule and remove if found.
if (state == PushNotificationState::Default || state == PushNotificationState::Mute) {
QJsonArray roomRuleArray = accountData["global"_ls].toObject()["room"_ls].toArray();
QJsonArray roomRuleArray = accountData["global"].toObject()["room"].toArray();
for (const auto &i : roomRuleArray) {
QJsonObject roomRule = i.toObject();
if (roomRule["rule_id"_ls] == id()) {
Controller::instance().activeConnection()->callApi<DeletePushRuleJob>("global"_ls, "room"_ls, id());
if (roomRule["rule_id"] == id()) {
Controller::instance().activeConnection()->callApi<DeletePushRuleJob>("global", "room", id());
}
}
}
// For default, all and @mentions and keywords check for an override rule and remove if found.
if (state == PushNotificationState::Default || state == PushNotificationState::All || state == PushNotificationState::MentionKeyword) {
QJsonArray overrideRuleArray = accountData["global"_ls].toObject()["override"_ls].toArray();
QJsonArray overrideRuleArray = accountData["global"].toObject()["override"].toArray();
for (const auto &i : overrideRuleArray) {
QJsonObject overrideRule = i.toObject();
if (overrideRule["rule_id"_ls] == id()) {
Controller::instance().activeConnection()->callApi<DeletePushRuleJob>("global"_ls, "override"_ls, id());
if (overrideRule["rule_id"] == id()) {
Controller::instance().activeConnection()->callApi<DeletePushRuleJob>("global", "override", id());
}
}
}
@@ -1481,7 +1483,7 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
* "don't_notify"
* ]
*/
const QVector<QVariant> actions = {"dont_notify"_ls};
const QVector<QVariant> actions = {"dont_notify"};
/**
* Setup the push condition to get all events for the current room
* see https://spec.matrix.org/v1.3/client-server-api/#conditions-1
@@ -1495,17 +1497,15 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
* ]
*/
PushCondition pushCondition;
pushCondition.kind = "event_match"_ls;
pushCondition.key = "room_id"_ls;
pushCondition.kind = "event_match";
pushCondition.key = "room_id";
pushCondition.pattern = id();
const QVector<PushCondition> conditions = {pushCondition};
// Add new override rule and make sure it's enabled
auto job = Controller::instance()
.activeConnection()
->callApi<SetPushRuleJob>("global"_ls, "override"_ls, id(), actions, QString(), QString(), conditions, QString());
auto job = Controller::instance().activeConnection()->callApi<SetPushRuleJob>("global", "override", id(), actions, "", "", conditions, "");
connect(job, &BaseJob::success, this, [this]() {
auto enableJob = Controller::instance().activeConnection()->callApi<SetPushRuleEnabledJob>("global"_ls, "override"_ls, id(), true);
auto enableJob = Controller::instance().activeConnection()->callApi<SetPushRuleEnabledJob>("global", "override", id(), true);
connect(enableJob, &BaseJob::success, this, [this]() {
m_pushNotificationStateUpdating = false;
});
@@ -1525,15 +1525,13 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
* "don't_notify"
* ]
*/
const QVector<QVariant> actions = {"dont_notify"_ls};
const QVector<QVariant> actions = {"dont_notify"};
// No conditions for a room rule
const QVector<PushCondition> conditions;
auto setJob = Controller::instance()
.activeConnection()
->callApi<SetPushRuleJob>("global"_ls, "room"_ls, id(), actions, QString(), QString(), conditions, QString());
auto setJob = Controller::instance().activeConnection()->callApi<SetPushRuleJob>("global", "room", id(), actions, "", "", conditions, "");
connect(setJob, &BaseJob::success, this, [this]() {
auto enableJob = Controller::instance().activeConnection()->callApi<SetPushRuleEnabledJob>("global"_ls, "room"_ls, id(), true);
auto enableJob = Controller::instance().activeConnection()->callApi<SetPushRuleEnabledJob>("global", "room", id(), true);
connect(enableJob, &BaseJob::success, this, [this]() {
m_pushNotificationStateUpdating = false;
});
@@ -1555,18 +1553,16 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
* ]
*/
QJsonObject tweaks;
tweaks.insert("set_tweak"_ls, "sound"_ls);
tweaks.insert("value"_ls, "default"_ls);
const QVector<QVariant> actions = {"notify"_ls, tweaks};
tweaks.insert("set_tweak", "sound");
tweaks.insert("value", "default");
const QVector<QVariant> actions = {"notify", tweaks};
// No conditions for a room rule
const QVector<PushCondition> conditions;
// Add new room rule and make sure enabled
auto setJob = Controller::instance()
.activeConnection()
->callApi<SetPushRuleJob>("global"_ls, "room"_ls, id(), actions, QString(), QString(), conditions, QString());
auto setJob = Controller::instance().activeConnection()->callApi<SetPushRuleJob>("global", "room", id(), actions, "", "", conditions, "");
connect(setJob, &BaseJob::success, this, [this]() {
auto enableJob = Controller::instance().activeConnection()->callApi<SetPushRuleEnabledJob>("global"_ls, "room"_ls, id(), true);
auto enableJob = Controller::instance().activeConnection()->callApi<SetPushRuleEnabledJob>("global", "room", id(), true);
connect(enableJob, &BaseJob::success, this, [this]() {
m_pushNotificationStateUpdating = false;
});
@@ -1580,23 +1576,23 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
void NeoChatRoom::updatePushNotificationState(QString type)
{
if (type != "m.push_rules"_ls || m_pushNotificationStateUpdating) {
if (type != "m.push_rules" || m_pushNotificationStateUpdating) {
return;
}
QJsonObject accountData = connection()->accountDataJson("m.push_rules"_ls);
QJsonObject accountData = connection()->accountDataJson("m.push_rules");
// First look for a room rule with the room id
QJsonArray roomRuleArray = accountData["global"_ls].toObject()["room"_ls].toArray();
QJsonArray roomRuleArray = accountData["global"].toObject()["room"].toArray();
for (const auto &i : roomRuleArray) {
QJsonObject roomRule = i.toObject();
if (roomRule["rule_id"_ls] == id()) {
QString notifyAction = roomRule["actions"_ls].toArray()[0].toString();
if (notifyAction == "notify"_ls) {
if (roomRule["rule_id"] == id()) {
QString notifyAction = roomRule["actions"].toArray()[0].toString();
if (notifyAction == "notify") {
m_currentPushNotificationState = PushNotificationState::All;
Q_EMIT pushNotificationStateChanged(m_currentPushNotificationState);
return;
} else if (notifyAction == "dont_notify"_ls) {
} else if (notifyAction == "dont_notify") {
m_currentPushNotificationState = PushNotificationState::MentionKeyword;
Q_EMIT pushNotificationStateChanged(m_currentPushNotificationState);
return;
@@ -1605,12 +1601,12 @@ void NeoChatRoom::updatePushNotificationState(QString type)
}
// Check for an override rule with the room id
QJsonArray overrideRuleArray = accountData["global"_ls].toObject()["override"_ls].toArray();
QJsonArray overrideRuleArray = accountData["global"].toObject()["override"].toArray();
for (const auto &i : overrideRuleArray) {
QJsonObject overrideRule = i.toObject();
if (overrideRule["rule_id"_ls] == id()) {
QString notifyAction = overrideRule["actions"_ls].toArray()[0].toString();
if (notifyAction == "dont_notify"_ls) {
if (overrideRule["rule_id"] == id()) {
QString notifyAction = overrideRule["actions"].toArray()[0].toString();
if (notifyAction == "dont_notify") {
m_currentPushNotificationState = PushNotificationState::Mute;
Q_EMIT pushNotificationStateChanged(m_currentPushNotificationState);
return;
@@ -1766,9 +1762,9 @@ void NeoChatRoom::replyLastMessage()
if (e->msgtype() != MessageEventType::Unknown) {
QString eventId;
if (content.contains("m.new_content"_ls)) {
if (content.contains("m.new_content")) {
// The message has been edited so we have to return the id of the original message instead of the replacement
eventId = content["m.relates_to"_ls].toObject()["event_id"_ls].toString();
eventId = content["m.relates_to"].toObject()["event_id"].toString();
} else {
// For any message that isn't an edit return the id of the current message
eventId = (*it)->id();
@@ -1800,9 +1796,9 @@ void NeoChatRoom::editLastMessage()
if (e->msgtype() != MessageEventType::Unknown) {
QString eventId;
if (content.contains("m.new_content"_ls)) {
if (content.contains("m.new_content")) {
// The message has been edited so we have to return the id of the original message instead of the replacement
eventId = content["m.relates_to"_ls].toObject()["event_id"_ls].toString();
eventId = content["m.relates_to"].toObject()["event_id"].toString();
} else {
// For any message that isn't an edit return the id of the current message
eventId = (*it)->id();
@@ -1816,7 +1812,10 @@ void NeoChatRoom::editLastMessage()
bool NeoChatRoom::canEncryptRoom() const
{
return !usesEncryption() && canSendState("m.room.encryption"_ls);
#ifdef Quotient_E2EE_ENABLED
return !usesEncryption() && canSendState("m.room.encryption");
#endif
return false;
}
PollHandler *NeoChatRoom::poll(const QString &eventId)
@@ -1917,25 +1916,25 @@ Quotient::User *NeoChatRoom::directChatRemoteUser() const
void NeoChatRoom::sendLocation(float lat, float lon, const QString &description)
{
QJsonObject locationContent{
{"uri"_ls, "geo:%1,%2"_ls.arg(QString::number(lat), QString::number(lon))},
{"uri", "geo:%1,%2"_ls.arg(QString::number(lat), QString::number(lon))},
};
if (!description.isEmpty()) {
locationContent["description"_ls] = description;
locationContent["description"] = description;
}
QJsonObject content{
{"body"_ls, i18nc("'Lat' and 'Lon' as in Latitude and Longitude", "Lat: %1, Lon: %2", lat, lon)},
{"msgtype"_ls, "m.location"_ls},
{"geo_uri"_ls, "geo:%1,%2"_ls.arg(QString::number(lat), QString::number(lon))},
{"org.matrix.msc3488.location"_ls, locationContent},
{"org.matrix.msc3488.asset"_ls,
{"body", i18nc("'Lat' and 'Lon' as in Latitude and Longitude", "Lat: %1, Lon: %2", lat, lon)},
{"msgtype", "m.location"},
{"geo_uri", "geo:%1,%2"_ls.arg(QString::number(lat), QString::number(lon))},
{"org.matrix.msc3488.location", locationContent},
{"org.matrix.msc3488.asset",
QJsonObject{
{"type"_ls, "m.pin"_ls},
{"type", "m.pin"},
}},
{"org.matrix.msc1767.text"_ls, i18nc("'Lat' and 'Lon' as in Latitude and Longitude", "Lat: %1, Lon: %2", lat, lon)},
{"org.matrix.msc1767.text", i18nc("'Lat' and 'Lon' as in Latitude and Longitude", "Lat: %1, Lon: %2", lat, lon)},
};
postJson("m.room.message"_ls, content);
postJson("m.room.message", content);
}
QByteArray NeoChatRoom::roomAcountDataJson(const QString &eventType)
@@ -1959,7 +1958,7 @@ QUrl NeoChatRoom::avatarForMember(Quotient::User *user) const
const RoomEvent *NeoChatRoom::getReplyForEvent(const RoomEvent &event) const
{
const QString &replyEventId = event.contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString();
const QString &replyEventId = event.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString();
if (replyEventId.isEmpty()) {
return {};
};

View File

@@ -186,6 +186,9 @@ class NeoChatRoom : public Quotient::Room
/**
* @brief Whether the local user can encrypt the room.
*
* Requires libQuotient 0.7 compiled with the Quotient_E2EE_ENABLED parameter to
* be able to return true.
*
* A local user can encrypt a room if they have permission to send the m.room.encryption
* state event.
*

View File

@@ -62,7 +62,7 @@ void NotificationsManager::processNotificationJob(QPointer<Quotient::Connection>
const auto connectionId = connection->user()->id();
// If pagination has occurred set off the next job
auto nextToken = job->jsonData()["next_token"_ls].toString();
auto nextToken = job->jsonData()["next_token"].toString();
if (!nextToken.isEmpty()) {
auto nextJob = connection->callApi<GetNotificationsJob>(nextToken);
m_connActiveJob.append(connectionId);
@@ -72,58 +72,60 @@ void NotificationsManager::processNotificationJob(QPointer<Quotient::Connection>
});
}
const auto notifications = job->jsonData()["notifications"_ls].toArray();
const auto notifications = job->jsonData()["notifications"].toArray();
if (initialization) {
m_oldNotifications[connectionId] = QStringList();
for (const auto &n : notifications) {
if (!m_initialTimestamp.contains(connectionId)) {
m_initialTimestamp[connectionId] = n.toObject()["ts"_ls].toDouble();
m_initialTimestamp[connectionId] = n.toObject()["ts"].toDouble();
} else {
qint64 timestamp = n.toObject()["ts"_ls].toDouble();
qint64 timestamp = n.toObject()["ts"].toDouble();
if (timestamp > m_initialTimestamp[connectionId]) {
m_initialTimestamp[connectionId] = timestamp;
}
}
auto connectionNotifications = m_oldNotifications.value(connectionId);
connectionNotifications += n.toObject()["event"_ls].toObject()["event_id"_ls].toString();
connectionNotifications += n.toObject()["event"].toObject()["event_id"].toString();
m_oldNotifications[connectionId] = connectionNotifications;
}
return;
}
for (const auto &n : notifications) {
const auto notification = n.toObject();
if (notification["read"_ls].toBool()) {
if (notification["read"].toBool()) {
continue;
}
auto connectionNotifications = m_oldNotifications.value(connectionId);
if (connectionNotifications.contains(notification["event"_ls].toObject()["event_id"_ls].toString())) {
if (connectionNotifications.contains(notification["event"].toObject()["event_id"].toString())) {
continue;
}
connectionNotifications += notification["event"_ls].toObject()["event_id"_ls].toString();
connectionNotifications += notification["event"].toObject()["event_id"].toString();
m_oldNotifications[connectionId] = connectionNotifications;
auto room = connection->room(notification["room_id"_ls].toString());
auto room = connection->room(notification["room_id"].toString());
if (shouldPostNotification(connection, n)) {
// The room might have been deleted (for example rejected invitation).
auto sender = room->user(notification["event"_ls].toObject()["sender"_ls].toString());
auto sender = room->user(notification["event"].toObject()["sender"].toString());
QString body;
if (notification["event"_ls].toObject()["type"_ls].toString() == "org.matrix.msc3381.poll.start"_ls) {
body = notification["event"_ls]
.toObject()["content"_ls]
.toObject()["org.matrix.msc3381.poll.start"_ls]
.toObject()["question"_ls]
.toObject()["body"_ls]
if (notification["event"].toObject()["type"].toString() == "org.matrix.msc3381.poll.start") {
body = notification["event"]
.toObject()["content"]
.toObject()["org.matrix.msc3381.poll.start"]
.toObject()["question"]
.toObject()["body"]
.toString();
} else {
body = notification["event"_ls].toObject()["content"_ls].toObject()["body"_ls].toString();
body = notification["event"].toObject()["content"].toObject()["body"].toString();
}
if (notification["event"_ls]["type"_ls] == "m.room.encrypted"_ls) {
if (notification["event"]["type"] == "m.room.encrypted") {
#ifdef Quotient_E2EE_ENABLED
auto decrypted = connection->decryptNotification(notification);
body = decrypted["content"_ls].toObject()["body"_ls].toString();
body = decrypted["content"].toObject()["body"].toString();
#endif
if (body.isEmpty()) {
body = i18n("Encrypted Message");
}
@@ -139,7 +141,7 @@ void NotificationsManager::processNotificationJob(QPointer<Quotient::Connection>
sender->displayname(room),
body,
avatar_image,
notification["event"_ls].toObject()["event_id"_ls].toString(),
notification["event"].toObject()["event_id"].toString(),
true);
}
}
@@ -151,7 +153,7 @@ bool NotificationsManager::shouldPostNotification(QPointer<Quotient::Connection>
return false;
}
auto room = connection->room(notification["room_id"_ls].toString());
auto room = connection->room(notification["room_id"].toString());
if (room == nullptr) {
return false;
}
@@ -167,7 +169,7 @@ bool NotificationsManager::shouldPostNotification(QPointer<Quotient::Connection>
// If the notification timestamp is earlier than the initial timestamp assume
// the notification is old and shouldn't be posted.
qint64 timestamp = notification["ts"_ls].toDouble();
qint64 timestamp = notification["ts"].toDouble();
if (timestamp < m_initialTimestamp[connection->user()->id()]) {
return false;
}
@@ -185,7 +187,7 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
const QString roomId = room->id();
KNotification *notification = m_notifications.value(roomId);
if (!notification) {
notification = new KNotification(QStringLiteral("message"));
notification = new KNotification("message");
m_notifications.insert(roomId, notification);
connect(notification, &KNotification::closed, this, [this, roomId] {
m_notifications.remove(roomId);
@@ -201,7 +203,7 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
entry = i18n("%1: %2", sender, text.toHtmlEscaped());
}
notification->setText(notification->text() + QLatin1Char('\n') + entry);
notification->setText(notification->text() + '\n' + entry);
notification->setPixmap(createNotificationImage(icon, room));
notification->setDefaultAction(i18n("Open NeoChat in this room"));
@@ -235,7 +237,7 @@ void NotificationsManager::postInviteNotification(NeoChatRoom *room, const QStri
{
QPixmap img;
img.convertFromImage(icon);
KNotification *notification = new KNotification(QStringLiteral("invite"));
KNotification *notification = new KNotification("invite");
notification->setText(i18n("%1 invited you to a room", sender));
notification->setTitle(title);
notification->setPixmap(createNotificationImage(icon, nullptr));
@@ -291,12 +293,7 @@ QPixmap NotificationsManager::createNotificationImage(const QImage &icon, NeoCha
roundedImage.fill(Qt::transparent);
QPainter painter(&roundedImage);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setPen(Qt::NoPen);
// Fill background for transparent avatars
painter.setBrush(Qt::white);
painter.drawRoundedRect(imageRect, imageRect.width(), imageRect.height());
painter.setRenderHint(QPainter::Antialiasing);
QBrush brush(icon.scaledToHeight(biggestDimension));
painter.setBrush(brush);
@@ -307,9 +304,6 @@ QPixmap NotificationsManager::createNotificationImage(const QImage &icon, NeoCha
if (icon != roomAvatar) {
const QRect lowerQuarter{imageRect.center(), imageRect.size() / 2};
painter.setBrush(Qt::white);
painter.drawRoundedRect(lowerQuarter, lowerQuarter.width(), lowerQuarter.height());
painter.setBrush(roomAvatar.scaled(lowerQuarter.size()));
painter.drawRoundedRect(lowerQuarter, lowerQuarter.width(), lowerQuarter.height());
}

View File

@@ -105,7 +105,7 @@ void PollHandler::handleAnswer(const QJsonObject &content, const QString &sender
m_answerTimestamps[sender] = timestamp;
m_answers[sender] = {};
int i = 0;
for (const auto &answer : content["org.matrix.msc3381.poll.response"_ls]["answers"_ls].toArray()) {
for (const auto &answer : content["org.matrix.msc3381.poll.response"]["answers"].toArray()) {
auto array = m_answers[sender].toArray();
array.insert(0, answer);
m_answers[sender] = array;

View File

@@ -28,8 +28,6 @@ Delegates.RoundedItemDelegate {
TapHandler {
acceptedButtons: Qt.RightButton
acceptedDevices: PointerDevice.Mouse
grabPermissions: PointerHandler.TakeOverForbidden
gesturePolicy: TapHandler.WithinBounds
onTapped: root.contextMenuRequested()
}

View File

@@ -6,7 +6,6 @@ import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Window 2.15
import Qt.labs.platform 1.1 as Platform
import org.kde.kirigami 2.18 as Kirigami
import org.kde.neochat 1.0
@@ -86,20 +85,18 @@ QQC2.Control {
property bool isBusy: false
visible: !Kirigami.Settings.isMobile
icon.name: "smiley"
text: i18n("Emojis & Stickers")
displayHint: Kirigami.DisplayHint.IconOnly
checkable: true
onTriggered: {
if (emojiDialog.item.visible) {
emojiDialog.item.close()
if (emojiDialog.visible) {
emojiDialog.close()
} else {
emojiDialog.item.open()
emojiDialog.open()
}
}
tooltip: text
},
Kirigami.Action {
id: mapButton
@@ -111,7 +108,6 @@ QQC2.Control {
onTriggered: {
locationChooserComponent.createObject(QQC2.ApplicationWindow.overlay, {room: root.currentRoom}).open()
}
tooltip: text
},
Kirigami.Action {
id: sendAction
@@ -166,9 +162,10 @@ QQC2.Control {
leftPadding: LayoutMirroring.enabled ? actionsRow.width : Kirigami.Units.largeSpacing
rightPadding: LayoutMirroring.enabled ? Kirigami.Units.largeSpacing : actionsRow.width + x * 2 + Kirigami.Units.largeSpacing * 2
placeholderText: root.currentRoom.usesEncryption ? i18n("Send an encrypted message…") : root.currentRoom.chatBoxAttachmentPath.length > 0 ? i18n("Set an attachment caption...") : i18n("Send a message…")
placeholderText: readOnly ? i18n("This room is encrypted. Build libQuotient with encryption enabled to send encrypted messages.") : root.currentRoom.usesEncryption ? i18n("Send an encrypted message…") : root.currentRoom.chatBoxAttachmentPath.length > 0 ? i18n("Set an attachment caption...") : i18n("Send a message…")
verticalAlignment: TextEdit.AlignVCenter
wrapMode: Text.Wrap
readOnly: (root.currentRoom.usesEncryption && !Controller.encryptionSupported)
Accessible.description: placeholderText
@@ -240,9 +237,9 @@ QQC2.Control {
completionMenu.complete()
}
}
Keys.onPressed: (event) => {
Keys.onPressed: {
if (event.key === Qt.Key_V && event.modifiers & Qt.ControlModifier) {
event.accepted = root.pasteImage();
root.pasteImage();
} else if (event.key === Qt.Key_Up && event.modifiers & Qt.ControlModifier) {
root.currentRoom.replyLastMessage();
} else if (event.key === Qt.Key_Up && textField.text.length === 0) {
@@ -387,7 +384,6 @@ QQC2.Control {
QQC2.ToolTip.visible: modelData.tooltip !== "" && hoverHandler.hovered
QQC2.ToolTip.text: modelData.tooltip
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
HoverHandler { id: hoverHandler }
PieProgressBar {
@@ -398,22 +394,19 @@ QQC2.Control {
}
}
Loader {
EmojiDialog {
id: emojiDialog
active: !Kirigami.Settings.isMobile
sourceComponent: EmojiDialog {
x: root.width - width
y: -implicitHeight // - Kirigami.Units.smallSpacing
x: parent.width - width
y: -implicitHeight // - Kirigami.Units.smallSpacing
modal: false
includeCustom: true
closeOnChosen: false
modal: false
includeCustom: true
closeOnChosen: false
currentRoom: root.currentRoom
currentRoom: root.currentRoom
onChosen: insertText(emoji)
onClosed: if (emojiAction.checked) emojiAction.checked = false
}
onChosen: insertText(emoji)
onClosed: if (emojiButton.checked) emojiButton.checked = false
}
background: Rectangle {
@@ -475,10 +468,9 @@ QQC2.Control {
function pasteImage() {
let localPath = Clipboard.saveImage();
if (localPath.length === 0) {
return false;
return;
}
root.currentRoom.chatBoxAttachmentPath = localPath;
return true;
root.currentRoom.chatBoxAttachmentPath = localPath
}
function postMessage() {
@@ -538,61 +530,6 @@ QQC2.Control {
LocationChooser {}
}
QQC2.Popup {
anchors.centerIn: parent
id: attachDialog
padding: 16
contentItem: RowLayout {
QQC2.ToolButton {
Layout.preferredWidth: 160
Layout.fillHeight: true
icon.name: 'mail-attachment'
text: i18n("Choose local file")
onClicked: {
attachDialog.close()
var fileDialog = openFileDialog.createObject(QQC2.ApplicationWindow.overlay)
fileDialog.chosen.connect(function (path) {
if (!path) {
return;
}
root.currentRoom.chatBoxAttachmentPath = path;
})
fileDialog.open()
}
}
Kirigami.Separator {
}
QQC2.ToolButton {
Layout.preferredWidth: 160
Layout.fillHeight: true
padding: 16
icon.name: 'insert-image'
text: i18n("Clipboard image")
onClicked: {
const localPath = Platform.StandardPaths.writableLocation(Platform.StandardPaths.CacheLocation) + "/screenshots/" + (new Date()).getTime() + ".png"
if (!Clipboard.saveImage(localPath)) {
return;
}
root.currentRoom.chatBoxAttachmentPath = localPath;
attachDialog.close();
}
}
}
}
Component {
id: openFileDialog

View File

@@ -71,7 +71,7 @@ QQC2.Popup {
visible: completionDelegate.iconName !== "invalid"
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
source: completionDelegate.iconName === "invalid" ? "" : completionDelegate.iconName
source: completionDelegate.iconName === "invalid" ? "" : ("image://" + completionDelegate.iconName)
name: completionDelegate.text
}
Delegates.SubtitleContentItem {

View File

@@ -6,122 +6,107 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
import org.kde.kitemmodels 1.0
import org.kde.neochat 1.0
FormCard.FormCardPage {
id: root
required property var room
FormCard.FormCard {
Layout.topMargin: Kirigami.Units.gridUnit
FormCard.FormComboBoxDelegate {
id: roomChooser
text: i18n("Room")
textRole: "displayName"
valueRole: "roomId"
model: RoomListModel {
id: roomListModel
connection: Controller.activeConnection
}
onCurrentValueChanged: room = roomListModel.roomByAliasOrId(currentValue)
Component.onCompleted: currentIndex = indexOfValue(room.id)
}
FormCard.FormDelegateSeparator { above: showRoomMember }
FormCard.FormCheckDelegate {
id: showRoomMember
text: i18n("Show m.room.member events")
checked: true
onToggled: {
if (checked) {
stateEventFilterModel.removeStateEventTypeFiltered("m.room.member");
} else {
stateEventFilterModel.addStateEventTypeFiltered("m.room.member");
ColumnLayout {
MobileForm.FormCard {
Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormComboBoxDelegate {
text: i18n("Room")
textRole: "displayName"
valueRole: "id"
model: RoomListModel {
id: roomListModel
connection: Controller.activeConnection
}
Component.onCompleted: currentIndex = indexOfValue(room.id)
onCurrentValueChanged: room = roomListModel.roomByAliasOrId(currentValue)
}
}
FormCard.FormDelegateSeparator { above: roomAccoutnDataVisibleCheck; below: showRoomMember }
FormCard.FormCheckDelegate {
id: roomAccoutnDataVisibleCheck
text: i18n("Show room account data")
checked: false
}
FormCard.FormDelegateSeparator { below: roomAccoutnDataVisibleCheck }
FormCard.FormTextDelegate {
text: i18n("Room id")
description: room.id
}
}
FormCard.FormHeader {
title: i18n("Room Account Data for %1", room.displayName)
visible: roomAccoutnDataVisibleCheck.checked
}
FormCard.FormCard {
visible: roomAccoutnDataVisibleCheck.checked
Repeater {
model: room.accountDataEventTypes
delegate: FormCard.FormTextDelegate {
text: modelData
onClicked: applicationWindow().pageStack.pushDialogLayer("qrc:/MessageSourceSheet.qml", {
"sourceText": room.roomAcountDataJson(text)
}, {
"title": i18n("Event Source"),
"width": Kirigami.Units.gridUnit * 25
})
}
}
}
FormCard.FormHeader {
id: stateEventListHeader
title: i18n("Room State for %1", room.displayName)
}
FormCard.FormCard {
Layout.fillHeight: true
QQC2.ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumHeight: Kirigami.Units.gridUnit * 20
// HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890)
QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
ListView {
id: stateEventListView
clip: true
model: StateFilterModel {
id: stateEventFilterModel
sourceModel: StateModel {
id: stateModel
room: root.room
MobileForm.FormCheckDelegate {
text: i18n("Show m.room.member events")
checked: true
onToggled: {
if (checked) {
stateEventFilterModel.removeStateEventTypeFiltered("m.room.member");
} else {
stateEventFilterModel.addStateEventTypeFiltered("m.room.member");
}
}
}
MobileForm.FormCheckDelegate {
id: roomAccoutnDataVisibleCheck
text: i18n("Show room account data")
checked: false
}
}
}
MobileForm.FormCard {
Layout.fillWidth: true
visible: roomAccoutnDataVisibleCheck.checked
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCardHeader {
title: i18n("Room Account Data for %1 - %2", room.displayName, room.id)
}
delegate: FormCard.FormTextDelegate {
text: model.type
description: model.stateKey
onClicked: applicationWindow().pageStack.pushDialogLayer('qrc:/MessageSourceSheet.qml', {
sourceText: stateModel.stateEventJson(stateEventFilterModel.mapToSource(stateEventFilterModel.index(model.index, 0)))
Repeater {
model: room.accountDataEventTypes
delegate: MobileForm.FormTextDelegate {
text: modelData
onClicked: applicationWindow().pageStack.pushDialogLayer("qrc:/MessageSourceSheet.qml", {
"sourceText": room.roomAcountDataJson(text)
}, {
title: i18n("Event Source"),
width: Kirigami.Units.gridUnit * 25
});
"title": i18n("Event Source"),
"width": Kirigami.Units.gridUnit * 25
})
}
}
}
}
MobileForm.FormCard {
Layout.fillWidth: true
Layout.fillHeight: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCardHeader {
id: stateEventListHeader
title: i18n("Room State for %1", room.displayName)
subtitle: room.id
}
QQC2.ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
// HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890)
QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
ListView {
id: stateEventListView
clip: true
model: StateFilterModel {
id: stateEventFilterModel
sourceModel: StateModel {
id: stateModel
room: devtoolsPage.room
}
}
delegate: MobileForm.FormTextDelegate {
text: model.type
description: model.stateKey
onClicked: applicationWindow().pageStack.pushDialogLayer('qrc:/MessageSourceSheet.qml', {
sourceText: stateModel.stateEventJson(stateEventFilterModel.mapToSource(stateEventFilterModel.index(model.index, 0)))
}, {
title: i18n("Event Source"),
width: Kirigami.Units.gridUnit * 25
});
}
}
}
}

View File

@@ -6,50 +6,58 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 as FormCard
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
import org.kde.kitemmodels 1.0
import org.kde.neochat 1.0
FormCard.FormCardPage {
id: root
FormCard.FormHeader {
title: i18n("Server Capabilities")
}
FormCard.FormCard {
FormCard.FormTextDelegate {
text: i18n("Can change password")
description: Controller.activeConnection.canChangePassword
ColumnLayout {
MobileForm.FormCard {
Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCardHeader {
title: i18n("Server Capabilities")
}
MobileForm.FormTextDelegate {
text: i18n("Can change password")
description: Controller.activeConnection.canChangePassword
}
}
}
FormCard.FormHeader {
title: i18n("Default Room Version")
}
FormCard.FormCard {
FormCard.FormTextDelegate {
text: Controller.activeConnection.defaultRoomVersion
MobileForm.FormCard {
Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCardHeader {
title: i18n("Default Room Version")
}
MobileForm.FormTextDelegate {
text: Controller.activeConnection.defaultRoomVersion
}
}
}
MobileForm.FormCard {
Layout.fillWidth: true
contentItem: ColumnLayout {
spacing: 0
MobileForm.FormCardHeader {
title: i18n("Available Room Versions")
}
Repeater {
model: Controller.getSupportedRoomVersions(room.connection)
FormCard.FormHeader {
title: i18n("Available Room Versions")
}
FormCard.FormCard {
Repeater {
model: Controller.getSupportedRoomVersions(room.connection)
delegate: FormCard.FormTextDelegate {
text: modelData.id
contentItem.children: QQC2.Label {
text: modelData.status
color: Kirigami.Theme.disabledTextColor
delegate: MobileForm.FormTextDelegate {
text: modelData.id
contentItem.children: QQC2.Label {
text: modelData.status
color: Kirigami.Theme.disabledTextColor
}
}
}
}
}
Item {
Layout.fillHeight: true
}
}

View File

@@ -17,6 +17,7 @@ ColumnLayout {
property bool includeCustom: false
property bool showQuickReaction: false
property NeoChatRoom currentRoom
readonly property var currentEmojiModel: {
if (includeCustom) {

Some files were not shown because too many files have changed in this diff Show More