Compare commits

...

463 Commits

Author SHA1 Message Date
l10n daemon script
13042d9ba6 GIT_SILENT Sync po/docbooks with svn 2025-12-04 03:20:39 +00:00
Heiko Becker
0e4b52ee62 GIT_SILENT Update Appstream for new release 2025-12-04 00:19:55 +01:00
Heiko Becker
4c32280343 GIT_SILENT Upgrade release service version to 25.12.0. 2025-12-03 23:04:35 +01:00
l10n daemon script
a2e540d6ef GIT_SILENT Sync po/docbooks with svn 2025-12-03 03:26:04 +00:00
Carl Schwan
573c8925d2 Fix krunner integration with Flatpak
(cherry picked from commit 1da24191f0)

Co-authored-by: renner 03 <renner0@posteo.de>
2025-12-02 23:00:25 +01:00
l10n daemon script
6c0bd850b0 GIT_SILENT Sync po/docbooks with svn 2025-12-01 03:28:35 +00:00
l10n daemon script
1da9719314 GIT_SILENT Sync po/docbooks with svn 2025-11-25 03:15:21 +00:00
Heiko Becker
3cd5f3a1c6 Drop unused dependencies
Both KF6Crash and KF6IconThemes aren't used anymore after porting to
KirigamiApp in eab45e761a.

(cherry picked from commit 0cb3fd32f4)
2025-11-24 21:56:55 +01:00
Albert Astals Cid
b4108f2eef GIT_SILENT Upgrade release service version to 25.11.90. 2025-11-24 00:57:39 +01:00
l10n daemon script
bb7de18341 GIT_SILENT Sync po/docbooks with svn 2025-11-23 03:19:33 +00:00
l10n daemon script
7b8328fce6 GIT_SILENT Sync po/docbooks with svn 2025-11-21 03:20:12 +00:00
l10n daemon script
aeee6570c0 GIT_SILENT Sync po/docbooks with svn 2025-11-20 03:14:24 +00:00
l10n daemon script
780b9a6f9b GIT_SILENT Sync po/docbooks with svn 2025-11-17 15:49:57 +00:00
l10n daemon script
0ba06882d1 GIT_SILENT Sync po/docbooks with svn 2025-11-17 03:16:16 +00:00
l10n daemon script
ce131a53e5 GIT_SILENT Sync po/docbooks with svn 2025-11-16 03:16:40 +00:00
l10n daemon script
e9421e28dd 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"
2025-11-16 03:13:00 +00:00
l10n daemon script
1c64a6b5f0 GIT_SILENT Sync po/docbooks with svn 2025-11-15 03:19:51 +00:00
l10n daemon script
9b5200c344 GIT_SILENT Sync po/docbooks with svn 2025-11-14 03:21:54 +00:00
l10n daemon script
5baf4ab823 GIT_SILENT Sync po/docbooks with svn 2025-11-13 03:20:11 +00:00
l10n daemon script
58a72a08f2 GIT_SILENT Sync po/docbooks with svn 2025-11-11 03:37:16 +00:00
l10n daemon script
c9b97d4d0d GIT_SILENT Sync po/docbooks with svn 2025-11-10 03:26:49 +00:00
Carl Schwan
2a7d61c73b Improve invited room counting
I didn't realize when redoing the tooltip for DMs that directChatInvites
was a boolean, not an integer type. Now it's changed to an integer type,
which fixes the DM invite count.

NeoChat apparently didn't count normal room invites until now either, so
now Home is highlighted in that case. Now it should be harder to miss
these kinds of invites.


(cherry picked from commit 887865c0aa)

Co-authored-by: Joshua Goins <josh@redstrate.com>
2025-11-09 22:23:09 +01:00
l10n daemon script
f55bd28e10 GIT_SILENT Sync po/docbooks with svn 2025-11-09 03:45:49 +00:00
Albert Astals Cid
2a67861099 GIT_SILENT Upgrade release service version to 25.11.80. 2025-11-06 17:40:37 +01:00
l10n daemon script
273d962707 GIT_SILENT Sync po/docbooks with svn 2025-11-06 01:40:42 +00:00
Paul Brown
5e8b44fea6 Adding Akseli as supporter 2025-11-05 21:56:17 +00:00
l10n daemon script
be9e2ec7d0 GIT_SILENT Sync po/docbooks with svn 2025-11-05 01:48:44 +00:00
l10n daemon script
ee042cc1a2 GIT_SILENT Sync po/docbooks with svn 2025-11-04 01:47:11 +00:00
Kristen McWilliam
25c0bc131a feat: add font size scaling setting
Adds an option in Appearance Settings to adjust font size scaling,
improving accessibility and user customization.
2025-11-03 10:18:23 -05:00
Paul Brown
7def8c066c Added anonymous donot to list of supporters 2025-11-03 12:50:59 +00:00
l10n daemon script
1ddaf37e52 GIT_SILENT Sync po/docbooks with svn 2025-11-02 01:39:31 +00:00
Heiko Becker
40694f502a Fix version in appstream file
GIT_SILENT
2025-11-01 20:01:46 +01:00
l10n daemon script
d9f4a0a032 GIT_SILENT Sync po/docbooks with svn 2025-11-01 01:44:57 +00:00
l10n daemon script
5e392f3101 GIT_SILENT Sync po/docbooks with svn 2025-10-31 01:39:58 +00:00
Heiko Becker
ce1ac6128e GIT_SILENT Update Appstream for new release
(cherry picked from commit c6fa5a10dd)
2025-10-31 01:23:25 +01:00
l10n daemon script
a9d08a6ee2 GIT_SILENT Sync po/docbooks with svn 2025-10-30 01:41:27 +00:00
Joshua Goins
24d4829ba9 Clarify what is "recent activity" in our room list ordering settings
As seen in the bug report, this setting is a bit confusing. First, it
refers to "message activity" but in reality it does take into account
all events. This is fine in my opinion, so I clarified that point.

Another thing is that it wasn't clear that timeline visibility settings
currently affect the sorting, so I added a tip about that.

Finally I wasn't happy with these two options being called "Activity"
so the old "Activity" setting is now called "Importance". The "Last
Message Activity" setting is now called "Newest Events".

BUG: 508480
FIXED-IN: 25.12.0
2025-10-29 18:18:53 -04:00
l10n daemon script
a121c39b6e GIT_SILENT Sync po/docbooks with svn 2025-10-29 01:41:34 +00:00
Joshua Goins
f009420c20 Improve the design of the room notifications settings
Now it has icons that match what we have in the room menu, and the
duplicate header text is removed.
2025-10-28 12:27:23 -04:00
Joshua Goins
069e0d8f16 Add informational Keyboard Shortcuts settings page
While we don't have customizable keyboard shortcuts (yet!) we have been
asked before for some way to view all of NeoChat's keyboard shortcuts.
2025-10-28 10:29:55 -04:00
Joshua Goins
1f1db11197 Fix plugin on LocationsPage
This lives in the base NeoChat QML module, not the libneochat one.
2025-10-28 09:17:18 -04:00
Joshua Goins
be92e56c3a Show less scary icon for neutral reasons when cancelling verification
For example, accepting a verification on another device shows a giant
red security icon which isn't really suitable. I chucked the
dialog-information icon in for some of the neutral-sounding messages so
this dialog can be a little less intimidating.

BUG: 510421
FIXED-IN: 24.08.3
2025-10-28 09:16:17 -04:00
l10n daemon script
d1fc426513 GIT_SILENT Sync po/docbooks with svn 2025-10-28 01:41:19 +00:00
Joshua Goins
c778ba8b24 Fix jump to previous/next unread room shortcuts
These were dependent on a renamed property and ended up breaking, oops.
2025-10-27 18:09:00 -04:00
Joshua Goins
07fb3160eb Add "Inspect Room Data" button in the room sidebar
I find myself doing the same routine: I want to inspect a room's state,
so I have to go hunting for the Developer Tools button. And then I have
to do a few clicks to even get the correct room, what a waste of time!

So I added a new button to the sidebar to open the Developer Tools for
the current room.
2025-10-27 18:08:51 -04:00
Joshua Goins
7444d68280 Change room sidebar action text
As we've continued to add more and more room actions, I'm not entirely
happy with how they're worded. Some are super short and sweet like
"Verify User" while others refer to the room as if the sidebar wasn't
enough context: "Search in this room".

I redid all of the button's text so they're shorter, like "Search
Messages".
2025-10-27 18:08:42 -04:00
Joshua Goins
1d5536401d Make the CTRL+F shortcut search the current room's messages
Right now there's not an easy way to quickly bring up message search. If
you press CTRL+F (with the room information sidebar *closed*, for some
reason) that brings up the same dialog as CTRL+K which seems redundant.

I assigned that shortcut to the message search dialog instead, which is
makes much more sense in my opinion. I also made sure its disabled in
spaces or when there's not a room open.

BUG: 487270
FIXED-IN: 25.12.0
2025-10-27 18:08:29 -04:00
Joshua Goins
099e996f2f Improve standalone images in link preview and more
We would incorrectly show a "truncate" button for standalone images
which isn't applicable since there's no text. That check has been fixed,
and it doesn't seem to regress normal link previews.

Another is that if there's only an image, our layout would center the
image which looks awkward since almost everything else is left-aligned
in chat. This is also fixed, which notably matches up to Element Web's
behavior.

I added support for the hover link indicator as well. Someone could
maliciously hide it via Markdown but have a legitimate-looking link
preview, for example. You can check that by hovering over the link in
the message itself, but now the link preview is another way to confirm
that!
2025-10-27 18:08:21 -04:00
Joshua Goins
6d9974b2b1 Improve the Jitsi meeting button UX
Widgets support is incredibly useful and so is this button, but it has a
few problems. The most obvious is that it's still enabled even if you
don't actually have the permission to start Jitsi meetings, so I fixed
that. I also made sure it's hidden when viewing spaces too.

Another problem is that you can't easily tell if a meeting is currently
in progress either, nor do we have a good icon for that in Breeze. So I
changed the tooltip and colored the icon in this case.

The final problem I fixed is something not exclusive to NeoChat, but
generally all chat applications with this feature - there's no
confirmation! To stop "butt-dialing" random people or rooms, I added a
prompt before starting or joining a meeting.
2025-10-27 18:08:08 -04:00
James Graham
f65e9f7599 Fix the chatbar so that the icons show on android. Overring the contentItem was what was causing them to disappear. 2025-10-27 16:13:54 -04:00
l10n daemon script
4a39810923 GIT_SILENT Sync po/docbooks with svn 2025-10-26 01:38:47 +00:00
l10n daemon script
6720e2dfaa GIT_SILENT Sync po/docbooks with svn 2025-10-25 01:39:53 +00:00
l10n daemon script
eb1bf2ed2b GIT_SILENT Sync po/docbooks with svn 2025-10-24 01:39:25 +00:00
l10n daemon script
cc26b1b62f GIT_SILENT Sync po/docbooks with svn 2025-10-23 01:38:07 +00:00
l10n daemon script
59c2c88eb6 GIT_SILENT made messages (after extraction) 2025-10-22 00:43:30 +00:00
l10n daemon script
99e8fd16eb GIT_SILENT Sync po/docbooks with svn 2025-10-21 01:39:43 +00:00
l10n daemon script
eaa4bdb0b7 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"
2025-10-21 01:34:16 +00:00
l10n daemon script
892b61e6bb GIT_SILENT Sync po/docbooks with svn 2025-10-20 01:41:26 +00:00
Nicolas Fella
6d56b673c4 Don't call direct messages friends
Not every person I communicate with is necessarily my friend

Use a more neutral term

BUG: 480167
2025-10-19 19:42:21 +02:00
l10n daemon script
f59e5a4b3c GIT_SILENT Sync po/docbooks with svn 2025-10-19 01:42:36 +00:00
Nicolas Fella
16e3fd4476 Don't show direct messages in room list when not in a space
2b0251c593 changed the logic to also show direct messages inside a space

However this also causes direct messages to be shown when *not* inside a space, which is undesirable
2025-10-18 15:02:07 +02:00
l10n daemon script
82d0fdefd2 GIT_SILENT Sync po/docbooks with svn 2025-10-18 02:03:22 +00:00
Tobias Fella
cbde14d58b Cleanup DevicesPage 2025-10-17 12:23:58 +00:00
l10n daemon script
f3c37e4304 GIT_SILENT Sync po/docbooks with svn 2025-10-17 01:57:08 +00:00
l10n daemon script
369008cec3 GIT_SILENT Sync po/docbooks with svn 2025-10-16 01:40:30 +00:00
l10n daemon script
1a2af57901 GIT_SILENT Sync po/docbooks with svn 2025-10-15 01:39:22 +00:00
l10n daemon script
dbb41d061c 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"
2025-10-15 01:33:59 +00:00
l10n daemon script
d1d3c43c6f GIT_SILENT Sync po/docbooks with svn 2025-10-14 01:40:53 +00:00
Paul Brown
ba2b1529ea Edit org.kde.neochat.appdata.xml 2025-10-13 10:50:10 +00:00
l10n daemon script
b5150f82f0 GIT_SILENT Sync po/docbooks with svn 2025-10-13 01:40:08 +00:00
Tobias Fella
00c81de035 Fix pushing welcome page onto layer
BUG: 510285
2025-10-12 10:58:21 +00:00
Tobias Fella
52d4451932 Add state event texts for some element-specific widget events 2025-10-12 10:49:45 +00:00
l10n daemon script
3efc11b9aa GIT_SILENT Sync po/docbooks with svn 2025-10-12 01:39:29 +00:00
James Graham
5fd9f07664 Some further belt and braces to ensure that we don't crash in the timeline
Some further belt and braces to ensure that we don't crash in the timeline. This does the following:
- Checks all callback inputs
- Makes sure that any objects are cleaned up from incubators when deleting the delegate as it turns out that clear() doesn't do this. Hopefully this stops callbacks into an already deleted parent.

Hopefully helps with https://crash-reports.kde.org/organizations/kde/issues/261627/events/0b6bef500c5641e1924aa0bc2b0c11bd/
2025-10-11 18:11:57 +00:00
l10n daemon script
bec9f36bce GIT_SILENT Sync po/docbooks with svn 2025-10-11 10:19:58 +00:00
l10n daemon script
a631acc0ac GIT_SILENT Sync po/docbooks with svn 2025-10-10 01:38:30 +00:00
l10n daemon script
b729aaf6ee GIT_SILENT Sync po/docbooks with svn 2025-10-09 01:43:02 +00:00
Tobias Fella
94b7fc5cdf Fix delegate menu for state events 2025-10-08 21:50:56 +00:00
Marco Martin
ec5355d86e Push to PageRow on mobile too
This fixes some glitches during animation, which had the background
disappearing when the pop animation was running,
and now uses always the pagerow for viewing the room.

This depends from the new PageRow animation on mobile,
https://invent.kde.org/frameworks/kirigami/-/merge_requests/1925
which makes all applications coherent with an application which
looks a bit more like the one on most android apps.

Also, the swipe back gesture now will work there too
2025-10-08 15:44:46 +00:00
Arno Rehn
1a43d15c6d EventHandler: Acknowledge that non-room-events can have a body as well
Specifically, in the current architecture, these can be EncryptedEvents
which are redactions of previous events. These will have artifical bodies.
2025-10-08 14:01:48 +00:00
James Graham
7356a68f4c Hopefully this stops any crashes around QuickActions.qml and EmojiDialog.qml
Hopefully this stops any crashes around QuickActions.qml and EmojiDialog.qml. Best I can guess this is some race condition where QuickActions are deleted in the time it takes to instnatiate the EmojiDialog popup. I've also rearranged the updateQuickActions function to stop a possible race condition there.

BUG: 509484
2025-10-08 13:07:02 +00:00
Tobias Fella
1070427a0d Try fixing crash in QConcatenateTablesProxyModel 2025-10-08 11:39:39 +00:00
l10n daemon script
196ef535ca GIT_SILENT Sync po/docbooks with svn 2025-10-08 01:40:26 +00:00
Tobias Fella
88fd173829 Show a placeholder message if there are no extensions 2025-10-07 22:43:18 +02:00
Arno Rehn
8b0698c670 Support adding Jitsi and removing widgets 2025-10-07 21:58:34 +02:00
Arno Rehn
5b07a0ff45 Add jitsi button to RoomPage 2025-10-07 21:58:34 +02:00
Arno Rehn
ba1d175d67 Add "Extensions" item to the room info 2025-10-07 21:58:34 +02:00
Arno Rehn
36ce55e892 Add WidgetModel 2025-10-07 21:56:18 +02:00
Arno Rehn
ba4a83d38c Don't switch to global DMs when space contains DM 2025-10-06 14:14:04 +00:00
Arno Rehn
5c49c35b82 Space overview: Fix displayed name of direct chats
When in the space overview page, direct chats were previously only
shown with their room ID. Fix this by getting the actual NeoChatRoom
and its displayName.
2025-10-06 14:14:04 +00:00
Arno Rehn
2b0251c593 Room list: Show direct chats in spaces
Direct Chats can be added to spaces as well. No need to exclude them.
2025-10-06 14:14:04 +00:00
l10n daemon script
3b08d0f382 GIT_SILENT Sync po/docbooks with svn 2025-10-06 01:43:51 +00:00
l10n daemon script
f64e8a3192 GIT_SILENT Sync po/docbooks with svn 2025-10-04 15:09:41 +00:00
Tobias Fella
eab45e761a Use KirigamiApp 2025-10-03 11:32:15 +00:00
l10n daemon script
0f03290c57 GIT_SILENT Sync po/docbooks with svn 2025-10-03 01:42:04 +00:00
Tobias Fella
59f87bb2c2 Set deprecation level 2025-10-02 16:43:27 +02:00
Tobias Fella
9afc10160d Raise compiler settings level to 6.17 2025-10-02 16:19:01 +02:00
Tobias Fella
cfc7f50a1f MessageContentModel: Guard data() against being called when there is no room 2025-10-01 23:48:49 +02:00
Heiko Becker
a2fc00365e GIT_SILENT Update Appstream for new release
(cherry picked from commit debbe8e478)
2025-10-01 00:40:10 +02:00
Joshua Goins
466cfd971d Fix room succession not actually working
I broke this in 409b6da160 making it not
possible to join a succeeding room. I decided to keep the old behavior
of not prompting you to join, because:

1. You are intentionally choosing to tap the button.
2. Room successions aren't random, a privileged user in the room is
creating it and there's already some implicit existing trust

(Also the current join confirmation dialog isn't useful enough yet to
make an actual informed decision anyway.)
2025-09-30 16:05:36 -04:00
Joshua Goins
8e83febb24 Remove some dead code from MessageModel::createEventObjects
This senderId variable doesn't seem to be used in the current iteration
of this function, lets remove it.
2025-09-30 12:07:49 -04:00
l10n daemon script
12072b0a73 GIT_SILENT Sync po/docbooks with svn 2025-09-30 01:47:20 +00:00
l10n daemon script
83b1daac07 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"
2025-09-30 01:36:30 +00:00
Arno Rehn
981ea053a6 Pinned messages: Decrypt events before handling them 2025-09-29 18:59:53 +02:00
Arno Rehn
e41fd7d986 PollHandler: Decrypt EncryptedEvents
Related events for a poll will be EncryptedEvents in an encrypted
room. Decrypt them before handling.
2025-09-29 18:59:53 +02:00
Arno Rehn
a88a82ca08 PollHandler: Correctly handle paginated events 2025-09-29 18:59:20 +02:00
Arno Rehn
23dc88df60 PollComponent: Apply word wrapping on long messages
Long messages were not wrapped and would overflow.
Correctly apply word wrapping and align all elements on the top of a
row.
2025-09-29 18:58:57 +02:00
l10n daemon script
520b1daeec GIT_SILENT Sync po/docbooks with svn 2025-09-29 01:41:25 +00:00
l10n daemon script
cbe7ace32d GIT_SILENT Sync po/docbooks with svn 2025-09-28 01:46:45 +00:00
l10n daemon script
2b4471ea91 GIT_SILENT Sync po/docbooks with svn 2025-09-27 01:40:14 +00:00
Joshua Goins
88e1e1dd2a Add the ability to scroll up in the message search window
This wasn't a thing yet, so the search experience compared to something
like Element Web was much worse. Now you can scroll back as far as any
other client can!

I had to do a bit of refactoring to stop resetting the model all the
time, and append instead. Otherwise, it was quite straightforward to
implement.
2025-09-26 17:49:22 -04:00
Joshua Goins
94ea1305b2 Fix some miscellaneous weirdness around push notifications
For some reason, I *stopped* the timer if we get a push message - which
makes *no* sense. It meant that NeoChat kept running in the background
for basically no reason.

We can also make the NotificationsManager::postPushNotification function
static and avoid creating some singletons.
2025-09-26 15:14:05 -04:00
Joshua Goins
960377838d Replace KDBusService usage with QDBusConnection when D-Bus activated
This is lighter and more reliable when it comes to being activated by
KUnifiedPush. We also don't need all of the features of KDBusService
here.
2025-09-26 15:14:05 -04:00
Joshua Goins
a48e8662d6 Remove useless translated string from dbus-activated CLI option
It never gets shown, so let's not waste our translators time.
2025-09-26 15:12:56 -04:00
l10n daemon script
9c90a38efc GIT_SILENT Sync po/docbooks with svn 2025-09-26 01:39:23 +00:00
l10n daemon script
8696a24127 GIT_SILENT Sync po/docbooks with svn 2025-09-25 01:40:55 +00:00
l10n daemon script
f2d1b4c1e1 GIT_SILENT Sync po/docbooks with svn 2025-09-24 01:40:47 +00:00
Laurent Montel
4cdc2b5e58 GIT_SILENT: Don't duplicate headers between .h/.cpp 2025-09-22 04:43:02 +00:00
l10n daemon script
e26f02d9e2 GIT_SILENT Sync po/docbooks with svn 2025-09-22 01:38:51 +00:00
l10n daemon script
5d83fe9a1d GIT_SILENT Sync po/docbooks with svn 2025-09-21 01:41:04 +00:00
l10n daemon script
6a506f237a GIT_SILENT Sync po/docbooks with svn 2025-09-20 01:41:10 +00:00
l10n daemon script
3a5a0153d8 GIT_SILENT Sync po/docbooks with svn 2025-09-18 01:40:38 +00:00
l10n daemon script
27519b8788 GIT_SILENT Sync po/docbooks with svn 2025-09-17 01:39:11 +00:00
l10n daemon script
dd45fe16a5 GIT_SILENT Sync po/docbooks with svn 2025-09-16 01:41:59 +00:00
Vlad Zahorodnii
161815acff Fix inserting UserListModel items without beginInsertRows()
If an item is added, the corresponding code should be wrapped with
beginInsertRows() and endInsertRows(), otherwise proxy or filter models
can end up with corrupted internal state.

m_members.insert() in refreshMember() should be unnecessary because
if pos is not the same as m_members.size(), then it means there's already
a member.id() item in the member list.
2025-09-15 18:04:29 +00:00
Tobias Fella
438edf2155 Fix qml warnings in ImageEditorPage 2025-09-15 16:13:49 +02:00
Tobias Fella
6607a4b72c Fix qml warnings in ChatBar 2025-09-15 16:11:20 +02:00
Tobias Fella
8f0c4ab133 Fix warning in FullScreenMap 2025-09-15 16:06:58 +02:00
Tobias Fella
78e5cd51cd remove unused imports 2025-09-15 16:05:22 +02:00
Tobias Fella
f5da44655e Fix qml warnings in SpaceDrawer 2025-09-15 16:03:38 +02:00
Tobias Fella
a91863c60d Fix qml warnings in AccountSwitchDialog 2025-09-15 14:39:40 +02:00
Tobias Fella
29e3a09aba Fix qml warning 2025-09-15 14:29:55 +02:00
Tobias Fella
a59952f189 Fix qml warnings in AccountData 2025-09-15 14:24:42 +02:00
Tobias Fella
b169da25ab Fix qml warnings in RoomSortParameterDialog 2025-09-15 14:21:47 +02:00
Tobias Fella
833e357d70 Fix qml warnings in login module 2025-09-15 14:15:38 +02:00
Tobias Fella
f9bf2b8f7a Fix warnings in NeoChatMaximizeComponent 2025-09-15 14:06:17 +02:00
Tobias Fella
7b27579f2d Fix qml warnings in ExploreRoomsPage 2025-09-15 13:54:43 +02:00
Tobias Fella
edb9d9f54e Remove unused import 2025-09-15 13:51:23 +02:00
Tobias Fella
abf9a486d0 Fix qml warnings in RoomData 2025-09-15 13:49:08 +02:00
Tobias Fella
b0bc19c055 Fix qml warnings in RoomInformation 2025-09-15 13:41:32 +02:00
Tobias Fella
71776ef275 Fix qml warnings in TypingPane 2025-09-15 13:30:55 +02:00
Tobias Fella
8dc7d1d39d Fix most qml warnings in StateKeys 2025-09-15 13:25:41 +02:00
Tobias Fella
adb9e59503 Fix qml warnings 2025-09-15 13:21:17 +02:00
Tobias Fella
518044e34a Fix qml warning 2025-09-15 13:17:32 +02:00
Tobias Fella
d6d747bb99 Fix qml warnings in EmoticonFormCard 2025-09-15 13:15:59 +02:00
l10n daemon script
f390702a7a GIT_SILENT Sync po/docbooks with svn 2025-09-15 01:39:42 +00:00
Tobias Fella
e056360ddd Various fixes for ExportKeysDialog 2025-09-14 18:31:26 +02:00
l10n daemon script
85163791ce GIT_SILENT Sync po/docbooks with svn 2025-09-14 01:39:17 +00:00
l10n daemon script
b5a853bc96 GIT_SILENT Sync po/docbooks with svn 2025-09-13 01:46:27 +00:00
Tobias Fella
e4cd6ce5a6 Add "copy user id" menu to delegate in user search page
BUG: 499792
2025-09-12 11:37:07 +00:00
l10n daemon script
84fa68e3ae GIT_SILENT Sync po/docbooks with svn 2025-09-12 01:38:40 +00:00
Joshua Goins
649dc7a815 Add placeholder message when there's no public rooms at all
I guess we never tested this against a truly empty server yet, as the
"no search" message was empty. This would normally never show up since
the top public rooms are usually listed instead.
2025-09-11 14:09:52 -04:00
Joshua Goins
b87e43660c Use better-fitting icons for "Explore rooms" and "Find your friends"
Only a problem on the room list, which used list-add which is odd as it
doesn't match up with how these are displayed elsewhere.
2025-09-11 11:52:24 -04:00
Joshua Goins
511138e3bb Revert back to normal, non-master KNotifications
It requires KF6.18, and while we could also force that it's probably
easier to wait for the full release.
2025-09-11 17:47:29 +02:00
Volker Krause
5a3c23d000 Fix KNotifications Craft path 2025-09-11 17:22:04 +02:00
Joshua Goins
1036384023 Add recently pinned message to the top of the window
This makes pinned messages actually quite useful, as rooms can stick
persistent and important information for users to see. (For example, the
KWin has crash triage meeting information pinned in their room.)

