Compare commits

..

189 Commits

Author SHA1 Message Date
Tobias Fella
27f4dfbf8e Work 2024-05-26 14:43:41 +02:00
Tobias Fella
1235e46575 Add basic cross-signing support 2024-05-25 19:40:13 +02:00
James Graham
31dd981104 Don't store RoomMembers in ReactionModel
Don't store RoomMember objects in the reaction model just grab them everytime incase the state event is replaced.
2024-05-25 19:40:13 +02:00
James Graham
645438525f Use new libquotient functionality to encrypt direct chats by default
Needs https://github.com/quotient-im/libQuotient/pull/730
2024-05-25 19:40:13 +02:00
Tobias Fella
a29d3790c8 Disable failing CIs 2024-05-25 19:40:13 +02:00
James Graham
a47cbeca81 Use the new libquotient version of the serveracl event
Use with https://github.com/quotient-im/libQuotient/pull/729
2024-05-25 19:40:12 +02:00
James Graham
ab06d24f66 Use updated membersTyping functions from libquotient 2024-05-25 19:40:12 +02:00
James Graham
6f4a52024b Request direct chat by userId to avoid breakage with upcoming libquotient changes 2024-05-25 19:40:12 +02:00
Tobias Fella
83d21634c3 Unconditionally use SSSS 2024-05-25 19:40:12 +02:00
James Graham
8d6340f84c Actually user.h needs to still be included in actionsmodel 2024-05-25 19:40:12 +02:00
James Graham
a9713b1f1c Make use of new RoomMember item from libquotient
Depends on https://github.com/quotient-im/libQuotient/pull/695

Currently basic just to show a working implementation using RoomMember. Currently only the room event and search models are moved over. Will change everything else over once the dependent pr is complete.
2024-05-25 19:40:10 +02:00
James Graham
9e05f17cb7 handle remaining stuff for Quotient::Omittable deprecation 2024-05-25 19:38:32 +02:00
James Graham
15b7c04834 Remove uses of Quotient:Omittable
Note this technically won't build for now because of the lack of RoomMember support but I'll push that at the quotient-next branch next. 

This is needed as well to get a branch that builds on dev.
2024-05-25 19:38:32 +02:00
James Graham
31f0e39617 Convert TimelineDelegate to cpp
There are 2 main reason for doing this:
1. Because I can, I wanted to see if I could do it
2. It gets rid of the janky qml re parenting stuff so should be faster.
2024-05-25 17:06:13 +00:00
James Graham
a48151920d Permission model
Add a model for managing permissions (power levels) in rooms. This gets rid of a whole bunch of boiler plate in NeoChat and as a bonus makes it easy to add a feature to allow setting the permission level for any event.
2024-05-25 16:25:39 +00:00
Tobias Fella
8199653ddd Use simpler and less restrictive server url regex
The old regex was too restrictive. The new one will allow invalid urls, but we don't gain anything from preventing that

BUG: 486888
2024-05-25 15:00:12 +02:00
Tobias Fella
9d650519c7 Don't suggest joining the last opened room when neochat is started after the cache was cleared 2024-05-25 14:45:45 +02:00
l10n daemon script
a545eaca97 GIT_SILENT Sync po/docbooks with svn 2024-05-25 01:25:23 +00:00
James Graham
9da9de2d2d Make sure to ask before leaving a room
Make sure to ask before leaving a room

BUG: 486546
2024-05-24 08:12:26 +00:00
James Graham
c9ddd9d513 Improve the behaviour of jump to last unread message.
Improve the behaviour of jump to last unread message. The view will now jump as high as possible if the last unread message isn't loaded. This at least triggers more items to load which will eventually get the user to the last unread message.
2024-05-24 07:55:05 +00:00
Carl Schwan
415cfd57e7 Use standard Dialog background for emoji dialog 2024-05-22 10:00:51 +00:00
l10n daemon script
b1ede93cdb SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-05-22 01:19:14 +00:00
l10n daemon script
32df465c8a GIT_SILENT made messages (after extraction) 2024-05-22 00:39:06 +00:00
l10n daemon script
2f1c5df11d GIT_SILENT Sync po/docbooks with svn 2024-05-21 01:29:24 +00:00
l10n daemon script
f85f6a7fdc GIT_SILENT Sync po/docbooks with svn 2024-05-20 01:24:20 +00:00
l10n daemon script
93cc80a4b3 GIT_SILENT Sync po/docbooks with svn 2024-05-19 01:24:46 +00:00
Heiko Becker
0f3e401d42 GIT_SILENT Update Appstream for new release
(cherry picked from commit c66c035dbb)
2024-05-17 00:50:28 +02:00
l10n daemon script
a9f2c33053 GIT_SILENT Sync po/docbooks with svn 2024-05-16 01:36:22 +00:00
l10n daemon script
c5ef8c3fec SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-05-16 01:17:33 +00:00
l10n daemon script
ad696bd60b GIT_SILENT Sync po/docbooks with svn 2024-05-15 01:23:49 +00:00
Tobias Fella
9da7462f3e Fix compatibility with newer quotient job api 2024-05-14 16:50:38 +02:00
l10n daemon script
0ecdf354c6 GIT_SILENT Sync po/docbooks with svn 2024-05-14 01:25:59 +00:00
l10n daemon script
67f10632fb GIT_SILENT Sync po/docbooks with svn 2024-05-13 01:27:15 +00:00
l10n daemon script
044b910357 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-05-13 01:17:24 +00:00
James Graham
3de943e50f Set Identity server
Part of network/neochat#565
2024-05-12 18:22:27 +00:00
James Graham
1a2272249d Support adding 3 PIDs
Implements part of network/neochat#565

Note the phone number stuff is untested as neither kde.org or matrix.org have them switched on.
2024-05-12 17:02:09 +00:00
James Graham
0dfeec6cae Make sure that the link preview sizes correctly so that there is no bubble overflow 2024-05-12 13:13:11 +00:00
l10n daemon script
8d193021ab GIT_SILENT Sync po/docbooks with svn 2024-05-12 01:30:54 +00:00
Carl Schwan
f45226a680 Port all confirm dialogs to Kirigami.PromptDialog 2024-05-10 12:54:13 +00:00
l10n daemon script
40d55805ff GIT_SILENT Sync po/docbooks with svn 2024-05-10 01:24:43 +00:00
l10n daemon script
7d6d0b012b GIT_SILENT Sync po/docbooks with svn 2024-05-09 01:29:36 +00:00
l10n daemon script
d7d2c6bf01 GIT_SILENT made messages (after extraction) 2024-05-09 00:39:06 +00:00
Akseli Lahtinen
ce1c6096d3 Check for tagToken length
Sometimes this part of the code causes segfault for me.

I don't know what the root cause is though, it's *very* random. I guess the tagToken should always be long enough, but sometimes it's just one character.
2024-05-08 19:41:39 +00:00
l10n daemon script
8c4ea6180a GIT_SILENT Sync po/docbooks with svn 2024-05-08 01:30:36 +00:00
l10n daemon script
95649ba758 GIT_SILENT Sync po/docbooks with svn 2024-05-07 01:25:20 +00:00
l10n daemon script
2b61f2a9e8 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-05-07 01:16:57 +00:00
Tobias Fella
47242aa66c Remove remaining uses of MatrixImageProvider and remove it 2024-05-06 18:18:48 +02:00
Tobias Fella
31a8abe615 Don't use applicationWindow() for loading key verification sessions 2024-05-06 15:54:50 +02:00
Tobias Fella
4dae3c34b4 Move HoverLinkIndicator to separate file 2024-05-06 15:54:49 +02:00
Tobias Fella
65aa8919b9 Port ConfirmUrlDialog away from applicationWindow() 2024-05-06 15:54:49 +02:00
Tobias Fella
acf8eac0d4 Cleanup JoinRoomDialog 2024-05-06 15:54:49 +02:00
Tobias Fella
e8aa29d3c2 Move direct chat confirmation dialog to separate file 2024-05-06 15:54:49 +02:00
Tobias Fella
a36194afe2 Remove unused component 2024-05-06 15:54:49 +02:00
Tobias Fella
8554898e45 Move consent sheet to separate file 2024-05-06 15:54:46 +02:00
l10n daemon script
55b29f645b GIT_SILENT Sync po/docbooks with svn 2024-05-06 01:25:56 +00:00
l10n daemon script
52cc91ba3e GIT_SILENT made messages (after extraction) 2024-05-06 00:38:19 +00:00
Tobias Fella
c9e3a9f8fe Add back include 2024-05-05 21:56:00 +02:00
Tobias Fella
c3de788956 Cleanup includes 2024-05-05 21:49:43 +02:00
Tobias Fella
53e3c36f7e Explicitely include QFont 2024-05-05 21:33:47 +02:00
Tobias Fella
20908107a0 Remove unused includes 2024-05-05 21:21:43 +02:00
l10n daemon script
cbe1a0d6f8 GIT_SILENT Sync po/docbooks with svn 2024-05-05 01:26:11 +00:00
Tobias Fella
7d8c79ec57 Remove unused include 2024-05-04 11:27:30 +02:00
Tobias Fella
9bb89c728f Move KUnifiedPush include to source file 2024-05-04 11:22:00 +02:00
Tobias Fella
be2e28cc53 Cleanup API 2024-05-04 11:17:45 +02:00
Tobias Fella
57be57971d Remove unused include 2024-05-04 11:17:08 +02:00
Tobias Fella
64eed47f04 Port some things away from Omittable 2024-05-04 10:56:12 +02:00
l10n daemon script
7659105fda GIT_SILENT Sync po/docbooks with svn 2024-05-04 01:33:07 +00:00
Carl Schwan
18c9376992 Fix micro spacing inconsistency in SpaceHierarchyDelegate
Exposing index allows RoundedItemDelegate to use a consistent padding
for the first and last item in the listview.
2024-05-04 00:36:34 +02:00
Tobias Fella
3a4aca7fbd Fix module 2024-05-03 22:40:32 +02:00
Tobias Fella
85ff8cdd4a Fix spacing of HiddenDelegate 2024-05-03 14:57:18 +02:00
l10n daemon script
b1048cb84a GIT_SILENT Sync po/docbooks with svn 2024-05-03 01:24:47 +00:00
l10n daemon script
ff9cf9abf6 GIT_SILENT Sync po/docbooks with svn 2024-05-02 01:23:33 +00:00
l10n daemon script
157c84663d GIT_SILENT Sync po/docbooks with svn 2024-05-01 01:23:12 +00:00
Tobias Fella
908e4fb5a4 Add test for room creation 2024-04-30 23:37:33 +02:00
Tobias Fella
fdca7d58e5 Push ImageEditorPage using pushDialogLayer
BUG: 486315
2024-04-30 23:36:17 +02:00
Tobias Fella
2eb26d512b Fix opening room on mobile 2024-04-30 22:05:22 +02:00
Tobias Fella
b7fdf7d60f Port away from qstr 2024-04-30 21:39:13 +02:00
Tobias Fella
2a1e66468d Fix if X11 on apple 2024-04-30 21:28:38 +02:00
Tobias Fella
cd7faf751e Show captions 2024-04-30 20:28:53 +02:00
Bart De Vries
d79d806cda Add "No Proxy" option to proxy settings 2024-04-30 20:19:22 +02:00
Bart De Vries
cae389c04c Make neochat obey the system-wide proxy settings 2024-04-30 20:19:22 +02:00
Tobias Fella
4e6850a60c Adapt to behavior change in libQuotient 2024-04-30 17:37:22 +02:00
l10n daemon script
a71f8cf358 GIT_SILENT Sync po/docbooks with svn 2024-04-30 01:24:36 +00:00
Carl Schwan
fe6ff9b2b6 Cleanup quick switcher
- Make it modal
- Fix spacing
- Use bottom separator instead of frame for search field
2024-04-29 16:54:25 +00:00
l10n daemon script
5a0f3e474d GIT_SILENT Sync po/docbooks with svn 2024-04-29 01:25:09 +00:00
Nate Graham
cd9c4239b1 Revert "Preserve mx-reply in the edited message if it exists"
This reverts commit fa57db8e83, because it
caused the last message you replied to to be shown as a reply in every
subsequent message you send, but they're only visible to people using
clients that aren't NeoChat, so you don't immediately realize that
you're causing pandemonium in your chatrooms.
2024-04-28 08:05:52 -06:00
James Graham
0cf1d87b12 Fix the master show link preview setting and add back the per room setting
Title