For simplicity and space reasons, only one line of the generic message
body is shown.
2025-09-11 08:57:22 -04:00
Tobias Fella
e3f618489b Remove flatpak patches 2025-09-11 12:00:44 +00:00
Joshua Goins
cfedd4fdb5 Stop erroring out when setting avatar if you never set it
The code didn't actually check the avatar URLs were different until now.
2025-09-11 07:43:04 -04:00
Joshua Goins
812e5beee6 Allow pressing enter/return on "Add Account" in account switcher dialog
Because "Add Account" is a "fake item" by being the footer, it should be
the null fallback when accessing currentItem.
2025-09-11 07:41:56 -04:00
Joshua Goins
17b632eb78 Add a small margin between the border of media and "Hide Media" button
I thought we had this already, I don't know where it went, but now it's
back.
2025-09-11 13:36:51 +02:00
Joshua Goins
877d5f34f7 Hide "Scan a QR Code" with no camera connected
Also when you disconnect/turn off the camera while the QR scanner is
open, show a better error message instead of freezing the last frame.
2025-09-11 05:15:39 -04:00
Tobias Fella
c93ce52ba1 Remove various outdated ifdefs 2025-09-11 10:47:23 +02:00
l10n daemon script
2504ca3f5c GIT_SILENT Sync po/docbooks with svn 2025-09-11 01:38:19 +00:00
l10n daemon script
5be05032be GIT_SILENT Sync po/docbooks with svn 2025-09-10 01:39:56 +00:00
Joshua Goins
81e5061831 Fix-up QR code scanning actions
I cleaned up how resolving QR codes work, I made sure to test both user
and room links and everything works great.

A more awkward bug I fixed is
a workaround around a quirk in Kirigami.Dialog, but actually regresses
QR codes. Because the QR code scanner is currently an extra window (at
least on desktop) the UserDetailDialog will reparent itself to the
soon-to-be-destroyed scanner window.
2025-09-09 13:35:12 -04:00
Joshua Goins
3b419e18a3 Build KNotifications master in Craft for now
This is needed to make Android notifications work again, as it narrowly
missed 6.18. We can remove it upon the next release.
2025-09-09 10:44:25 -04:00
Joshua Goins
1a1190d7bd Fix URL previews on modern Matrix servers never loading
This was a regression in 5d5295d06d where
the job never connected to the onSuccess function.
2025-09-09 08:51:54 -04:00
Joshua Goins
5b4d3df6ee Make rooms in the room list bold when there's unread messages
This used to be a feature but kinda broke/changed when we switched to
focusing on context-aware or notable events. Basically instead of only
notable events making a room bold in the room list, it's any unread
messages now.
2025-09-09 11:43:25 +02:00
Tobias Fella
f53d47fa28 Require libQuotient 0.9.3 2025-09-09 07:47:39 +00:00
l10n daemon script
67d5711cc4 GIT_SILENT Sync po/docbooks with svn 2025-09-09 02:18:13 +00:00
l10n daemon script
9f51b1e7ab 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"
2025-09-09 02:04:03 +00:00
l10n daemon script
5ac296ee71 GIT_SILENT made messages (after extraction) 2025-09-09 00:54:31 +00:00
Joshua Goins
1b8adcc91a Don't import Purpose on Android
This prevents the app from launching on Android (and probably Windows
too) because our module declares a dependency on a non-existent Purpose.
2025-09-08 16:10:12 +02:00
Joshua Goins
1e78209cd7 Fix missing appWindow property for GlobalMenuStub
This was one of the issues with the current Android version.
2025-09-08 15:47:04 +02:00
Tobias Fella
0fd924be7b Fix showing permissions settings for v12 rooms 2025-09-08 08:14:17 +00:00
l10n daemon script
d67cb89505 GIT_SILENT Sync po/docbooks with svn 2025-09-08 02:13:16 +00:00
l10n daemon script
0d0f88e251 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"
2025-09-08 01:51:40 +00:00
Joshua Goins
4cbd4a034c Remove incorrect context for "Always allow device verification" 2025-09-07 12:57:08 -04:00
Joshua Goins
e7ed07e386 Show the "Verify This Device" warning when turning on reverification
This is the only way to reverify your device again, so it's useful to
show this in that case.
2025-09-07 12:57:08 -04:00
Joshua Goins
390654fa4a Fix deprecation warning about QHoverEvent::pos
We should be using position().
2025-09-07 12:26:27 -04:00
Joshua Goins
e8830b56d8 Add "Done" button when verification session is finished
It isn't immediately obvious when to close the window, other clients
(e.g. Element Web) has a "Got It" button in addition to the regular
dialog close button.
2025-09-07 12:25:16 -04:00
Tobias Fella
bbf2587908 Don't use raw json for getting reply event id 2025-09-07 16:43:35 +02:00
Joshua Goins
409b6da160 Bring up the room confirmation dialog in more situations
This super helpful and nice dialog went mostly unused, especially if you
only joined links to rooms through matrix.to or within NeoChat itself.

The reason why this never showed up for said links is because we were
greedily overwriting the "action". I don't think the code made solid
sense anyway, so I redone it a bit so there's a clearer
"join_confirmed" our UI uses. I added a test case to showcase this
working.
2025-09-07 08:43:51 -04:00
l10n daemon script
9d8c9853ce GIT_SILENT Sync po/docbooks with svn 2025-09-07 01:40:17 +00:00
Joshua Goins
b3781e0db4 Turn NeoChatConnection::isVerifiedSession into a notifiable property
This should allow the devices page to hide the "Verify this Device"
warning, once you actually complete verification. I also made sure to
update the other consumer - the menu item under the user menu.

Additionally, I also fixed the password field not being automatically
focused when trying to remove a device.
2025-09-06 07:51:38 -04:00
l10n daemon script
fbcb2379fb GIT_SILENT Sync po/docbooks with svn 2025-09-06 01:40:56 +00:00
Tobias Fella
e8ad4a5dee Fixes for logging out the active connection
- Don't crash
- Fall back to WelcomePage
2025-09-05 10:11:43 +00:00
l10n daemon script
6c57c41993 GIT_SILENT Sync po/docbooks with svn 2025-09-05 01:41:21 +00:00
Joshua Goins
ce0014f846 Don't accidentally hide relevant error banners
We use error banners for intermittent errors (failing to join a room),
along with more long-standing/important errors (like going offline.) And
due to the nature of how we manage banner visibility - for example, the
online check could accidentally hide joining rooms errors which is
pretty bad.

To fix this, each error banner is assigned an id. All errors can still
overwrite each other as they could before, but they can only hide
banners of their own kind.
2025-09-04 20:48:56 -04:00
l10n daemon script
e5df412258 GIT_SILENT Sync po/docbooks with svn 2025-09-04 01:41:16 +00:00
Heiko Becker
0c482aa463 GIT_SILENT Update Appstream for new release
(cherry picked from commit 681a3c4036)
2025-09-04 01:31:22 +02:00
Joshua Goins
2df3a21fb5 Show the room name when failing to join it
The previous error message generically said you failed to join a room,
but it doesn't say *which* one!
2025-09-03 10:19:26 -04:00
l10n daemon script
9dd438e8a2 GIT_SILENT Sync po/docbooks with svn 2025-09-03 01:45:00 +00:00
Tobias Fella
cea5006e15 Revert "Use libQuotient qml module"
This reverts commit b80a2f94f4.
2025-09-03 00:00:16 +02:00
Tobias Fella
8ff3b31497 Fix some qml warnings in RoomDelegate 2025-09-02 23:00:15 +02:00
Tobias Fella
c7a9f9f07e Fix qml warnings in NotificationsView 2025-09-02 22:57:39 +02:00
Tobias Fella
1de10a4b87 Fix qml warnings in RoomAdvancedPage 2025-09-02 22:51:45 +02:00
Tobias Fella
d7f19efbd6 Fix qml warnings in MimeComponent 2025-09-02 22:49:27 +02:00
Tobias Fella
a3a28b2472 Fix qml warnings in PolLDelegate 2025-09-02 22:48:19 +02:00
Tobias Fella
919fc8b821 Fix qml warnings in DelegateContextMenu 2025-09-02 20:43:46 +00:00
Tobias Fella
b80a2f94f4 Use libQuotient qml module 2025-09-02 22:36:07 +02:00
Tobias Fella
6d18d1a237 Fix qml warnings 2025-09-02 15:36:21 +02:00
Tobias Fella
a2d64d2955 Fix some qml warnings 2025-09-02 15:06:58 +02:00
l10n daemon script
95617e3210 GIT_SILENT Sync po/docbooks with svn 2025-09-02 01:52:19 +00:00
Tobias Fella
1522f7086e Fix various qmllint warnings 2025-09-01 23:50:17 +02:00
Tobias Fella
14167d197f Fix some qml warnings 2025-09-01 23:33:25 +02:00
Tobias Fella
c377cf05b8 Fix qml warnings 2025-09-01 23:27:21 +02:00
Tobias Fella
4a52bc04fb Fix warning 2025-09-01 23:12:31 +02:00
Tobias Fella
53cd230d16 Remove redundant TapHandlers 2025-09-01 23:09:18 +02:00
Tobias Fella
e7b204b9fd Fix various qmllint warnings 2025-09-01 23:06:46 +02:00
Tobias Fella
4d91ae96e3 Only build required parts of opencv 2025-09-01 15:46:08 +02:00
Tobias Fella
b422d641de Add opencv to flatpak
Dependency of KQuickImageEditor
2025-09-01 14:58:27 +02:00
Tobias Fella
adc23e22cd Fix qml warnings in ExploreComponentMobile 2025-09-01 13:39:13 +02:00
Tobias Fella
a673d97144 Fix qml warnings in ExploreComponent 2025-09-01 13:25:36 +02:00
Tobias Fella
5a71dfcd7a Fix qml warnings in SpaceHomePage 2025-09-01 13:22:05 +02:00
Tobias Fella
5f6c248181 Also disable i18n warnings 2025-09-01 13:12:53 +02:00
Tobias Fella
8e04a5ed2f Fix warnings in InvitationView 2025-09-01 13:10:11 +02:00
Tobias Fella
f45582dc03 Fix warnings and add message contexts in ServerComboBox 2025-09-01 13:06:04 +02:00
Tobias Fella
19cfe118ac Fix warnings in SpaceListContextMenu 2025-09-01 13:03:31 +02:00
Tobias Fella
79b8987d85 Fix UserSearchPage warnings 2025-09-01 13:00:57 +02:00
l10n daemon script
1d9708ffa4 GIT_SILENT Sync po/docbooks with svn 2025-09-01 01:41:21 +00:00
Tobias Fella
c55f30be5b Fix some more warnings around emoji components 2025-08-31 23:01:51 +02:00
Tobias Fella
669a00a7e3 Fix most qml warnings in RoomContextMenu 2025-08-31 22:55:58 +02:00
Tobias Fella
51fe090043 Fix warnings in EmojiPicker 2025-08-31 22:51:30 +02:00
Tobias Fella
cf85d0fc0d Fix some qml warnings 2025-08-31 22:38:24 +02:00
Tobias Fella
c257ac504b Fix warning 2025-08-31 22:35:19 +02:00
Joshua Goins
9412f7e189 Fix compact mode not filling all available space
This seems to be an unintentional change in compact mode caused by 054f87cae2,
where an if check for "straight line" or "fill width" mode ended up
being removed. But this was needed for availableWidth() to return the
correct width for compact mode, otherwise it got weirdly centered and
ended up with a limited width.
2025-08-31 10:03:57 -04:00
Joshua Goins
385fafa51c Re-arrange appearance page to group similar settings together
I re-arranged everything now so it makes more semantic sense, e.g. all
the message layout stuff is together in one card. I also made
bubble-only options hide themselves to reduce the amount of clutter
for compact layout users. Some small grammatical things were changed
like "Show Avatar" -> "Show Avatars".
2025-08-31 10:03:46 -04:00
Joshua Goins
c7e409abe9 Improve the event loading indicator somewhat
I added ellipses so it matches the other loading placeholder we have. I
also removed the spacing in it's layout, because there is more than
enough space inside of BusyIndicator itself that it makes the
additional spacing look odd.
2025-08-30 22:01:19 -04:00
Joshua Goins
98816aedd4 Set the correct palette colors for selections in quotes
This bothered me a for a while, but I finally remembered to change it
now.
2025-08-30 22:01:07 -04:00
Joshua Goins
38c66d1b7d Clip commonly seen labels used for display names to prevent Unicode spam
Unfortunately a pretty common spam/annoyance online is putting "spam"
via abusing Unicode symbols - which is used for multilingual support -
in display names. This typically results in an unreadable word jumble in
our UI, which looks bad.

So I decided to put a stop to that by clipping some labels that could be
used for this crap. I didn't cover *everything* yet, but this at least
prevents these idiots from showing up in the completion menu, the room
member list and as authors for messages.
2025-08-30 22:00:55 -04:00
Joshua Goins
0e01a43aab Ensure we update the avatar item when switching to Compact mode
This fixes an always-reproducible bug by switching from Bubbles (with
"move local messages to the right" enabled) to Compact, and your
avatar is missing until you switch rooms or restart NeoChat.

The various flags to inform the rest of the delegate of the avatar were
returning true, but the actual avatar item was never created when the
option was switched on.
2025-08-30 21:52:33 -04:00
l10n daemon script
ddf67aef94 GIT_SILENT Sync po/docbooks with svn 2025-08-31 01:42:36 +00:00
Joshua Goins
fa8294d4b9 Add action to user detail dialog to search for their messages in room
In other messaging applications (e.g. Discord) this is possible through
text modifiers like "from:@user". We don't support that, and I'm not
super keen on implementing yet-another-parsing-thing, so an action in
the user detail dialog should work for now.

Very useful to sift through large rooms but when you only care about a
specific person's messages (maybe your own?)
2025-08-30 13:19:46 -04:00
James Graham
8ad822fd0b Fix the link preview insert lambda to make sure that it doesn't crash
Fix the link preview insert lambda to make sure that it doesn't crash and also make sure that the system doesn't lock up on link preview load
2025-08-30 12:49:11 +01:00
Tobias Fella
69568c628f Also fix live locations 2025-08-30 11:39:20 +00:00
Tobias Fella
62a770b3e2 Fix showing Location events
- Initialize required properties
- Use event's body as display
2025-08-30 11:39:20 +00:00
Tobias Fella
9b65ae1e66 Cleanup LocationsModel
Use libQuotient's event properties instead of accessing data from raw json
2025-08-30 11:30:28 +00:00
Tobias Fella
5d5295d06d Modernize job handling 2025-08-30 10:23:45 +00:00
l10n daemon script
8f7be9993c GIT_SILENT Sync po/docbooks with svn 2025-08-30 01:43:35 +00:00
Joshua Goins
821d7621e3 Change chat bar text field back to plain text
This was changed in 9ed5224470 but this
ended up causing all sorts of strange formatting issues like the quick
format bar not working, and pastes from other applications that kept the
formatting.
2025-08-29 18:18:01 -04:00
Tobias Fella
91b00a34b7 Simplify code 2025-08-29 22:22:44 +02:00
Tobias Fella
19e74b60a9 Reduce nesting 2025-08-29 22:22:44 +02:00
Tobias Fella
5ee5991c39 Use contentPart instead of contentJson 2025-08-29 22:22:44 +02:00
Tobias Fella
abffeec938 Refactor accountmanager 2025-08-29 17:08:15 +02:00
Tobias Fella
77ac811498 Make delegate take maximum width while editing a message 2025-08-29 15:07:20 +00:00
Tobias Fella
1ba6b840db Bump Qt version dependency 2025-08-29 15:06:57 +00:00
Tobias Fella
bfb640487f Fix connection 2025-08-29 14:21:19 +00:00
Joshua Goins
4b3cc750a1 Remove Kirigami.OverlayZStacking from HoverLinkIndicator
I forgot this is for Popups only, let's just go back to the good
old days of hardcoding a Z value.
2025-08-29 10:06:08 -04:00
Joshua Goins
8bef9713fd Hide Purpose's own "Copy to Clipboard" function
This was added recently to Purpose, and it's not too useful for us.
We already have a bunch of better, more integrated ways to copy
events to the clipboard.
2025-08-29 10:02:50 -04:00
Tobias Fella
889bf9cbc6 Simplify event context menu open
There's no reason to pass the author from QML to C++, we can query the author in the backend
2025-08-29 15:17:19 +02:00
l10n daemon script
003ab4f278 GIT_SILENT Sync po/docbooks with svn 2025-08-29 01:41:59 +00:00
Tobias Fella
a6b9759a31 Unify Delegate context menus
The menus have always been split into a menu for file-like content and text-like content

This split makes some things a bit more complicated then necessary.
2025-08-28 22:43:42 +02:00
Tobias Fella
5c5dcd555b Fix compilation warnings about QFile::open 2025-08-28 15:16:08 +02:00
Tobias Fella
8098fce461 Fix qml name of timeline-memtest 2025-08-28 14:32:54 +02:00
l10n daemon script
227ea231d5 GIT_SILENT Sync po/docbooks with svn 2025-08-28 01:46:47 +00:00
Tobias Fella
35ac1b7a55 Tests: Rewrite server sync handling
Implements #696
2025-08-27 22:59:39 +02:00
l10n daemon script
86be1d82bc GIT_SILENT Sync po/docbooks with svn 2025-08-27 01:44:37 +00:00
Tobias Fella
c6dd82d2ff Don't link kirigami in memorytests 2025-08-26 13:40:25 +02:00
l10n daemon script
2624ed1817 GIT_SILENT Sync po/docbooks with svn 2025-08-26 01:42:10 +00:00
Tobias Fella
8706ee950e Minor fix to StateModel 2025-08-25 15:21:51 +02:00
l10n daemon script
bde27dc826 GIT_SILENT Sync po/docbooks with svn 2025-08-25 01:42:35 +00:00
Tobias Fella
25b4ee2efb Ifdef trayicon a bit more for android 2025-08-24 16:25:52 +02:00
Tobias Fella
e7f6adaa01 Refactor Controller 2025-08-24 16:12:52 +02:00
Tobias Fella
bb3e28bc43 Fix runtime qml warning 2025-08-24 11:56:22 +02:00
Tobias Fella
026db80391 Use logging category for some qDebugs 2025-08-24 10:07:59 +02:00
l10n daemon script
2c09a48c8d GIT_SILENT Sync po/docbooks with svn 2025-08-24 01:40:42 +00:00
Joshua Goins
6e0931e31b Improve search experience somewhat
So I noticed that searching for messages feels "buggy". I dove into the
code and gave it a pretty nice refresh, I know you'll like it once you
try it!

Some of the issues I noticed and are now fixed:
* The search doesn't clear immediately when you clear the text box, it's
delayed like everything else. This also has the knock-on effect of
starting random network requests.
* If you now press the search button (either with a mouse, pen, etc. or
by the keyboard) the search delay timer was still running.
* The "nothing is here" placeholder message appears when the search
timer is running, making you think no messages were found.

These changes also help other places where SearchPage is used, not just
message search.
2025-08-23 17:52:11 -04:00
Joshua Goins
1424b8ce42 Add icons to placeholder messages in search pages 2025-08-23 17:52:11 -04:00
Joshua Goins
f5f151681d Fix HAVE_KUNIFIEDPUSH not applying anymore
This compile-time definition was separated from the code during some
refactor.
2025-08-23 17:23:53 -04:00
Tobias Fella
306d75a9b0 Refactor saved room management and fix closing room when switching account
Relevant fixes hidden behind some refactoring:
- set m_lastRoomConfig per-user while setting the connection
- fold m_lastSpaceConfig into m_lastRoomConfig
- set current room to empty explicitely when there is no room
2025-08-23 23:04:39 +02:00
Tobias Fella
ee33a70bb2 Fix opening "Home space" on startup
There was a mismatch here between the value used in the config ("Home") and the value used in the property (empty string)
2025-08-23 23:04:39 +02:00
Tobias Fella
bd80390daa Improve InviteUserPage 2025-08-23 22:53:42 +02:00
Tobias Fella
0fa490f532 Fix crash on shutdown and simplify code 2025-08-23 22:39:25 +02:00
Tobias Fella
1c7cc45d8e Remove unused member 2025-08-23 12:17:49 +02:00
l10n daemon script
f3288c2e34 GIT_SILENT Sync po/docbooks with svn 2025-08-23 01:42:57 +00:00
Volker Krause
7eff1eec56 Only build the KUnifiedPush client inside a Flatpak
We neither need nor want the distributor nor the host configuration UI
here.

While at it, update to 25.08.0.
2025-08-22 17:34:05 +02:00
Tobias Fella
85c7b1a3fc Enable qmllint on CI 2025-08-22 14:15:55 +00:00
Tobias Fella
5c82c07f06 Fix search menu items 2025-08-22 10:49:39 +02:00
l10n daemon script
fcf125f9ca GIT_SILENT Sync po/docbooks with svn 2025-08-22 01:41:37 +00:00
l10n daemon script
8ae13adbcd GIT_SILENT made messages (after extraction) 2025-08-22 00:42:21 +00:00
Tobias Fella
1e1ad389e3 UserSearchPage: Move "Enter User ID" action into placeholder 2025-08-21 17:50:48 -04:00
Joshua Goins
f58212e8de Improve look of the HoverLinkIndicator and other refactorings
It still looks generally the same, except now:
* It doesn't take up the full width of the window (this was a mistake.)
* It now nicely fades in and out.
* It uses Kirigami's built-in OverlayZStacking object instead of
hardcoding a Z of 20.
* A border is now added which helps make it stand out compared to the
chat bar, which it frequently is on top of.
* The seemingly unused accessibility string is removed.
2025-08-21 17:50:33 -04:00
Tobias Fella
8622087e51 Cleanup Permissions page 2025-08-21 23:20:32 +02:00
Tobias Fella
5fc59b0d66 Cleanup RoomSecurityPage 2025-08-21 23:20:32 +02:00
Tobias Fella
5aeefea5c0 Cleanup RoomGeneralPage 2025-08-21 23:20:32 +02:00
Tobias Fella
52e9c9e8e2 Fix room list placeholders 2025-08-21 23:16:28 +02:00
Tobias Fella
ae69401d57 Fix clicking on a reply to get to the replied-to message 2025-08-21 17:27:45 +02:00
Justin Zobel
2339cad49f Uppercase OK 2025-08-21 22:58:00 +09:30
Tobias Fella
8f6683fd1d Fix most qml warnings in RoomListPage 2025-08-21 09:30:17 +02:00
Tobias Fella
74deb684e1 Don't show AddDirect delegate if we don't have any DMs
In this case, it's nicer to fall back to the placeholder, which has the same action
2025-08-21 09:15:36 +02:00
l10n daemon script
54a918b0cf GIT_SILENT Sync po/docbooks with svn 2025-08-21 01:45:15 +00:00
Tobias Fella
55c9b09b24 Add translation context 2025-08-20 20:19:13 +02:00
James Graham
0d63fce59a Apply all the required styling in cpp
Apply all the required styling to show links, table, spoilers, etc in cpp. This also updates the method of revealing spoilers so now you can click to reveal then click again to hide.
2025-08-20 17:10:44 +01:00
Joshua Goins
4498d4457b Set source size in link preview images
This prevents them from looking super jagged when we scale down a
high-res image into a small (usually ~70px in height) space.
2025-08-20 08:58:37 -04:00
Joshua Goins
83415d202a Handle more states in KeyVerificationDialog
We were specifically missing WAITINGFORKEY and WAITINGFORACCEPT, which
does happen and could be delayed - resulting in a blank screen for a few
seconds.