BUG: 486126
2024-04-28 10:51:44 +00:00
l10n daemon script
99d91c1e07 GIT_SILENT Sync po/docbooks with svn 2024-04-28 01:21:04 +00:00
l10n daemon script
457f80bc9b GIT_SILENT Sync po/docbooks with svn 2024-04-27 01:20:24 +00:00
Tobias Fella
968e3fc23b Cleanup Main.qml 2024-04-26 22:59:06 +02:00
Tobias Fella
b1e338579d Port UserConsentSheet to Kirigami.Dialog 2024-04-26 22:51:48 +02:00
Tobias Fella
7e4361bb5e Fix AddServerSheet 2024-04-26 19:11:03 +02:00
l10n daemon script
dd35fa3d91 GIT_SILENT Sync po/docbooks with svn 2024-04-26 01:20:19 +00:00
Tobias Fella
affb911d97 Create QML module for chatbar 2024-04-25 23:02:59 +02:00
Tobias Fella
785f9cd1b6 Fix some warnings 2024-04-25 22:57:24 +02:00
Tobias Fella
419056f098 Fix QML warnings 2024-04-25 22:56:28 +02:00
Tobias Fella
396db18de2 Fix unqualified access 2024-04-25 22:53:16 +02:00
Tobias Fella
f124721cd9 Fix qmlls warning 2024-04-25 22:52:38 +02:00
Tobias Fella
52e49b49fb Remove unnecessary parent 2024-04-25 22:51:59 +02:00
Tobias Fella
10e03777e9 Fix qmlls warning 2024-04-25 22:48:55 +02:00
Tobias Fella
27538b72e9 Remove unused imports 2024-04-25 22:48:20 +02:00
Tobias Fella
19ace37a75 Fix HoverLinkIndicator warnings 2024-04-25 22:47:55 +02:00
Tobias Fella
90c5377ef0 Port direct chat confirmation dialog away from OverlaySheet 2024-04-25 22:47:17 +02:00
Tobias Fella
f0e3d3e474 Fix some dialog parenting 2024-04-25 22:46:03 +02:00
Tobias Fella
26064ebf8c Remove stray log statement 2024-04-25 22:34:40 +02:00
Tobias Fella
1d92b74131 Use escaped room name in ConfirmLeaveDialog 2024-04-25 22:30:53 +02:00
l10n daemon script
5f83c137d2 GIT_SILENT Sync po/docbooks with svn 2024-04-25 01:21:47 +00:00
Joshua Goins
fa57db8e83 Preserve mx-reply in the edited message if it exists 2024-04-24 19:03:28 +00:00
Joshua Goins
9d3c2e19f5 Strip replies when calling EventHandler::getMarkdownBody()
This matches previous behavior before
e2eb6ab33c and including the markdown
blockquote breaks edits. This also adds a test to ensure it does indeed
get stripped.
2024-04-24 19:03:28 +00:00
l10n daemon script
46a9600d55 GIT_SILENT Sync po/docbooks with svn 2024-04-24 01:29:43 +00:00
James Graham
de40701cf6 Multiple Link Previews
- Show a preview for each link in the text below the block in which it appears.
- Allow link previews to be dismissed
2024-04-23 19:45:33 +00:00
Tobias Fella
307536c6b6 Use escaped title in devtools 2024-04-23 13:27:15 +02:00
Tobias Fella
203be8bd35 Work around QML opening dialog in wrong window 2024-04-23 13:24:00 +02:00
Tobias Fella
1e644587b3 Replace Quotient::Connection with NeoChatConnection where possible 2024-04-23 12:35:15 +02:00
James Graham
66a60f09e3 Refactor the MessageComponentModel component update 2024-04-23 11:39:18 +02:00
Tobias Fella
69b6f16ec1 Remove search bar; Use QuickSwitcher instead 2024-04-23 10:19:43 +02:00
l10n daemon script
10b4274a3d GIT_SILENT Sync po/docbooks with svn 2024-04-23 01:29:16 +00:00
James Graham
28c9d94457 Fix Roomlist Shortcuts
Fix the ctrl + pgup/pgdwn shortcuts for the room list so that they work with tree model

BUG: 485949
2024-04-22 22:01:46 +00:00
Tobias Fella
d74fd1a560 Force author display name in HiddenDelegate to PlainText 2024-04-22 23:14:31 +02:00
James Graham
624b1b06c5 Make the SpaceDrawer navigable with the keyboard. 2024-04-22 18:18:15 +02:00
Carl Schwan
95376c2ccc Apply 1 suggestion(s) to 1 file(s)
Co-authored-by: Carl Schwan <carl@carlschwan.eu>
2024-04-22 14:58:44 +00:00
James Graham
1eb622165b Use AvatarButton in UserInfo instead of a custom button. This has the advantage of showing keyboard focus properly 2024-04-22 16:50:56 +02:00
Nate Graham
9d6ba324fb Use more appropriate icons and tooltips for the room info drawer handles
Right now they use the standard text but left and right arrow icons,
which is a bit odd, and I think fails to convey what will happen when
clicked especially whern the drawer is closed.

Instead, let's use descriptive tooltip text for both, and a descriptive
icon for the the "this will open the drawer" handle button. For the one
to close the drawer, the default icon seems better, so let's stop
overriding it.
2024-04-22 08:10:39 +00:00
l10n daemon script
d462852ab9 GIT_SILENT Sync po/docbooks with svn 2024-04-22 01:28:36 +00:00
l10n daemon script
eeec81898b SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-04-22 01:15:14 +00:00
James Graham
ab0c8b8170 Use new cornerRadius Kirigami unit across the app 2024-04-21 19:19:57 +02:00
James Graham
91d295e0bb Make sure that tab can be used to navigate away from the chatbar 2024-04-21 17:18:12 +00:00
James Graham
125974dd7a Add Carl's focus title hack as a devtool option 2024-04-21 17:02:26 +00:00
Tobias Fella
92895a7d00 Improve CodeComponent background 2024-04-21 18:21:54 +02:00
Nate Graham
d9308440e6 Make the "add new" menu button a hamburger menu
I know hamburger menus sometimes aren't amazing, but the current icon is
misleading. It's a plus button which generally means "create new".
However the menu is full of actions not related to creating new things,
including:

- Explore Rooms
- Find your Friends
- Scan a QR Code

These actions may technically result in a new room appearing in the
sidebar, but that's not a user's definition of creating a new thing;
these are *joining* a thing, and the fact that a new entry appears in
the sidebar is an implementation detail.

As a result the existing icon is inaccurate, and also holds back the
menu from adding additional items in the future that are even less
related to creating new rooms. An example would be the quick room
switcher, which is not exposed visibly in the UI anywhere, and could not
logically live in the current menu without changing its icon and text.
2024-04-21 15:07:29 +00:00
James Graham
5340142c06 Change actionChanged to notificationActionChanged
Change actionChanged to notificationActionChanged to avoid any clashes with ItemDelegate action property signals
2024-04-21 14:37:02 +00:00
James Graham
012d30ee9f Elide the Hidden delegate text 2024-04-21 13:33:00 +02:00
James Graham
031d69d996 Only override the DelegateType when showing hidden messages 2024-04-21 13:25:49 +02:00
James Graham
8b63c18f65 Implement devtoool to show hidden timeline messages 2024-04-21 10:50:59 +00:00
James Graham
dc2f11eb2b Fancy Effects 2021-2024 gone but never forgotten
Remove fancy effects as it's busted and causing CPU spikes.
2024-04-21 10:50:45 +00:00
James Graham
13e64a9487 Use 0.8.x for libQuotient flatpak 2024-04-21 12:41:21 +02:00
Albert Astals Cid
6a3c88ae5b GIT_SILENT Upgrade release service version to 24.07.70. 2024-04-21 12:28:32 +02:00
l10n daemon script
08a7e324aa GIT_SILENT Sync po/docbooks with svn 2024-04-21 01:23:23 +00:00
James Graham
9202a4525f Make sure the user can get to the navigationtabbar 2024-04-20 17:21:21 +00:00
Carl Schwan
bfc756fb35 rejrejore 2024-04-20 17:21:21 +00:00
Carl Schwan
2a735ff1cc jreojreojr 2024-04-20 17:21:21 +00:00
James Graham
551092a1b4 Make sure the drawer get active focus on open 2024-04-20 17:21:21 +00:00
Carl Schwan
ddd12688aa RoomInformation: allow tabbing on actions 2024-04-20 17:21:21 +00:00
l10n daemon script
71767c4172 GIT_SILENT Sync po/docbooks with svn 2024-04-20 01:23:40 +00:00
l10n daemon script
ee405fbff6 GIT_SILENT Sync po/docbooks with svn 2024-04-19 01:25:40 +00:00
James Graham
c87c6fbabb Add kitemmodels back to Permissions.qml 2024-04-18 20:48:24 +01:00
Tobias Fella
096b36b89b Try fixing test some more 2024-04-18 19:19:31 +02:00
Tobias Fella
c3db90d2e3 Make DrKonqi work with NeoChat 2024-04-18 18:49:12 +02:00
Tobias Fella
b7df10aa45 Try fixing appium test 2024-04-18 18:15:15 +02:00
l10n daemon script
fea5e02e7d GIT_SILENT Sync po/docbooks with svn 2024-04-18 01:18:34 +00:00
Tobias Fella
cb94261727 Fix compatibility with libQuotient dev branch 2024-04-17 13:01:32 +02:00
l10n daemon script
efac7e4860 GIT_SILENT Sync po/docbooks with svn 2024-04-17 01:25:31 +00:00
Tobias Fella
0f6fd3adee Remove outdated event registrations 2024-04-16 22:39:16 +02:00
James Graham
e5e0405401 Fix typo 2024-04-16 21:16:21 +01:00
Tobias Fella
bb35e9ce15 Add option to show all rooms in "uncategorized" tab 2024-04-16 20:49:17 +02:00
Tobias Fella
5881db4e55 Add missing import to global menu 2024-04-16 20:25:04 +02:00
Tobias Fella
89f7167b08 Remember previous downloads after restarts
Fixes #636
2024-04-16 17:55:26 +02:00
l10n daemon script
3b39fcff84 GIT_SILENT Sync po/docbooks with svn 2024-04-16 01:27:26 +00:00
Tobias Fella
0daf45a465 Fix opening account editor 2024-04-15 17:48:26 +02:00
Tobias Fella
c0d7b96e79 Mark ThreePIdModel as uncreatable 2024-04-15 17:15:01 +02:00
Laurent Montel
a247e40865 Add missing includes moc 2024-04-15 08:10:50 +02:00
Laurent Montel
c3e7a99bca Add missing #pragma once 2024-04-15 08:10:22 +02:00
l10n daemon script
9080d8be6a GIT_SILENT Sync po/docbooks with svn 2024-04-15 01:20:15 +00:00
James Graham
b7ee83f6b6 Add visualisation of the account's third party IDs in the account editor.
A category won't be shown if there are no relevant IDs (will add the ability to add new ones later).

Part of network/neochat#565

![image](/uploads/7da00b0b4acf90d145c09969ac2a91e1/image.png)
2024-04-14 16:37:34 +00:00
James Graham
1e24bde9a9 Add hover button for maximising a code block
Forgot to add it with the maximize mr
2024-04-14 16:32:12 +00:00
l10n daemon script
ba82df1152 GIT_SILENT Sync po/docbooks with svn 2024-04-14 01:20:38 +00:00
Tobias Fella
8980fe7838 Improve README 2024-04-13 21:59:16 +02:00
James Graham
ef34ed7c20 Fix Verification Window Sizing
Update the layouts in the device verifcation process to make sure that all possible window sizes can be handled

BUG: 485309
2024-04-13 18:51:06 +00:00
James Graham
17d60b79ca Fix showing the unread count for DM section when not selected 2024-04-13 15:15:27 +00:00
James Graham
ab0a32c339 Add a debug options page to devtools with the option to always allow verification for now
Closes network/neochat#646
2024-04-13 15:11:25 +00:00
James Graham
697778df8d Fix feature flag devtools page by adding necohat import as this is where config comes from now 2024-04-13 15:28:26 +01:00
Yuri Chornoivan
55caf84b94 Fix minor typos 2024-04-13 08:47:48 +03:00
l10n daemon script
335c012f1b GIT_SILENT Sync po/docbooks with svn 2024-04-13 01:25:05 +00:00
Tobias Fella
3c4c538de8 Use declarative type registration for remaining types 2024-04-12 22:17:39 +02:00
Tobias Fella
c344a3ee55 Devtools: Implement changing room state 2024-04-12 22:08:33 +02:00
l10n daemon script
d2695947ed GIT_SILENT Sync po/docbooks with svn 2024-04-12 01:22:49 +00:00
Tobias Fella
21beeef920 Load Main qml component from module 2024-04-11 21:01:55 +02:00
James Graham
a4630a53fa Create QML module for login 2024-04-11 18:56:08 +00:00
Tobias Fella
f5aef8d0c3 Use Qt.createComponent in non-weird way
Fixed #647
2024-04-11 18:16:19 +02:00
l10n daemon script
e044e66030 GIT_SILENT Sync po/docbooks with svn 2024-04-11 01:23:29 +00:00
James Graham
88bfacd386 Show QR code for room in drawer 2024-04-10 18:19:05 +00:00
James Graham
c61c73088f Add button to get a QR code for the local user to the account editor page 2024-04-10 17:19:11 +00:00
l10n daemon script
2887263f26 GIT_SILENT Sync po/docbooks with svn 2024-04-10 01:24:51 +00:00
James Graham
72b90bdf5c Fix gaps at the top and bottom of SpaceHomePage witht he wrong background colour.
Note: the bottom gap only happened after a room was loaded for the first time
2024-04-09 19:03:24 +00:00
James Graham
163b02f023 Add image info for stickers
Closes network/neochat#584
2024-04-09 18:54:59 +00:00
James Graham
1a96899336 Linkpreviewer Improvements
- Have LinkPreviewers stored in NeoChatConnection so that they don't have to be reloaded everytime the MessageContentModel is refreshed
- This means the link is never changed (it will be swiched for a new previewer with the new link)
- LinkPreviewers are stored by URL so they can be re-used by any event with the same URL

BUG: 484927  (because the offending code is ripped out)
2024-04-09 18:35:16 +00:00
l10n daemon script
554c086aba GIT_SILENT Sync po/docbooks with svn 2024-04-09 01:25:03 +00:00
Heiko Becker
1fad9bf7db GIT_SILENT Update Appstream for new release
(cherry picked from commit 86e8dc2e40)
2024-04-08 17:57:25 +02:00
l10n daemon script
22d922e451 GIT_SILENT Sync po/docbooks with svn 2024-04-08 01:23:31 +00:00
327 changed files with 54765 additions and 38703 deletions

View File

@@ -2,7 +2,7 @@
"id": "org.kde.neochat",
"branch": "master",
"runtime": "org.kde.Platform",
"runtime-version": "6.7",
"runtime-version": "6.6",
"sdk": "org.kde.Sdk",
"command": "neochat",
"tags": [
@@ -110,7 +110,7 @@
{
"type": "git",
"url": "https://github.com/quotient-im/libQuotient.git",
"branch": "dev",
"branch": "0.8.x",
"disable-submodules": true
}
],

1
.gitignore vendored
View File

@@ -12,3 +12,4 @@ kate.project.ctags.*
.idea/
cmake-build-*
src/res.generated.qrc
.qmlls.ini

View File

@@ -5,11 +5,11 @@ include:
- project: sysadmin/ci-utilities
file:
- /gitlab-templates/reuse-lint.yml
- /gitlab-templates/android-qt6.yml
- /gitlab-templates/linux-qt6.yml
- /gitlab-templates/windows-qt6.yml
- /gitlab-templates/freebsd-qt6.yml
# - /gitlab-templates/android-qt6.yml
# - /gitlab-templates/linux-qt6.yml
# - /gitlab-templates/windows-qt6.yml
# - /gitlab-templates/freebsd-qt6.yml
- /gitlab-templates/flatpak.yml
- /gitlab-templates/craft-android-qt6-apks.yml
- /gitlab-templates/craft-appimage-qt6.yml
- /gitlab-templates/craft-windows-x86-64-qt6.yml
# - /gitlab-templates/craft-android-qt6-apks.yml
# - /gitlab-templates/craft-appimage-qt6.yml
# - /gitlab-templates/craft-windows-x86-64-qt6.yml

View File

@@ -28,6 +28,7 @@ Dependencies:
'frameworks/kio': '@latest-kf6'
'frameworks/kwindowsystem': '@latest-kf6'
'frameworks/kstatusnotifieritem': '@latest-kf6'
'frameworks/kcrash': '@latest-kf6'
- 'on': ['Linux', 'FreeBSD']
'require':
'frameworks/kdbusaddons': '@latest-kf6'

View File

@@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.16)
# KDE Applications version, managed by release script.
set(RELEASE_SERVICE_VERSION_MAJOR "24")
set(RELEASE_SERVICE_VERSION_MINOR "04")
set(RELEASE_SERVICE_VERSION_MINOR "07")
set(RELEASE_SERVICE_VERSION_MICRO "70")
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
@@ -84,7 +84,7 @@ if(ANDROID)
)
else()
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem)
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem Crash)
find_package(KF6SyntaxHighlighting ${KF_MIN_VERSION} REQUIRED)
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
TYPE RUNTIME

View File