CCBUG: 508483
2025-08-20 08:58:26 -04:00
Tobias Fella
ed65855cdd Add autotest for server notice handling 2025-08-19 23:09:38 +02:00
Tobias Fella
1477159376 Show banner informing the user about server notices 2025-08-19 23:09:38 +02:00
Tobias Fella
53a88708d6 Only show server notices at the top if they have unread messages 2025-08-19 23:09:13 +02:00
Tobias Fella
8eb8803afd Add room category for server notices 2025-08-19 23:09:10 +02:00
l10n daemon script
20e30982cf GIT_SILENT Sync po/docbooks with svn 2025-08-19 02:05:09 +00:00
Tobias Fella
e13b82f66a Revert patch using features not yet available in flatpak 2025-08-18 17:09:50 +00:00
Tobias Fella
8e50388031 Revert KF6 version bump in flatpak 2025-08-18 17:09:50 +00:00
Tobias Fella
fb21686894 Bump KF6 dependency version 2025-08-18 17:09:50 +00:00
l10n daemon script
62faf0f784 GIT_SILENT Sync po/docbooks with svn 2025-08-18 01:41:27 +00:00
Tobias Fella
be377d9ad8 Update uri for libquotient 2025-08-17 22:01:09 +02:00
l10n daemon script
ab8e2f7573 GIT_SILENT Sync po/docbooks with svn 2025-08-17 01:40:12 +00:00
Darshan Phaldesai
7991429ef4 appstream: fix developer id 2025-08-16 12:28:53 +09:30
l10n daemon script
e3b70a14be GIT_SILENT Sync po/docbooks with svn 2025-08-16 01:42:20 +00:00
Tobias Fella
39abf6b5f3 Start adding tests for RoomManager 2025-08-15 08:10:08 +00:00
l10n daemon script
096842bd3a GIT_SILENT Sync po/docbooks with svn 2025-08-15 01:51:42 +00:00
Tobias Fella
c69db9d375 Improve chatbar actions
Introduce a new type BusyAction that wraps Kirigami.Action with the added isBusy property. This makes QML a bit happier
2025-08-14 20:56:26 +00:00
Tobias Fella
ec36d519b1 Cleanup and fix GlobalMenu 2025-08-14 22:47:42 +02:00
Tobias Fella
45b02ae34e Cleanup buttons
Mostly removing the usage of the action property, since there's no point in using it. Also add some translation contexts and some other minor cleanup
2025-08-14 20:46:46 +00:00
Kai Uwe Broulik
9b763daf52 notificationsmanager: Don't draw room avatar if it is null
Ideally, we painted the avatar with initials here but for now
it's better to not paint anything than an awkward white circle.
2025-08-14 11:28:18 +00:00
Tobias Fella
6e8ed5b341 Fix qml warnings in NewPollDialog 2025-08-14 09:23:04 +00:00
Tobias Fella
63a3c3e58a Fix build with kio 2025-08-14 09:22:16 +00:00
Tobias Fella
aadd9b0189 Fix qmllint warnings in QuickFormatBar 2025-08-14 09:20:28 +00:00
l10n daemon script
39f595e45d GIT_SILENT Sync po/docbooks with svn 2025-08-14 01:46:59 +00:00
Tobias Fella
823b2d3747 Add translation context 2025-08-13 22:13:59 +02:00
Tobias Fella
eb268576da Fix some warnings 2025-08-13 22:13:53 +02:00
Tobias Fella
8e51f3ec8e Fix some type warnings 2025-08-13 21:52:36 +02:00
Tobias Fella
de03e1ce2b Remove unused import 2025-08-13 21:52:22 +02:00
Tobias Fella
21b1258b8d Only allow opening QuickSwitcher if there is an active connection 2025-08-13 21:46:43 +02:00
Tobias Fella
becad8c127 Fix qml warnings in QuickSwitcher 2025-08-13 21:45:15 +02:00
Tobias Fella
4044048352 Add translation context 2025-08-13 21:44:34 +02:00
Tobias Fella
7d6bd7ab4c Add contexts to string 2025-08-13 21:37:05 +02:00
Tobias Fella
209ae00f8f Remove unused imports 2025-08-13 21:36:45 +02:00
Tobias Fella
f64c860453 Register dependency on KSyntaxHighlighting 2025-08-13 21:36:14 +02:00
Tobias Fella
36fccaffe6 Fix warnings 2025-08-13 21:32:45 +02:00
Tobias Fella
13deb2d928 Fix qmllint warnings 2025-08-13 21:26:24 +02:00
Tobias Fella
14fe71b556 Fix most warnings in AccountSwitchDialog 2025-08-13 19:37:21 +02:00
Tobias Fella
ecb900994b Remove unused import 2025-08-13 19:30:14 +02:00
Tobias Fella
55b97b469e Fix some qmllint warnings 2025-08-13 19:20:45 +02:00
Tobias Fella
1d594b492d Remove unused imports 2025-08-13 19:18:26 +02:00
Tobias Fella
3902293de7 Add translation contexts 2025-08-13 19:14:54 +02:00
Tobias Fella
a8bc51667c Fix various warnings and add translation contexts 2025-08-13 19:07:06 +02:00
Tobias Fella
0bcf6e74c0 Fix warnings in SearchPage 2025-08-13 18:56:37 +02:00
Tobias Fella
78b218fef3 Fix some qml type warnings 2025-08-13 17:43:51 +02:00
Tobias Fella
964bcfd5f5 Register dependency on KConfig to qml 2025-08-13 17:41:32 +02:00
Tobias Fella
fc733f9ba1 Fix some unqualified access warnings 2025-08-13 17:41:23 +02:00
l10n daemon script
e7e83fa789 GIT_SILENT Sync po/docbooks with svn 2025-08-13 01:41:50 +00:00
Tobias Fella
ef4f11546f Fix copying images 2025-08-12 14:20:57 +00:00
l10n daemon script
648796b9e0 GIT_SILENT Sync po/docbooks with svn 2025-08-12 01:42:57 +00:00
Tobias Fella
3b5da2473d Add missing copyright statement 2025-08-11 23:18:56 +02:00
Tobias Fella
9a04ae3e02 Fix opening files externally 2025-08-11 23:05:57 +02:00
James Graham
9ed5224470 Have ChatDocumentHandler update ChatBarCache text
Have ChatDocumentHandler update ChatBarCache text so all text operations in the ChatBar go through it
2025-08-11 19:33:58 +01:00
James Graham
bc82ceeb5f Simpify the API for ChatDocumentHandler
Simpify the API for ChatDocumentHandler by taking the text item and grabbing everything else needed from there
2025-08-11 19:23:40 +01:00
Tobias Fella
5f7ff209d3 Add .contextProperties.ini
Tells qmlls to ignore i18n context properties
2025-08-11 17:35:02 +02:00
Tobias Fella
35b363fdce Update room versions in security settings
We need to come up with a better way of testing the versions here, but that's for different patch
2025-08-11 10:07:19 +00:00
Tobias Fella
a74931e794 Refactor qml 2025-08-11 12:04:10 +02:00
Tobias Fella
6698bbcf79 Fix warning 2025-08-11 12:04:10 +02:00
Tobias Fella
8c78992b1a Remove broken and duplicate code 2025-08-11 12:04:08 +02:00
l10n daemon script
04e3b88e8c GIT_SILENT Sync po/docbooks with svn 2025-08-11 01:42:20 +00:00
l10n daemon script
9b8b13e98e GIT_SILENT made messages (after extraction) 2025-08-11 00:42:48 +00:00
l10n daemon script
e6dd6aec7f GIT_SILENT Sync po/docbooks with svn 2025-08-10 01:44:51 +00:00
l10n daemon script
c6f0879c9c GIT_SILENT Sync po/docbooks with svn 2025-08-09 01:39:31 +00:00
Joshua Goins
9e7ae37add Partially revert recent RoomMedia change to make it work again
This reverts part of f288367653 which
touches this file. I'm not entirely sure why it was changed, it looks
like a piece of refactoring that isn't complete yet, but MessageDelegate
still depends on a required room property.
2025-08-08 08:39:08 -04:00
Tobias Fella
0c727237ee Remove Edit menu
This menu providers a few text editing related functions, like undo/redo, copy, paste, etc.
As far as I can tell, it never worked in a useful way, though: It operates on the activeFocusItem,
but as soon as one clicks on the menu, this becomes null. It is somewhat useable through shortcuts,
but the text fields have these shortcuts natively.
2025-08-08 08:25:51 -04:00
Joshua Goins
bf66118355 Change "Copy Room Address" action to "Copy Room Link"
This is way more useful for sharing, as you can use this link in and
outside Matrix rooms. It also matches behavior with other clients like
Element Web.

I also cut some places where this shows unnecessarily, such as direct
chats and invite-only private rooms.
2025-08-08 08:25:34 -04:00
Tobias Fella
aacb097650 Add libQuotient qml module dependencies
The module doesn't exist upstream yet; this will just be ignored in that case
2025-08-08 13:42:24 +02:00
Tobias Fella
ce5d60fc5d Fix QML warning 2025-08-08 13:42:00 +02:00
Tobias Fella
96a0b86c33 Fix some unqualified access warnings 2025-08-08 13:39:06 +02:00
Tobias Fella
279b611754 Remove unused prison 2025-08-08 10:42:38 +02:00
Tobias Fella
f7c74a60cd Port away from applicationWindow() 2025-08-08 10:29:48 +02:00
l10n daemon script
3465fc7d39 GIT_SILENT Sync po/docbooks with svn 2025-08-07 19:27:58 +00:00
l10n daemon script
6381f06acb GIT_SILENT made messages (after extraction) 2025-08-07 18:30:01 +00:00
l10n daemon script
a7c7a5c72d GIT_SILENT Sync po/docbooks with svn 2025-08-07 01:42:12 +00:00
l10n daemon script
c8ded65e46 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"
2025-08-07 01:33:59 +00:00
l10n daemon script
729b46fc71 GIT_SILENT made messages (after extraction) 2025-08-07 00:42:54 +00:00
Tobias Fella
e63e04aa57 Fix QML warning 2025-08-07 00:21:10 +02:00
Tobias Fella
ae88879651 Remove unused kitemmodels imports 2025-08-07 00:19:18 +02:00
Tobias Fella
dfd106258b Fix some warnings around pagestack calls 2025-08-07 00:05:52 +02:00
Tobias Fella
4d29b9fd57 Fix qml warning 2025-08-06 23:53:04 +02:00
Tobias Fella
3de7ad237a Fix qml warning 2025-08-06 23:51:56 +02:00
Tobias Fella
7d4e589894 Remove some unused includes 2025-08-06 23:49:27 +02:00
Tobias Fella
4bbd127fe8 Fix some unqualified access 2025-08-06 23:47:28 +02:00
Tobias Fella
f2a0a66b01 Fix connection 2025-08-06 23:47:28 +02:00
James Graham
143c685045 Fix creating a new thread locally
Fix creating a new thread locally. We need to listen for the newThread signal and update the thread root event mode content
2025-08-06 18:10:03 +01:00
Tobias Fella
b8fa6f0690 Fix font sizes 2025-08-06 15:34:33 +02:00
Joshua Goins
93b6c53c82 Remind the user if they're trying to reply to someone who has left
This happens semi-frequently to me and others - we reply to a user who
has left the room. Sometimes this is useful (for example, bringing up a
previous topic) but in most cases this is accidental, and almost
guaranteed to happen if you turned off join/leave events.

So I added a reminder when replying - which manifests as a small label
in the chatbar - that the user has left and can't be notified of your
reply.
2025-08-06 08:13:49 -04:00
l10n daemon script
6822a1ef08 GIT_SILENT Sync po/docbooks with svn 2025-08-06 01:47:29 +00:00
Justin Zobel
12b7c25395 Flatpak: Update kunifiedpush project ID and URL as it is now in KDE Gear and update the version 2025-08-05 09:30:29 +00:00
Justin Zobel
42c0060122 Flatpak: Upgrade libsecret 2025-08-05 09:30:29 +00:00
Justin Zobel
b30ee55a81 Flatpak: Add cleanup 2025-08-05 09:30:29 +00:00
Tobias Fella
9d2ef838bb Don't crash when trying to open a context menu on a pending event 2025-08-05 09:17:13 +00:00
Tobias Fella
b5351e48dd Add tooltip to "remove server" button 2025-08-05 09:16:27 +00:00
l10n daemon script
7b437d91e1 GIT_SILENT Sync po/docbooks with svn 2025-08-05 01:54:03 +00:00
Nicolas Fella
a9d39353ab Add XDG activation support to rooms runner 2025-08-04 21:49:05 +02:00
Tobias Fella
5f778dbd81 Add some translation contexts 2025-08-04 21:27:28 +02:00
Nate Graham
b01286eae3 plasma-runner-neochat: remove unnecessary minimum letter count
Users generally expect search results to start appearing with the first
character typed; we shouldn't be setting minimum letter counts without
a very good reason. Excessive minimum letter counts are also bad
specifically for Chinese, which is highly information-dense.

Get rid of the minimum letter count.

CCBUG: 490972
2025-08-04 09:18:18 -06:00
Tobias Fella
4688802628 Cleanup CommonRoomsModel
- Remove unused include
- Remove roles that don't make sense
2025-08-04 17:14:32 +02:00
l10n daemon script
0282f2c7aa GIT_SILENT Sync po/docbooks with svn 2025-08-04 01:47:41 +00:00
Tobias Fella
53d0fd1663 Improve spacing in mobile UserInfo 2025-08-03 17:26:39 +02:00
l10n daemon script
24bdb7d651 GIT_SILENT Sync po/docbooks with svn 2025-08-03 01:41:12 +00:00
James Graham
dc32f2f947 Update ChatDocumentHandler so RoomManger is no longer required for saving text
Update `ChatDocumentHandler` so `RoomManger` is no longer required for saving the text in the chatbar between room switches. This is achieved by allowing `ChatDocumentHandler` to get the correct `ChatBarChache` itself rather than having to have it passed from `ChatBar.qml`. This avoids any race conditions.
2025-08-02 10:56:20 +01:00
l10n daemon script
401cf29ca8 GIT_SILENT Sync po/docbooks with svn 2025-08-02 01:39:43 +00:00
Nate Graham
f16dea85ed flatpak: add org.kde.kuiserver talk permission
This lets it use the notification infrastructure, e.g. when uploading or
downloading files.
2025-08-01 18:57:28 -06:00
James Graham
b4e1740cad Separate out a base MessageContentModel.
Separate out a base `MessageContentModel` that can be extended to get the component types from different places. This is used currently for `EventMessageContentModel` but will be used later as part of the rich chat bar.

All display text is now in the text component so it never needs special casing. This also cleans up some of the model parameters so more things come from attributes including location and file data (which was already a qvariantmap anyway).

Also cleaned up the itinerary and file enhancement views,
2025-08-01 12:15:51 +01:00
Tobias Fella
501f14fead Fix account switching on logout 2025-08-01 12:27:35 +02:00
Tobias Fella
d14466451d Fix loading 2025-08-01 12:11:35 +02:00
Tobias Fella
f7cd4bd2fb Don't set initial properties that don't exist 2025-08-01 11:43:09 +02:00
Tobias Fella
7742c6d4b0 Fix common crash during login 2025-08-01 09:26:31 +00:00
l10n daemon script
4f6dd50320 GIT_SILENT Sync po/docbooks with svn 2025-08-01 01:44:41 +00:00
Heiko Becker
92f77860dd GIT_SILENT Update Appstream for new release
(cherry picked from commit 699026fc2f)
2025-08-01 00:54:12 +02:00
l10n daemon script
03035b735d GIT_SILENT Sync po/docbooks with svn 2025-07-31 01:38:18 +00:00
Wang Yu
4e0b295f66 Replace duplicate beginResetModel with endResetModel
The initialize method was calling beginResetModel twice without
a corresponding endResetModel call. This could cause model state
inconsistencies.
2025-07-30 16:31:56 +08:00
l10n daemon script
8cbd3f5e0f GIT_SILENT Sync po/docbooks with svn 2025-07-30 01:40:03 +00:00
Joshua Goins
a0b3e484f5 Send thumbnails when uploading videos
NeoChat will now generate thumbnails from the first frame of the video,
since we are loading it anyway. This makes the experience of exchanging
videos in NeoChat much nicer!
2025-07-29 16:41:33 -04:00
Tobias Fella
8ff83ca6df Cleanup QML code for AccountMenu 2025-07-29 20:16:14 +00:00
Joshua Goins
5fe28cb183 Suggest verifying your own device in Devices settings
This button is currently hidden under the user menu, but it should be
shown more prominently - especially under the Devices settings. The
button under the user menu and this new one is now hidden when your
device is already verified.
2025-07-29 15:02:30 -04:00
l10n daemon script
17af4dfddb GIT_SILENT Sync po/docbooks with svn 2025-07-29 01:40:25 +00:00
Tobias Fella
43c6349359 Add translation context 2025-07-28 22:37:28 +02:00
Tobias Fella
265494ee44 Remove unused import 2025-07-28 22:37:05 +02:00
Tobias Fella
a9e4996191 Remove broken code 2025-07-28 22:35:30 +02:00
Tobias Fella
6e3276826d Fix positioning of mobile accounts popup 2025-07-28 22:35:15 +02:00
Tobias Fella
bfe976c438 Remove some unused includes 2025-07-28 21:50:41 +02:00
James Graham
f288367653 Add a dev setting to allow relations to be sent to any message
Add a dev setting to allow relations to be sent to any message using the right click delegate menu. This shouldn't be a main feature, but since it's technically allowed in matrix this will help any future debugging
2025-07-28 19:47:29 +01:00
Tobias Fella
6082bc89b0 Remove "NeoChat" menu item in global menu
BUG: 504429
2025-07-28 15:24:51 +00:00
l10n daemon script
4d3791250b GIT_SILENT Sync po/docbooks with svn 2025-07-28 01:37:39 +00:00
l10n daemon script
04472dae4f GIT_SILENT Sync po/docbooks with svn 2025-07-27 01:40:53 +00:00
Tobias Fella
aa40fc84ea Adapt to power level changes in room version 12 2025-07-26 22:19:07 +00:00
Tobias Fella
24e43d063a Fix test 2025-07-27 00:18:37 +02:00
l10n daemon script
c5caffcdf9 GIT_SILENT Sync po/docbooks with svn 2025-07-25 01:40:12 +00:00
l10n daemon script
95d334ad86 GIT_SILENT Sync po/docbooks with svn 2025-07-23 01:40:50 +00:00
Tobias Fella
602ac5c55f Fix opening EditStateDialog 2025-07-22 21:02:51 +02:00
l10n daemon script
247423bf83 GIT_SILENT Sync po/docbooks with svn 2025-07-22 01:42:47 +00:00
l10n daemon script
24d35b3eae GIT_SILENT Sync po/docbooks with svn 2025-07-21 01:41:16 +00:00
l10n daemon script
8bcd9f7469 GIT_SILENT Sync po/docbooks with svn 2025-07-20 01:41:17 +00:00
Tobias Fella
edf5d55da4 Prepare for new RoomId format
See MSC4291
2025-07-19 13:45:23 +00:00
l10n daemon script
976af783e2 GIT_SILENT Sync po/docbooks with svn 2025-07-19 06:16:11 +00:00
l10n daemon script
d87954838e GIT_SILENT Sync po/docbooks with svn 2025-07-18 01:38:52 +00:00
Joshua Goins
e757331dce Fix reference to Security & Safety settings on the invite screen
It's now called "Security & Safety", not just "Security". I also added a
note for translators to ensure they keep their strings consistent here.
2025-07-17 19:02:37 -04:00
l10n daemon script
bf4f6f5728 GIT_SILENT Sync po/docbooks with svn 2025-07-17 01:38:43 +00:00
Joshua Goins
c73bc8fc29 Redesign the enable encryption room setting
Clients like Element and ours show the room encryption mode as a toggle,
which in my opinion doesn't make sense. It's an irreversible operation,
so it should be a button!

When encryption is already used in the room, the button turns into a
non-interactive card.
2025-07-16 18:23:58 -04:00
Joshua Goins
211a08db68 Add ellipses to various settings actions that have confirm dialogs 2025-07-16 18:23:46 -04:00
Joshua Goins
38987e6d4c Add ellipses to the Report message action
This has a dialog to enter a message associated with the report, so as
suggested by the HIG it should have ellipses.
2025-07-16 18:23:46 -04:00
Joshua Goins
9d76e7e30b Show ellipses for leaving rooms and space actions, and always confirm
The HIG suggests using ellipses for actions that have a confirmation,
and leaving a space or room is one such cases. Otherwise, the user has
no idea if leaving is an immediate, irreversible action.

It turns out there *was* some cases where pressing this button
(especially for spaces) would actually do it without confirmation, which
is now fixed.
2025-07-16 18:23:46 -04:00
Joshua Goins
4c1a8d3657 Show the user's id or a room's canonical alias (if set) in invites
This should prevent the easiest way of masquerading, and provide an \
important identifier for rooms. Note that *only* the room canonical
alias is shown, if it's not set then it's just the display name. This is
intentional as regular users rarely interact with room IDs, but they can
still check it elsewhere in NeoChat.
2025-07-16 18:08:36 -04:00
James Graham
7a5de25885 Further refactor MessageContentModel
Further refactor MessageContentModel. Move away from special casing certian MessageContentTypes. Use forEachComponentOfType more
2025-07-16 18:27:03 +01:00
l10n daemon script
a17aa2c6fa GIT_SILENT Sync po/docbooks with svn 2025-07-16 01:56:47 +00:00
Tobias Fella
207a7876b6 Improve visualization of replies to non-message events 2025-07-15 19:55:35 +00:00
Tobias Fella
4c638a740e Set object ownership for NeoChatRoomMembers 2025-07-15 19:54:24 +00:00
Joshua Goins
0ee89e1b2b Show unable to decrypt events in the room list
These were previously (unintentionally) filtered, but I wanted to add
them because without showing and caching them my DMs look extremely out
of order. And assuming that you get an unexpected "unable to decrypt"
event, you would want that room to "shoot to the top" anyway.
2025-07-15 19:14:54 +00:00
Joshua Goins
4af42a57f4 Fix undefined QML reference in TimelineView
markAllMessagesAsRead() has moved it seems, and this specific case
wasn't changed.
2025-07-15 19:14:41 +00:00
Joshua Goins
34f2c2dabc Stop a room's lastActiveTime from changing because of hidden events
This was just a missed oversight during the refactoring, we need to pass
the hidden filter into NeoChatRoom::lastEvent so it doesn't pick up on
hidden events and push rooms to the top for no discernible reason.

Also, I simplified the function to take out the cached event handling,
because lastEvent is already doing that. The function is const now, too
and has some nicer comments.
2025-07-15 14:44:23 -04:00
l10n daemon script
9ff942915a GIT_SILENT Sync po/docbooks with svn 2025-07-15 01:44:46 +00:00
Tobias Fella
10123abc5b Fix maximizing replied-to media
The previous index-based handling opened the wrong media, as it used the wrong index.
2025-07-14 20:16:34 +00:00
l10n daemon script
ad993d4340 GIT_SILENT Sync po/docbooks with svn 2025-07-14 01:49:19 +00:00
l10n daemon script
ddc0a66d5b GIT_SILENT Sync po/docbooks with svn 2025-07-13 01:40:25 +00:00
l10n daemon script
e8981bdc0f GIT_SILENT Sync po/docbooks with svn 2025-07-12 01:42:05 +00:00
l10n daemon script
c42486a061 GIT_SILENT Sync po/docbooks with svn 2025-07-11 01:40:27 +00:00
l10n daemon script
64d82b8d2a GIT_SILENT Sync po/docbooks with svn 2025-07-10 01:40:11 +00:00
l10n daemon script
677abee890 GIT_SILENT Sync po/docbooks with svn 2025-07-09 01:42:04 +00:00
Joshua Goins
3a25a62350 Refer to global notification settings as "Default Settings" instead
This changes references to "global notification settings" to "default
settings", which should hopefully make it clearer what these actually
are.

Also, a information tip has been added to the settings page to clarify
what these settings do and imply that the per-room settings take
precedence.
2025-07-08 17:17:04 -04:00
l10n daemon script
bc7b480c41 GIT_SILENT Sync po/docbooks with svn 2025-07-08 01:40:16 +00:00
Tobias Fella
d9b495356d Fix roomlist positioning when changing rooms
The room list is supposed to center the new room, but, since the current room as stored in SortFilterRoomTreeModel is only updated after we're jumping to the room, mostly just jumped to the old room.
2025-07-07 18:31:40 +00:00
Tobias Fella
ce82606e6e Fix jumping to replied-to event 2025-07-07 14:20:02 +00:00
l10n daemon script
07837c2e64 GIT_SILENT Sync po/docbooks with svn 2025-07-07 01:38:29 +00:00
Tobias Fella
1738253e6f Don't crash when calling RoomManager::viewEventMenu with empty event id 2025-07-06 23:14:28 +02:00
James Graham
17fa2246da Refine MessageContentModel further
Create some standard functions that should hopefully make it easier to manage the model contents. Used for file stuff for now.
2025-07-06 21:16:17 +01:00
l10n daemon script
4f5e096e7e GIT_SILENT Sync po/docbooks with svn 2025-07-06 01:37:58 +00:00
Albert Astals Cid
b125c284bd GIT_SILENT Upgrade release service version to 25.11.70. 2025-07-05 11:59:46 +02:00
308 changed files with 101466 additions and 64938 deletions

2
.contextProperties.ini Normal file
View File

@@ -0,0 +1,2 @@
[General]
disableUnqualifiedAccess = "i18nc,xi18nc,i18ncp,i18n"

View File