@@ -1,6 +1,6 @@
<!--
SPDX-FileCopyrightText: 2020-2021 Carl Schwan <carlschwan@kde.org>
SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
SPDX-FileCopyrightText: 2020-2024 Tobias Fella <tobias.fella@kde.org>
SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
SPDX-License-Identifier: CC0-1.0
-->
@@ -16,19 +16,18 @@ A Qt/QML based Matrix client.
## Introduction
NeoChat is a client for [Matrix](https://matrix.org), the decentralized communication protocol for instant
messaging. It is a fork of Spectral, using KDE frameworks, most notably [Kirigami](https://invent.kde.org/frameworks/kirigami)
to provide a convergent experience across multiple platforms.
messaging.
NeoChat also make use of other KDE Frameworks as well as [libQuotient](https://github.com/quotient-im/libQuotient), a
NeoChat is based on KDE frameworks and as [libQuotient](https://github.com/quotient-im/libQuotient), a
Qt-based SDK for the [Matrix Protocol](https://spec.matrix.org/).
![Timeline](https://cdn.kde.org/screenshots/neochat/application.png)
## Features
NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions
of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly
evolving but the aim remains to provide eventual support for the entire spec.
NeoChat aims to be a fully featured application for the Matrix specification. As such most parts of the current specification are supported, with the notable exceptions
of VoIP, threads, and some aspects of End-to-End Encryption. There are a few other smaller omissions due to the fact that the Matrix spec is constantly
evolving, but the aim remains to provide eventual support for the entire spec.
Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:
- Polls - MSC3381
@@ -39,26 +38,9 @@ Due to the nature of the Matrix specification development NeoChat also supports
Details where to find stable releases for NeoChat can be found on its [homepage](https://apps.kde.org/neochat).
In addition to the stable builds, unstable nightly builds are available for all platforms. These can be downloaded
from the [binary factory](https://binary-factory.kde.org/). There are unstable versions for the following platforms
in addition to stable ones:
- Android
- MacOS
- Windows
Additionally the nightly Flatpak version can be obtained from the nightly Flatpak repo using the following commands in your terminal:
```
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak remote-add --if-not-exists kdeapps --from https://distribute.kde.org/kdeapps.flatpakrepo
flatpak install kdeapps org.kde.neochat
```
The unstable Android version can also be obtained from the [KDE nightly F-Droid repo](https://community.kde.org/Android/FDroid).
## Running
Just start the executable in your preferred way - either from the build directory or from the installed location.
Nightly builds for linux and windows can be downloaded from [cdn.kde.org](https://cdn.kde.org/ci-builds/network/neochat/).
Nightly builds for android are available from [KDE's nightly F-Droid repository](https://community.kde.org/Android/F-Droid).
Nightly Flatpaks are available from [KDE's nightly Flatpak repository](https://userbase.kde.org/Tutorials/Flatpak).
## Building NeoChat
@@ -69,14 +51,18 @@ is primarily aimed at Linux development.
For Windows and Android [Craft](https://invent.kde.org/packaging/craft) is the primary choice. There are guides for setting up
development environments for [Windows](https://community.kde.org/Get_Involved/development/Windows) and [Android](https://develop.kde.org/docs/packaging/android/building_applications/).
## Running
Just start the executable in your preferred way - either from the build directory or from the installed location.
## Tests
Tests are in the repository under [autotests](autotests) and should all pass for any contribution.
Tests are in the repository under [autotests](autotests) and [appiumtests](appiumtests).
The project has CI setup to test new commits to the repository. All tests are expected to pass for a merge request to
be complete.
Current build status
## Current build status
![coverage](https://invent.kde.org/network/neochat/badges/master/pipeline.svg)
@@ -100,9 +86,9 @@ The best place to reach the maintainers is on the KDE Matrix instance in the Neo
## Acknowledgement
This program utilizes [libQuotient](https://github.com/quotient-im/libQuotient/) as its Matrix SDK.
NeoChat utilizes [libQuotient](https://github.com/quotient-im/libQuotient/) as its Matrix SDK.
This program is a fork of [Spectral](https://gitlab.com/spectral-im/spectral/).
NeoChat is a fork of [Spectral](https://gitlab.com/spectral-im/spectral/).
## License

56
appiumtests/createroomtest.py Executable file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
import os
import subprocess
import sys
import unittest
import time
from appium import webdriver
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
class CreateRoomTest(unittest.TestCase):
mockServerProcess: subprocess.Popen
@classmethod
def setUpClass(cls):
cls.mockServerProcess = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), "login-server.py")])
options = AppiumOptions()
options.set_capability("app", "neochat --ignore-ssl-errors --test")
cls.driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', options=options)
def setUp(self):
pass
def tearDown(self):
if not self._outcome.result.wasSuccessful():
self.driver.get_screenshot_as_file("failed_test_shot_{}.png".format(self.id()))
@classmethod
def tearDownClass(self):
self.mockServerProcess.terminate()
self.driver.quit()
def test_create_room(self):
self.driver.find_element(by=AppiumBy.NAME, value="@user:localhost:1234").click()
self.driver.find_element(by=AppiumBy.NAME, value="Show Menu").click()
self.driver.find_element(by=AppiumBy.NAME, value="Create a Room").click()
self.driver.find_element(by=AppiumBy.NAME, value="Name:").send_keys("Super awesome room name")#
time.sleep(0.1) # without this, the second half of the text is sent to the topic field?!
self.driver.find_element(by=AppiumBy.NAME, value="Topic:").send_keys("There are not enough raccoons here")
time.sleep(0.1)
self.driver.find_element(by=AppiumBy.NAME, value="Create Room").click()
time.sleep(0.1)
self.driver.find_element(by=AppiumBy.NAME, value="Super awesome room name").click()
self.driver.find_element(by=AppiumBy.NAME, value="Show Room Information").click()
self.driver.find_element(by=AppiumBy.NAME, value="There are not enough raccoons here")
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,78 @@
{
"next_batch": "batch1234",
"rooms": {
"join": {
"!newroom123321:localhost:1234": {
"state": {
"events": [
{
"type": "m.room.member",
"state_key": "@user:localhost:1234",
"sender": "@user:localhost:1234",
"origin_server_ts": 1432735824653,
"event_id": "$event_id_1234_0:localhost:1234",
"room_id": "!newroom123321:localhost:1234",
"content": {
"avatar_url": "",
"displayname": "A Display Name",
"membership": "join",
"reason": "Nothing"
},
"unsigned": {
"age": 1234
}
},
{
"type": "m.room.name",
"state_key": "",
"sender": "@user:localhost:1234",
"origin_server_ts": 1432735824653,
"event_id": "$event_id_1234_1:localhost:1234",
"room_id": "!newroom123321:localhost:1234",
"content": {
"name": "Super awesome room name"
},
"unsigned": {
"age": 1234
}
},
{
"type": "m.room.topic",
"state_key": "",
"sender": "@user:localhost:1234",
"origin_server_ts": 1432735824653,
"event_id": "$event_id_1234_2:localhost:1234",
"room_id": "!newroom123321:localhost:1234",
"content": {
"topic": "There are not enough raccoons here"
},
"unsigned": {
"age": 1234
}
}
]
},
"timeline": {
"events": [
{
"type": "m.room.message",
"sender": "@user:localhost:1234",
"origin_server_ts": 1432735824653,
"event_id": "$event_id_1234_1:localhost:1234",
"room_id": "!newroom123321:localhost:1234",
"content": {
"body": "This is a message",
"format": "org.matrix.custom.html",
"formatted_body": "<a href=\"https://matrix.to/#/@user:localhost:1234\">User</a>:",
"msgtype": "m.text"
},
"unsigned": {
"age": 1234
}
}
]
}
}
}
}
}

View File

@@ -6,6 +6,8 @@ from flask import Flask, request, abort
import os
app = Flask(__name__)
next_sync_payload = ""
@app.route("/_matrix/client/v3/login", methods=["GET"])
def login_get():
@@ -42,8 +44,13 @@ def load_json(name):
@app.route("/_matrix/client/r0/sync")
def sync():
result = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms")
global next_sync_payload
result = dict()
if len(next_sync_payload) > 0:
result = load_json(next_sync_payload)
next_sync_payload = ""
else:
result = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms")
return result
@app.route("/.well-known/matrix/client")
@@ -65,6 +72,18 @@ def upload_keys():
reply = dict()
return reply
@app.route("/_matrix/client/v3/createRoom", methods=["POST"])
def create_room():
global next_sync_payload
data = request.get_json()
if data["name"] != "Super awesome room name" or data["topic"] != "There are not enough raccoons here":
return dict(), 400
response = dict()
response["room_id"] = "!newroom123321:localhost:1234"
next_sync_payload = "sync_response_new_room"
return response
if __name__ == "__main__":
app.run(ssl_context='adhoc', port=1234)

View File

@@ -39,6 +39,10 @@ class OpenUserDetailsTest(unittest.TestCase):
def test_open_sheet(self):
self.driver.find_element(by=AppiumBy.NAME, value="@user:localhost:1234").click()
try:
self.driver.find_element(by=AppiumBy.NAME, value="Expand Normal").click()
except:
pass
self.driver.find_element(by=AppiumBy.NAME, value="Empty room (!room_id_1234:localhost:1234)").click()
self.driver.find_element(by=AppiumBy.NAME, value="A Display Name").click()
self.driver.find_element(by=AppiumBy.NAME, value="Account Details")

View File

@@ -6,6 +6,7 @@
#include <QObject>
#include <QTest>
#include <Quotient/roommember.h>
#include <Quotient/syncdata.h>
#include <qtestcase.h>
@@ -50,7 +51,7 @@ void ChatBarCacheTest::empty()
QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
QCOMPARE(chatBarCache->relationUser(), room->member(QString()));
QCOMPARE(chatBarCache->relationMessage(), QString());
QCOMPARE(chatBarCache->attachmentPath(), QString());
}
@@ -64,7 +65,7 @@ void ChatBarCacheTest::noRoom()
// ChatBarCache has no parent.
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationUser(), QVariantMap());
QCOMPARE(chatBarCache->relationUser(), Quotient::RoomMember());
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationMessage(), QString());
@@ -80,7 +81,7 @@ void ChatBarCacheTest::badParent()
// ChatBarCache has no parent.
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationUser(), QVariantMap());
QCOMPARE(chatBarCache->relationUser(), Quotient::RoomMember());
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationMessage(), QString());
@@ -98,7 +99,7 @@ void ChatBarCacheTest::reply()
QCOMPARE(chatBarCache->replyId(), QLatin1String("$153456789:example.org"));
QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
QCOMPARE(chatBarCache->relationUser(), room->member(QLatin1String("@example:example.org")));
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
QCOMPARE(chatBarCache->attachmentPath(), QString());
}
@@ -115,7 +116,7 @@ void ChatBarCacheTest::edit()
QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), true);
QCOMPARE(chatBarCache->editId(), QLatin1String("$153456789:example.org"));
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
QCOMPARE(chatBarCache->relationUser(), room->member(QLatin1String("@example:example.org")));
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
QCOMPARE(chatBarCache->attachmentPath(), QString());
}
@@ -132,7 +133,7 @@ void ChatBarCacheTest::attachment()
QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
QCOMPARE(chatBarCache->relationUser(), room->member(QString()));
QCOMPARE(chatBarCache->relationMessage(), QString());
QCOMPARE(chatBarCache->attachmentPath(), QLatin1String("some/path"));
}

View File

@@ -35,7 +35,7 @@
"content": {
"$153456789:example.org": {
"m.read": {
"@alice:matrix.org": {
"@alice:example.org": {
"ts": 1436451550453
}
}

View File

@@ -1,14 +0,0 @@
{
"content": {
"body": "https://matrix.to/#/@alice:example.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -1,14 +0,0 @@
{
"content": {
"body": "mxc://example.org/SEsfnsuifSDFSSEF",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -1,14 +0,0 @@
{
"content": {
"body": "testhttps://kde.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -37,16 +37,14 @@
"events": [
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice Margatroid",
"membership": "join",
"reason": "Looking for support"
"displayname": "Example",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@alice:example.org",
"state_key": "@example:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234

View File

@@ -51,6 +51,21 @@
"unsigned": {
"age": 1234
}
},
{
"content": {
"displayname": "Example",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@example:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
}
]
},

View File

@@ -1,14 +0,0 @@
{
"content": {
"body": "https://kde.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -1,14 +0,0 @@
{
"content": {
"body": "www.example.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -1,16 +0,0 @@
{
"content": {
"body": "[Rich Link](https://kde.org)",
"format": "org.matrix.custom.html",
"formatted_body": "<a href=\"https://kde.org\">Rich Link</a>",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -130,7 +130,7 @@ void DelegateSizeHelperTest::equalBreakpoint_data()
}
/**
* We expect a default return except in the case where the the two percentages are
* We expect a default return except in the case where the two percentages are
* equal as that case can be calculated without dividing by zero.
*/
void DelegateSizeHelperTest::equalBreakpoint()

View File

@@ -56,6 +56,7 @@ private Q_SLOTS:
void genericBody();
void nullGenericBody();
void markdownBody();
void markdownBodyReply();
void subtitle();
void nullSubtitle();
void mediaInfo();
@@ -100,28 +101,27 @@ void EventHandlerTest::nullEventId()
void EventHandlerTest::author()
{
auto event = room->messageEvents().at(0).get();
auto author = room->user(event->senderId());
auto author = room->member(event->senderId());
EventHandler eventHandler(room, event);
auto eventHandlerAuthor = eventHandler.getAuthor();
QCOMPARE(eventHandlerAuthor["isLocalUser"_ls], author->id() == room->localUser()->id());
QCOMPARE(eventHandlerAuthor["id"_ls], author->id());
QCOMPARE(eventHandlerAuthor["displayName"_ls], author->displayname(room));
QCOMPARE(eventHandlerAuthor["avatarSource"_ls], room->avatarForMember(author));
QCOMPARE(eventHandlerAuthor["avatarMediaId"_ls], author->avatarMediaId(room));
QCOMPARE(eventHandlerAuthor["color"_ls], Utils::getUserColor(author->hueF()));
QCOMPARE(eventHandlerAuthor["object"_ls], QVariant::fromValue(author));
QCOMPARE(eventHandlerAuthor.isLocalMember(), author.id() == room->localMember().id());
QCOMPARE(eventHandlerAuthor.id(), author.id());
QCOMPARE(eventHandlerAuthor.displayName(), author.displayName());
QCOMPARE(eventHandlerAuthor.avatarUrl(), author.avatarUrl());
QCOMPARE(eventHandlerAuthor.avatarMediaId(), author.avatarMediaId());
QCOMPARE(eventHandlerAuthor.color(), author.color());
}
void EventHandlerTest::nullAuthor()
{
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getAuthor(), QVariantMap());
QCOMPARE(emptyHandler.getAuthor(), RoomMember());
EventHandler noEventHandler(room, nullptr);
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_event set to nullptr. Returning empty user.");
QCOMPARE(noEventHandler.getAuthor(), room->getUser(nullptr));
QCOMPARE(noEventHandler.getAuthor(), RoomMember());
}
void EventHandlerTest::authorDisplayName()
@@ -301,6 +301,13 @@ void EventHandlerTest::markdownBody()
QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("This is an example\ntext message"));
}
void EventHandlerTest::markdownBodyReply()
{
EventHandler eventHandler(room, room->messageEvents().at(5).get());
QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("reply"));
}
void EventHandlerTest::subtitle()
{
EventHandler eventHandler(room, room->messageEvents().at(0).get());
@@ -385,31 +392,30 @@ void EventHandlerTest::nullReplyId()
void EventHandlerTest::replyAuthor()
{
auto replyEvent = room->messageEvents().at(0).get();
auto replyAuthor = room->user(replyEvent->senderId());
auto replyAuthor = room->member(replyEvent->senderId());
EventHandler eventHandler(room, room->messageEvents().at(5).get());
auto eventHandlerReplyAuthor = eventHandler.getReplyAuthor();
QCOMPARE(eventHandlerReplyAuthor["isLocalUser"_ls], replyAuthor->id() == room->localUser()->id());
QCOMPARE(eventHandlerReplyAuthor["id"_ls], replyAuthor->id());
QCOMPARE(eventHandlerReplyAuthor["displayName"_ls], replyAuthor->displayname(room));
QCOMPARE(eventHandlerReplyAuthor["avatarSource"_ls], room->avatarForMember(replyAuthor));
QCOMPARE(eventHandlerReplyAuthor["avatarMediaId"_ls], replyAuthor->avatarMediaId(room));
QCOMPARE(eventHandlerReplyAuthor["color"_ls], Utils::getUserColor(replyAuthor->hueF()));
QCOMPARE(eventHandlerReplyAuthor["object"_ls], QVariant::fromValue(replyAuthor));
QCOMPARE(eventHandlerReplyAuthor.isLocalMember(), replyAuthor.id() == room->localMember().id());
QCOMPARE(eventHandlerReplyAuthor.id(), replyAuthor.id());
QCOMPARE(eventHandlerReplyAuthor.displayName(), replyAuthor.displayName());
QCOMPARE(eventHandlerReplyAuthor.avatarUrl(), replyAuthor.avatarUrl());
QCOMPARE(eventHandlerReplyAuthor.avatarMediaId(), replyAuthor.avatarMediaId());
QCOMPARE(eventHandlerReplyAuthor.color(), replyAuthor.color());
EventHandler eventHandlerNoAuthor(room, room->messageEvents().at(0).get());
QCOMPARE(eventHandlerNoAuthor.getReplyAuthor(), room->getUser(nullptr));
QCOMPARE(eventHandlerNoAuthor.getReplyAuthor(), RoomMember());
}
void EventHandlerTest::nullReplyAuthor()
{
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReplyAuthor(), QVariantMap());
QCOMPARE(emptyHandler.getReplyAuthor(), RoomMember());
EventHandler noEventHandler(room, nullptr);
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_event set to nullptr. Returning empty user.");
QCOMPARE(noEventHandler.getReplyAuthor(), room->getUser(nullptr));
QCOMPARE(noEventHandler.getReplyAuthor(), RoomMember());
}
void EventHandlerTest::replyBody()
@@ -523,10 +529,10 @@ void EventHandlerTest::readMarkers()
auto readMarkers = eventHandler.getReadMarkers();
QCOMPARE(readMarkers.size(), 1);
QCOMPARE(readMarkers[0].toMap()["id"_ls], QStringLiteral("@alice:matrix.org"));
QCOMPARE(readMarkers[0].id(), QStringLiteral("@alice:example.org"));
QCOMPARE(eventHandler.getNumberExcessReadMarkers(), QString());
QCOMPARE(eventHandler.getReadMarkersString(), QStringLiteral("1 user: @alice:matrix.org"));
QCOMPARE(eventHandler.getReadMarkersString(), QStringLiteral("1 user: Alice Margatroid"));
EventHandler eventHandler2(room, room->messageEvents().at(2).get());
QCOMPARE(eventHandler2.hasReadMarkers(), true);
@@ -546,7 +552,7 @@ void EventHandlerTest::nullReadMarkers()
QCOMPARE(emptyHandler.hasReadMarkers(), false);
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReadMarkers(), QVariantList());
QCOMPARE(emptyHandler.getReadMarkers(), QList<Quotient::RoomMember>());
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getNumberExcessReadMarkers(), QString());
@@ -560,7 +566,7 @@ void EventHandlerTest::nullReadMarkers()
QCOMPARE(noEventHandler.hasReadMarkers(), false);
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReadMarkers(), QVariantList());
QCOMPARE(noEventHandler.getReadMarkers(), QList<Quotient::RoomMember>());
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getNumberExcessReadMarkers(), QString());

View File

@@ -6,12 +6,11 @@
#include "linkpreviewer.h"
#include "utils.h"
#include <Quotient/events/roommessageevent.h>
#include <Quotient/quotient_common.h>
#include <Quotient/syncdata.h>
#include "utils.h"
#include "testutils.h"
using namespace Quotient;
@@ -30,10 +29,11 @@ private Q_SLOTS:
void linkPreviewsMatch_data();
void linkPreviewsMatch();
void multipleLinkPreviewsMatch_data();
void multipleLinkPreviewsMatch();
void linkPreviewsReject_data();
void linkPreviewsReject();
void editedLink();
};
void LinkPreviewerTest::initTestCase()
@@ -44,60 +44,59 @@ void LinkPreviewerTest::initTestCase()
void LinkPreviewerTest::linkPreviewsMatch_data()
{
QTest::addColumn<QString>("eventSource");
QTest::addColumn<QString>("inputString");
QTest::addColumn<QUrl>("testOutputLink");
QTest::newRow("plainHttps") << QStringLiteral("test-validplainlink-event.json") << QUrl("https://kde.org"_ls);
QTest::newRow("richHttps") << QStringLiteral("test-validrichlink-event.json") << QUrl("https://kde.org"_ls);
QTest::newRow("plainWww") << QStringLiteral("test-validplainwwwlink-event.json") << QUrl("www.example.org"_ls);
QTest::newRow("multipleHttps") << QStringLiteral("test-multiplelink-event.json") << QUrl("www.example.org"_ls);
QTest::newRow("plainHttps") << QStringLiteral("https://kde.org") << QUrl("https://kde.org"_ls);
QTest::newRow("richHttps") << QStringLiteral("<a href=\"https://kde.org\">Rich Link</a>") << QUrl("https://kde.org"_ls);
QTest::newRow("richHttpsLinkDescription") << QStringLiteral("<a href=\"https://kde.org\">https://kde.org</a>") << QUrl("https://kde.org"_ls);
}
void LinkPreviewerTest::linkPreviewsMatch()
{
QFETCH(QString, eventSource);
QFETCH(QString, inputString);
QFETCH(QUrl, testOutputLink);
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
auto linkPreviewer = LinkPreviewer(room, event.get());
auto link = LinkPreviewer::linkPreviews(inputString)[0];
QCOMPARE(linkPreviewer.empty(), false);
QCOMPARE(linkPreviewer.url(), testOutputLink);
QCOMPARE(link, testOutputLink);
}
void LinkPreviewerTest::multipleLinkPreviewsMatch_data()
{
QTest::addColumn<QString>("inputString");
QTest::addColumn<QList<QUrl>>("testOutputLinks");
QTest::newRow("multipleHttps") << QStringLiteral("www.example.org https://kde.org") << QList{QUrl("www.example.org"_ls), QUrl("https://kde.org"_ls)};
QTest::newRow("multipleHttps1Invalid") << QStringLiteral("www.example.org mxc://example.org/SEsfnsuifSDFSSEF") << QList{QUrl("www.example.org"_ls)};
}
void LinkPreviewerTest::multipleLinkPreviewsMatch()
{
QFETCH(QString, inputString);
QFETCH(QList<QUrl>, testOutputLinks);
auto links = LinkPreviewer::linkPreviews(inputString);
QCOMPARE(links, testOutputLinks);
}
void LinkPreviewerTest::linkPreviewsReject_data()
{
QTest::addColumn<QString>("eventSource");
QTest::addColumn<QString>("inputString");
QTest::newRow("mxc") << QStringLiteral("test-invalidmxclink-event.json");
QTest::newRow("matrixTo") << QStringLiteral("test-invalidmatrixtolink-event.json");
QTest::newRow("noSpace") << QStringLiteral("test-invalidnospacelink-event.json");
QTest::newRow("mxc") << QStringLiteral("mxc://example.org/SEsfnsuifSDFSSEF");
QTest::newRow("matrixTo") << QStringLiteral("https://matrix.to/#/@alice:example.org");
QTest::newRow("noSpace") << QStringLiteral("testhttps://kde.org");
}
void LinkPreviewerTest::linkPreviewsReject()
{
QFETCH(QString, eventSource);
QFETCH(QString, inputString);
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
auto linkPreviewer = LinkPreviewer(room, event.get());
auto links = LinkPreviewer::linkPreviews(inputString);
QCOMPARE(linkPreviewer.empty(), true);
QCOMPARE(linkPreviewer.url(), QUrl());
}
void LinkPreviewerTest::editedLink()
{
room->syncNewEvents(QStringLiteral("test-linkpreviewerintial-sync.json"));
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
auto linkPreviewer = LinkPreviewer(room, event);
QCOMPARE(linkPreviewer.empty(), false);
QCOMPARE(linkPreviewer.url(), QUrl("https://kde.org"_ls));
room->syncNewEvents(QStringLiteral("test-linkpreviewerreplace-sync.json"));
QCOMPARE(linkPreviewer.empty(), true);
QCOMPARE(linkPreviewer.url(), QUrl());
QCOMPARE(links.empty(), true);
}
QTEST_MAIN(LinkPreviewerTest)

View File

@@ -53,9 +53,7 @@ void ReactionModelTest::basicReaction()
QCOMPARE(model.data(model.index(0), ReactionModel::ReactionRole), QStringLiteral("👍"));
QCOMPARE(model.data(model.index(0), ReactionModel::ToolTipRole),
QStringLiteral("@alice:matrix.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
auto authorList = QVariantList{room->getUser(room->user(QStringLiteral("@alice:matrix.org")))};
QCOMPARE(model.data(model.index(0), ReactionModel::AuthorsRole), authorList);
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalUser), false);
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalMember), false);
}
void ReactionModelTest::newReaction()

View File

@@ -54,6 +54,7 @@
<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="cs">Mluvte se svými přáteli na Matrixu</summary>
<summary xml:lang="en-GB">Chat with your friends on 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>
@@ -81,10 +82,11 @@
<p>NeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.</p>
<p xml:lang="ca">El NeoChat és una aplicació de xat que us permet aprofitar plenament la xarxa Matrix. Proporciona una manera segura d'enviar missatges de text, vídeos i arxius d'àudio a la vostra família, companys i amics.</p>
<p xml:lang="ca-valencia">NeoChat és una aplicació de xat que us permet aprofitar plenament la xarxa Matrix. Proporciona una manera segura d'enviar missatges de text, vídeos i arxius d'àudio a la vostra família, companys i amics.</p>
<p xml:lang="en-GB">NeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.</p>
<p xml:lang="eo">NeoChat estas babilej-apo, kiu ebligas al vi plene profiti de la Matrix-reto. Ĝi provizas al vi sekuran manieron sendi tekstmesaĝojn, filmetojn kaj sondosierojn al via familio, kolegoj kaj amikoj.</p>
<p xml:lang="es">NeoChat es una aplicación de chat que le permite aprovechar al máximo la red Matrix. Le proporciona un modo seguro de enviar mensajes de texto, vídeos y archivos de sonido a su familia, colegas y amigos.</p>
<p xml:lang="eu">NeoChat, Matrix sarearen abantaila guztiei probetsua ateratzeko aukera ematen dizun berriketa aplikaizo bat da. Zure familiari, kideei eta lagunei testu mezuak, bideoak eta audio fitxategiak era seguruan bidaltzeko aukera ematen dizu.</p>
<p xml:lang="fr">NeoChat est une application de discussions vous permettant de profiter pleinement du réseau Matrix. Elle vous offre un moyen sécurisé denvoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos ami(e)s.</p>
<p xml:lang="fr">NeoChat est une application de discussions vous permettant de profiter pleinement du réseau Matrix. Elle vous offre un moyen sécurisé d'envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos ami(e)s.</p>
<p xml:lang="hu">A NeoChat egy olyan csevegőalkalmazás, amellyel teljes mértékben kihasználhatja a Matrix hálózatot. Biztonságos módot biztosít szöveges üzenetek, videók és hangfájlok küldéséhez családtagjainak, kollégáinak és barátainak.</p>
<p xml:lang="ia">NeoChat es un app de conversation que te permitte prender avantage plen del rete Matrix. Il te forni un modo secur de inviar messages de texto, videos e files audio a tui familia, collegas e amicos.</p>
<p xml:lang="it">NeoChat è un'applicazione di chat che ti consente di sfruttare appieno la rete Matrix. Ti fornisce un modo sicuro per inviare messaggi di testo, video e file audio a familiari, colleghi e amici.</p>
@@ -118,6 +120,7 @@
<p xml:lang="nn">NeoChat har som mål å støtta all funksjonalitet i Matrix-spesifikasjonen. Førebels er alt i den gjeldande stabile spesifikasjonen støtta, med unntak av VoIP, trådar og nokre delar av ende-til-kryptering. Det finst òg andre småting som ikkje er støtta, sidan Matrix-spesifikasjon er i stadig endring, men målet er altså støtte for alt.</p>
<p xml:lang="pl">NeoChat w zamyśle ma być pełnowartościową aplikacją wg wytycznych Matriksa. Z tego powodu, wszystko, co jest obecnie w stabilnych wytycznych z pominięciem VoIP, wątków i niektórych części szyfrowania Użytkownik-do-Użytkownika są obecnie obsługiwane. Pominięto też kilka mniejszych rzeczy ze względu na ciągły rozwój wytycznych Matriksa, lecz celem nadal jest zapewnienie obsługi wszystkich wytycznych.</p>
<p xml:lang="pt">O NeoChat pretende ser uma aplicação completa para a especificação do Matrix. Como tal, tudo o que existe na especificação estável actual, com as notáveis excepções do VoIP, tópicos e alguns aspectos da Encriptação Ponto-a-Ponto, são suportados. Existem mais algumas omissões, devido ao facto que a norma do Matrix está em constante evolução, mas o objectivo continua a ser oferecer o suporte eventual para a norma por inteiro.</p>
<p xml:lang="ru">Целью создания NeoChat является полноценная реализация программы для спецификации Matrix. Как следствие, реализовано всё в текущей стабильной спецификации (за исключением голосовой интернет-связи, потоков и некоторых аспектов сквозного шифрования). Есть также несколько других незначительных пробелов, обусловленных постоянными изменениями спецификации Matrix. Тем не менее, стоит задача в итоге предоставить полную поддержку спецификации.</p>
<p xml:lang="sl">Neochat cilja, da bi bila popolna aplikacija po specifikaciji Matrixa. Kot takšna vsebuje vse v trenutni stabilni specifikaciji z pomembnimi izjemami pri VoIP, nitih in nekaterih vidikov šifriranja od konca do konca. Obstaja nekaj drugih manjših opustitev zaradi dejstva, da se specifikacija Matrix nenehno razvija, vendar cilj ostaja zagotoviti morebitno podporo celotni specifikaciji.</p>
<p xml:lang="sv">NeoChat har som mål att vara ett fullständigt program enligt Matrix-specifikationen. Som sådant stöds allt i den nuvarande stabila specifikationen, med de nämnvärda undantagen VoIP, trådar och några aspekter av kryptering hela vägen. Det finns några ytterligare utelämnanden på grund av att Matrix-specifikationen hela tiden utvecklas, men målet förblir att till slut erbjuda stöd för hela specifikationen.</p>
<p xml:lang="tr">NeoChat, Matrix belirtimi için tam özellikli bir uygulama olmayı hedefler. Bu nedenle; VoIP, ileti zincirleri ve Uçtan Uca Şifrelemenin bazı yönleri gibi dikkate değer istisnalar dışında var olan kararlı belirtimdeki her şey desteklenir. Matrix belirtiminin sürekli gelişmesi nedeniyle birkaç küçük eksiklik daha var; ancak amaç tüm belirtim için nihai destek sağlamak olmayı sürdürüyor.</p>
@@ -145,6 +148,7 @@
<p xml:lang="nn">På grunn av måten Matrix-spesifikasjonen vert utvikla på, støttar NeoChat òg nokre uferdige funksjonar:</p>
<p xml:lang="pl">Ze względu na sposób rozwoju Matriksa, NeoChat obsługuje także kilka niestabilnych możliwości. Obecnie są to:</p>
<p xml:lang="pt">Devido à natureza do desenvolvimento da especificação do Matrix, o NeoChat também suporta diversas funcionalidades instáveis. De momento são:</p>
<p xml:lang="ru">В силу природы разработки спецификации Matrix в NeoChat тоже предусмотрена поддержка многочисленных нестабильных возможностей. В текущей версии это следующие возможности:</p>
<p xml:lang="sl">Zaradi narave razvoja specifikacije Matrixa NeoChat podpira tudi številne nestabilne zmožnosti. Trenutno so to:</p>
<p xml:lang="sv">På grund av sättet Matrix-specifikationens utvecklas, stöder NeoChat också ett stor antal instabila funktioner. För närvarande är de:</p>
<p xml:lang="ta">மேட்ரிக்ஸு நெறிமுறை வரையறுக்கப்படும் வித‍த்தின் காரணமாக, பல நிலையற்ற அம்சங்களையும் நியோச்சாட் ஆதரிக்கிறது. தற்போது ஆதரிக்கப்படுபவை:</p>
@@ -202,6 +206,7 @@
<li xml:lang="nn">Klistremerke-pakkar  MSC2545</li>
<li xml:lang="pl">Paczki naklejek - MSC2545</li>
<li xml:lang="pt">Pacotes de Autocolantes - MSC2545</li>
<li xml:lang="ru">Наборы стикеров — MSC2545</li>
<li xml:lang="sl">Sticker Packs - MSC2545</li>
<li xml:lang="sv">Sticker Packs - MSC2545</li>
<li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li>
@@ -230,6 +235,7 @@
<li xml:lang="nn">Posisjonshendingar  MSC3488</li>
<li xml:lang="pl">Wydarzenia w miejscach - MSC3488</li>
<li xml:lang="pt">Eventos com Localizações - MSC3488</li>
<li xml:lang="ru">События местоположения — MSC3488</li>
<li xml:lang="sl">Location Events - MSC3488</li>
<li xml:lang="sv">Location Events - MSC3488</li>
<li xml:lang="ta">இட நிகழ்வுகள் - MSC3488</li>
@@ -275,6 +281,7 @@
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
<caption xml:lang="en-GB">Main view with room list, chat, and room information</caption>
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
@@ -291,6 +298,7 @@
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
@@ -304,6 +312,7 @@
<caption>Discover new communities with Matrix Spaces</caption>
<caption xml:lang="ca">Descobriu comunitats noves amb els espais de Matrix</caption>
<caption xml:lang="ca-valencia">Descobriu comunitats noves amb els espais de Matrix</caption>
<caption xml:lang="en-GB">Discover new communities with Matrix Spaces</caption>
<caption xml:lang="eo">Malkovru novajn komunumojn per Matrix Spaces</caption>
<caption xml:lang="es">Descubra nuevas comunidades con los espacios de Matrix</caption>
<caption xml:lang="eu">Ezagutu komunitate berriak Matrixeko Tokiak erabiliz</caption>
@@ -334,6 +343,7 @@
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
<caption xml:lang="en-GB">Main view with room list, chat, and room information</caption>
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
@@ -350,6 +360,7 @@
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
@@ -365,6 +376,7 @@
<caption xml:lang="ca">Pantalla d'inici de sessió</caption>
<caption xml:lang="ca-valencia">Pantalla d'inici de sessió</caption>
<caption xml:lang="cs">Přihlašovací obrazovka</caption>
<caption xml:lang="en-GB">Login screen</caption>
<caption xml:lang="eo">Ensaluta ekrano</caption>
<caption xml:lang="es">Pantalla de inicio de sesión</caption>
<caption xml:lang="eu">Saio-hasteko pantaila</caption>
@@ -381,6 +393,7 @@
<caption xml:lang="nn">Innloggingsbilete</caption>
<caption xml:lang="pl">Ekran logowania</caption>
<caption xml:lang="pt">Ecrã de autenticação</caption>
<caption xml:lang="ru">Окно входа</caption>
<caption xml:lang="sl">Prijavni zaslon</caption>
<caption xml:lang="sv">Inloggningsfönster</caption>
<caption xml:lang="ta">நுழைவுத் திரை</caption>
@@ -394,6 +407,8 @@
<content_attribute id="social-chat">intense</content_attribute>
</content_rating>
<releases>
<release version="24.05.0" date="2024-05-23"/>
<release version="24.02.2" date="2024-04-11"/>
<release version="24.02.1" date="2024-03-21"/>
<release version="24.02.0" date="2024-02-28">
<url>https://kde.org/announcements/megarelease/6/#neochat</url>

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

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

@@ -20,8 +20,6 @@ add_library(neochat STATIC
models/customemojimodel.h
clipboard.cpp
clipboard.h
matriximageprovider.cpp
matriximageprovider.h
models/messageeventmodel.cpp
models/messageeventmodel.h
models/messagefiltermodel.cpp
@@ -158,7 +156,6 @@ add_library(neochat STATIC
models/linemodel.cpp
models/linemodel.h
events/locationbeaconevent.h
events/serveraclevent.h
events/widgetevent.h
enums/messagecomponenttype.h
models/messagecontentmodel.cpp
@@ -174,6 +171,19 @@ add_library(neochat STATIC
sharehandler.h
models/roomtreeitem.cpp
models/roomtreeitem.h
foreigntypes.h
models/threepidmodel.cpp
models/threepidmodel.h
threepidaddhelper.cpp
threepidaddhelper.h
jobs/neochatadd3pidjob.cpp
jobs/neochatadd3pidjob.h
identityserverhelper.cpp
identityserverhelper.h
enums/powerlevel.cpp
enums/powerlevel.h
models/permissionsmodel.cpp
models/permissionsmodel.h
)
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
@@ -183,7 +193,7 @@ set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat
QML_FILES
qml/main.qml
qml/Main.qml
qml/AccountMenu.qml
qml/ExploreComponent.qml
qml/ExploreComponentMobile.qml
@@ -200,35 +210,14 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/ExplorerDelegate.qml
qml/InviteUserPage.qml
qml/ImageEditorPage.qml
qml/WelcomePage.qml
qml/NeochatMaximizeComponent.qml
qml/FancyEffectsContainer.qml
qml/TypingPane.qml
qml/QuickSwitcher.qml
qml/HoverActions.qml
qml/ChatBar.qml
qml/AttachmentPane.qml
qml/ReplyPane.qml
qml/CompletionMenu.qml
qml/PieProgressBar.qml
qml/QuickFormatBar.qml
qml/EmojiPicker.qml
qml/LoginStep.qml
qml/Login.qml
qml/Homeserver.qml
qml/Username.qml
qml/RegisterPassword.qml
qml/Captcha.qml
qml/Terms.qml
qml/Email.qml
qml/Password.qml
qml/LoginRegister.qml
qml/Loading.qml
qml/LoginMethod.qml
qml/Sso.qml
qml/UserDetailDialog.qml
qml/CreateRoomDialog.qml
qml/EmojiDialog.qml
qml/OpenFileDialog.qml
qml/KeyVerificationDialog.qml
qml/ConfirmLogoutDialog.qml
@@ -248,9 +237,6 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/ConfirmEncryptionDialog.qml
qml/RemoveSheet.qml
qml/BanSheet.qml
qml/EmojiTonesPicker.qml
qml/EmojiDelegate.qml
qml/EmojiGrid.qml
qml/RoomSearchPage.qml
qml/LocationChooser.qml
qml/TimelineView.qml
@@ -274,7 +260,6 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/SelectParentDialog.qml
qml/QrCodeMaximizeComponent.qml
qml/SelectSpacesDialog.qml
qml/AttachDialog.qml
qml/NotificationsView.qml
qml/SearchPage.qml
qml/ServerComboBox.qml
@@ -291,14 +276,17 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/AccountSwitchDialog.qml
qml/ConfirmLeaveDialog.qml
qml/CodeMaximizeComponent.qml
RESOURCES
qml/confetti.png
qml/glowdot.png
qml/EditStateDialog.qml
qml/ConsentDialog.qml
qml/AskDirectChatConfirmation.qml
qml/HoverLinkIndicator.qml
)
add_subdirectory(settings)
add_subdirectory(timeline)
add_subdirectory(devtools)
add_subdirectory(login)
add_subdirectory(chatbar)
if(UNIX)
qt_target_qml_sources(neochat QML_FILES qml/ShareAction.qml)
@@ -381,16 +369,18 @@ endif()
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
target_compile_definitions(neochat PUBLIC -DHAVE_RUNNER)
target_compile_definitions(neochat PUBLIC -DHAVE_X11)
target_compile_definitions(neochat PUBLIC -DHAVE_X11=1)
target_sources(neochat PRIVATE runner.cpp)
if (TARGET KUnifiedPush)
target_sources(neochat PRIVATE fakerunner.cpp)
endif()
else()
target_compile_definitions(neochat PUBLIC -DHAVE_X11=0)
endif()
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
target_link_libraries(neochat PRIVATE settingsplugin timelineplugin devtoolsplugin)
target_link_libraries(neochat PRIVATE settingsplugin timelineplugin devtoolsplugin loginplugin chatbarplugin)
target_link_libraries(neochat PUBLIC
Qt::Core
Qt::Quick
@@ -414,6 +404,10 @@ target_link_libraries(neochat PUBLIC
QCoro::Network
)
if (TARGET KF6::Crash)
target_link_libraries(neochat PUBLIC KF6::Crash)
endif()
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
if(NEOCHAT_FLATPAK)

View File

@@ -91,7 +91,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha
for (auto it = m_room->messageEvents().crbegin(); it != m_room->messageEvents().crend(); it++) {
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
if (event->senderId() == m_room->localUser()->id() && event->hasTextContent()) {
if (event->senderId() == m_room->localMember().id() && event->hasTextContent()) {
QString originalString;
if (event->content()) {
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;

View File

@@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
# SPDX-License-Identifier: BSD-2-Clause
qt_add_library(chatbar STATIC)
qt_add_qml_module(chatbar
URI org.kde.neochat.chatbar
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/chatbar
QML_FILES
AttachDialog.qml
ChatBar.qml
CompletionMenu.qml
EmojiDelegate.qml
EmojiGrid.qml
ReplyPane.qml
PieProgressBar.qml
EmojiPicker.qml
EmojiDialog.qml
EmojiTonesPicker.qml
)

View File

@@ -9,7 +9,6 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.neochat
import org.kde.neochat.config
/**
* @brief A component for typing and sending chat messages.
@@ -279,6 +278,8 @@ QQC2.Control {
Keys.onTabPressed: {
if (completionMenu.visible) {
completionMenu.complete();
} else {
contextDrawer.handle.children[0].forceActiveFocus()
}
}
Keys.onPressed: event => {

View File

@@ -24,7 +24,7 @@ QQC2.ItemDelegate {
contentItem: Item {
Kirigami.Heading {
anchors.fill: parent
visible: !root.emoji.startsWith("image") && !root.isImage
visible: !root.emoji.startsWith("mxc") && !root.isImage
text: root.emoji
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
@@ -41,17 +41,17 @@ QQC2.ItemDelegate {
}
Image {
anchors.fill: parent
visible: root.emoji.startsWith("image") || root.isImage
visible: root.emoji.startsWith("mxc") || root.isImage
source: visible ? root.emoji : ""
}
}
background: Rectangle {
color: root.checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
radius: Kirigami.Units.cornerRadius
Rectangle {
radius: Kirigami.Units.smallSpacing
radius: Kirigami.Units.cornerRadius
anchors.fill: parent
color: Kirigami.Theme.highlightColor
opacity: root.hovered && !root.pressed ? 0.2 : 0

View File

@@ -38,18 +38,22 @@ QQC2.Popup {
}
background: Kirigami.ShadowedRectangle {
Kirigami.Theme.colorSet: Kirigami.Theme.View
radius: Kirigami.Units.cornerRadius
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.mediumSpacing
shadow {
size: Kirigami.Units.largeSpacing
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)
yOffset: 2
}
border {
color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
width: 2
width: 1
color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, Kirigami.Theme.frameContrast)
}
shadow {
size: Kirigami.Units.gridUnit
yOffset: 0
color: Qt.rgba(0, 0, 0, 0.2)
}
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.View
}
modal: true

View File

@@ -30,7 +30,7 @@ QQC2.Popup {
onOpened: x = Math.min(parent.mapFromGlobal(QQC2.Overlay.overlay.width - root.width, 0).x, -(width - parent.width) / 2)
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.mediumSpacing
radius: Kirigami.Units.cornerRadius
shadow {
size: Kirigami.Units.largeSpacing
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)

View File

@@ -3,6 +3,8 @@
#include "chatbarcache.h"
#include <Quotient/roommember.h>
#include "chatdocumenthandler.h"
#include "eventhandler.h"
#include "neochatroom.h"
@@ -84,7 +86,7 @@ void ChatBarCache::setEditId(const QString &editId)
Q_EMIT attachmentPathChanged();
}
QVariantMap ChatBarCache::relationUser() const
Quotient::RoomMember ChatBarCache::relationUser() const
{
if (parent() == nullptr) {
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
@@ -96,9 +98,9 @@ QVariantMap ChatBarCache::relationUser() const
return {};
}
if (m_relationId.isEmpty()) {
return room->getUser(nullptr);
return room->member(QString());
}
return room->getUser(room->user((*room->findInTimeline(m_relationId))->senderId()));
return room->member((*room->findInTimeline(m_relationId))->senderId());
}
QString ChatBarCache::relationMessage() const

View File

@@ -10,6 +10,12 @@
class ChatDocumentHandler;
namespace Quotient
{
class RoomMember;
}
/**
* @brief Defines a user mention in the current chat or edit text.
*/
@@ -88,26 +94,13 @@ class ChatBarCache : public QObject
Q_PROPERTY(QString editId READ editId WRITE setEditId NOTIFY relationIdChanged)
/**
* @brief Get the user for the message being replied to.
* @brief Get the RoomMember object for the message being replied to.
*
* This is different to getting a Quotient::User object
* as neither of those can provide details like the displayName or avatarMediaId
* without the room context as these can vary from room to room.
* Returns an empty RoomMember if not replying to a message.
*
* Returns an empty user if not replying to a message.
*
* The user QVariantMap has the following properties:
* - isLocalUser - Whether the user is the local user.
* - id - The matrix ID of the user.
* - displayName - Display name in the context of this room.
* - avatarSource - The mxc URL for the user's avatar in the current room.
* - avatarMediaId - Avatar id in the context of this room.
* - color - Color for the user.
* - object - The Quotient::User object for the user.
*
* @sa getUser, Quotient::User
* @sa Quotient::RoomMember
*/
Q_PROPERTY(QVariantMap relationUser READ relationUser NOTIFY relationIdChanged)
Q_PROPERTY(Quotient::RoomMember relationUser READ relationUser NOTIFY relationIdChanged)
/**
* @brief The content of the related message.
@@ -161,7 +154,7 @@ public:
QString editId() const;
void setEditId(const QString &editId);
QVariantMap relationUser() const;
Quotient::RoomMember relationUser() const;
QString relationMessage() const;

View File

@@ -91,7 +91,7 @@ class ChatDocumentHandler : public QObject
Q_PROPERTY(CompletionModel *completionModel READ completionModel CONSTANT)
/**
* @brief The current room that the the text document is being handled for.
* @brief The current room that the text document is being handled for.
*/
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)

View File

@@ -9,28 +9,20 @@
#include <KLocalizedString>
#include <QGuiApplication>
#include <QNetworkProxy>
#include <QQuickTextDocument>
#include <QQuickWindow>
#include <QStandardPaths>
#include <QStringBuilder>
#include <QTimer>
#include <signal.h>
#include <Quotient/accountregistry.h>
#include <Quotient/connection.h>
#include <Quotient/csapi/logout.h>
#include <Quotient/csapi/notifications.h>
#include <Quotient/eventstats.h>
#include <Quotient/qt_connection_util.h>
#include <Quotient/settings.h>
#include "neochatconfig.h"
#include "neochatconnection.h"
#include "neochatroom.h"
#include "notificationsmanager.h"
#include "proxycontroller.h"
#include "roommanager.h"
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
#include "trayicon.h"
@@ -46,6 +38,10 @@
#endif
#endif
#ifdef HAVE_KUNIFIEDPUSH
#include <kunifiedpush/connector.h>
#endif
bool testMode = false;
using namespace Quotient;
@@ -157,7 +153,7 @@ void Controller::addConnection(NeoChatConnection *c)
});
connect(c, &NeoChatConnection::loggedOut, this, [this, c] {
if (accounts().count() > 1) {
// Only set the connection if the the account being logged out is currently active
// Only set the connection if the account being logged out is currently active
if (c == activeConnection()) {
setActiveConnection(dynamic_cast<NeoChatConnection *>(accounts().accounts()[0]));
}
@@ -190,7 +186,7 @@ void Controller::invokeLogin()
m_accountsLoading += accountId;
Q_EMIT accountsLoadingChanged();
if (!account.homeserver().isEmpty()) {
auto accessTokenLoadingJob = loadAccessTokenFromKeyChain(account);
auto accessTokenLoadingJob = loadAccessTokenFromKeyChain(account.userId());
connect(accessTokenLoadingJob, &QKeychain::Job::finished, this, [accountId, this, accessTokenLoadingJob](QKeychain::Job *) {
AccountSettings account{accountId};
QString accessToken;
@@ -218,11 +214,11 @@ void Controller::invokeLogin()
}
}
QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const AccountSettings &account)
QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const QString &userId)
{
qDebug() << "Reading access token from the keychain for" << account.userId();
qDebug() << "Reading access token from the keychain for" << userId;
auto job = new QKeychain::ReadPasswordJob(qAppName(), this);
job->setKey(account.userId());
job->setKey(userId);
// Handling of errors
connect(job, &QKeychain::Job::finished, this, [this, job]() {
@@ -253,12 +249,12 @@ QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const Accoun
return job;
}
bool Controller::saveAccessTokenToKeyChain(const AccountSettings &account, const QByteArray &accessToken)
bool Controller::saveAccessTokenToKeyChain(const QString &userId, const QByteArray &accessToken)
{
qDebug() << "Save the access token to the keychain for " << account.userId();
qDebug() << "Save the access token to the keychain for " << userId;
QKeychain::WritePasswordJob job(qAppName());
job.setAutoDelete(false);
job.setKey(account.userId());
job.setKey(userId);
job.setBinaryData(accessToken);
QEventLoop loop;
QKeychain::WritePasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
@@ -411,11 +407,11 @@ void Controller::removeConnection(const QString &userId)
}
}
bool Controller::ssssSupported() const
void Controller::saveFileContent(const QString &path, const QByteArray &data) const
{
#if __has_include("Quotient/e2ee/sssshandler.h")
return true;
#else
return false;
#endif
QUrl url(path);
QFile file(url.toLocalFile());
file.open(QFile::WriteOnly);
file.write(data);
file.close();
}

View File

@@ -5,15 +5,9 @@
#include <QObject>
#include <QQmlEngine>
#include <QQuickItem>
#include "neochatconnection.h"
#include <Quotient/accountregistry.h>
#include <Quotient/settings.h>
#ifdef HAVE_KUNIFIEDPUSH
#include <kunifiedpush/connector.h>
#endif
class TrayIcon;
class QQuickTextDocument;
@@ -56,8 +50,6 @@ class Controller : public QObject
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
Q_PROPERTY(bool ssssSupported READ ssssSupported CONSTANT)
public:
static Controller &instance();
static Controller *create(QQmlEngine *engine, QJSEngine *)
@@ -82,7 +74,7 @@ public:
/**
* @brief Save an access token to the keychain for the given account.
*/
bool saveAccessTokenToKeyChain(const Quotient::AccountSettings &account, const QByteArray &accessToken);
bool saveAccessTokenToKeyChain(const QString &userId, const QByteArray &accessToken);
[[nodiscard]] bool supportSystemTray() const;
@@ -95,6 +87,7 @@ public:
static void listenForNotifications();
Q_INVOKABLE QString loadFileContent(const QString &path) const;
Q_INVOKABLE void saveFileContent(const QString &path, const QByteArray &data) const;
Quotient::AccountRegistry &accounts();
@@ -102,22 +95,20 @@ public:
Q_INVOKABLE void removeConnection(const QString &userId);
bool ssssSupported() const;
private:
explicit Controller(QObject *parent = nullptr);
QPointer<NeoChatConnection> m_connection;
TrayIcon *m_trayIcon = nullptr;
QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const Quotient::AccountSettings &account);
QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const QString &account);
void loadSettings();
void saveSettings() const;
Quotient::AccountRegistry m_accountRegistry;
QStringList m_accountsLoading;
QMap<QString, QPointer<Quotient::Connection>> m_connectionsLoading;
QMap<QString, QPointer<NeoChatConnection>> m_connectionsLoading;
QString m_endpoint;
private Q_SLOTS:

View File

@@ -23,7 +23,7 @@ ColumnLayout {
model: root.connection.accountDataEventTypes
delegate: FormCard.FormButtonDelegate {
text: modelData
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet.qml'), {
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
sourceText: root.connection.accountDataJsonString(modelData)
}, {
title: i18nc("@title:window", "Event Source"),

View File

@@ -8,6 +8,7 @@ qt_add_qml_module(devtools
QML_FILES
DevtoolsPage.qml
AccountData.qml
DebugOptions.qml
FeatureFlagPage.qml
RoomData.qml
ServerData.qml

View File

@@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
import QtQuick
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.neochat
FormCard.FormCardPage {
id: root
FormCard.FormCard {
Layout.topMargin: Kirigami.Units.largeSpacing
FormCard.FormCheckDelegate {
text: i18nc("@option:check", "Show hidden events in the timeline")
checked: Config.showAllEvents
onToggled: Config.showAllEvents = checked
}
FormCard.FormCheckDelegate {
id: roomAccountDataVisibleCheck
text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification")
description: i18n("Allow the user to start a verification session with devices that were already verified")
checked: Config.alwaysVerifyDevice
onToggled: Config.alwaysVerifyDevice = checked
}
FormCard.FormCheckDelegate {
text: i18nc("@option:check", "Show focus in window header")
checked: Config.windowTitleFocus
onToggled: {
Config.windowTitleFocus = checked;
Config.save();
}
}
}
}

View File

@@ -26,12 +26,17 @@ FormCard.FormCardPage {
readonly property real tabWidth: tabBar.width / tabBar.count
QQC2.TabButton {
text: qsTr("Room Data")
text: i18nc("@title:tab", "Debug Options")
implicitWidth: tabBar.tabWidth
}
QQC2.TabButton {
text: qsTr("Server Info")
text: i18nc("@title:tab", "Room Data")
implicitWidth: tabBar.tabWidth
}
QQC2.TabButton {
text: i18nc("@title:tab", "Server Info")
implicitWidth: tabBar.tabWidth
}
@@ -52,6 +57,7 @@ FormCard.FormCardPage {
currentIndex: tabBar.currentIndex
DebugOptions {}
RoomData {
room: root.room
connection: root.connection

View File

@@ -7,7 +7,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.neochat.config
import org.kde.neochat
FormCard.FormCardPage {
id: root
@@ -28,5 +28,14 @@ FormCard.FormCardPage {
onToggled: Config.secretBackup = checked
}
FormCard.FormCheckDelegate {
text: i18nc("@option:check Enable the matrix feature to add a phone number as a third party ID", "Add phone numbers as 3PIDs")
checked: Config.phone3PId
onToggled: {
Config.phone3PId = checked
Config.save();
}
}
}
}

View File

@@ -25,9 +25,10 @@ ColumnLayout {
text: i18n("Room")
textRole: "escapedDisplayName"
valueRole: "roomId"
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.DisplayNameRole)
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.EscapedDisplayNameRole)
model: RoomManager.roomListModel
currentIndex: 0
displayMode: FormCard.FormComboBoxDelegate.Page
Component.onCompleted: currentIndex = RoomManager.roomListModel.rowForRoom(root.room)
onCurrentValueChanged: root.room = RoomManager.roomListModel.roomByAliasOrId(roomComboBox.currentValue)
}
@@ -46,7 +47,7 @@ ColumnLayout {
model: root.room.accountDataEventTypes
delegate: FormCard.FormButtonDelegate {
text: modelData
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet.qml'), {
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
sourceText: root.room.roomAcountDataJson(text)
}, {
title: i18n("Event Source"),
@@ -74,14 +75,9 @@ ColumnLayout {
description: i18ncp("'Event' being some JSON data, not something physically happening.", "%1 event of this type", "%1 events of this type", model.eventCount)
onClicked: {
if (model.eventCount === 1) {
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet.qml'), {
sourceText: stateModel.stateEventJson(stateModel.index(model.index, 0))
}, {
title: i18n("Event Source"),
width: Kirigami.Units.gridUnit * 25
})
openEventSource(model.type, model.stateKey);
} else {
pageStack.pushDialogLayer(stateKeysComponent, {
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'StateKeys'), {
room: root.room,
eventType: model.type
}, {
@@ -91,9 +87,17 @@ ColumnLayout {
}
}
}
Component {
id: stateKeysComponent
StateKeys {}
}
}
function openEventSource(type: string, stateKey: string): void {
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
model: stateModel,
allowEdit: true,
room: root.room,
type: type,
stateKey: stateKey,
}, {
title: i18n("Event Source"),
width: Kirigami.Units.gridUnit * 25
});
}
}

View File

@@ -31,13 +31,21 @@ FormCard.FormCardPage {
delegate: FormCard.FormButtonDelegate {
text: model.stateKey
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet.qml'), {
sourceText: stateKeysModel.stateEventJson(stateKeysModel.index(model.index, 0))
}, {
title: i18nc("@title:window", "Event Source"),
width: Kirigami.Units.gridUnit * 25
})
onClicked: openEventSource(model.stateKey)
}
}
}
function openEventSource(stateKey: string): void {
applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
model: stateKeysModel,
allowEdit: true,
room: root.room,
type: root.eventType,
stateKey: stateKey
}, {
title: i18nc("@title:window", "Event Source"),
width: Kirigami.Units.gridUnit * 25
});
}
}

View File

@@ -21,7 +21,6 @@ public:
* @brief Defines the room list categories a room can be assigned.
*/
enum Types {
Search = 0, /**< So we can show a search delegate if needed, e.g. collapsed mode. */
Invited, /**< The user has been invited to the room. */
Favorite, /**< The room is set as a favourite. */
Direct, /**< The room is a direct chat. */
@@ -68,8 +67,6 @@ public:
return i18n("Low priority");
case NeoChatRoomType::Space:
return i18n("Spaces");
case NeoChatRoomType::Search:
return i18n("Search");
default:
return {};
}
@@ -89,8 +86,6 @@ public:
return QStringLiteral("object-order-lower");
case NeoChatRoomType::Space:
return QStringLiteral("group");
case NeoChatRoomType::Search:
return QStringLiteral("search");
default:
return QStringLiteral("tools-report-bug");
}

107
src/enums/powerlevel.cpp Normal file
View File

@@ -0,0 +1,107 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include "powerlevel.h"
QString PowerLevel::nameForLevel(Level level)
{
switch (level) {
case PowerLevel::Member:
return i18n("Member");
case PowerLevel::Moderator:
return i18n("Moderator");
case PowerLevel::Admin:
return i18n("Admin");
case PowerLevel::Mute:
return i18n("Mute");
case PowerLevel::Custom:
return i18n("Custom");
default:
return {};
}
}
int PowerLevel::valueForLevel(Level level)
{
switch (level) {
case PowerLevel::Member:
return 0;
case PowerLevel::Moderator:
return 50;
case PowerLevel::Admin:
return 100;
case PowerLevel::Mute:
return -1;
default:
return {};
}
}
PowerLevel::Level PowerLevel::levelForValue(int value)
{
switch (value) {
case 0:
return PowerLevel::Member;
case 50:
return PowerLevel::Moderator;
case 100:
return PowerLevel::Admin;
case -1:
return PowerLevel::Mute;
default:
return PowerLevel::Custom;
}
}
PowerLevelModel::PowerLevelModel(QObject *parent)
: QAbstractListModel(parent)
{
}
bool PowerLevelModel::showMute() const
{
return m_showMute;
}
void PowerLevelModel::setShowMute(bool showMute)
{
if (showMute == m_showMute) {
return;
}
m_showMute = showMute;
Q_EMIT showMuteChanged();
}
QVariant PowerLevelModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return {};
}
if (index.row() >= rowCount()) {
qDebug() << "PowerLevelModel, something's wrong: index.row() >= m_rules.count()";
return {};
}
const auto level = static_cast<PowerLevel::Level>(index.row());
if (role == NameRole) {
return i18nc("%1 is the name of the power level, e.g. admin and %2 is the value that represents.",
"%1 (%2)",
PowerLevel::nameForLevel(level),
PowerLevel::valueForLevel(level));
}
if (role == ValueRole) {
return PowerLevel::valueForLevel(level);
}
return {};
}
int PowerLevelModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return PowerLevel::NUMLevels - (m_showMute ? 0 : 1);
}
QHash<int, QByteArray> PowerLevelModel::roleNames() const
{
return {{NameRole, "name"}, {ValueRole, "value"}};
}

110
src/enums/powerlevel.h Normal file
View File

@@ -0,0 +1,110 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#pragma once
#include <QAbstractListModel>
#include <QObject>
#include <QQmlEngine>
#include <KLocalizedString>
/**
* @class PowerLevel
*
* This class is designed to define the PowerLevel enumeration.
*/
class PowerLevel : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
public:
/**
* @brief The type of delegate that is needed for the event.
*
* @note While similar this is not the matrix event or message type. This is
* to tell a QML ListView what delegate to show for each event. So while
* similar to the spec it is not the same.
*/
enum Level {
Member, /**< A basic member. */
Moderator, /**< A moderator with enhanced powers. */
Admin, /**< The highest power level in the room. */
Mute, /**< The level to remove posting privileges. */
NUMLevels,
Custom, /**< A non-standard value. Intentionally after NUMLevels so it doesn't appear in the model. */
};
Q_ENUM(Level);
/**
* @brief Return a string representation of the enum value.
*/
static QString nameForLevel(Level level);
/**
* @brief Return the integer representation of the enum value.
*/
static int valueForLevel(Level level);
/**
* @brief Return the enum value for the given integer power level.
*/
static Level levelForValue(int value);
};
/**
* @class PowerLevelModel
*
* A model visualize the allowed power levels.
*/
class PowerLevelModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(bool showMute READ showMute WRITE setShowMute NOTIFY showMuteChanged)
public:
/**
* @brief Defines the model roles.
*/
enum Roles {
NameRole = Qt::DisplayRole, /**< The power level name. */
ValueRole, /**< The power level value. */
};
Q_ENUM(Roles)
explicit PowerLevelModel(QObject *parent = nullptr);
[[nodiscard]] bool showMute() const;
void setShowMute(bool showMute);
/**
* @brief Get the given role value at the given index.
*
* @sa QAbstractItemModel::data
*/
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
/**
* @brief Number of rows in the model.
*
* @sa QAbstractItemModel::rowCount
*/
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
/**
* @brief Returns a mapping from Role enum values to role names.
*
* @sa Roles, QAbstractItemModel::roleNames()
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
Q_SIGNALS:
void showMuteChanged();
private:
bool m_showMute = true;
};

View File

@@ -19,11 +19,11 @@
#include <Quotient/events/simplestateevents.h>
#include <Quotient/events/stickerevent.h>
#include <Quotient/quotient_common.h>
#include <Quotient/roommember.h>
#include "eventhandler_logging.h"
#include "events/locationbeaconevent.h"
#include "events/pollevent.h"
#include "events/serveraclevent.h"
#include "events/widgetevent.h"
#include "linkpreviewer.h"
#include "messagecomponenttype.h"
@@ -61,20 +61,18 @@ MessageComponentType::Type EventHandler::messageComponentType() const
return MessageComponentType::typeForEvent(*m_event);
}
QVariantMap EventHandler::getAuthor(bool isPending) const
Quotient::RoomMember EventHandler::getAuthor(bool isPending) const
{
if (m_room == nullptr) {
qCWarning(EventHandling) << "getAuthor called with m_room set to nullptr.";
return {};
}
// If we have a room we can return an empty user by handing nullptr to m_room->getUser.
if (m_event == nullptr) {
qCWarning(EventHandling) << "getAuthor called with m_event set to nullptr. Returning empty user.";
return m_room->getUser(nullptr);
return {};
}
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
return m_room->getUser(author);
return isPending ? m_room->localMember() : m_room->member(m_event->senderId());
}
QString EventHandler::getAuthorDisplayName(bool isPending) const
@@ -96,8 +94,8 @@ QString EventHandler::getAuthorDisplayName(bool isPending) const
}
return previousDisplayName;
} else {
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
return m_room->htmlSafeMemberName(author->id());
const auto author = isPending ? m_room->localMember() : m_room->member(m_event->senderId());
return author.htmlSafeDisplayName();
}
}
@@ -112,8 +110,8 @@ QString EventHandler::singleLineAuthorDisplayname(bool isPending) const
return {};
}
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
auto displayName = m_room->safeMemberName(author->id());
const auto author = isPending ? m_room->localMember() : m_room->member(m_event->senderId());
auto displayName = author.displayName();
displayName.replace(QStringLiteral("<br>\n"), QStringLiteral(" "));
displayName.replace(QStringLiteral("<br>"), QStringLiteral(" "));
displayName.replace(QStringLiteral("<br />\n"), QStringLiteral(" "));
@@ -220,7 +218,7 @@ bool EventHandler::isHidden()
}
}
if (m_room->connection()->isIgnored(m_room->user(m_event->senderId()))) {
if (m_room->connection()->isIgnored(m_event->senderId())) {
return true;
}
@@ -255,7 +253,7 @@ QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
QString body;
if (event.hasTextContent() && event.content()) {
body = static_cast<const MessageEventContent::TextContent *>(event.content())->body;
body = static_cast<const EventContent::TextContent *>(event.content())->body;
} else {
body = event.plainBody();
}
@@ -293,7 +291,10 @@ QString EventHandler::getMarkdownBody() const
}
const auto roomMessageEvent = eventCast<const RoomMessageEvent>(m_event);
return roomMessageEvent->plainBody();
QString plainBody = roomMessageEvent->plainBody();
plainBody.remove(TextRegex::removeReply);
return plainBody;
}
QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines) const
@@ -315,7 +316,7 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
},
[this, prettyPrint](const RoomMemberEvent &e) {
// FIXME: Rewind to the name that was at the time of this event
auto subjectName = m_room->htmlSafeMemberName(e.userId());
auto subjectName = m_room->member(e.userId()).htmlSafeDisplayName();
if (e.membership() == Membership::Leave) {
if (e.prevContent() && e.prevContent()->displayName) {
subjectName = sanitized(*e.prevContent()->displayName).toHtmlEscaped();
@@ -323,7 +324,8 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
}
if (prettyPrint) {
subjectName = QStringLiteral("<a href=\"https://matrix.to/#/%1\">%2</a>").arg(e.userId(), subjectName);
subjectName = QStringLiteral("<a href=\"https://matrix.to/#/%1\" style=\"color: %2\">%3</a>")
.arg(e.userId(), m_room->member(e.userId()).color().name(), subjectName);
}
// The below code assumes senderName output in AuthorRole
@@ -437,7 +439,7 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
[](const LocationBeaconEvent &e) {
return e.contentJson()["description"_ls].toString();
},
[](const ServerAclEvent &) {
[](const RoomServerAclEvent &) {
return i18n("changed the server access control lists for this room");
},
[](const WidgetEvent &e) {
@@ -476,7 +478,7 @@ QString EventHandler::getMessageBody(const RoomMessageEvent &event, Qt::TextForm
QString body;
if (event.hasTextContent() && event.content()) {
body = static_cast<const MessageEventContent::TextContent *>(event.content())->body;
body = static_cast<const EventContent::TextContent *>(event.content())->body;
} else {
body = event.plainBody();
}
@@ -606,7 +608,7 @@ QString EventHandler::getGenericBody() const
[](const LocationBeaconEvent &) {
return i18n("sent a live location beacon");
},
[](const ServerAclEvent &) {
[](const RoomServerAclEvent &) {
return i18n("changed the server access control lists for this room");
},
[](const WidgetEvent &e) {
@@ -797,25 +799,21 @@ MessageComponentType::Type EventHandler::replyMessageComponentType() const
return MessageComponentType::typeForEvent(*replyEvent);
}
QVariantMap EventHandler::getReplyAuthor() const
Quotient::RoomMember EventHandler::getReplyAuthor() const
{
if (m_room == nullptr) {
qCWarning(EventHandling) << "getReplyAuthor called with m_room set to nullptr.";
return {};
}
// If we have a room we can return an empty user by handing nullptr to m_room->getUser.
if (m_event == nullptr) {
qCWarning(EventHandling) << "getReplyAuthor called with m_event set to nullptr. Returning empty user.";
return m_room->getUser(nullptr);
return {};
}
auto replyPtr = m_room->getReplyForEvent(*m_event);
if (replyPtr) {
auto replyUser = m_room->user(replyPtr->senderId());
return m_room->getUser(replyUser);
if (auto replyPtr = m_room->getReplyForEvent(*m_event)) {
return m_room->member(replyPtr->senderId());
} else {
return m_room->getUser(nullptr);
return m_room->member(QString());
}
}
@@ -963,11 +961,11 @@ bool EventHandler::hasReadMarkers() const
}
auto userIds = m_room->userIdsAtEvent(m_event->id());
userIds.remove(m_room->localUser()->id());
userIds.remove(m_room->localMember().id());
return userIds.size() > 0;
}
QVariantList EventHandler::getReadMarkers(int maxMarkers) const
QList<Quotient::RoomMember> EventHandler::getReadMarkers(int maxMarkers) const
{
if (m_room == nullptr) {
qCWarning(EventHandling) << "getReadMarkers called with m_room set to nullptr.";
@@ -979,18 +977,17 @@ QVariantList EventHandler::getReadMarkers(int maxMarkers) const
}
auto userIds_temp = m_room->userIdsAtEvent(m_event->id());
userIds_temp.remove(m_room->localUser()->id());
userIds_temp.remove(m_room->localMember().id());
auto userIds = userIds_temp.values();
if (userIds.count() > maxMarkers) {
userIds = userIds.mid(0, maxMarkers);
}
QVariantList users;
QList<Quotient::RoomMember> users;
users.reserve(userIds.size());
for (const auto &userId : userIds) {
auto user = m_room->user(userId);
users += m_room->getUser(user);
users += m_room->member(userId);
}
return users;
@@ -1008,7 +1005,7 @@ QString EventHandler::getNumberExcessReadMarkers(int maxMarkers) const
}
auto userIds = m_room->userIdsAtEvent(m_event->id());
userIds.remove(m_room->localUser()->id());
userIds.remove(m_room->localMember().id());
if (userIds.count() > maxMarkers) {
return QStringLiteral("+ ") + QString::number(userIds.count() - maxMarkers);
@@ -1029,7 +1026,7 @@ QString EventHandler::getReadMarkersString() const
}
auto userIds = m_room->userIdsAtEvent(m_event->id());
userIds.remove(m_room->localUser()->id());
userIds.remove(m_room->localMember().id());
/**
* The string ends up in the form
@@ -1037,8 +1034,14 @@ QString EventHandler::getReadMarkersString() const
*/
QString readMarkersString = i18np("1 user: ", "%1 users: ", userIds.size());
for (const auto &userId : userIds) {
auto user = m_room->user(userId);
readMarkersString += user->displayname(m_room) + i18nc("list separator", ", ");
auto member = m_room->member(userId);
QString displayName;
if (member.isEmpty()) {
displayName = i18nc("A member who is not in the room has been requested.", "unknown member");
} else {
displayName = member.displayName();
}
readMarkersString += displayName + i18nc("list separator", ", ");
}
readMarkersString.chop(2);
return readMarkersString;

View File

@@ -13,6 +13,11 @@
#include "enums/messagecomponenttype.h"
namespace Quotient
{
class RoomMember;
}
class LinkPreviewer;
class NeoChatRoom;
class ReactionModel;
@@ -51,30 +56,17 @@ public:
/**
* @brief Get the author of the event in context of the room.
*
* This is different to getting a Quotient::User object
* as neither of those can provide details like the displayName or avatarMediaId
* without the room context as these can vary from room to room. This function
* uses the room context and outputs the result as QVariantMap.
*
* An empty QVariantMap will be returned if the EventHandler hasn't had the room
* intialised. An empty user (i.e. a QVariantMap with all the correct keys
* but empty values) will be returned if the room has been set but not an event.
* An empty Quotient::RoomMember will be returned if the EventHandler hasn't had
* the room or event initialised.
*
* @param isPending if the event is pending, i.e. has not been confirmed by
* the server.
*
* @return a QVariantMap for the user with the following properties:
* - isLocalUser - Whether the user is the local user.
* - id - The matrix ID of the user.
* - displayName - Display name in the context of this room.
* - avatarSource - The mxc URL for the user's avatar in the current room.
* - avatarMediaId - Avatar id in the context of this room.
* - color - Color for the user.
* - object - The Quotient::User object for the user.
* @return a Quotient::RoomMember object for the user.
*
* @sa Quotient::User
* @sa Quotient::RoomMember
*/
QVariantMap getAuthor(bool isPending = false) const;
Quotient::RoomMember getAuthor(bool isPending = false) const;
/**
* @brief Get the display name of the event author.
@@ -251,27 +243,17 @@ public:
/**
* @brief Get the author of the event replied to in context of the room.
*
* This is different to getting a Quotient::User object
* as neither of those can provide details like the displayName or avatarMediaId
* without the room context as these can vary from room to room. This function
* uses the room context and outputs the result as QVariantMap.
* An empty Quotient::RoomMember will be returned if the EventHandler hasn't had
* the room or event initialised.
*
* An empty QVariantMap will be returned if the EventHandler hasn't had the room
* intialised. An empty user (i.e. a QVariantMap with all the correct keys
* but empty values) will be returned if the room has been set but not an event.
* @param isPending if the event is pending, i.e. has not been confirmed by
* the server.
*
* @return a QVariantMap for the user with the following properties:
* - isLocalUser - Whether the user is the local user.
* - id - The matrix ID of the user.
* - displayName - Display name in the context of this room.
* - avatarSource - The mxc URL for the user's avatar in the current room.
* - avatarMediaId - Avatar id in the context of this room.
* - color - Color for the user.
* - object - The Quotient::User object for the user.
* @return a Quotient::RoomMember object for the user.
*
* @sa Quotient::User
* @sa Quotient::RoomMember
*/
QVariantMap getReplyAuthor() const;
Quotient::RoomMember getReplyAuthor() const;
/**
* @brief Output a string for the message content of the event replied to ready
@@ -375,7 +357,7 @@ public:
* the number of users shown plus the excess number will be
* the total number of other user read markers at an event.
*/
QVariantList getReadMarkers(int maxMarkers = 5) const;
QList<Quotient::RoomMember> getReadMarkers(int maxMarkers = 5) const;
/**
* @brief Returns the number of excess user read markers for the event.

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<std::optional<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
fromJson<std::optional<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
fromJson<std::optional<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
};
} else {
pack = none;
pack = std::nullopt;
}
const auto &keys = json["images"_ls].toObject().keys();
for (const auto &k : keys) {
Omittable<EventContent::ImageInfo> info;
std::optional<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);
} else {
info = none;
info = std::nullopt;
}
images += ImagePackImage{
k,
fromJson<QUrl>(json["images"_ls][k]["url"_ls].toString()),
fromJson<Omittable<QString>>(json["images"_ls][k]["body"_ls]),
fromJson<std::optional<QString>>(json["images"_ls][k]["body"_ls]),
info,
fromJson<Omittable<QStringList>>(json["images"_ls][k]["usage"_ls]),
fromJson<std::optional<QStringList>>(json["images"_ls][k]["usage"_ls]),
};
}
}
@@ -74,6 +74,9 @@ void ImagePackEventContent::fillJson(QJsonObject *o) const
}
imageJson["usage"_ls] = usageJson;
}
if (image.info.has_value()) {
imageJson["info"_ls] = Quotient::EventContent::toInfoJson(*image.info);
}
imagesJson[image.shortcode] = imageJson;
}
(*o)["images"_ls] = imagesJson;

View File

@@ -26,10 +26,10 @@ public:
* @brief Defines the properties of an image pack.
*/
struct Pack {
Quotient::Omittable<QString> displayName; /**< The display name of the pack. */
Quotient::Omittable<QUrl> avatarUrl; /**< The source mxc URL for the pack avatar. */
Quotient::Omittable<QStringList> usage; /**< An array of the usages for this pack. Possible usages are "emoticon" and "sticker". */
Quotient::Omittable<QString> attribution; /**< The attribution for the pack author(s). */
std::optional<QString> displayName; /**< The display name of the pack. */
std::optional<QUrl> avatarUrl; /**< The source mxc URL for the pack avatar. */
std::optional<QStringList> usage; /**< An array of the usages for this pack. Possible usages are "emoticon" and "sticker". */
std::optional<QString> attribution; /**< The attribution for the pack author(s). */
};
/**
@@ -38,14 +38,14 @@ public:
struct ImagePackImage {
QString shortcode; /**< The shortcode for the image. */
QUrl url; /**< The mxc URL for this image. */
Quotient::Omittable<QString> body; /**< An optional text body for this image. */
Quotient::Omittable<Quotient::EventContent::ImageInfo> info; /**< The ImageInfo object used for the info block of m.sticker events. */
std::optional<QString> body; /**< An optional text body for this image. */
std::optional<Quotient::EventContent::ImageInfo> info; /**< The ImageInfo object used for the info block of m.sticker events. */
/**
* @brief An array of the usages for this image.
*
* The possible values match those of the usage key of a pack object.
*/
Quotient::Omittable<QStringList> usage;
std::optional<QStringList> usage;
};
/**
@@ -53,7 +53,7 @@ public:
*
* @sa Pack
*/
Quotient::Omittable<Pack> pack;
std::optional<Pack> pack;
/**
* @brief Return a vector of images in the pack.
@@ -89,6 +89,4 @@ public:
QUO_EVENT(ImagePackEvent, "im.ponies.room_emotes")
using KeyedStateEventBase::KeyedStateEventBase;
};
REGISTER_EVENT_TYPE(ImagePackEvent)
}

View File

@@ -40,5 +40,4 @@ public:
*/
QJsonArray allow() const;
};
REGISTER_EVENT_TYPE(JoinRulesEvent)
}

View File

@@ -1,14 +0,0 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#pragma once
#include <Quotient/events/simplestateevents.h>
namespace Quotient
{
// Defined so we can directly switch on type.
DEFINE_SIMPLE_STATE_EVENT(ServerAclEvent, "m.room.server_acl", bool, allow_ip_literals, "allow_ip_literals")
} // namespace Quotient

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