@@ -20,8 +20,16 @@
"--talk-name=org.kde.kwalletd5",
"--talk-name=org.kde.StatusNotifierWatcher",
"--talk-name=org.freedesktop.secrets",
"--talk-name=org.kde.kuiserver",
"--own-name=org.kde.StatusNotifierItem-2-2"
],
"cleanup": [
"/include",
"/lib/*.a",
"/lib/cmake",
"/lib/pkgconfig",
"/share/ndk-modules"
],
"modules": [
{
"name": "kirigamiaddons",
@@ -36,6 +44,22 @@
}
]
},
{
"name": "opencv",
"config-opts": [
"-DBUILD_TESTS=OFF",
"-DWITH_GTK=OFF",
"-DBUILD_LIST=core,imgproc"
],
"buildsystem": "cmake-ninja",
"sources": [
{
"type": "git",
"url": "https://github.com/opencv/opencv"
}
],
"builddir": true
},
{
"name": "kquickimageeditor",
"config-opts": [
@@ -82,8 +106,8 @@
"sources": [
{
"type": "archive",
"url": "https://download.gnome.org/sources/libsecret/0.21/libsecret-0.21.6.tar.xz",
"sha256": "747b8c175be108c880d3adfb9c3537ea66e520e4ad2dccf5dce58003aeeca090",
"url": "https://download.gnome.org/sources/libsecret/0.21/libsecret-0.21.7.tar.xz",
"sha256": "6b452e4750590a2b5617adc40026f28d2f4903de15f1250e1d1c40bfd68ed55e",
"x-checker-data": {
"type": "gnome",
"name": "libsecret",
@@ -153,16 +177,20 @@
"name": "kunifiedpush",
"buildsystem": "cmake-ninja",
"builddir": true,
"config-opts": [
"-DENABLE_TESTING=OFF",
"-DKUNIFIEDPUSH_CLIENT_ONLY=ON"
],
"sources": [
{
"type": "archive",
"url": "https://download.kde.org/stable/kunifiedpush/kunifiedpush-1.0.0.tar.xz",
"sha256": "2ddeba21306d0307114ec50a2c38159ec62359f9fc6cdd58da30a369fbd550cf",
"url": "https://download.kde.org/stable/release-service/25.08.0/src/kunifiedpush-25.08.0.tar.xz",
"sha256": "846db6ffc7d93f6afea7ce0d5a9f10b52792157ceb593856542279f4197f3518",
"x-checker-data": {
"type": "anitya",
"project-id": 375055,
"project-id": 8763,
"stable-only": true,
"url-template": "https://download.kde.org/stable/kunifiedpush/kunifiedpush-$version.tar.xz"
"url-template": "https://download.kde.org/stable/release-service/$version/src/kunifiedpush-$version.tar.xz"
}
}
]

View File

@@ -14,7 +14,6 @@ Dependencies:
'frameworks/kquickcharts': '@latest-kf6'
'frameworks/knotifications': '@latest-kf6'
'frameworks/kcolorscheme': '@latest-kf6'
'frameworks/kiconthemes': '@latest-kf6'
'libraries/kquickimageeditor': '@latest-kf6'
'frameworks/sonnet': '@latest-kf6'
'frameworks/prison': '@latest-kf6'
@@ -29,7 +28,6 @@ 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'
@@ -43,3 +41,4 @@ Dependencies:
Options:
per-test-timeout: 90
require-passing-tests-on: ['Linux', 'Android', 'FreeBSD', 'Windows']
run-qmllint: True

View File

@@ -8,14 +8,14 @@ cmake_minimum_required(VERSION 3.16)
# KDE Applications version, managed by release script.
set(RELEASE_SERVICE_VERSION_MAJOR "25")
set(RELEASE_SERVICE_VERSION_MINOR "07")
set(RELEASE_SERVICE_VERSION_MICRO "70")
set(RELEASE_SERVICE_VERSION_MINOR "12")
set(RELEASE_SERVICE_VERSION_MICRO "0")
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
set(KF_MIN_VERSION "6.12")
set(QT_MIN_VERSION "6.5")
set(KF_MIN_VERSION "6.17")
set(QT_MIN_VERSION "6.9")
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
@@ -24,7 +24,7 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(KDE_COMPILERSETTINGS_LEVEL 6.0)
set(KDE_COMPILERSETTINGS_LEVEL 6.17)
include(FeatureSummary)
include(ECMSetupVersion)
@@ -39,6 +39,7 @@ include(ECMCheckOutboundLicense)
include(ECMQtDeclareLoggingCategory)
include(ECMAddAndroidApk)
include(ECMQmlModule)
include(ECMDeprecationSettings)
include(GenerateExportHeader)
include(ECMGenerateHeaders)
if (NOT ANDROID)
@@ -51,6 +52,8 @@ endif()
set(QUOTIENT_FORCE_NAMESPACED_INCLUDES TRUE)
ecm_set_disabled_deprecation_versions(Qt 6.9.0 KF 6.17.0)
ecm_setup_version(${PROJECT_VERSION}
VARIABLE_PREFIX NEOCHAT
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h
@@ -66,7 +69,7 @@ if (QT_KNOWN_POLICY_QTP0004)
qt_policy(SET QTP0004 NEW)
endif ()
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels IconThemes ColorScheme)
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme)
set_package_properties(KF6 PROPERTIES
TYPE REQUIRED
PURPOSE "Basic application components"
@@ -75,7 +78,7 @@ set_package_properties(KF6Kirigami PROPERTIES
TYPE REQUIRED
PURPOSE "Kirigami application UI framework"
)
find_package(KF6KirigamiAddons 1.6.0 REQUIRED)
find_package(KF6KirigamiAddons 1.10.0 REQUIRED)
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE)
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS Purpose)
@@ -89,7 +92,7 @@ if(ANDROID)
)
else()
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem Crash)
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem)
find_package(KF6SyntaxHighlighting ${KF_MIN_VERSION} REQUIRED)
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
TYPE RUNTIME
@@ -107,7 +110,7 @@ if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU)
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
endif()
find_package(QuotientQt6 0.9.1)
find_package(QuotientQt6 0.9.3)
set_package_properties(QuotientQt6 PROPERTIES
TYPE REQUIRED
DESCRIPTION "Qt wrapper around Matrix API"

View File

@@ -88,3 +88,9 @@ path = "memorytests/memtest-sync.json"
precedence = "aggregate"
SPDX-FileCopyrightText = "2024 James Graham <james.h.graham@protonmail.com>"
SPDX-License-Identifier = "BSD-2-Clause"
[[annotations]]
path = ".contextProperties.ini"
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 Tobias Fella <tobias.fella@kde.org>"
SPDX-License-Identifier = "BSD-2-Clause"

View File

@@ -92,3 +92,15 @@ ecm_add_test(
LINK_LIBRARIES neochat Qt::Test neochat_server
TEST_NAME actionstest
)
ecm_add_test(
servernoticestest.cpp
LINK_LIBRARIES neochat Qt::Test neochat_server
TEST_NAME servernoticestest
)
ecm_add_test(
roommanagertest.cpp
LINK_LIBRARIES neochat Qt::Test neochat_server
TEST_NAME roommanagertest
)

View File

@@ -6,6 +6,7 @@
#include <QObject>
#include <QTest>
#include <QSignalSpy>
#include <Quotient/roommember.h>
#include <Quotient/syncdata.h>
#include <qtestcase.h>
@@ -32,6 +33,7 @@ private Q_SLOTS:
void noRoom();
void badParent();
void reply();
void replyMissingUser();
void edit();
void attachment();
};
@@ -102,6 +104,33 @@ void ChatBarCacheTest::reply()
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
QCOMPARE(chatBarCache->attachmentPath(), QString());
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
}
void ChatBarCacheTest::replyMissingUser()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(u"some text"_s);
chatBarCache->setAttachmentPath(u"some/path"_s);
chatBarCache->setReplyId(u"$153456789:example.org"_s);
QCOMPARE(chatBarCache->text(), u"some text"_s);
QCOMPARE(chatBarCache->isReplying(), true);
QCOMPARE(chatBarCache->replyId(), u"$153456789:example.org"_s);
QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
QCOMPARE(chatBarCache->attachmentPath(), QString());
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
QSignalSpy relationAuthorIsPresentSpy(chatBarCache.get(), &ChatBarCache::relationAuthorIsPresentChanged);
// sync again, which will simulate the reply user leaving the room
room->syncNewEvents(u"test-min-sync-extra-sync.json"_s);
QTRY_COMPARE(relationAuthorIsPresentSpy.count(), 1);
QCOMPARE(chatBarCache->relationAuthorIsPresent(), false);
}
void ChatBarCacheTest::edit()

View File

@@ -0,0 +1,20 @@
{
"state": {
"events": [
{
"content": {
"membership": "leave"
},
"event_id": "$1432735824666PhrSA:example.org",
"origin_server_ts": 1432735824666,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@example:example.org",
"type": "m.room.member",
"unsigned": {
"replaces_state": "$143273582443PhrSn:example.org"
}
}
]
}
}

View File

@@ -130,7 +130,8 @@ void EventHandlerTest::timeString()
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().time(), QLocale::ShortFormat));
QCOMPARE(EventHandler::timeString(room, event, true),
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().date(), QLocale::ShortFormat));
QCOMPARE(EventHandler::timeString(room, event, u"hh:mm"_s), QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toString(u"hh:mm"_s));
QCOMPARE(EventHandler::timeString(room, event, u"hh:mm"_s),
QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::LocalTime)).toString(u"hh:mm"_s));
const auto txID = room->postJson("m.room.message"_L1, event->fullJson());
QCOMPARE(room->pendingEvents().size(), 1);

View File

@@ -10,7 +10,7 @@
#include <Quotient/roommember.h>
#include <Quotient/syncdata.h>
#include "models/messagecontentmodel.h"
#include "models/eventmessagecontentmodel.h"
#include "neochatconnection.h"
#include "testutils.h"
@@ -39,17 +39,17 @@ void MessageContentModelTest::initTestCase()
void MessageContentModelTest::missingEvent()
{
auto room = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
auto model1 = MessageContentModel(room, u"$153456789:example.org"_s);
auto model1 = EventMessageContentModel(room, u"$153456789:example.org"_s);
QCOMPARE(model1.rowCount(), 1);
QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
QCOMPARE(model1.data(model1.index(0), MessageContentModel::DisplayRole), u"Loading"_s);
QCOMPARE(model1.data(model1.index(0), MessageContentModel::DisplayRole), u"Loading"_s);
auto model2 = MessageContentModel(room, u"$153456789:example.org"_s, true);
auto model2 = EventMessageContentModel(room, u"$153456789:example.org"_s, true);
QCOMPARE(model2.rowCount(), 1);
QCOMPARE(model2.data(model2.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
QCOMPARE(model2.data(model2.index(0), MessageContentModel::DisplayRole), u"Loading reply"_s);
QCOMPARE(model2.data(model2.index(0), MessageContentModel::DisplayRole), u"Loading reply"_s);
room->syncNewEvents(u"test-min-sync.json"_s);
QCOMPARE(model1.rowCount(), 2);

View File

@@ -9,7 +9,7 @@
#include <Quotient/events/roommessageevent.h>
#include "models/messagecontentmodel.h"
#include "models/eventmessagecontentmodel.h"
#include "testutils.h"
using namespace Quotient;
@@ -21,7 +21,7 @@ class ReactionModelTest : public QObject
private:
Connection *connection = nullptr;
TestUtils::TestRoom *room = nullptr;
MessageContentModel *parentModel;
EventMessageContentModel *parentModel;
private Q_SLOTS:
void initTestCase();
@@ -34,7 +34,7 @@ void ReactionModelTest::initTestCase()
{
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-reactionmodel-sync.json"_s);
parentModel = new MessageContentModel(room, "123456"_L1);
parentModel = new EventMessageContentModel(room, "123456"_L1);
}
void ReactionModelTest::basicReaction()

View File

@@ -0,0 +1,141 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QObject>
#include <QSignalSpy>
#include <QTest>
#include <QVariantList>
#include "accountmanager.h"
#include "models/actionsmodel.h"
#include "roommanager.h"
#include "server.h"
#include "testutils.h"
using namespace Quotient;
class RoomManagerTest : public QObject
{
Q_OBJECT
private:
NeoChatConnection *connection = nullptr;
NeoChatRoom *room = nullptr;
Server server;
private Q_SLOTS:
void initTestCase();
void testMaximizeMedia();
void testResolveMatrixLinks();
};
void RoomManagerTest::initTestCase()
{
Connection::setRoomType<NeoChatRoom>();
server.start();
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
auto accountManager = new AccountManager(true);
QSignalSpy spy(accountManager, &AccountManager::connectionAdded);
connection = dynamic_cast<NeoChatConnection *>(accountManager->accounts()->front());
QVERIFY(connection);
auto roomId = server.createRoom(u"@user:localhost:1234"_s);
QSignalSpy syncSpy(connection, &Connection::syncDone);
// We need to wait for two syncs, as the next one won't have the changes yet
QVERIFY(syncSpy.wait());
QVERIFY(syncSpy.wait());
room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
QVERIFY(room);
RoomManager::instance().setConnection(connection);
QSignalSpy roomSpy(&RoomManager::instance(), &RoomManager::currentRoomChanged);
RoomManager::instance().resolveResource(room->id());
QVERIFY(roomSpy.size() > 0);
}
void RoomManagerTest::testMaximizeMedia()
{
QSignalSpy spy(&RoomManager::instance(), &RoomManager::showMaximizedMedia);
QSignalSpy syncSpy(connection, &Connection::syncDone);
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Tried to open media for empty event id");
RoomManager::instance().maximizeMedia(QString());
QVERIFY(!spy.wait(10));
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Tried to open media for unknown event id \"Doesn't exist\"");
RoomManager::instance().maximizeMedia(u"Doesn't exist"_s);
QVERIFY(!spy.wait(10));
const auto eventWithoutMedia = server.sendEvent(room->id(),
u"m.room.message"_s,
QJsonObject({
{u"body"_s, u"Foo"_s},
{u"format"_s, u"org.matrix.custom.html"_s},
{u"formatted_body"_s, u"Foo"_s},
{u"msgtype"_s, u"m.text"_s},
}));
QVERIFY(syncSpy.wait());
QVERIFY(syncSpy.wait());
QTest::ignoreMessage(QtMsgType::QtWarningMsg, u"Tried to open media for unknown event id \"%1\""_s.arg(eventWithoutMedia).toLatin1().data());
RoomManager::instance().maximizeMedia(eventWithoutMedia);
QVERIFY(!spy.wait(10));
// NOTE: This is supposed to test that maximizing pending media works correctly. This probably doesn't work in the UI yet, but at least the backend supports
// it. If the server ever learns how to process events, this becomes pointless and we need to find a way of preventing *these* events from arriving
auto pendingEventWithoutMedia = room->postText(u"Hello"_s);
QTest::ignoreMessage(QtMsgType::QtWarningMsg, u"Tried to open media for unknown event id \"%1\""_s.arg(pendingEventWithoutMedia).toLatin1().data());
RoomManager::instance().maximizeMedia(pendingEventWithoutMedia);
QVERIFY(!spy.wait(10));
const auto eventWithMedia = server.sendEvent(room->id(),
u"m.room.message"_s,
QJsonObject({
{u"body"_s, u"Foo"_s},
{u"filename"_s, u"foo.jpg"_s},
{u"info"_s,
QJsonObject{
{u"h"_s, 1000},
{u"w"_s, 2000},
{u"size"_s, 10000},
{u"mimetype"_s, u"image/png"_s},
}},
{u"msgtype"_s, u"m.image"_s},
{u"url"_s, u"mxc://foo.bar/asdf"_s},
}));
QVERIFY(syncSpy.wait());
QVERIFY(syncSpy.wait());
QVERIFY(syncSpy.wait());
RoomManager::instance().maximizeMedia(eventWithMedia);
QVERIFY(spy.size() == 1);
QVERIFY(spy[0][0] == 0);
auto pendingEventWithMedia = room->postJson(u"m.room.message"_s,
QJsonObject({
{u"body"_s, u"Foo"_s},
{u"filename"_s, u"foo.jpg"_s},
{u"info"_s,
QJsonObject{
{u"h"_s, 1000},
{u"w"_s, 2000},
{u"size"_s, 10000},
{u"mimetype"_s, u"image/png"_s},
}},
{u"msgtype"_s, u"m.image"_s},
{u"url"_s, u"mxc://foo.bar/asdf"_s},
}));
RoomManager::instance().maximizeMedia(pendingEventWithMedia);
QVERIFY(spy.size() == 2);
QVERIFY(spy[1][0] == 0);
}
void RoomManagerTest::testResolveMatrixLinks()
{
// Test if resolving a non-joined room will bring up the confirmation dialog.
const QSignalSpy askToJoinSpy(&RoomManager::instance(), &RoomManager::askJoinRoom);
RoomManager::instance().resolveResource(QStringLiteral("matrix:r/testbuild:matrix.org"), QStringLiteral("join"));
QTRY_COMPARE(askToJoinSpy.size(), 1);
}
QTEST_MAIN(RoomManagerTest)
#include "roommanagertest.moc"

View File

@@ -4,15 +4,12 @@
#include "server.h"
#include <QFile>
#include <QHttpServer>
#include <QHttpServerResponder>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkReply>
#include <QSslCertificate>
#include <QSslKey>
#include <QSslServer>
#include <QUuid>
#include <Quotient/networkaccessmanager.h>
@@ -109,98 +106,20 @@ void Server::start()
m_server.route(u"/_matrix/client/v3/rooms/<arg>/invite"_s,
QHttpServerRequest::Method::Post,
[this](const QString &roomId, QHttpServerResponder &responder, const QHttpServerRequest &request) {
m_invitedUsers[roomId] += QJsonDocument::fromJson(request.body()).object()[u"user_id"_s].toString();
Changes changes;
changes.invitations += Changes::InviteUser{
.userId = QJsonDocument::fromJson(request.body()).object()[u"user_id"_s].toString(),
.roomId = roomId,
};
m_state += changes;
responder.write(QJsonDocument(QJsonObject{}), QHttpServerResponder::StatusCode::Ok);
});
m_server.route(u"/_matrix/client/r0/sync"_s, QHttpServerRequest::Method::Get, [this](QHttpServerResponder &responder) {
QMap<QString, QJsonArray> stateEvents;
for (const auto &[roomId, matrixId] : m_roomsToCreate) {
stateEvents[roomId] += QJsonObject{
{u"content"_s, QJsonObject{{u"room_version"_s, u"11"_s}}},
{u"event_id"_s, generateEventId()},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, roomId},
{u"sender"_s, matrixId},
{u"state_key"_s, QString()},
{u"type"_s, u"m.room.create"_s},
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
};
stateEvents[roomId] += QJsonObject{
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"join"_s}}},
{u"event_id"_s, generateEventId()},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, roomId},
{u"sender"_s, matrixId},
{u"state_key"_s, matrixId},
{u"type"_s, u"m.room.member"_s},
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
};
}
m_roomsToCreate.clear();
for (const auto &roomId : m_invitedUsers.keys()) {
const auto &values = m_invitedUsers[roomId];
for (const auto &value : values) {
stateEvents[roomId] += QJsonObject{
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"invite"_s}}},
{u"event_id"_s, generateEventId()},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, roomId},
{u"sender"_s, u"@user:localhost:1234"_s},
{u"state_key"_s, value},
{u"type"_s, u"m.room.member"_s},
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
};
}
}
m_invitedUsers.clear();
for (const auto &roomId : m_bannedUsers.keys()) {
const auto &values = m_bannedUsers[roomId];
for (const auto &value : values) {
stateEvents[roomId] += QJsonObject{
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"ban"_s}}},
{u"event_id"_s, generateEventId()},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, roomId},
{u"sender"_s, u"@user:localhost:1234"_s},
{u"state_key"_s, value},
{u"type"_s, u"m.room.member"_s},
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
};
}
}
m_bannedUsers.clear();
for (const auto &roomId : m_joinedUsers.keys()) {
const auto &values = m_joinedUsers[roomId];
for (const auto &value : values) {
stateEvents[roomId] += QJsonObject{
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"join"_s}}},
{u"event_id"_s, generateEventId()},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, roomId},
{u"sender"_s, u"@user:localhost:1234"_s},
{u"state_key"_s, value},
{u"type"_s, u"m.room.member"_s},
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
};
}
}
m_joinedUsers.clear();
QJsonObject rooms;
for (const auto &roomId : stateEvents.keys()) {
rooms[roomId] = QJsonObject{{u"state"_s, QJsonObject{{u"events"_s, stateEvents[roomId]}}}};
}
responder.write(QJsonDocument(QJsonObject{{u"rooms"_s, QJsonObject{{u"join"_s, rooms}}}}), QHttpServerResponder::StatusCode::Ok);
});
m_server.route(u"/_matrix/client/r0/sync"_s, QHttpServerRequest::Method::Get, this, &Server::sync);
QSslConfiguration config;
QFile key(QStringLiteral(DATA_DIR) + u"/localhost.key"_s);
key.open(QFile::ReadOnly);
void(key.open(QFile::ReadOnly));
config.setPrivateKey(QSslKey(&key, QSsl::Rsa));
config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(DATA_DIR) + u"/localhost.crt"_s).front());
m_sslServer.setSslConfiguration(config);
@@ -214,22 +133,239 @@ void Server::start()
QString Server::createRoom(const QString &matrixId)
{
auto roomId = generateRoomId();
m_roomsToCreate += {roomId, matrixId};
const auto roomId = generateRoomId();
Changes changes;
changes.newRooms += Changes::NewRoom{
.initialMembers = {matrixId},
.roomId = {roomId},
.tags = {},
};
m_state += changes;
return roomId;
}
void Server::inviteUser(const QString &roomId, const QString &matrixId)
{
m_invitedUsers[roomId] += matrixId;
Changes changes;
changes.invitations += Changes::InviteUser{
.userId = matrixId,
.roomId = roomId,
};
m_state += changes;
}
void Server::banUser(const QString &roomId, const QString &matrixId)
{
m_bannedUsers[roomId] += matrixId;
Changes changes;
changes.bans += Changes::BanUser{
.userId = matrixId,
.roomId = roomId,
};
m_state += changes;
}
void Server::joinUser(const QString &roomId, const QString &matrixId)
{
m_joinedUsers[roomId] += matrixId;
Changes changes;
changes.joins += Changes::JoinUser{
.userId = matrixId,
.roomId = roomId,
};
m_state += changes;
}
QString Server::createServerNoticesRoom(const QString &matrixId)
{
const auto roomId = generateRoomId();
Changes changes;
changes.newRooms += Changes::NewRoom{
.initialMembers = {matrixId},
.roomId = {roomId},
.tags = {u"m.server_notice"_s},
};
m_state += changes;
return roomId;
}
QString Server::sendEvent(const QString &roomId, const QString &eventType, const QJsonObject &content)
{
Changes changes;
const auto eventId = generateEventId();
changes.events += Changes::Event{
.fullJson = QJsonObject{{u"type"_s, eventType},
{u"content"_s, content},
{u"sender"_s, u"@foo:server.com"_s},
{u"event_id"_s, eventId},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, roomId}},
};
m_state += changes;
return eventId;
}
void Server::sync(const QHttpServerRequest &request, QHttpServerResponder &responder)
{
QJsonObject joinRooms;
auto token = request.query().queryItemValue(u"since"_s).toInt();
for (const auto &change : m_state.mid(token)) {
for (const auto &newRoom : change.newRooms) {
QJsonArray stateEvents;
stateEvents += QJsonObject{
{u"content"_s, QJsonObject{{u"room_version"_s, u"11"_s}}},
{u"event_id"_s, generateEventId()},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, newRoom.roomId},
{u"sender"_s, newRoom.initialMembers[0]},
{u"state_key"_s, QString()},
{u"type"_s, u"m.room.create"_s},
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
};
for (const auto &member : newRoom.initialMembers) {
stateEvents += QJsonObject{
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"join"_s}}},
{u"event_id"_s, generateEventId()},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, newRoom.roomId},
{u"sender"_s, member},
{u"state_key"_s, member},
{u"type"_s, u"m.room.member"_s},
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
};
}
auto room = QJsonObject{{u"state"_s, QJsonObject{{u"events"_s, stateEvents}}}};
QJsonArray roomAccountData;
QJsonObject tags;
for (const auto &tag : newRoom.tags) {
tags[tag] = QJsonObject();
}
if (!tags.empty()) {
roomAccountData += QJsonObject{{u"type"_s, u"m.tag"_s}, {u"content"_s, QJsonObject{{u"tags"_s, tags}}}};
}
if (roomAccountData.size() > 0) {
room[u"account_data"] = QJsonObject{{u"events"_s, roomAccountData}};
}
joinRooms[newRoom.roomId] = room;
}
}
for (const auto &change : m_state.mid(token)) {
for (const auto &invitation : change.invitations) {
// TODO: The invitation could be for a room we haven't joined yet. Shouldn't be necessary for now, though.
auto stateEvents = joinRooms[invitation.roomId][u"state"_s][u"events"_s].toArray();
stateEvents += QJsonObject{
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"invite"_s}}},
{u"event_id"_s, generateEventId()},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, invitation.roomId},
{u"sender"_s, u"@user:localhost:1234"_s},
{u"state_key"_s, invitation.userId},
{u"type"_s, u"m.room.member"_s},
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
};
if (joinRooms.contains(invitation.roomId)) {
auto room = joinRooms[invitation.roomId].toObject();
room[u"state"_s] = QJsonObject{{u"events"_s, stateEvents}};
joinRooms[invitation.roomId] = room;
} else {
joinRooms[invitation.roomId] = QJsonObject{{u"state"_s,
QJsonObject{
{u"events"_s, stateEvents},
}}};
}
}
}
for (const auto &change : m_state.mid(token)) {
for (const auto &ban : change.bans) {
// TODO: The ban could be for a room we haven't joined yet. Shouldn't be necessary for now, though.
auto stateEvents = joinRooms[ban.roomId][u"state"_s][u"events"_s].toArray();
stateEvents += QJsonObject{
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"ban"_s}}},
{u"event_id"_s, generateEventId()},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, ban.roomId},
{u"sender"_s, u"@user:localhost:1234"_s},
{u"state_key"_s, ban.userId},
{u"type"_s, u"m.room.member"_s},
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
};
if (joinRooms.contains(ban.roomId)) {
auto room = joinRooms[ban.roomId].toObject();
room[u"state"_s] = QJsonObject{{u"events"_s, stateEvents}};
joinRooms[ban.roomId] = room;
} else {
joinRooms[ban.roomId] = QJsonObject{{u"state"_s,
QJsonObject{
{u"events"_s, stateEvents},
}}};
}
}
}
for (const auto &change : m_state.mid(token)) {
for (const auto &join : change.joins) {
// TODO: The join could be for a room we haven't joined yet. Shouldn't be necessary for now, though.
auto stateEvents = joinRooms[join.roomId][u"state"_s][u"events"_s].toArray();
stateEvents += QJsonObject{
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"join"_s}}},
{u"event_id"_s, generateEventId()},
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
{u"room_id"_s, join.roomId},
{u"sender"_s, u"@user:localhost:1234"_s},
{u"state_key"_s, join.userId},
{u"type"_s, u"m.room.member"_s},
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
};
if (joinRooms.contains(join.roomId)) {
auto room = joinRooms[join.roomId].toObject();
room[u"state"_s] = QJsonObject{{u"events"_s, stateEvents}};
joinRooms[join.roomId] = room;
} else {
joinRooms[join.roomId] = QJsonObject{{u"state"_s,
QJsonObject{
{u"events"_s, stateEvents},
}}};
}
}
}
for (const auto &change : m_state.mid(token)) {
for (const auto &event : change.events) {
// TODO the room might be in a different join state.
auto timeline = joinRooms[event.fullJson[u"room_id"_s].toString()][u"timeline"_s][u"events"_s].toArray();
timeline += event.fullJson;
if (joinRooms.contains(event.fullJson[u"room_id"_s].toString())) {
auto room = joinRooms[event.fullJson[u"room_id"_s].toString()].toObject();
room[u"timeline"_s] = QJsonObject{{u"events"_s, timeline}};
joinRooms[event.fullJson[u"room_id"_s].toString()] = room;
} else {
joinRooms[event.fullJson[u"room_id"_s].toString()] = QJsonObject{
{u"timeline"_s, QJsonObject{{u"events"_s, timeline}}},
};
}
}
}
QJsonObject syncData = {
// {u"account_data"_s, QJsonObject {}},
// {u"presence"_s, QJsonObject {}},
{u"next_batch"_s, QString::number(m_state.size())},
};
QJsonObject rooms;
if (!joinRooms.isEmpty()) {
rooms[u"join"_s] = joinRooms;
}
if (!rooms.empty()) {
syncData[u"rooms"_s] = rooms;
}
qWarning() << syncData;
responder.write(QJsonDocument(syncData), QHttpServerResponder::StatusCode::Ok);
}

View File

@@ -2,10 +2,51 @@
// SPDX-License-Identifier: LGPL-2.0-or-later
#include <QHttpServer>
#include <QJsonObject>
#include <QSslServer>
class Server
struct Changes {
struct NewRoom {
QStringList initialMembers;
QString roomId;
QStringList tags;
};
QList<NewRoom> newRooms;
struct InviteUser {
QString userId;
QString roomId;
};
QList<InviteUser> invitations;
struct BanUser {
QString userId;
QString roomId;
};
QList<BanUser> bans;
struct JoinUser {
QString userId;
QString roomId;
};
QList<JoinUser> joins;
struct Event {
QJsonObject fullJson;
};
QList<Event> events;
};
struct RoomData {
QStringList members;
QString id;
QStringList tags;
};
class Server : public QObject
{
Q_OBJECT
public:
Server();
@@ -21,13 +62,17 @@ public:
void banUser(const QString &roomId, const QString &matrixId);
void joinUser(const QString &roomId, const QString &matrixId);
/**
* Create a server notices room.
*/
QString createServerNoticesRoom(const QString &matrixId);
QString sendEvent(const QString &roomId, const QString &eventType, const QJsonObject &content);
private:
QHttpServer m_server;
QSslServer m_sslServer;
QHash<QString, QList<QString>> m_invitedUsers;
QHash<QString, QList<QString>> m_bannedUsers;
QHash<QString, QList<QString>> m_joinedUsers;
void sync(const QHttpServerRequest &request, QHttpServerResponder &responder);
QList<std::pair<QString, QString>> m_roomsToCreate;
QList<Changes> m_state;
};

View File

@@ -0,0 +1,87 @@
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QObject>
#include <QSignalSpy>
#include <QTest>
#include <KLocalizedString>
#include <Quotient/connection.h>
#include <Quotient/eventstats.h>
#include <Quotient/quotient_common.h>
#include <Quotient/syncdata.h>
#include "accountmanager.h"
#include "neochatroom.h"
#include "roommanager.h"
#include "server.h"
#include "testutils.h"
using namespace Quotient;
class ServerNoticesTest : public QObject
{
Q_OBJECT
private:
NeoChatConnection *connection = nullptr;
Server server;
private Q_SLOTS:
void initTestCase();
void test();
};
void ServerNoticesTest::initTestCase()
{
Connection::setRoomType<NeoChatRoom>();
server.start();
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
auto accountManager = new AccountManager(true);
QSignalSpy spy(accountManager, &AccountManager::connectionAdded);
connection = dynamic_cast<NeoChatConnection *>(accountManager->accounts()->front());
QVERIFY(connection);
auto roomId = server.createRoom(u"@user:localhost:1234"_s);
RoomManager::instance().setConnection(connection);
QSignalSpy syncSpy(connection, &Connection::syncDone);
// We need to wait for two syncs, as the next one won't have the changes yet
QVERIFY(syncSpy.wait());
QVERIFY(syncSpy.wait());
auto room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
QVERIFY(room);
}
void ServerNoticesTest::test()
{
auto roomTreeModel = RoomManager::instance().roomTreeModel();
QCOMPARE(roomTreeModel->rowCount(roomTreeModel->index(NeoChatRoomType::ServerNotice, 0)), 0);
auto sortFilterRoomTreeModel = RoomManager::instance().sortFilterRoomTreeModel();
const auto roomId = server.createServerNoticesRoom(u"@user:localhost:1234"_s);
QSignalSpy syncSpy(connection, &Connection::syncDone);
QVERIFY(syncSpy.wait());
QVERIFY(syncSpy.wait());
const auto room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
QVERIFY(connection->room(roomId)->isServerNoticeRoom());
QCOMPARE(roomTreeModel->rowCount(roomTreeModel->index(NeoChatRoomType::ServerNotice, 0)), 1);
QCOMPARE(sortFilterRoomTreeModel->mapFromSource(roomTreeModel->indexForRoom(room)).parent().row(), 1 /* Below the normal room */);
server.sendEvent(roomId,
u"m.room.message"_s,
QJsonObject{
{u"body"_s, u"Foo"_s},
{u"format"_s, u"org.matrix.custom.html"_s},
{u"formatted_body"_s, u"Foo"_s},
{u"msgtype"_s, u"m.text"_s},
});
QVERIFY(syncSpy.wait());
QVERIFY(syncSpy.wait());
sortFilterRoomTreeModel->invalidate();
QCOMPARE(sortFilterRoomTreeModel->mapFromSource(roomTreeModel->indexForRoom(room)).parent().row(), 0);
room->markAllMessagesAsRead();
QCOMPARE(sortFilterRoomTreeModel->mapFromSource(roomTreeModel->indexForRoom(room)).parent().row(), 1 /* Below the normal room */);
}
QTEST_GUILESS_MAIN(ServerNoticesTest)
#include "servernoticestest.moc"

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2023 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 <QTest>
#include <Quotient/events/event.h>
#include <Quotient/syncdata.h>
@@ -32,7 +33,7 @@ public:
if (!syncFileName.isEmpty()) {
QFile testSyncFile;
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName);
testSyncFile.open(QIODevice::ReadOnly);
Q_UNUSED(testSyncFile.open(QIODevice::ReadOnly));
const auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll());
Quotient::SyncRoomData roomData(id(), Quotient::JoinState::Join, testSyncJson.object());
update(std::move(roomData));
@@ -46,7 +47,7 @@ inline Quotient::event_ptr_tt<EventT> loadEventFromFile(const QString &eventFile
if (!eventFileName.isEmpty()) {
QFile testEventFile;
testEventFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + eventFileName);
testEventFile.open(QIODevice::ReadOnly);
Q_UNUSED(testEventFile.open(QIODevice::ReadOnly));
auto testSyncJson = QJsonDocument::fromJson(testEventFile.readAll()).object();
return Quotient::loadEvent<EventT>(testSyncJson);
}

View File

@@ -34,6 +34,10 @@ private Q_SLOTS:
void stripDisallowedTags();
void stripDisallowedAttributes();
void emptyCodeTags();
void addStyle_data();
void addStyle();
void dontAddStyle_data();
void dontAddStyle();
void sendSimpleStringCase();
void sendSingleParaMarkup();
@@ -71,6 +75,9 @@ private Q_SLOTS:
void componentOutput_data();
void componentOutput();
void updateSpoiler_data();
void updateSpoiler();
};
void TextHandlerTest::initTestCase()
@@ -89,21 +96,26 @@ void TextHandlerTest::initTestCase()
void TextHandlerTest::allowedAttributes()
{
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
const QString testInputString1 = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
const QString testOutputString1 = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
const QString testOutputString1S = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
const QString testOutputString1R = u"<span data-mx-spoiler style=\"color: transparent; background: %1;\"><font color=#FFFFFF>Test</font><span>"_s.arg(
theme->alternateBackgroundColor().name());
// Handle urls where the href has either single (') or double (") quotes.
const QString testInputString2 = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s;
const QString testOutputString2 = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s;
const QString testOutputString2S = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s;
const QString testOutputString2R =
u"<a href=\"https://kde.org\" style=\"text-decoration: none;\">link</a><a href='https://kde.org' style=\"text-decoration: none;\">link</a>"_s;
TextHandler testTextHandler;
testTextHandler.setData(testInputString1);
QCOMPARE(testTextHandler.handleSendText(), testOutputString1);
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString1);
QCOMPARE(testTextHandler.handleSendText(), testOutputString1S);
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString1R);
testTextHandler.setData(testInputString2);
QCOMPARE(testTextHandler.handleSendText(), testOutputString2);
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString2);
QCOMPARE(testTextHandler.handleSendText(), testOutputString2S);
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString2R);
}
void TextHandlerTest::stripDisallowedTags()
@@ -146,6 +158,56 @@ void TextHandlerTest::emptyCodeTags()
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
}
void TextHandlerTest::addStyle_data()
{
QTest::addColumn<QString>("testInputString");
QTest::addColumn<QString>("testOutputString");
QTest::newRow("link") << u"<a href=\"https://kde.org\">link</a>"_s << u"<a href=\"https://kde.org\" style=\"text-decoration: none;\">link</a>"_s;
QTest::newRow("table")
<< u"<table><tr><th>Company</th><th>Contact</th><th>Country</th></tr><tr><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>Germany</td></tr><tr><td>Centro comercial Moctezuma</td><td>Francisco Chang</td><td>Mexico</td></tr></table>"_s
<< u"<table style=\"width: 100%; border-collapse: collapse; border: 1px; border-style: solid;\"><tr><th style=\"border: 1px solid black; padding: 3px;\">Company</th><th style=\"border: 1px solid black; padding: 3px;\">Contact</th><th style=\"border: 1px solid black; padding: 3px;\">Country</th></tr><tr><td style=\"border: 1px solid black; padding: 3px;\">Alfreds Futterkiste</td><td style=\"border: 1px solid black; padding: 3px;\">Maria Anders</td><td style=\"border: 1px solid black; padding: 3px;\">Germany</td></tr><tr><td style=\"border: 1px solid black; padding: 3px;\">Centro comercial Moctezuma</td><td style=\"border: 1px solid black; padding: 3px;\">Francisco Chang</td><td style=\"border: 1px solid black; padding: 3px;\">Mexico</td></tr></table>"_s;
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
QTest::newRow("spoiler") << u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\"><font color=#FFFFFF>Test</font><span>"_s.arg(
theme->alternateBackgroundColor().name());
}
void TextHandlerTest::addStyle()
{
QFETCH(QString, testInputString);
QFETCH(QString, testOutputString);
TextHandler testTextHandler;
testTextHandler.setData(testInputString);
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
}
void TextHandlerTest::dontAddStyle_data()
{
QTest::addColumn<QString>("testInputString");
QTest::addColumn<QString>("testOutputString");
QTest::newRow("link") << u"<a href=\"https://kde.org\">link</a>"_s << u"<a href=\"https://kde.org\">link</a>"_s;
QTest::newRow("table")
<< u"<table><tr><th>Company</th><th>Contact</th><th>Country</th></tr><tr><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>Germany</td></tr><tr><td>Centro comercial Moctezuma</td><td>Francisco Chang</td><td>Mexico</td></tr></table>"_s
<< u"<table><tr><th>Company</th><th>Contact</th><th>Country</th></tr><tr><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>Germany</td></tr><tr><td>Centro comercial Moctezuma</td><td>Francisco Chang</td><td>Mexico</td></tr></table>"_s;
QTest::newRow("spoiler") << u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s
<< u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
}
void TextHandlerTest::dontAddStyle()
{
QFETCH(QString, testInputString);
QFETCH(QString, testOutputString);
TextHandler testTextHandler;
testTextHandler.setData(testInputString);
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
}
void TextHandlerTest::sendSimpleStringCase()
{
const QString testInputString = u"This data should just be left alone."_s;
@@ -338,7 +400,8 @@ void TextHandlerTest::receiveRichInPlainOut()
void TextHandlerTest::receivePlainTextIn()
{
const QString testInputString = u"<plain text in tag bracket>\nTest link https://kde.org."_s;
const QString testOutputStringRich = u"&lt;plain text in tag bracket&gt;<br>Test link <a href=\"https://kde.org\">https://kde.org</a>."_s;
const QString testOutputStringRich =
u"&lt;plain text in tag bracket&gt;<br>Test link <a href=\"https://kde.org\" style=\"text-decoration: none;\">https://kde.org</a>."_s;
QString testOutputStringPlain = u"<plain text in tag bracket>\nTest link https://kde.org."_s;
// Make sure quotes are maintained in a plain string.
@@ -408,7 +471,7 @@ void TextHandlerTest::receivePlainStripMarkup()
void TextHandlerTest::receiveRichUserPill()
{
const QString testInputString = u"<p><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></p>"_s;
const QString testOutputString = u"<b><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></b>"_s;
const QString testOutputString = u"<b><a href=\"https://matrix.to/#/@alice:example.org\" style=\"text-decoration: none;\">@alice:example.org</a></b>"_s;
TextHandler testTextHandler;
testTextHandler.setData(testInputString);
@@ -460,21 +523,23 @@ void TextHandlerTest::receiveRichPlainUrl_data()
// so we can confirm consistent behaviour for complex urls.
QTest::addRow("link 1")
<< u"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\">Link already rich</a>"_s
<< u"<a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\">https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im</a> <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\">Link already rich</a>"_s;
<< u"<a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\" style=\"text-decoration: none;\">https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im</a> <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\" style=\"text-decoration: none;\">Link already rich</a>"_s;
// Another real case. The linkification wasn't handling it when a single link
// contains what looks like and email. It was broken into 3 but needs to
// be just single link.
QTest::addRow("link 2")
<< u"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/"_s
<< u"<a href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\">https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>"_s;
<< u"<a href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\" style=\"text-decoration: none;\">https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>"_s;
QTest::addRow("email") << uR"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)"_s
<< uR"(<a href="mailto:email@example.com">email@example.com</a> <a href="mailto:email@example.com">Link already rich</a>)"_s;
QTest::addRow("email")
<< uR"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)"_s
<< uR"(<a href="mailto:email@example.com" style="text-decoration: none;">email@example.com</a> <a href="mailto:email@example.com" style="text-decoration: none;">Link already rich</a>)"_s;
QTest::addRow("mxid")
<< u"@user:kde.org <a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a>"_s
<< u"<b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a></b>"_s;
QTest::addRow("mxid with prefix") << u"a @user:kde.org b"_s << u"a <b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> b"_s;
<< u"<b><a href=\"https://matrix.to/#/@user:kde.org\" style=\"text-decoration: none;\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\" style=\"text-decoration: none;\">Link already rich</a></b>"_s;
QTest::addRow("mxid with prefix") << u"a @user:kde.org b"_s
<< u"a <b><a href=\"https://matrix.to/#/@user:kde.org\" style=\"text-decoration: none;\">@user:kde.org</a></b> b"_s;
}
/**
@@ -596,5 +661,35 @@ void TextHandlerTest::componentOutput()
QCOMPARE(testTextHandler.textComponents(testInputString), testOutputComponents);
}
void TextHandlerTest::updateSpoiler_data()
{
QTest::addColumn<QString>("testInputString");
QTest::addColumn<QString>("testOutputString");
QTest::addColumn<bool>("spoilerRevealed");
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
QTest::newRow("same length") << u"<span data-mx-spoiler style=\"color: #123456; background: #123456;\">Test<span>"_s
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\">Test<span>"_s.arg(
theme->alternateBackgroundColor().name())
<< false;
QTest::newRow("different length") << u"<span data-mx-spoiler style=\"color: short; background: looooooooooong;\">Test<span>"_s
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\">Test<span>"_s.arg(
theme->alternateBackgroundColor().name())
<< false;
QTest::newRow("spoiler revealed")
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\">Test<span>"_s.arg(theme->alternateBackgroundColor().name())
<< u"<span data-mx-spoiler style=\"color: %1; background: %2;\">Test<span>"_s.arg(theme->textColor().name(), theme->alternateBackgroundColor().name())
<< true;
}
void TextHandlerTest::updateSpoiler()
{
QFETCH(QString, testInputString);
QFETCH(QString, testOutputString);
QFETCH(bool, spoilerRevealed);
QCOMPARE(TextHandler::updateSpoilerText(this, testInputString, spoilerRevealed), testOutputString);
}
QTEST_MAIN(TextHandlerTest)
#include "texthandlertest.moc"

View File

@@ -161,7 +161,7 @@ void TimelineMessageModelTest::pendingEvent()
// different every time.
QFile testSyncFile;
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + u"test-pending-sync.json"_s);
testSyncFile.open(QIODevice::ReadOnly);
QVERIFY(testSyncFile.open(QIODevice::ReadOnly));
auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll());
auto root = testSyncJson.object();
auto timeline = root["timeline"_L1].toObject();

View File

@@ -3,12 +3,12 @@
add_definitions(-DDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}" )
qt_add_executable(timeline-memtest
qt_add_executable(timeline_memtest
main.cpp
)
target_link_libraries(timeline-memtest PRIVATE neochatplugin Timelineplugin)
target_link_libraries(timeline-memtest PUBLIC
target_link_libraries(timeline_memtest PRIVATE neochatplugin Timelineplugin)
target_link_libraries(timeline_memtest PUBLIC
Qt::Core
Qt::Quick
Qt::Qml
@@ -16,14 +16,13 @@ target_link_libraries(timeline-memtest PUBLIC
Qt::QuickControls2
Qt::Widgets
KF6::I18nQml
KF6::Kirigami
QuotientQt6
LibNeoChat
Timeline
)
ecm_add_qml_module(timeline-memtest URI org.kde.neochat.timeline-memtest GENERATE_PLUGIN_SOURCE
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/timeline-memtest
ecm_add_qml_module(timeline_memtest URI org.kde.neochat.timeline_memtest GENERATE_PLUGIN_SOURCE
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/timeline_memtest
QML_FILES
Main.qml
SOURCES

View File

@@ -28,7 +28,7 @@ int main(int argc, char **argv)
engine.rootContext()->setContextProperty(u"memTestTimelineModel"_s, memTestTimelineModel);
engine.rootContext()->setContextProperty(u"messageFilterModel"_s, messageFilterModel);
engine.loadFromModule("org.kde.neochat.timeline-memtest", "Main");
engine.loadFromModule("org.kde.neochat.timeline_memtest", "Main");
return app.exec();
}

View File

@@ -37,7 +37,11 @@ public:
if (!syncFileName.isEmpty()) {
QFile testSyncFile;
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName);
testSyncFile.open(QIODevice::ReadOnly);
auto ok = testSyncFile.open(QIODevice::ReadOnly);
if (!ok) {
qWarning() << "Failed to open" << testSyncFile.fileName() << testSyncFile.errorString();
}
auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll()).object();
auto timelineJson = testSyncJson["timeline"_L1].toObject();
timelineJson["events"_L1] = multiplyEvents(timelineJson["events"_L1].toArray(), 100);

View File

@@ -41,6 +41,7 @@
<name xml:lang="pl">NeoChat</name>
<name xml:lang="pt">NeoChat</name>
<name xml:lang="pt-BR">NeoChat</name>
<name xml:lang="ro">NeoChat</name>
<name xml:lang="ru">NeoChat</name>
<name xml:lang="sa">नवचैट्</name>
<name xml:lang="sk">NeoChat</name>
@@ -49,7 +50,6 @@
<name xml:lang="ta">நியோச்சாட்</name>
<name xml:lang="tr">NeoChat</name>
<name xml:lang="uk">NeoChat</name>
<name xml:lang="x-test">xxNeoChatxx</name>
<name xml:lang="zh-CN">NeoChat</name>
<name xml:lang="zh-TW">NeoChat</name>
<summary>Chat on Matrix</summary>
@@ -75,6 +75,8 @@
<summary xml:lang="nl">Chat op Matrix</summary>
<summary xml:lang="nn">Prat med via Matrix</summary>
<summary xml:lang="pl">Rozmawiaj na Matriksie</summary>
<summary xml:lang="pt-BR">Bate-papo na Matrix</summary>
<summary xml:lang="ro">Discutați pe Matrix</summary>
<summary xml:lang="ru">Общение в Matrix</summary>
<summary xml:lang="sa">Matrix इत्यत्र गपशपं कुर्वन्तु</summary>
<summary xml:lang="sl">Klepet na Matrixu</summary>
@@ -82,7 +84,6 @@
<summary xml:lang="ta">மேட்ரிக்ஸுக்கான உரையாடல் செயலி</summary>
<summary xml:lang="tr">Matrix Üzerinde Sohbet</summary>
<summary xml:lang="uk">Спілкування у Matrix</summary>
<summary xml:lang="x-test">xxChat on Matrixxx</summary>
<summary xml:lang="zh-TW">在 Matrix 上聊天</summary>
<description>
<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>
@@ -109,16 +110,17 @@
<p xml:lang="nl">NeoChat is een chat-toepassing die u het volledige voordeel van het Matrix-netwerk laat genieten. Het levert u op een veilige manier tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden te verzenden.</p>
<p xml:lang="nn">NeoChat er ein prateapp som lèt deg bruka all funksjonalitet i Matrix-nettverket. Du kan utveksla tekst, lyd og videoar med vennar, familie og kollegaar på ein trygg måte.</p>
<p xml:lang="pl">NoeChat to aplikacja do rozmów, która umożliwia wykorzystanie wszystkich możliwości Matriksa. Umożliwia wysyłanie wiadomości tekstowych, filmów i dźwięków w bezpieczny sposób do twojej rodziny, kolegów i przyjaciół.</p>
<p xml:lang="pt-BR">O NeoChat é um aplicativo de bate-papo que permite que você aproveite ao máximo a rede Matrix. Ele oferece uma maneira segura de enviar mensagens de texto, vídeos e arquivos de áudio para sua família, colegas e amigos.</p>
<p xml:lang="ro">NeoChat e o aplicație de discuții ce vă ajută să profitați din plin de rețeaua Matrix. Aceasta oferă o modalitate sigură de a trimite mesaje textuale, videoclipuri și fișiere audio familiei, colegilor și prietenilor.</p>
<p xml:lang="ru">NeoChat — приложение для общения, предоставляющее все преимущества сети Matrix. С его помощью можно безопасно отправлять текстовые сообщения, видеозаписи и звуковые файлы родственникам, коллегам и друзьям.</p>
<p xml:lang="sa">NeoChat इति एकं गपशप-अनुप्रयोगं यत् भवान् Matrix-जालस्य पूर्णं लाभं ग्रहीतुं शक्नोति । एतत् भवन्तं भवतः परिवाराय, सहकारिभ्यः, मित्रेभ्यः च पाठसन्देशान्, भिडियो, श्रव्यसञ्चिकाः च प्रेषयितुं सुरक्षितं मार्गं प्रदाति ।</p>
<p xml:lang="sl">NeoChat je aplikacija za klepet, ki vam omogoča, da v celoti izkoristite omrežje Matrix. Zagotavlja vam varen način za pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, sodelavcem in prijateljem.</p>
<p xml:lang="sv">NeoChat är ett chattprogram som låter dig dra full nytta av Matrix-nätverket. Det ger dig ett säkert sätt att skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner.</p>
<p xml:lang="tr">NeoChat, Matrix ağının tüm özelliklerini kullanan bir sohbet uygulamasıdır. Ailenize, arkadaşlarınıza ve iş arkadaşlarınıza metin iletileri, ses ve video dosyaları göndermenin kolay bir yolunu sunar.</p>
<p xml:lang="uk">NeoChat є програмою для спілкування, за допомогою якої ви можете скористатися усіма перевагами мережі Matrix. За її допомогою ви можете безпечно надсилати текстові повідомлення, відео та звукові файли вашим родичам, колегам та друзям.</p>
<p xml:lang="x-test">xxNeoChat 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.xx</p>
<p xml:lang="zh-TW">NeoChat 是一個讓您能夠完全利用 Matrix 網路的聊天應用程式。它讓您安全地傳送文字訊息、影片或音訊檔給家人、同事或朋友等等。</p>
<p>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.</p>
<p xml:lang="ar">يهدف نيوتشات إلى أن يكون تطبيقًا كامل الميزات لمواصفات ماتركس. على هذا النحو يتم دعم كل شيء في المواصفات المستقرة الحالية مع الاستثناءات الملحوظة لـ VoIP والخيوط وبعض جوانب التشفير من طرف إلى طرف. هناك عدد قليل من الإغفالات الصغيرة الأخرى بسبب حقيقة أن مواصفات ماتركس تتطور باستمرار ، ولكن يبقى الهدف توفير الدعم النهائي للمواصفات بأكملها.</p>
<p xml:lang="ar">يهدف نيوتشات إلى أن يكون تطبيقًا كامل الميزات لمواصفات ماتركس. يوفر نيوتشات كل شيء في المواصفات المستقرة الحالية مع الاستثناءات الملحوظة لـ VoIP و تعدد الخيوط وبعض جوانب التعمية من طرف إلى طرف. هناك عدد قليل من الإغفالات الصغيرة الأخرى بسبب حقيقة أن مواصفات ماتركس تتطور باستمرار، ولكن يبقى الهدف توفير تطبيق للمواصفات بأكملها.</p>
<p xml:lang="ca">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptatge d'extrem a extrem. Hi ha algunes altres omissions més petites a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu segueix sent proporcionar suport eventual per a tota l'especificació.</p>
<p xml:lang="ca-valencia">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptació d'extrem a extrem. Hi ha algunes altres omissions més xicotetes a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu seguix sent proporcionar suport eventual per a tota l'especificació.</p>
<p xml:lang="de">NeoChat versucht eine vollumfängliche Anwendung für die Spezifikation von Matrix zu sein. Damit wird alles der aktuellen stabilen Spezifikation mit den erwähnenswerten Ausnahmen von VoIP, Diskussionsfäden und ein paar Teilen der Ende-zu-Ende-Verschlüsselung unterstützt. Zudem sind andere kleinere Auslassungen vorhanden, da sich die Matrixspezifikation ständig weiterentwickelt. Nichtsdestotrotz soll letztendlich die gesamte Spezifikation unterstützt werden.</p>
@@ -142,16 +144,17 @@
<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="pt-BR">O NeoChat pretende ser um aplicativo completo para a especificação Matrix. Dessa forma, tudo na especificação estável atual, com as notáveis exceções de VoIP, tópicos e alguns aspectos da criptografia de ponta a ponta, é suportado. Há algumas outras pequenas omissões devido ao fato de a especificação Matrix estar em constante evolução, mas o objetivo continua sendo fornecer suporte eventual para toda a especificação.</p>
<p xml:lang="ro">NeoChat vrea să fie o aplicație completă pentru specificațiile Matrix. Astfel, susține tot ce se găsește acum în specificațiile stabile cu excepția VoIP, a firelor de discuții, și a unor părți din criptarea punct-la-punct. Sunt și câteva omisiuni minore din cauza faptului că specificația Matrix evoluează continuu, dar scopul rămâne acela de a implementa întreaga specificație.</p>
<p xml:lang="ru">Целью создания NeoChat является полноценная реализация программы для спецификации Matrix. Как следствие, реализовано всё в текущей стабильной спецификации (за исключением голосовой интернет-связи, потоков и некоторых аспектов сквозного шифрования). Есть также несколько других незначительных пробелов, обусловленных постоянными изменениями спецификации Matrix. Тем не менее, стоит задача в итоге предоставить полную поддержку спецификации.</p>
<p xml:lang="sa">NeoChat इत्यस्य उद्देश्यं Matrix विनिर्देशस्य कृते पूर्णतया विशेषतायुक्तः अनुप्रयोगः भवितुम् अस्ति । यथा तथा वर्तमानस्थिरविनिर्देशे सर्वं VoIP इत्यस्य उल्लेखनीयअपवादैः सह, थ्रेड्स तथा च End-to-End Encryption इत्यस्य केचन पक्षाः समर्थिताः सन्ति । अन्ये कतिचन लघु लोपाः सन्ति यतोहि Matrix spec निरन्तरं विकसितः अस्ति परन्तु उद्देश्यं सम्पूर्ण spec कृते अन्ततः समर्थनं प्रदातुं अवशिष्टम् अस्ति</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>
<p xml:lang="uk">Метою створення NeoChat є повноцінна реалізація програми для специфікації Matrix. Як наслідок, реалізовано усе у поточній стабільній специфікації, окрім голосового інтернет-зв'язку, потоків та деяких аспектів міжвузлового шифрування. Є також декілька інших незначних прогалин через те, що специфікація Matrix постійно змінюється, але метою лишається повна підтримка специфікації.</p>
<p xml:lang="x-test">xxNeoChat 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.xx</p>
<p xml:lang="zh-TW">NeoChat 以完整支援 Matrix 標準為目標,因此目前穩定版標準除了 VoIP、對話串與端對端加密的某些部分以外的所有部分都有支援。其他部分還有一些較小的不支援的部分這是因為 Matrix 標準隨時都在改進,但目標仍然時最終提供整個標準的完整支援。</p>
<p>Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:</p>
<p xml:lang="ar">نظرًا لطبيعة تطوير مواصفات ماتركس، يدعم نيوتشات أيضًا العديد من الميزات غير المستقرة وهي:</p>
<p xml:lang="ar">نظرًا لطبيعة تطوير مواصفات ماتركس، يوفر نيوتشات أيضًا العديد من الميزات غير المستقرة وهي:</p>
<p xml:lang="ca">A causa de la naturalesa del desenvolupament de l'especificació de Matrix, el NeoChat també implementa nombroses característiques inestables. Actualment són:</p>
<p xml:lang="ca-valencia">A causa de la naturalea del desenvolupament de l'especificació de Matrix, NeoChat també implementa nombroses característiques inestables. Actualment són:</p>
<p xml:lang="de">Durch die Weiterentwicklung der Matrix-Spezifikation unterstützt auch NeoChat einige als noch instabil gekennzeichnete Funktionen. Derzeit sind das:</p>
@@ -175,6 +178,8 @@
<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="pt-BR">Devido à natureza do desenvolvimento da especificação Matrix, o NeoChat também suporta diversos recursos instáveis. Atualmente, são eles:</p>
<p xml:lang="ro">Datorită modului de dezvoltare a specificațiilor Matrix, NeoChat susține și numeroase caracteristici nestabile. Acum, acestea sunt:</p>
<p xml:lang="ru">В силу природы разработки спецификации Matrix в NeoChat тоже предусмотрена поддержка многочисленных нестабильных возможностей. В текущей версии это следующие возможности:</p>
<p xml:lang="sa">Matrix विनिर्देशविकासस्य प्रकृतेः कारणात् NeoChat अपि अनेकानाम् अस्थिरविशेषतानां समर्थनं करोति । सम्प्रति एते सन्ति :</p>
<p xml:lang="sl">Zaradi narave razvoja specifikacije Matrixa NeoChat podpira tudi številne nestabilne zmožnosti. Trenutno so to:</p>
@@ -182,13 +187,12 @@
<p xml:lang="ta">மேட்ரிக்ஸு நெறிமுறை வரையறுக்கப்படும் வித‍த்தின் காரணமாக, பல நிலையற்ற அம்சங்களையும் நியோச்சாட் ஆதரிக்கிறது. தற்போது ஆதரிக்கப்படுபவை:</p>
<p xml:lang="tr">NeoChat, Matrix belirtimi geliştirmesinin doğası gereği çok sayıda kararsız özelliği de destekler. Şu anda bunlar:</p>
<p xml:lang="uk">Через природу розробки специфікації Matrix, у NeoChat також передбачено підтримку численних нестабільних можливостей. У поточній версії цими можливостями є:</p>
<p xml:lang="x-test">xxDue to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:xx</p>
<p xml:lang="zh-TW">由於 Matrix 標準的開發流程的緣故NeoChat 也支援數個非穩定版的功能。目前這些功能是:</p>
<ul>
<li>Polls - MSC3381</li>
<li xml:lang="ar">التصويت - MSC3381</li>
<li xml:lang="ca">Enquestes - MSC3381</li>
<li xml:lang="ca-valencia">Enquestes - MSC3381</li>
<li xml:lang="ca">Votacions - MSC3381</li>
<li xml:lang="ca-valencia">Votacions - MSC3381</li>
<li xml:lang="el">Δημοσκοπήσεις - MSC3381</li>
<li xml:lang="en-GB">Polls - MSC3381</li>
<li xml:lang="eo">Enketoj - MSC3381</li>
@@ -209,6 +213,8 @@
<li xml:lang="nn">Avstemmingar  MSC3381</li>
<li xml:lang="pl">Ankiety - MSC3381</li>
<li xml:lang="pt">Inquéritos - MSC3381</li>
<li xml:lang="pt-BR">Enquetes - MSC3381</li>
<li xml:lang="ro">Sondaje - MSC3381</li>
<li xml:lang="ru">Голосования — MSC3381</li>
<li xml:lang="sa">मतदान - MSC3381</li>
<li xml:lang="sl">Polls - MSC3381</li>
@@ -216,7 +222,6 @@
<li xml:lang="ta">வாக்கெடுப்புகள் - MSC3381</li>
<li xml:lang="tr">Anketler — MSC3381</li>
<li xml:lang="uk">Опитування - MSC3381</li>
<li xml:lang="x-test">xxPolls - MSC3381xx</li>
<li xml:lang="zh-TW">投票 - MSC3381</li>
<li>Sticker Packs - MSC2545</li>
<li xml:lang="ar">حزم الملصقات - MSC2545</li>
@@ -242,6 +247,8 @@
<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="pt-BR">Pacotes de Stickers - MSC2545</li>
<li xml:lang="ro">Colecții de abțibilduri - MSC2545</li>
<li xml:lang="ru">Наборы стикеров — MSC2545</li>
<li xml:lang="sa">स्टिकर पैक - MSC2545</li>
<li xml:lang="sl">Sticker Packs - MSC2545</li>
@@ -249,7 +256,6 @@
<li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li>
<li xml:lang="tr">Çıkartma Paketleri — MSC2545</li>
<li xml:lang="uk">Пакунки наліпок - MSC2545</li>
<li xml:lang="x-test">xxSticker Packs - MSC2545xx</li>
<li xml:lang="zh-TW">貼圖包 - MSC2545</li>
<li>Location Events - MSC3488</li>
<li xml:lang="ar">موقع الأحداث - MSC3488</li>
@@ -275,6 +281,8 @@
<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="pt-BR">Localização de eventos - MSC3488</li>
<li xml:lang="ro">Evenimente de amplasare - MSC3488</li>
<li xml:lang="ru">События местоположения — MSC3488</li>
<li xml:lang="sa">स्थान घटनाएँ - MSC3488</li>
<li xml:lang="sl">Location Events - MSC3488</li>
@@ -282,7 +290,6 @@
<li xml:lang="ta">இட நிகழ்வுகள் - MSC3488</li>
<li xml:lang="tr">Konum Etkinlikleri — MSC3488</li>
<li xml:lang="uk">Місцеві зустрічі - MSC3488</li>
<li xml:lang="x-test">xxLocation Events - MSC3488xx</li>
<li xml:lang="zh-TW">位置事件 - MSC3488</li>
</ul>
</description>
@@ -299,8 +306,8 @@
<keyword>Matrix</keyword>
<keyword>Kirigami</keyword>
</keywords>
<developer id="kde.org">
<name>The KDE Community</name>
<developer id="org.kde">
<name translate="no">KDE</name>
<url>https://kde.org</url>
</developer>
<metadata_license>CC0-1.0</metadata_license>
@@ -313,7 +320,7 @@
<value key="KDE::windows_store::StoreLogoSquare">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/storelogo-1080x1080.png</value>
<value key="KDE::windows_store::Icon">https://invent.kde.org/network/neochat/-/raw/master/icons/300-apps-neochat.png</value>
<value key="KDE::windows_store::PromotionalArt16x9">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/promoimage-1920x1080.png</value>
<value key="KDE::supporters">Tanguy Fardet;[dabe](https://freeradical.zone/@dabe);[lengau](https://mastodon.world/@lengau);Joshua Strobl;Stuart Turton</value>
<value key="KDE::supporters">Anonymous donor, Akseli</value>
</custom>
<launchable type="desktop-id">org.kde.neochat.desktop</launchable>
<screenshots>
@@ -344,6 +351,8 @@
<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="pt-BR">Visão principal com lista de salas, bate-papo e informações sobre as salas</caption>
<caption xml:lang="ro">Vederea principală cu lista de camere, discuție, și informații despre cameră</caption>
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
<caption xml:lang="sa">कक्षसूची, गपशपः, कक्षसूचना च सह मुख्यदृश्यम्</caption>
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
@@ -351,7 +360,6 @@
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
<caption xml:lang="tr">Oda listesini, sohbet penceresini ve oda bilgisini gösteren ana görünüm</caption>
<caption xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</caption>
<caption xml:lang="x-test">xxMain view with room list, chat, and room informationxx</caption>
<caption xml:lang="zh-TW">主頁面,包含聊天室列表、聊天內容,與聊天室資訊</caption>
</screenshot>
<screenshot type="default">
@@ -380,6 +388,8 @@
<caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption>
<caption xml:lang="nn">Oppdag nye fellesskap med Matrix Spaces</caption>
<caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption>
<caption xml:lang="pt-BR">Descubra novas comunidades com os Espaços Matrix</caption>
<caption xml:lang="ro">Descoperiți comunități noi cu Spații Matrix</caption>
<caption xml:lang="ru">Поиск новых сообществ с помощью Matrix Spaces</caption>
<caption xml:lang="sa">Matrix Spaces इत्यनेन सह नूतनानां समुदायानाम् अन्वेषणं कुर्वन्तु</caption>
<caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption>
@@ -387,7 +397,6 @@
<caption xml:lang="ta">மேட்ரிக்ஸு இடங்களின் மூலம் புதிய சமூகங்களைக் கண்டுபிடிக்கலாம்</caption>
<caption xml:lang="tr">Matrix Alanlar ile yeni topluluklar keşfedin</caption>
<caption xml:lang="uk">Пошук нових спільнот за допомогою Matrix Spaces</caption>
<caption xml:lang="x-test">xxDiscover new communities with Matrix Spacesxx</caption>
<caption xml:lang="zh-TW">利用 Matrix 聊天空間發現新的社群</caption>
</screenshot>
<!--
@@ -424,6 +433,8 @@
<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="pt-BR">Visão principal com lista de salas, bate-papo e informações sobre as salas</caption>
<caption xml:lang="ro">Vederea principală cu lista de camere, discuție, și informații despre cameră</caption>
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
<caption xml:lang="sa">कक्षसूची, गपशपः, कक्षसूचना च सह मुख्यदृश्यम्</caption>
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
@@ -431,7 +442,6 @@
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
<caption xml:lang="tr">Oda listesini, sohbet penceresini ve oda bilgisini gösteren ana görünüm</caption>
<caption xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</caption>
<caption xml:lang="x-test">xxMain view with room list, chat, and room informationxx</caption>
<caption xml:lang="zh-TW">主頁面,包含聊天室列表、聊天內容,與聊天室資訊</caption>
</screenshot>
<screenshot environment="windows">
@@ -462,6 +472,8 @@
<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="pt-BR">Tela de login</caption>
<caption xml:lang="ro">Ecran de autentificare</caption>
<caption xml:lang="ru">Окно входа</caption>
<caption xml:lang="sa">लॉगिन् स्क्रीन</caption>
<caption xml:lang="sl">Prijavni zaslon</caption>
@@ -469,7 +481,6 @@
<caption xml:lang="ta">நுழைவுத் திரை</caption>
<caption xml:lang="tr">Oturum açma ekranı</caption>
<caption xml:lang="uk">Вікно входу</caption>
<caption xml:lang="x-test">xxLogin screenxx</caption>
<caption xml:lang="zh-TW">登入畫面</caption>
</screenshot>
</screenshots>
@@ -477,6 +488,11 @@
<content_attribute id="social-chat">intense</content_attribute>
</content_rating>
<releases>
<release version="25.12.0" date="2025-12-11"/>
<release version="25.08.3" date="2025-11-06"/>
<release version="25.08.2" date="2025-10-09"/>
<release version="25.08.1" date="2025-09-11"/>
<release version="25.08.0" date="2025-08-14"/>
<release version="25.04.3" date="2025-07-03"/>
<release version="25.04.2" date="2025-06-05"/>
<release version="25.04.1" date="2025-05-08"/>

View File

@@ -44,7 +44,6 @@ Name[sv]=NeoChat
Name[ta]=நியோச்சாட்
Name[tr]=NeoChat
Name[uk]=NeoChat
Name[x-test]=xxNeoChatxx
Name[zh_CN]=NeoChat
Name[zh_TW]=NeoChat
GenericName=Matrix Client
@@ -88,7 +87,6 @@ GenericName[sv]=Matrix-klient
GenericName[ta]=Matrix வாங்கி
GenericName[tr]=Matrix İstemcisi
GenericName[uk]=Клієнт Matrix
GenericName[x-test]=xxMatrix Clientxx
GenericName[zh_CN]=Matrix 客户端
GenericName[zh_TW]=Matrix 用戶端
Comment=Chat on Matrix
@@ -114,6 +112,7 @@ Comment[lv]=Tērzējiet „Matrix“ tīklā
Comment[nl]=Chat op Matrix
Comment[pl]=Rozmawiaj na Matriksie
Comment[pt_BR]=Bate papo na Matrix
Comment[ro]=Discutați pe Matrix
Comment[ru]=Общение в Matrix
Comment[sa]=Matrix इत्यत्र गपशपं कुर्वन्तु
Comment[sl]=Klepet na Matrixu
@@ -121,7 +120,6 @@ Comment[sv]=Chatta på Matrix
Comment[ta]=மேட்ரிக்ஸில் உரையாட உதவும்
Comment[tr]=Matrix üzerinde sohbet edin
Comment[uk]=Спілкування у Matrix
Comment[x-test]=xxChat on Matrixxx
Comment[zh_CN]=在 Matrix 上聊天
Comment[zh_TW]=在 Matrix 上聊天
MimeType=x-scheme-handler/matrix;

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

7049
po/ro/neochat.po Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,122 @@
<?xml version="1.0" ?>
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
<!ENTITY % Russian "INCLUDE">
]>
<!--
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
SPDX-License-Identifier: CC-BY-SA-4.0
-->
<refentry lang="&language;">
<refentryinfo>
<title
>Руководство пользователя NeoChat</title>
<author
><firstname
>Carl</firstname
><surname
>Schwan</surname
> <contrib
>man-страница NeoChat.</contrib
> <email
>carl@carlschwan.eu</email
></author>
<date
>2022-11-01</date>
<releaseinfo
>22.09</releaseinfo>
<productname
>NeoChat</productname>
</refentryinfo>
<refmeta>
<refentrytitle>
<command
>neochat</command>
</refentrytitle>
<manvolnum
>1</manvolnum>
</refmeta>
<refnamediv>
<refname
>neochat</refname>
<refpurpose
>Клиент для взаимодействия с протоколом обмена сообщениями Matrix</refpurpose>
</refnamediv>
<!-- body begins here -->
<refsynopsisdiv id='synopsis'>
<cmdsynopsis
><command
>neochat</command
> <arg choice="opt"
><replaceable
>URI</replaceable
></arg
> </cmdsynopsis>
</refsynopsisdiv>
<refsect1 id="description">
<title
>Описание</title>
<para
><command
>neochat</command
> — приложение для настольных и мобильных устройств, позволяющее общаться в чатах с помощью протокола Matrix. </para>
</refsect1>
<refsect1 id="options"
><title
>Параметры</title>
<variablelist>
<varlistentry>
<term
><option
>URI</option
></term>
<listitem>
<para
>URI-адрес пользователя или комнаты в Matrix, например: matrix:u/user:example.org и matrix:r/root:example.org. NeoChat попытается открыть указанную комнату или беседу. </para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="bug">
<title
>Отчёты об ошибках</title>
<para
>Сообщать об ошибках и отправлять предложения по улучшению можно по адресу <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&amp;component=General"
>https://bugs.kde.org/enter_bug.cgi?product=NeoChat&amp;component=General</ulink
></para>
</refsect1>
<refsect1>
<title
>Смотрите также</title>
<simplelist>
<member
>Список наиболее часто задаваемых вопросов о Matrix <ulink url="https://matrix.org/faq/"
>https://matrix.org/faq/</ulink
> </member>
<member
>kf5options(7)</member>
<member
>qt5options(7)</member>
</simplelist>
</refsect1>
<refsect1 id="copyright"
><title
>Авторские права</title>
<para
>Авторские права &copy; Tobias Fella, 20202022 </para>
<para
>Авторские права &copy; Carl Schwan, 20202022 </para>
<para
>Лицензия: стандартная общественная лицензия GNU версии 3 или любой более поздней версии &lt;<ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
>&gt;</para>
</refsect1>
</refentry>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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

@@ -48,6 +48,8 @@ if(ANDROID OR WIN32)
set_source_files_properties(qml/GlobalMenuStub.qml PROPERTIES
QT_QML_SOURCE_TYPENAME GlobalMenu
)
else()
set(EXTRA_IMPORTS org.kde.purpose)
endif()
ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
@@ -101,9 +103,11 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
qml/ReasonDialog.qml
qml/NewPollDialog.qml
qml/UserMenu.qml
qml/MeetingDialog.qml
DEPENDENCIES
QtCore
QtQuick
io.github.quotient_im.libquotient
IMPORTS
org.kde.neochat.libneochat
org.kde.neochat.rooms
@@ -115,13 +119,15 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
org.kde.neochat.devtools
org.kde.neochat.login
org.kde.neochat.chatbar
org.kde.config
org.kde.syntaxhighlighting
${EXTRA_IMPORTS}
)
if(NOT ANDROID AND NOT WIN32)
qt_target_qml_sources(neochat QML_FILES
qml/ShareAction.qml
qml/GlobalMenu.qml
qml/EditMenu.qml
)
else()
qt_target_qml_sources(neochat QML_FILES
@@ -197,8 +203,9 @@ target_link_libraries(neochat PUBLIC
KF6::ConfigGui
KF6::CoreAddons
KF6::SonnetCore
KF6::IconThemes
KF6::ItemModels
KF6::I18nQml
KirigamiApp
QuotientQt6
Login
Rooms
@@ -206,10 +213,6 @@ target_link_libraries(neochat PUBLIC
Spaces
)
if (TARGET KF6::Crash)
target_link_libraries(neochat PUBLIC KF6::Crash)
endif()
kconfig_target_kcfg_file(neochat FILE neochatconfig.kcfg CLASS_NAME NeoChatConfig MUTATORS GENERATE_PROPERTIES DEFAULT_VALUE_GETTERS PARENT_IN_CONSTRUCTOR SINGLETON GENERATE_MOC QML_REGISTRATION)
if(NEOCHAT_FLATPAK)
@@ -320,6 +323,7 @@ if(ANDROID)
"kt-restore-defaults-symbolic"
"user-symbolic"
"mark-location-symbolic"
"amarok_playcount"
${KIRIGAMI_ADDONS_ICONS}
)
@@ -338,14 +342,7 @@ if(TARGET KF6::DBusAddons AND NOT WIN32)
target_compile_definitions(neochat PUBLIC -DHAVE_KDBUSADDONS)
endif()
if (TARGET KF6::KIOWidgets)
target_compile_definitions(neochat PUBLIC -DHAVE_KIO)
endif()
if (TARGET KUnifiedPush)
target_compile_definitions(neochat PUBLIC -DHAVE_KUNIFIEDPUSH)
target_link_libraries(neochat PUBLIC KUnifiedPush)
if (NOT ANDROID)
configure_file(org.kde.neochat.service.in ${CMAKE_CURRENT_BINARY_DIR}/org.kde.neochat.service)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.neochat.service DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR})
@@ -355,7 +352,8 @@ endif()
install(TARGETS neochat-app ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins)
# krunner plugin must be the same as the app id for flatpak to export it
install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins RENAME org.kde.neochat.desktop)
endif()
if (APPLE)

View File

@@ -5,7 +5,6 @@
#include "controller.h"
#include <Quotient/connection.h>
#include <qt6keychain/keychain.h>
#include <KLocalizedString>
@@ -14,23 +13,19 @@
#include <signal.h>
#include <Quotient/csapi/notifications.h>
#include <Quotient/events/roommemberevent.h>
#include <Quotient/qt_connection_util.h>
#include <Quotient/settings.h>
#include "accountmanager.h"
#include "enums/roomsortparameter.h"
#include "general_logging.h"
#include "mediasizehelper.h"
#include "models/actionsmodel.h"
#include "models/messagemodel.h"
#include "models/pushrulemodel.h"
#include "models/roomlistmodel.h"
#include "models/roomtreemodel.h"
#include "neochatconfig.h"
#include "neochatconnection.h"
#include "neochatroom.h"
#include "notificationsmanager.h"
#include "proxycontroller.h"
#include "roommanager.h"
@@ -40,14 +35,6 @@
#include "trayicon_sni.h"
#endif
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
#ifndef Q_OS_ANDROID
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusMessage>
#endif
#endif
#ifdef HAVE_KUNIFIEDPUSH
#include <kunifiedpush/connector.h>
#endif
@@ -136,8 +123,10 @@ Controller::Controller(QObject *parent)
connect(NeoChatConfig::self(), &NeoChatConfig::SystemTrayChanged, this, &Controller::setQuitOnLastWindowClosed);
#endif
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [this] {
connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [this] {
#ifndef Q_OS_ANDROID
delete m_trayIcon;
#endif
NeoChatConfig::self()->save();
});
@@ -203,13 +192,15 @@ void Controller::setAccountManager(AccountManager *manager)
m_accountManager = manager;
if (m_accountManager) {
connect(m_accountManager, &AccountManager::errorOccured, this, &Controller::errorOccured);
connect(m_accountManager, &AccountManager::accountsLoadingChanged, this, &Controller::accountsLoadingChanged);
connect(m_accountManager, &AccountManager::connectionAdded, this, &Controller::initConnection);
connect(m_accountManager, &AccountManager::connectionDropped, this, &Controller::teardownConnection);
connect(m_accountManager, &AccountManager::activeConnectionChanged, this, &Controller::initActiveConnection);
if (!m_accountManager) {
return;
}
connect(m_accountManager, &AccountManager::errorOccured, this, &Controller::errorOccured);
connect(m_accountManager, &AccountManager::accountsLoadingChanged, this, &Controller::accountsLoadingChanged);
connect(m_accountManager, &AccountManager::connectionAdded, this, &Controller::initConnection);
connect(m_accountManager, &AccountManager::connectionDropped, this, &Controller::teardownConnection);
connect(m_accountManager, &AccountManager::activeConnectionChanged, this, &Controller::initActiveConnection);
}
void Controller::initConnection(NeoChatConnection *connection)
@@ -265,8 +256,8 @@ bool Controller::supportSystemTray() const
#ifdef Q_OS_ANDROID
return false;
#else
auto de = QString::fromLatin1(qgetenv("XDG_CURRENT_DESKTOP"));
return de != u"GNOME"_s && de != u"Pantheon"_s;
QStringList unsupportedPlatforms{u"GNOME"_s, u"Pantheon"_s};
return !unsupportedPlatforms.contains(QString::fromLatin1(qgetenv("XDG_CURRENT_DESKTOP")));
#endif
}
@@ -276,11 +267,8 @@ void Controller::setQuitOnLastWindowClosed()
if (supportSystemTray() && NeoChatConfig::self()->systemTray()) {
m_trayIcon = new TrayIcon(this);
m_trayIcon->show();
} else {
if (m_trayIcon) {
delete m_trayIcon;
m_trayIcon = nullptr;
}
} else if (m_trayIcon) {
delete m_trayIcon;
}
#endif
}
@@ -318,8 +306,7 @@ void Controller::listenForNotifications()
connect(timer, &QTimer::timeout, qGuiApp, &QGuiApplication::quit);
connect(connector, &KUnifiedPush::Connector::messageReceived, [timer](const QByteArray &data) {
instance().m_notificationsManager.postPushNotification(data);
timer->stop();
NotificationsManager::postPushNotification(data);
});
// Wait five seconds to see if we received any messages or this happened to be an erroneous activation.
@@ -337,30 +324,7 @@ void Controller::clearInvitationNotification(const QString &roomId)
void Controller::updateBadgeNotificationCount(int count)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
#ifndef Q_OS_ANDROID
// copied from Telegram desktop
const auto launcherUrl = "application://org.kde.neochat.desktop"_L1;
// Gnome requires that count is a 64bit integer
const qint64 counterSlice = std::min(count, 9999);
QVariantMap dbusUnityProperties;
if (counterSlice > 0) {
dbusUnityProperties["count"_L1] = counterSlice;
dbusUnityProperties["count-visible"_L1] = true;
} else {
dbusUnityProperties["count-visible"_L1] = false;
}
auto signal = QDBusMessage::createSignal("/com/canonical/unity/launcherentry/neochat"_L1, "com.canonical.Unity.LauncherEntry"_L1, "Update"_L1);
signal.setArguments({launcherUrl, dbusUnityProperties});
QDBusConnection::sessionBus().send(signal);
#endif // Q_OS_ANDROID
#else
qGuiApp->setBadgeNumber(count);
#endif // QT_VERSION_CHECK(6, 6, 0)
}
bool Controller::isFlatpak() const
@@ -381,7 +345,10 @@ QString Controller::loadFileContent(const QString &path) const
{
QUrl url(path);
QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString());
file.open(QFile::ReadOnly);
if (!file.open(QFile::ReadOnly)) {
qCWarning(GENERAL) << "Failed to open file" << path;
return {};
}
return QString::fromLatin1(file.readAll());
}

View File

@@ -110,8 +110,9 @@ private:
void initActiveConnection(NeoChatConnection *oldConnection, NeoChatConnection *newConnection);
QPointer<NeoChatConnection> m_connection;
TrayIcon *m_trayIcon = nullptr;
#ifndef Q_OS_ANDROID
QPointer<TrayIcon> m_trayIcon;
#endif
QString m_endpoint;
QStringList m_shownImages;

View File

@@ -33,13 +33,9 @@
#include <KWindowSystem>
#endif
#if __has_include("KCrash")
#include <KCrash>
#endif
#include <KIconTheme>
#include <KLocalizedContext>
#include <KLocalizedQmlContext>
#include <KLocalizedString>
#include <KirigamiApp>
#include "neochat-version.h"
@@ -104,7 +100,6 @@ Q_DECL_EXPORT
#endif
int main(int argc, char *argv[])
{
KIconTheme::initTheme();
QNetworkProxyFactory::setUseSystemConfiguration(true);
#ifdef HAVE_WEBVIEW
@@ -113,24 +108,10 @@ int main(int argc, char *argv[])
QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi);
#endif
#ifdef Q_OS_ANDROID
QGuiApplication app(argc, argv);
QQuickStyle::setStyle(u"org.kde.breeze"_s);
#else
QIcon::setFallbackThemeName("breeze"_L1);
QApplication app(argc, argv);
// Default to org.kde.desktop style unless the user forces another style
if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) {
QQuickStyle::setStyle(u"org.kde.desktop"_s);
}
#endif
KirigamiApp::App app(argc, argv);
KirigamiApp kirigamiApp;
#ifdef Q_OS_WINDOWS
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
}
QApplication::setStyle(u"breeze"_s);
QFont font(u"Segoe UI Emoji"_s);
font.setPointSize(10);
@@ -177,10 +158,6 @@ int main(int argc, char *argv[])
KAboutData::setApplicationData(about);
QGuiApplication::setWindowIcon(QIcon::fromTheme(u"org.kde.neochat"_s));
#if __has_include("KCrash")
KCrash::initialize();
#endif
Connection::setEncryptionDefault(true);
Connection::setDirectChatEncryptionDefault(true);
@@ -205,7 +182,7 @@ int main(int argc, char *argv[])
parser.addOption(testOption);
#ifdef HAVE_KUNIFIEDPUSH
QCommandLineOption dbusActivatedOption(u"dbus-activated"_s, i18n("Internal usage only."));
QCommandLineOption dbusActivatedOption(u"dbus-activated"_s);
dbusActivatedOption.setFlags(QCommandLineOption::Flag::HiddenFromHelp);
parser.addOption(dbusActivatedOption);
#endif
@@ -219,8 +196,14 @@ int main(int argc, char *argv[])
#ifdef HAVE_KUNIFIEDPUSH
if (parser.isSet(dbusActivatedOption)) {
// We want to be replaceable by the main client
KDBusService service(KDBusService::Replace);
#ifdef HAVE_KDBUSADDONS
// We *don't* want to use KDBusService here. I don't know why, but it makes activation super unreliable. We don't really need it anyway.
if (!QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.neochat"))) {
// Gracefully fail if NeoChat is already running
qWarning() << "NeoChat already running, not sending push notifications.";
return 0;
}
#endif
#ifdef HAVE_RUNNER
// If we are built with KRunner and KUnifiedPush support, we need to do something special.
@@ -279,7 +262,7 @@ int main(int argc, char *argv[])
});
#endif
engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
KLocalization::setupLocalizedContext(&engine);
engine.setNetworkAccessManagerFactory(new NetworkAccessManagerFactory());
if (parser.isSet("ignore-ssl-errors"_L1)) {
@@ -294,7 +277,9 @@ int main(int argc, char *argv[])
engine.addImageProvider(u"blurhash"_s, new BlurhashImageProvider);
engine.loadFromModule("org.kde.neochat", "Main");
if (!kirigamiApp.start("org.kde.neochat", "Main", &engine)) {
return -1;
}
if (!parser.positionalArguments().isEmpty() && !parser.isSet("share"_L1)) {
RoomManager::instance().setUrlArgument(parser.positionalArguments()[0]);

View File

@@ -7,7 +7,6 @@
#include <QQmlEngine>
#include "neochatconnection.h"
#include "neochatroom.h"
#include <Quotient/events/roommessageevent.h>
#include <Quotient/roommember.h>
@@ -25,11 +24,7 @@ class CommonRoomsModel : public QAbstractListModel
public:
enum Roles {
TextRole = Qt::DisplayRole,
LongitudeRole,
LatitudeRole,
AssetRole,
AuthorRole,
RoomIdRole = Qt::DisplayRole,
};
Q_ENUM(Roles)

View File

@@ -58,7 +58,7 @@ QVariant NotificationsModel::data(const QModelIndex &index, int role) const
QHash<int, QByteArray> NotificationsModel::roleNames() const
{
return {
{TextRole, "text"},
{TextRole, "notificationText"},
{RoomIdRole, "roomId"},
{AuthorName, "authorName"},
{AuthorAvatar, "authorAvatar"},

View File

@@ -176,7 +176,7 @@ void ServerListModel::initialize()
true,
false,
});
beginResetModel();
endResetModel();
}
#include "moc_serverlistmodel.cpp"

View File

@@ -42,7 +42,6 @@ Name[sv]=NeoChat
Name[ta]=நியோச்சாட்
Name[tr]=NeoChat
Name[uk]=NeoChat
Name[x-test]=xxNeoChatxx
Name[zh_CN]=NeoChat
Name[zh_TW]=NeoChat
DesktopEntry=org.kde.neochat
@@ -87,7 +86,6 @@ Comment[sv]=En klient för matrix, det decentraliserade kommunikationsprotokolle
Comment[ta]=மையமில்லா தகவல் பரிமாற்ற நெறிமுறையான மேட்ரிக்ஸுக்கான செயலி
Comment[tr]=Merkezi olmayan iletişim protokolü Matrix için bir istemci
Comment[uk]=Клієнт matrix, децентралізованого протоколу обміну даними
Comment[x-test]=xxA client for matrix, the decentralized communication protocolxx
Comment[zh_CN]=分布式通讯协议 Matrix 的客户端
Comment[zh_TW]=去中心化通訊協定 Matrix 的用戶端
@@ -134,7 +132,6 @@ Name[sv]=Nytt meddelande
Name[ta]=புதிய செய்தி
Name[tr]=Yeni İleti
Name[uk]=Нове повідомлення
Name[x-test]=xxNew messagexx
Name[zh_CN]=新消息
Name[zh_TW]=新訊息
Comment=There is a new message
@@ -177,7 +174,6 @@ Comment[sv]=Det finns ett nytt meddelande
Comment[ta]=ஒரு புதிய செய்தி உள்ளது
Comment[tr]=Yeni bir ileti var
Comment[uk]=Надійшло нове повідомлення
Comment[x-test]=xxThere is a new messagexx
Comment[zh_CN]=有新消息
Comment[zh_TW]=有新的訊息
Action=Popup
@@ -215,6 +211,7 @@ Name[pa]=ਨਵਾਂ ਸੱਦਾ
Name[pl]=Nowe zaproszenie
Name[pt]=Novo Convite
Name[pt_BR]=Novo convite
Name[ro]=Invitație nouă
Name[ru]=Новое приглашение
Name[sa]=नवीन आमन्त्रणम्
Name[sl]=Novo povabilo
@@ -222,7 +219,6 @@ Name[sv]=Ny inbjudan
Name[ta]=புதிய அழைப்பிதழ்
Name[tr]=Yeni Davet
Name[uk]=Нове запрошення
Name[x-test]=xxNew Invitationxx
Name[zh_CN]=新邀请
Name[zh_TW]=新邀請
Comment=There is a new invitation to a room
@@ -257,14 +253,14 @@ Comment[pa]=ਰੂਮ ਲਈ ਨਵਾਂ ਸੱਦਾ ਹੈ
Comment[pl]=Dostępna jest nowe zaproszenie do pokoju
Comment[pt]=Existe um novo convite para uma sala
Comment[pt_BR]=Existe um novo convite para uma sala
Comment[ro]=E o nouă invitație la o cameră
Comment[ru]=Доступно новое приглашение в комнату
Comment[sa]=कक्षस्य नूतनं निमन्त्रणम् अस्ति
Comment[sl]=Tam je novo povabilo v sobo
Comment[sv]=Det finns en ny inbjudan till ett rum
Comment[ta]=ஓர் அரங்கிற்கான புதிய அழைப்பிதழ் உள்ளது
Comment[tr]=Bir odaya yeni bir davetiye var
Comment[tr]=Bir odaya yeni bir davet var
Comment[uk]=У кімнаті нове запрошення
Comment[x-test]=xxThere is a new invitation to a roomxx
Comment[zh_CN]=有新的聊天室邀请
Comment[zh_TW]=有新的加入聊天室邀請
Action=Popup
@@ -296,6 +292,7 @@ Name[nl]=Gedeelde
Name[nn]=Del
Name[pl]=Udostępnij
Name[pt_BR]=Compartilhar
Name[ro]=Partajare
Name[ru]=Публикация
Name[sa]=संविभागः
Name[sl]=Deli
@@ -303,7 +300,6 @@ Name[sv]=Dela
Name[ta]=பகிர்
Name[tr]=Paylaş
Name[uk]=Оприлюднення
Name[x-test]=xxSharexx
Name[zh_CN]=分享
Name[zh_TW]=分享
Comment=The result of sharing a piece of content
@@ -331,6 +327,7 @@ Comment[nl]=Het resultaat van het delen van een stukje inhoud
Comment[nn]=Resultatet av deling av innhald
Comment[pl]=Wynik udostępniania kawałka treści
Comment[pt_BR]=O resultado de compartilhar um conteúdo
Comment[ro]=Rezultatul partajării unei bucăți de conținut
Comment[ru]=Результат публикации данных
Comment[sa]=सामग्रीखण्डस्य साझाकरणस्य परिणामः
Comment[sl]=Rezultat deljenega kosa vsebine
@@ -338,7 +335,6 @@ Comment[sv]=Resultatet av att dela innehåll
Comment[ta]=எதையோ பகிர்ந்த‍தன் விளைவு
Comment[tr]=Bir parça içerik paylaşımının sonucu
Comment[uk]=Результат оприлюднення даних
Comment[x-test]=xxThe result of sharing a piece of contentxx
Comment[zh_CN]=分享一个内容得到的结果
Comment[zh_TW]=分享一份內容之後的結果
Action=Popup

View File

@@ -66,6 +66,10 @@
</entry>
</group>
<group name="Timeline">
<entry name="FontScale" type="double">
<label>Scaling factor for font sizes</label>
<default>1.0</default>
</entry>
<entry name="ShowAvatarInTimeline" type="bool">
<label>Show avatar in the timeline</label>
<default>true</default>
@@ -189,6 +193,10 @@
<label>Don't hide any events in the timeline</label>
<default>false</default>
</entry>
<entry name="RelateAnyEvent" type="bool">
<label>Send relations to any event, including state events and events normally hidden.</label>
<default>false</default>
</entry>
<entry name="AlwaysVerifyDevice" type="bool">
<label>Always allow device verification</label>
<default>false</default>

View File

@@ -60,9 +60,8 @@ void NotificationsManager::startNotificationJob(QPointer<NeoChatConnection> conn
}
if (!m_connActiveJob.contains(connection->user()->id())) {
auto job = connection->callApi<GetNotificationsJob>();
m_connActiveJob.append(connection->user()->id());
connect(job, &BaseJob::success, this, [this, job, connection]() {
connection->callApi<GetNotificationsJob>().onResult([this, connection](const auto &job) {
m_connActiveJob.removeAll(connection->user()->id());
processNotificationJob(connection, job, !m_oldNotifications.contains(connection->user()->id()));
});
@@ -389,7 +388,7 @@ void NotificationsManager::postPushNotification(const QByteArray &message)
#ifdef HAVE_KIO
auto openAction = notification->addAction(i18n("Open NeoChat"));
connect(openAction, &KNotificationAction::activated, this, [=]() {
connect(openAction, &KNotificationAction::activated, notification, [=]() {
QString properId = roomId;
properId = properId.replace(u"#"_s, QString());
properId = properId.replace(u"!"_s, QString());
@@ -403,8 +402,6 @@ void NotificationsManager::postPushNotification(const QByteArray &message)
connect(notification, &KNotification::closed, qGuiApp, &QGuiApplication::quit);
notification->sendEvent();
m_notifications.insert(roomId, {json["ts"_L1].toVariant().toLongLong(), notification});
} else {
qWarning() << "Skipping unsupported push notification" << type;
}
@@ -433,7 +430,7 @@ QPixmap NotificationsManager::createNotificationImage(const QImage &icon, NeoCha
if (room != nullptr) {
const QImage roomAvatar = room->avatar(imageRect.width(), imageRect.height());
if (icon != roomAvatar) {
if (!roomAvatar.isNull() && icon != roomAvatar) {
const QRect lowerQuarter{imageRect.center(), imageRect.size() / 2};
painter.setBrush(Qt::white);

View File

@@ -53,7 +53,7 @@ public:
/**
* @brief Display a native notification for the given push notification.
*/
void postPushNotification(const QByteArray &message);
static void postPushNotification(const QByteArray &message);
/**
* @brief Handle the notifications for the given connection.

View File

@@ -43,7 +43,6 @@ Name[sv]=NeoChat
Name[ta]=நியோச்சாட்
Name[tr]=NeoChat
Name[uk]=NeoChat
Name[x-test]=xxNeoChatxx
Name[zh_CN]=NeoChat
Name[zh_TW]=NeoChat
Comment=Find rooms in NeoChat
@@ -76,6 +75,7 @@ Comment[nn]=Finn rom i NeoChat
Comment[pl]=Znajdź pokoje w NeoChat
Comment[pt]=Procurar salas no NeoChat
Comment[pt_BR]=Encontrar salas no NeoChat
Comment[ro]=Găsește camere în NeoChat
Comment[ru]=Поиск комнат NeoChat
Comment[sa]=NeoChat इत्यत्र कक्ष्याः अन्वेषणं कुर्वन्तु
Comment[sl]=Najdi sobe v NeoChatu
@@ -83,7 +83,6 @@ Comment[sv]=Sök efter rum i NeoChat
Comment[ta]=நியோச்சாட்டில் அரங்குகளை கண்டுபிடிக்கும்
Comment[tr]=NeoChatte odalar bulun
Comment[uk]=Пошук кімнат у NeoChat
Comment[x-test]=xxFind rooms in NeoChatxx
Comment[zh_CN]=在 NeoChat 查找聊天室
Comment[zh_TW]=在 NeoChat 尋找聊天室
X-KDE-ServiceTypes=Plasma/Runner
@@ -93,4 +92,3 @@ X-Plasma-API=DBus
X-Plasma-DBusRunner-Service=org.kde.neochat
X-Plasma-DBusRunner-Path=/RoomRunner
X-Plasma-Request-Actions-Once=true
X-Plasma-Runner-Min-Letter-Count=3

View File

@@ -1,16 +1,16 @@
// SPDX-FileCopyrightText: 2022 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 ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.components as KirigamiComponents
import org.kde.neochat
import org.kde.neochat.settings
import org.kde.neochat.devtools
KirigamiComponents.ConvergentContextMenu {
id: root
@@ -18,21 +18,17 @@ KirigamiComponents.ConvergentContextMenu {
required property NeoChatConnection connection
required property Kirigami.ApplicationWindow window
QQC2.Action {
Kirigami.Action {
text: i18nc("@action:button", "Show QR Code")
icon.name: "view-barcode-qr-symbolic"
onTriggered: {
let qrMax = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
(Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
text: "https://matrix.to/#/" + root.connection.localUser.id,
title: root.connection.localUser.displayName,
subtitle: root.connection.localUser.id,
// Note: User::avatarUrl does not set user_id, and thus cannot be used directly here. Hence the makeMediaUrl.
avatarSource: root.connection.localUser.avatarUrl.toString().length > 0 ? root.connection.makeMediaUrl(root.connection.localUser.avatarUrl) : ""
});
if (typeof root.closeDialog === "function") {
root.closeDialog();
}
qrMax.open();
}) as QrCodeMaximizeComponent).open();
}
}
@@ -40,26 +36,27 @@ KirigamiComponents.ConvergentContextMenu {
text: i18nc("@action:inmenu", "Switch Account")
icon.name: "system-switch-user"
shortcut: "Ctrl+U"
onTriggered: accountSwitchDialog.createObject(QQC2.Overlay.overlay, {
onTriggered: (Qt.createComponent("org.kde.neochat", "AccountSwitchDialog").createObject(QQC2.Overlay.overlay, {
connection: root.connection
}).open();
}) as Kirigami.Dialog).open();
}
QQC2.Action {
text: i18n("Edit This Account")
Kirigami.Action {
text: i18nc("@action:inmenu", "Edit This Account")
icon.name: "document-edit"
onTriggered: NeoChatSettingsView.openWithInitialProperties("accounts", {initialAccount: root.connection});
}
QQC2.Action {
text: i18n("Notification Settings")
Kirigami.Action {
text: i18nc("@action:inmenu", "Notification Settings")
icon.name: "notifications"
onTriggered: {
NeoChatSettingsView.open('notifications');
}
}
QQC2.Action {
text: i18n("Devices")
Kirigami.Action {
text: i18nc("@action:inmenu", "Devices")
icon.name: "computer-symbolic"
onTriggered: {
NeoChatSettingsView.open('devices');
@@ -67,10 +64,10 @@ KirigamiComponents.ConvergentContextMenu {
}
Kirigami.Action {
text: i18n("Open Developer Tools")
text: i18nc("@action:inmenu", "Open Developer Tools")
icon.name: "tools"
visible: NeoChatConfig.developerTools
onTriggered: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'DevtoolsPage'), {
onTriggered: root.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'DevtoolsPage'), {
connection: root.connection
}, {
title: i18nc("@title:window", "Developer Tools"),
@@ -88,9 +85,10 @@ KirigamiComponents.ConvergentContextMenu {
})
}
QQC2.Action {
Kirigami.Action {
text: i18nc("@action:inmenu", "Verify This Device")
icon.name: "security-low"
visible: !root.connection.isVerifiedSession
onTriggered: {
root.connection.startSelfVerification();
const dialog = Qt.createComponent("org.kde.kirigami", "PromptDialog").createObject(QQC2.Overlay.overlay, {
@@ -99,19 +97,17 @@ KirigamiComponents.ConvergentContextMenu {
standardButtons: Kirigami.Dialog.Ok
})
dialog.open();
root.connection.onNewKeyVerificationSession.connect(() => {
root.connection.newKeyVerificationSession.connect(() => {
dialog.close();
});
}
}
QQC2.Action {
text: i18n("Logout")
Kirigami.Action {
text: i18nc("@action:inmenu", "Logout")
icon.name: "im-kick-user"
onTriggered: confirmLogoutDialogComponent.createObject(root).open()
}
readonly property Component confirmLogoutDialogComponent: ConfirmLogoutDialog {
connection: root.connection
onTriggered: (Qt.createComponent("org.kde.neochat", "ConfirmLogoutDialog").createObject(QQC2.Overlay.overlay, {
connection: root.connection
}) as Kirigami.Dialog).open()
}
}

View File

@@ -1,7 +1,10 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
@@ -16,8 +19,6 @@ Kirigami.Dialog {
required property NeoChatConnection connection
parent: applicationWindow().overlay
leftPadding: 0
rightPadding: 0
topPadding: 0
@@ -25,7 +26,7 @@ Kirigami.Dialog {
standardButtons: Kirigami.Dialog.NoButton
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24)
title: i18nc("@title: dialog to switch between logged in accounts", "Switch Account")
onVisibleChanged: if (visible) {
@@ -53,14 +54,14 @@ Kirigami.Dialog {
}
text: i18nc("@button: login to or register a new account.", "Add Account")
contentItem: Delegates.SubtitleContentItem {
itemDelegate: parent
subtitle: i18n("Log in or create a new account")
itemDelegate: addDelegate
subtitle: i18nc("@info", "Log in or create a new account")
labelItem.textFormat: Text.PlainText
subtitleItem.textFormat: Text.PlainText
}
onClicked: {
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.login', 'WelcomePage'), {}, {
((root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat.login', 'WelcomePage'), {}, {
title: i18nc("@title:window", "Login")
});
root.close();
@@ -94,8 +95,8 @@ Kirigami.Dialog {
accountView.decrementCurrentIndex();
}
}
Keys.onEnterPressed: accountView.currentItem.clicked()
Keys.onReturnPressed: accountView.currentItem.clicked()
Keys.onEnterPressed: ((accountView.currentItem ?? accountView.footerItem) as Delegates.RoundedItemDelegate).clicked()
Keys.onReturnPressed: ((accountView.currentItem ?? accountView.footerItem) as Delegates.RoundedItemDelegate).clicked()
onVisibleChanged: {
for (let i = 0; i < accountView.count; i++) {

View File

@@ -6,8 +6,6 @@ import QtQuick.Controls as QQC2
import org.kde.kirigami as Kirigami
import org.kde.neochat
Kirigami.Dialog {
id: root
@@ -20,7 +18,7 @@ Kirigami.Dialog {
title: i18nc("@title:dialog", "Start a chat")
contentItem: QQC2.Label {
text: i18n("Do you want to start a chat with %1?", root.user.displayName)
text: i18nc("@info", "Do you want to start a chat with %1?", root.user.displayName)
textFormat: Text.PlainText
wrapMode: Text.Wrap
horizontalAlignment: Qt.AlignHCenter

View File

@@ -33,7 +33,7 @@ ColumnLayout {
}
QQC2.ToolButton {
id: editImageButton
visible: hasImage
visible: root.hasImage
icon.name: "document-edit"
text: i18n("Edit")
display: QQC2.AbstractButton.IconOnly
@@ -46,9 +46,9 @@ ColumnLayout {
}
onClicked: {
let imageEditor = applicationWindow().pageStack.pushDialogLayer(imageEditorPage);
let imageEditor = (Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(imageEditorPage);
imageEditor.newPathChanged.connect(function (newPath) {
applicationWindow().pageStack.layers.pop();
imageEditor.closeDialog();
root.attachmentPath = newPath;
});
}
@@ -58,14 +58,18 @@ ColumnLayout {
QQC2.ToolButton {
id: cancelAttachmentButton
display: QQC2.AbstractButton.IconOnly
action: Kirigami.Action {
text: i18n("Cancel sending attachment")
icon.name: "dialog-close"
onTriggered: attachmentCancelled()
shortcut: "Escape"
}
text: i18nc("@action:button", "Cancel sending attachment")
icon.name: "dialog-close"
onClicked: root.attachmentCancelled()
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
Kirigami.Action {
shortcut: "Escape"
onTriggered: cancelAttachmentButton.clicked()
}
}
}
@@ -75,8 +79,8 @@ ColumnLayout {
asynchronous: true
cache: false // Cache is not needed. Images will rarely be shown repeatedly.
source: hasImage ? root.attachmentPath : ""
visible: hasImage
source: root.hasImage ? root.attachmentPath : ""
visible: root.hasImage
fillMode: Image.PreserveAspectFit
onSourceChanged: {
@@ -114,11 +118,11 @@ ColumnLayout {
id: mimetypeIcon
implicitWidth: Kirigami.Units.iconSizes.smallMedium
implicitHeight: Kirigami.Units.iconSizes.smallMedium
source: attachmentMimetype.iconName
source: root.attachmentMimetype.iconName
}
QQC2.Label {
id: fileLabel
text: baseFileName
text: root.baseFileName
}
}
}

View File

@@ -3,12 +3,9 @@
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2
import QtQuick.Templates as T
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.delegates as Delegates
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
Delegates.RoundedItemDelegate {
id: root

View File

@@ -48,7 +48,7 @@ Components.AbstractMaximizeComponent {
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
name: root.author.name ?? root.author.displayName
name: root.author.displayName
source: root.author.avatarUrl
color: root.author.color
}
@@ -57,7 +57,7 @@ Components.AbstractMaximizeComponent {
QQC2.Label {
id: userLabel
text: root.author.name ?? root.author.displayName
text: root.author.displayName
color: root.author.color
font.weight: Font.Bold
elide: Text.ElideRight
@@ -91,6 +91,7 @@ Components.AbstractMaximizeComponent {
color: Kirigami.Theme.textColor
font.family: "monospace"
font.pointSize: Kirigami.Theme.defaultFont.pointSize * NeoChatConfig.fontScale
Kirigami.SpellCheck.enabled: false

View File

@@ -8,7 +8,6 @@ import QtQml.Models
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
import org.kde.kitemmodels
import org.kde.neochat

View File

@@ -1,86 +0,0 @@
// SPDX-FileCopyrightText: 2021 Carson Black <uhhadd@gmail.com>
// SPDX-License-Identifier: LGPL-2.0-or-later
import Qt.labs.platform as Labs
import QtQuick
import QtQuick.Layouts
Labs.Menu {
id: root
required property Item field
Labs.MenuItem {
enabled: root.field !== null && root.field.canUndo
text: i18nc("text editing menu action", "Undo")
shortcut: StandardKey.Undo
onTriggered: {
root.field.undo();
root.close();
}
}
Labs.MenuItem {
enabled: root.field !== null && root.field.canRedo
text: i18nc("text editing menu action", "Redo")
shortcut: StandardKey.Redo
onTriggered: {
root.field.undo();
root.close();
}
}
Labs.MenuSeparator {}
Labs.MenuItem {
enabled: root.field !== null && root.field.selectedText
text: i18nc("text editing menu action", "Cut")
shortcut: StandardKey.Cut
onTriggered: {
root.field.cut();
root.close();
}
}
Labs.MenuItem {
enabled: root.field !== null && root.field.selectedText
text: i18nc("text editing menu action", "Copy")
shortcut: StandardKey.Copy
onTriggered: {
root.field.copy();
root.close();
}
}
Labs.MenuItem {
enabled: root.field !== null && root.field.canPaste
text: i18nc("text editing menu action", "Paste")
shortcut: StandardKey.Paste
onTriggered: {
root.field.paste();
root.close();
}
}
Labs.MenuItem {
enabled: root.field !== null && root.field.selectedText !== ""
text: i18nc("text editing menu action", "Delete")
shortcut: ""
onTriggered: {
root.field.remove(root.field.selectionStart, root.field.selectionEnd);
root.close();
}
}
Labs.MenuSeparator {}
Labs.MenuItem {
enabled: root.field !== null
text: i18nc("text editing menu action", "Select All")
shortcut: StandardKey.SelectAll
onTriggered: {
root.field.selectAll();
root.close();
}
}
}

View File

@@ -6,16 +6,15 @@ import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.neochat
ColumnLayout {
id: root
property alias emoji: emojiLabel.text
property alias description: descriptionLabel.text
required property string emoji
required property string description
QQC2.Label {
id: emojiLabel
text: root.emoji
Layout.fillWidth: true
Layout.preferredWidth: Kirigami.Units.iconSizes.huge
Layout.preferredHeight: Kirigami.Units.iconSizes.huge
@@ -25,7 +24,7 @@ ColumnLayout {
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 4
}
QQC2.Label {
id: descriptionLabel
text: root.description
Layout.fillWidth: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter

View File

@@ -17,9 +17,6 @@ RowLayout {
Repeater {
id: repeater
delegate: EmojiItem {
emoji: modelData.emoji
description: modelData.description
}
delegate: EmojiItem {}
}
}

View File

@@ -17,7 +17,7 @@ ApplicationWindow {
property real longitude: NaN
property string asset
property var author
property QtObject liveLocationModel: null
property LiveLocationsModel liveLocationModel: null
flags: Qt.FramelessWindowHint | Qt.WA_TranslucentBackground
visibility: Qt.WindowFullScreen
@@ -59,7 +59,7 @@ ApplicationWindow {
Connections {
target: mapView.map
function onCopyrightLinkActivated() {
function onCopyrightLinkActivated(link: string) {
Qt.openUrlExternally(link);
}
}

View File

@@ -5,7 +5,6 @@ import Qt.labs.platform as Labs
import QtQuick
import QtQuick.Window
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
@@ -16,12 +15,50 @@ Labs.MenuBar {
id: root
required property NeoChatConnection connection
required property Kirigami.ApplicationWindow appWindow
Labs.Menu {
title: i18nc("menu", "NeoChat")
title: i18nc("menu", "File")
Labs.MenuItem {
enabled: pageStack.layers.currentItem.title !== i18n("Configure NeoChat…")
icon.name: "list-add-user"
text: i18nc("@action:inmenu", "Find User")
enabled: root.connection
onTriggered: root.appWindow.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'UserSearchPage'), {
connection: root.connection
}, {
title: i18nc("@title", "Find User")
})
}
Labs.MenuItem {
icon.name: "system-users-symbolic"
text: i18nc("@action:inmenu", "Create a Room…")
enabled: root.connection
shortcut: StandardKey.New
onTriggered: {
Qt.createComponent('org.kde.neochat', 'CreateRoomDialog').createObject(root.appWindow, {
connection: root.connection
}, {
title: i18nc("@title", "Create a Room")
}).open();
}
}
Labs.MenuItem {
icon.name: "compass-symbolic"
text: i18nc("@action:inmenu", "Explore Rooms")
enabled: root.connection
onTriggered: {
let dialog = root.appWindow.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
connection: root.connection
}, {
title: i18nc("@title", "Explore Rooms")
});
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
RoomManager.resolveResource(roomId.length > 0 ? roomId : alias, isJoined ? "" : "join");
});
}
}
Labs.MenuItem {
text: i18nc("menu", "Configure NeoChat…")
shortcut: StandardKey.Preferences
@@ -34,58 +71,15 @@ Labs.MenuBar {
onTriggered: Qt.quit()
}
}
Labs.Menu {
title: i18nc("menu", "File")
Labs.MenuItem {
icon.name: "list-add-user"
text: i18nc("@action:inmenu", "Find your Friends")
enabled: pageStack.layers.currentItem.title !== i18n("Find your friends") && AccountRegistry.accountCount > 0
onTriggered: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'UserSearchPage'), {
connection: root.connection
}, {
title: i18nc("@title", "Find your friends")
})
}
Labs.MenuItem {
icon.name: "system-users-symbolic"
text: i18nc("@action:inmenu", "Create a Room…")
enabled: pageStack.layers.currentItem.title !== i18n("Find your friends") && AccountRegistry.accountCount > 0
shortcut: StandardKey.New
onTriggered: {
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'CreateRoomDialog'), {
connection: root.connection
}, {
title: i18nc("@title", "Create a Room")
});
}
}
Labs.MenuItem {
icon.name: "compass-symbolic"
text: i18nc("@action:inmenu", "Explore Rooms")
onTriggered: {
let dialog = pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
connection: root.connection
}, {
title: i18nc("@title", "Explore Rooms")
});
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
RoomManager.resolveResource(roomId.length > 0 ? roomId : alias, isJoined ? "" : "join");
});
}
}
}
EditMenu {
title: i18nc("menu", "Edit")
field: (root.activeFocusItem instanceof TextEdit || root.activeFocusItem instanceof TextInput) ? root.activeFocusItem : null
}
Labs.Menu {
title: i18nc("menu", "View")
Labs.MenuItem {
icon.name: "search-symbolic"
enabled: root.connection
text: i18nc("@action:inmenu opens a UI element called the 'Quick Switcher', which offers a fast keyboard-based interface for switching in between chats.", "Search Rooms")
onTriggered: quickSwitcher.open()
onTriggered: (root.appWindow as Main).quickSwitcher.open()
}
}
Labs.Menu {
@@ -93,8 +87,8 @@ Labs.MenuBar {
Labs.MenuItem {
icon.name: "view-fullscreen-symbolic"
text: root.visibility === Window.FullScreen ? i18nc("menu", "Exit Full Screen") : i18nc("menu", "Enter Full Screen")
onTriggered: root.visibility === Window.FullScreen ? root.showNormal() : root.showFullScreen()
text: root.appWindow.visibility === Window.FullScreen ? i18nc("menu", "Exit Full Screen") : i18nc("menu", "Enter Full Screen")
onTriggered: root.appWindow.visibility === Window.FullScreen ? root.appWindow.showNormal() : root.appWindow.showFullScreen()
}
}
Labs.Menu {
@@ -103,12 +97,12 @@ Labs.MenuBar {
Labs.MenuItem {
icon.name: "help-about-symbolic"
text: i18nc("menu", "About NeoChat")
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutPage"))
onTriggered: root.appWindow.pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutPage"))
}
Labs.MenuItem {
icon.name: "kde-symbolic"
text: i18nc("menu", "About KDE")
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutKDEPage"))
onTriggered: root.appWindow.pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutKDEPage"))
}
}
}

View File

@@ -3,8 +3,10 @@
import QtQuick
import org.kde.kirigami as Kirigami
import org.kde.neochat
Item {
required property NeoChatConnection connection
required property Kirigami.ApplicationWindow appWindow
}

View File

@@ -3,29 +3,54 @@
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2
import org.kde.kirigami as Kirigami
QQC2.Control {
RowLayout {
id: root
property string text
visible: !root.text.startsWith("https://matrix.to/") && root.text.length > 0
Kirigami.Theme.colorSet: Kirigami.Theme.View
z: 20
Accessible.ignored: true
contentItem: QQC2.Label {
text: root.text.startsWith("https://matrix.to/") ? "" : root.text
elide: Text.ElideRight
Accessible.description: i18nc("@info screenreader", "The currently selected link")
onTextChanged: {
// This is done so the text doesn't disappear for a split second while in the opacity transition
if (root.text.length > 0) {
urlLabel.text = root.text
}
}
background: Rectangle {
color: Kirigami.Theme.backgroundColor
z: 99
spacing: 0
opacity: (!root.text.startsWith("https://matrix.to/") && root.text.length > 0) ? 1 : 0
visible: opacity > 0
Behavior on opacity {
OpacityAnimator {
duration: Kirigami.Units.shortDuration
easing.type: Easing.InOutQuad
}
}
QQC2.Control {
Kirigami.Theme.colorSet: Kirigami.Theme.View
Accessible.ignored: true
contentItem: QQC2.Label {
id: urlLabel
elide: Text.ElideRight
}
background: Kirigami.ShadowedRectangle {
corners.topRightRadius: Kirigami.Units.cornerRadius
color: Kirigami.Theme.backgroundColor
border {
color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, Kirigami.Theme.frameContrast)
width: 1
}
}
}
}

View File

@@ -2,6 +2,8 @@
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-2.0-or-later
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
@@ -52,6 +54,15 @@ ColumnLayout {
Layout.alignment: Qt.AlignHCenter
}
Kirigami.SelectableLabel {
Layout.fillWidth: true
font: Kirigami.Theme.smallFont
textFormat: TextEdit.PlainText
visible: root.currentRoom && root.currentRoom.canonicalAlias
text: root.currentRoom && root.currentRoom.canonicalAlias ? root.currentRoom.canonicalAlias : ""
color: Kirigami.Theme.disabledTextColor
}
Kirigami.Heading {
text: root.currentRoom.displayName
@@ -70,7 +81,14 @@ ColumnLayout {
spacing: Kirigami.Units.smallSpacing
Kirigami.Heading {
text: root.currentRoom.displayName
text: root.invitingMember.displayName
Layout.alignment: Qt.AlignHCenter
}
QQC2.Label {
text: root.invitingMember.id
color: Kirigami.Theme.disabledTextColor
Layout.alignment: Qt.AlignHCenter
}
@@ -159,7 +177,7 @@ ColumnLayout {
QQC2.Label {
color: Kirigami.Theme.disabledTextColor
text: i18nc("@info:label", "You can reject invitations from unknown users under Security settings.")
text: xi18nc("@info:label Ensure you are referring to the same translation used for that settings page", "You can reject invitations from unknown users under the <interface>Security & Safety</interface> settings.")
wrapMode: Text.WordWrap
// + 5 to prevent it from wrapping unnecessarily

View File

@@ -8,7 +8,6 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.components as KirigamiComponents
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.prison
import org.kde.neochat
@@ -25,7 +24,7 @@ Kirigami.Dialog {
standardButtons: Kirigami.Dialog.NoButton
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24)
title: i18nc("@title:dialog", "Join Room")
contentItem: ColumnLayout {
@@ -67,7 +66,7 @@ Kirigami.Dialog {
text: i18nc("@action:button", "Join room")
icon.name: "irc-join-channel"
onClicked: {
RoomManager.resolveResource(root.room, "join");
RoomManager.resolveResource(root.room, "join_confirmed");
root.close();
}
}

View File

@@ -4,6 +4,7 @@
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import QtQuick.Window
import QtQml
import org.kde.kirigami as Kirigami
@@ -50,6 +51,22 @@ Kirigami.Page {
sourceComponent: message
}
},
State {
name: "waitingForKey"
when: root.session.state === KeyVerificationSession.WAITINGFORKEY
PropertyChanges {
target: stateLoader
sourceComponent: message
}
},
State {
name: "waitingForAccept"
when: root.session.state === KeyVerificationSession.WAITINGFORACCEPT
PropertyChanges {
target: stateLoader
sourceComponent: message
}
},
State {
name: "waitingForMac"
when: root.session.state === KeyVerificationSession.WAITINGFORMAC
@@ -127,7 +144,9 @@ Kirigami.Page {
case KeyVerificationSession.WAITINGFORREADY:
case KeyVerificationSession.INCOMING:
case KeyVerificationSession.WAITINGFORMAC:
return "security-medium-symbolic";
case KeyVerificationSession.WAITINGFORKEY:
case KeyVerificationSession.WAITINGFORACCEPT:
return "security-medium-symbolic";
case KeyVerificationSession.DONE:
return "security-high";
default:
@@ -141,13 +160,19 @@ Kirigami.Page {
case KeyVerificationSession.INCOMING:
return i18n("Incoming key verification request from device **%1**", root.session.remoteDeviceId);
case KeyVerificationSession.WAITINGFORMAC:
return i18n("Waiting for other party to send us keys.");
case KeyVerificationSession.WAITINGFORKEY:
return i18n("Waiting for other party to confirm our keys.");
case KeyVerificationSession.WAITINGFORACCEPT:
return i18n("Waiting for other party to verify.");
case KeyVerificationSession.DONE:
return i18n("Successfully verified device **%1**", root.session.remoteDeviceId)
return i18n("Successfully verified device **%1**", root.session.remoteDeviceId);
default:
return "";
}
}
isDone: root.session.state === KeyVerificationSession.DONE
onDone: root.closeDialog()
}
}

View File

@@ -3,7 +3,6 @@
// SPDX-License-Identifier: GPL-3.0-only
import QtQuick
import QtQuick.Controls as QQC2
import org.kde.kirigami as Kirigami
import org.kde.config as KConfig
@@ -20,6 +19,11 @@ Kirigami.ApplicationWindow {
property bool initialized: false
readonly property QuickSwitcher quickSwitcher: QuickSwitcher {
connection: root.connection
window: root
}
title: {
if (NeoChatConfig.windowTitleFocus) {
return activeFocusItem + " " + (activeFocusItem ? activeFocusItem.Accessible.name : "");
@@ -83,6 +87,7 @@ Kirigami.ApplicationWindow {
active: Kirigami.Settings.hasPlatformMenuBar && !Kirigami.Settings.isMobile
sourceComponent: GlobalMenu {
connection: root.connection
appWindow: root
}
}
@@ -90,19 +95,13 @@ Kirigami.ApplicationWindow {
configGroupName: "MainWindow"
}
QuickSwitcher {
id: quickSwitcher
connection: root.connection
}
Connections {
target: RoomManager
function onCurrentRoomChanged() {
if (RoomManager.currentRoom && pageStack.depth <= 1 && root.initialized && Kirigami.Settings.isMobile) {
let roomPage = pageStack.layers.push(Qt.createComponent('org.kde.neochat', 'RoomPage'), {
connection: root.connection
});
if (RoomManager.currentRoom && root.pageStack.depth <= 1 && root.initialized && Kirigami.Settings.isMobile) {
let roomPage = pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomPage'));
roomPage.forceActiveFocus();
roomPage.backRequested.connect(event => {
RoomManager.clearCurrentRoom();
});
@@ -110,33 +109,26 @@ Kirigami.ApplicationWindow {
}
function onAskJoinRoom(room) {
Qt.createComponent("org.kde.neochat", "JoinRoomDialog").createObject(root, {
(Qt.createComponent("org.kde.neochat", "JoinRoomDialog").createObject(root, {
room: room,
connection: root.connection
}).open();
}) as JoinRoomDialog).open();
}
function onShowUserDetail(user, room) {
root.showUserDetail(user, room);
}
function goToEvent(event) {
if (event.length > 0) {
roomItem.goToEvent(event);
}
roomItem.forceActiveFocus();
}
function onAskDirectChatConfirmation(user) {
Qt.createComponent("org.kde.neochat", "AskDirectChatConfirmation").createObject(this, {
(Qt.createComponent("org.kde.neochat", "AskDirectChatConfirmation").createObject(this, {
user: user
}).open();
}) as AskDirectChatConfirmation).open();
}
function onExternalUrl(url) {
let dialog = Qt.createComponent("org.kde.neochat", "ConfirmUrlDialog").createObject(this);
dialog.link = url;
dialog.open();
(Qt.createComponent("org.kde.neochat", "ConfirmUrlDialog").createObject(this, {
link: url
}) as ConfirmUrlDialog).open();
}
}
@@ -200,7 +192,7 @@ Kirigami.ApplicationWindow {
dim = false;
}
}
enabled: RoomManager.hasOpenRoom && pageStack.layers.depth < 2 && pageStack.depth < 3 && (pageStack.visibleItems.length > 1 || pageStack.currentIndex > 0) && !Kirigami.Settings.isMobile && root.pageStack.wideMode
enabled: RoomManager.hasOpenRoom && root.pageStack.layers.depth < 2 && root.pageStack.depth < 3 && (root.pageStack.visibleItems.length > 1 || root.pageStack.currentIndex > 0) && !Kirigami.Settings.isMobile && root.pageStack.wideMode
handleVisible: enabled
}
@@ -222,10 +214,10 @@ Kirigami.ApplicationWindow {
Connections {
target: NeoChatConfig
function onBlurChanged() {
WindowController.setBlur(pageStack, NeoChatConfig.blur && !NeoChatConfig.compactLayout);
WindowController.setBlur(root.pageStack, NeoChatConfig.blur && !NeoChatConfig.compactLayout);
}
function onCompactLayoutChanged() {
WindowController.setBlur(pageStack, NeoChatConfig.blur && !NeoChatConfig.compactLayout);
WindowController.setBlur(root.pageStack, NeoChatConfig.blur && !NeoChatConfig.compactLayout);
}
}
@@ -242,7 +234,7 @@ Kirigami.ApplicationWindow {
RoomListPage {
id: roomList
onSearch: quickSwitcher.open()
onSearch: root.quickSwitcher.open()
connection: root.connection
@@ -276,12 +268,23 @@ Kirigami.ApplicationWindow {
}
}
Connections {
target: root.connection
function onLoggedOut(): void {
root.pageStack.clear();
let page = root.pageStack.push(Qt.createComponent('org.kde.neochat.login', 'WelcomePage'), {
showExisting: true,
}) as WelcomePage;
page.connectionChosen.connect(() => root.load())
}
}
Connections {
target: AccountRegistry
function onRowsRemoved() {
if (AccountRegistry.rowCount() === 0) {
pageStack.clear();
pageStack.push(Qt.createComponent('org.kde.neochat.login', 'WelcomePage'));
root.pageStack.clear();
root.pageStack.push(Qt.createComponent('org.kde.neochat.login', 'WelcomePage'));
}
}
}
@@ -290,7 +293,7 @@ Kirigami.ApplicationWindow {
target: Controller
function onErrorOccured(error) {
showPassiveNotification(error, "short");
root.showPassiveNotification(error, "short");
}
}
@@ -305,9 +308,9 @@ Kirigami.ApplicationWindow {
});
}
function onUserConsentRequired(url) {
Qt.createComponent("org.kde.neochat", "ConsentDialog").createObject(this, {
(Qt.createComponent("org.kde.neochat", "ConsentDialog").createObject(this, {
url: url
}).open();
}) as ConsentDialog).open();
}
}
@@ -338,7 +341,7 @@ Kirigami.ApplicationWindow {
}
}
function handleShare(): void {
const dialog = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ChooseRoomDialog'), {
const dialog = root.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ChooseRoomDialog'), {
connection: root.connection
}, {
title: i18nc("@title", "Share"),
@@ -355,8 +358,12 @@ Kirigami.ApplicationWindow {
room: room,
user: user,
connection: root.connection,
});
dialog.parent = QmlUtils.focusedWindowItem(); // Kirigami Dialogs overwrite the parent, so we need to set it again
}) as UserDetailDialog;
// FIXME: The reason why we don't want the focusedWindowItem for the room null case (aka QR codes) is because it will parent it to the soon-to-be-destroyed window item.
// But this won't be a problem if we turn it into a Kirigami.Dialog or some other in-scene item, which it really should be.
if (room != null) {
dialog.parent = QmlUtils.focusedWindowItem(); // Kirigami Dialogs overwrite the parent, so we need to set it again
}
dialog.open();
}
@@ -365,9 +372,7 @@ Kirigami.ApplicationWindow {
RoomManager.loadInitialRoom();
if (!Kirigami.Settings.isMobile) {
let roomPage = pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomPage'), {
connection: root.connection
});
let roomPage = pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomPage'));
roomPage.forceActiveFocus();
}

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