Compare commits

...

127 Commits

Author SHA1 Message Date
Heiko Becker
ffbd92317e GIT_SILENT Update Appstream for new release 2023-10-07 18:01:35 +02:00
Heiko Becker
7c9173eb65 GIT_SILENT Upgrade release service version to 23.08.2. 2023-10-07 17:05:08 +02:00
l10n daemon script
c6a5a119e8 GIT_SILENT Sync po/docbooks with svn 2023-10-01 03:38:21 +00:00
l10n daemon script
edf2da1413 GIT_SILENT Sync po/docbooks with svn 2023-09-30 03:10:36 +00:00
l10n daemon script
3cacb10b9c GIT_SILENT Sync po/docbooks with svn 2023-09-26 03:21:35 +00:00
l10n daemon script
ce19275d8d GIT_SILENT Sync po/docbooks with svn 2023-09-20 03:07:35 +00:00
l10n daemon script
1d050c5264 GIT_SILENT Sync po/docbooks with svn 2023-09-19 03:12:29 +00:00
l10n daemon script
5f3ab888d0 GIT_SILENT Sync po/docbooks with svn 2023-09-17 04:02:52 +00:00
l10n daemon script
a7993d7b59 GIT_SILENT Sync po/docbooks with svn 2023-09-15 03:06:42 +00:00
l10n daemon script
eb837d2435 GIT_SILENT Sync po/docbooks with svn 2023-09-13 03:19:15 +00:00
l10n daemon script
c57354f974 GIT_SILENT Sync po/docbooks with svn 2023-09-11 03:12:35 +00:00
l10n daemon script
81a3ab95c5 GIT_SILENT made messages (after extraction) 2023-09-11 02:29:47 +00:00
q234 rty
0408956364 Use shortcode as a fallback for body when sending stickers
(cherry picked from commit 50551541ed)
2023-09-10 12:32:35 +02:00
Antonio Rojas
161412cbcf Add cmake check for qtlocation QML module
So that packagers are notified that it is a dependency

(cherry picked from commit 763198b2c3)
2023-09-10 12:32:32 +02:00
l10n daemon script
fdb02bebf5 GIT_SILENT Sync po/docbooks with svn 2023-09-10 03:04:18 +00:00
l10n daemon script
a756288a07 GIT_SILENT made messages (after extraction) 2023-09-10 02:23:23 +00:00
Ingo Klöcker
4853212326 Add Windows-specific screenshots as screenshots with custom attribute
Instead of using translated custom values (which are not accepted by
AppStream validation) this adds the Windows-specific screenshots as
normal screenshots with custom attribute x-kde-os="windows". AppStream
validation accepts custom attributes (in fact, it ignores any attributes
other than "type").

Upstream appstream tooling will treat those screenshots as any other
extra screenshots (screenshots without type="default").

(cherry picked from commit 6f4d2c0216)
2023-09-09 17:59:04 +02:00
Heiko Becker
3f36cbc2a4 Revert "GIT_SILENT made messages (after extraction)"
And restore the mistakenly removeed appdata file.

This reverts commit fe3933c96a.
2023-09-09 15:54:52 +02:00
Heiko Becker
ac9629258f GIT_SILENT Upgrade release service version to 23.08.1. 2023-09-09 10:23:39 +02:00
l10n daemon script
c085a5815b GIT_SILENT made messages (after extraction) 2023-09-09 02:24:55 +00:00
Luigi Toscano
7a25b151d4 Revert "GIT_SILENT made messages (after extraction)"
Restore a file which was removed by mistake.
Maybe we need to check the new ITS file.
This reverts commit fe3933c96a.
2023-09-08 11:24:29 +02:00
l10n daemon script
fe3933c96a GIT_SILENT made messages (after extraction) 2023-09-08 02:24:52 +00:00
l10n daemon script
3f59d988e7 GIT_SILENT Sync po/docbooks with svn 2023-09-06 03:02:15 +00:00
l10n daemon script
4355afae30 GIT_SILENT Sync po/docbooks with svn 2023-09-04 03:10:19 +00:00
l10n daemon script
99c7d0f5cc GIT_SILENT Sync po/docbooks with svn 2023-09-03 04:04:27 +00:00
l10n daemon script
528ad54136 GIT_SILENT Sync po/docbooks with svn 2023-09-02 03:15:32 +00:00
l10n daemon script
ee18e92d12 GIT_SILENT Sync po/docbooks with svn 2023-09-01 03:05:30 +00:00
l10n daemon script
67c0bf1881 GIT_SILENT Sync po/docbooks with svn 2023-08-31 03:04:57 +00:00
l10n daemon script
4e0c0fc3e4 GIT_SILENT Sync po/docbooks with svn 2023-08-29 03:04:34 +00:00
Tobias Fella
4886f1c3b9 Deselect space when leaving it
BUG: 473271
(cherry picked from commit cc60dde62d)
2023-08-28 11:48:40 +02:00
l10n daemon script
d1efa96b79 GIT_SILENT Sync po/docbooks with svn 2023-08-28 04:04:14 +00:00
Tobias Fella
56d7d1f313 Fix opening settings
BUG: 473789
(cherry picked from commit d11d6c74b3)
2023-08-27 19:17:49 +02:00
Tobias Fella
04682b077a Fix opening report sheet
(cherry picked from commit 68298f038d)
2023-08-27 14:59:43 +02:00
Tobias Fella
ed496e04bb Force plain text user display name in user detail sheet
(cherry picked from commit 5da9bba844)
2023-08-27 14:59:29 +02:00
Tobias Fella
8439768cc3 Fix opening ban sheet
(cherry picked from commit 405fd5841a)
2023-08-27 14:59:19 +02:00
Carl Schwan
33a4d476c6 Add release note for last two version
(cherry picked from commit 550d55cb1a)
2023-08-25 15:23:53 +02:00
Carl Schwan
bb2e2fddcc Remove debuging value
Otherwise like of connectivity never disapear

(cherry picked from commit 1e3c3dd1f4)
2023-08-24 16:11:06 +02:00
l10n daemon script
0d890ce3d6 GIT_SILENT Sync po/docbooks with svn 2023-08-21 03:07:33 +00:00
l10n daemon script
081dd5f1b0 GIT_SILENT made messages (after extraction) 2023-08-21 02:26:15 +00:00
l10n daemon script
79bba63864 GIT_SILENT Sync po/docbooks with svn 2023-08-20 03:05:14 +00:00
l10n daemon script
2b131b58a9 GIT_SILENT Sync po/docbooks with svn 2023-08-17 03:05:43 +00:00
Carl Schwan
97b7047a48 Don't inherit color in TimelineContainer
(cherry picked from commit 3bd93996c0)
2023-08-16 23:45:04 +02:00
Heiko Becker
91b5573016 GIT_SILENT Update Appstream for new release 2023-08-16 23:33:42 +02:00
Heiko Becker
8e9bb8a7e4 GIT_SILENT Upgrade release service version to 23.08.0. 2023-08-16 23:33:39 +02:00
Joshua Goins
916755b4ad Use view-list-details instead of expand icon in room drawer
(cherry picked from commit 24d0082048)
2023-08-16 16:24:13 -04:00
Joshua Goins
9ce288fe47 Destroy the correct component in space list context menu
(cherry picked from commit 2980af11b0)
2023-08-16 16:24:12 -04:00
Joshua Goins
aa461fe078 Prevent the TapHandler in AvatarTabButton from triggering clicked()
This caused right-clicks on this component (for example, in the space
drawer) to cause clicked() to be called on the delegate.

(cherry picked from commit 91d9406c38)
2023-08-16 16:24:12 -04:00
Joshua Goins
15d8c39185 Add icons to the space list context menu items
(cherry picked from commit 280d1e38e2)
2023-08-16 16:24:12 -04:00
Joshua Goins
4a1aa97d7b Prevent the chat bar from pasting a local file URL if we save the bitmap
There's no point in also putting the file:// URL, so catch the event if
saving the bitmap from the clipboard is successful.

(cherry picked from commit 7b520da4b4)
2023-08-16 16:24:12 -04:00
Joshua Goins
e332179ac4 Ensure that the notification avatar is drawn with no pen
(cherry picked from commit 419b4cea98)
2023-08-16 16:22:38 -04:00
Joshua Goins
7534f293c5 Further notification avatar improvements
The correct render hint is actually SmoothPixmapTransform, as
Antialiasing only matters for primitives. Also, render a white
background for potentially transparent avatars.

(cherry picked from commit 38824f30ac)
2023-08-16 16:22:38 -04:00
Joshua Goins
fc60a7c13e Fix the account switcher width so it doesn't spill off the side
(cherry picked from commit 9c4d8ef823)
2023-08-16 16:22:38 -04:00
Joshua Goins
48b8703156 Pick a better shadow and clean up emoji popup backgrounds
These shadows are now closer to how other popups look.

(cherry picked from commit fe3bf3a638)
2023-08-16 16:22:38 -04:00
Joshua Goins
5ca85dc670 Don't clip the emoji popups as they destroy shadows
(cherry picked from commit d678a446e2)
2023-08-16 16:22:38 -04:00
l10n daemon script
bf8ea41e6a GIT_SILENT Sync po/docbooks with svn 2023-08-16 03:06:00 +00:00
l10n daemon script
fda4ae8735 GIT_SILENT Sync po/docbooks with svn 2023-08-15 03:08:17 +00:00
Tobias Fella
aa0e9fff15 Improve tooltips in chatbar
(cherry picked from commit 4ea183b139)
2023-08-14 09:55:08 +02:00
Tobias Fella
28391b53e5 Wrap room display name in Room Drawer
(cherry picked from commit 22fd24549b)
2023-08-14 09:51:34 +02:00
l10n daemon script
a8d7744b42 GIT_SILENT Sync po/docbooks with svn 2023-08-13 03:05:29 +00:00
l10n daemon script
9fcc858841 GIT_SILENT made messages (after extraction) 2023-08-13 02:23:56 +00:00
l10n daemon script
f7092eee69 GIT_SILENT Sync po/docbooks with svn 2023-08-12 03:11:35 +00:00
l10n daemon script
9a426f941a GIT_SILENT Sync po/docbooks with svn 2023-08-11 03:06:07 +00:00
Albert Astals Cid
c77dee09f5 GIT_SILENT Upgrade release service version to 23.07.90. 2023-08-10 21:00:24 +02:00
l10n daemon script
26dde017d0 GIT_SILENT Sync po/docbooks with svn 2023-08-10 03:07:45 +00:00
l10n daemon script
5b27a84bcc GIT_SILENT Sync po/docbooks with svn 2023-08-09 03:12:18 +00:00
Carl Schwan
fc3c36838c Display big emoji correctly
We already check with a regex if the message only contains emoji so it is safe
to hardcode the font family as emoji for these messages.


(cherry picked from commit 58213ee3e6)
2023-08-08 15:00:29 +02:00
l10n daemon script
1fd2072cf8 GIT_SILENT Sync po/docbooks with svn 2023-08-08 03:23:23 +00:00
l10n daemon script
7770d412b3 GIT_SILENT made messages (after extraction) 2023-08-08 02:36:56 +00:00
Tobias Fella
56184920b4 Force plain text in room delegate
(cherry picked from commit 3ab04583ae)
2023-08-07 23:14:58 +02:00
l10n daemon script
b61685b151 GIT_SILENT Sync po/docbooks with svn 2023-08-07 03:49:13 +00:00
l10n daemon script
be0212a686 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"
2023-08-07 03:39:29 +00:00
l10n daemon script
37ed09f957 GIT_SILENT made messages (after extraction) 2023-08-07 03:00:36 +00:00
l10n daemon script
1b7e8ae77a GIT_SILENT Sync po/docbooks with svn 2023-08-06 03:13:44 +00:00
Tobias Fella
7571b0a9a3 Remove leftover debug statement
(cherry picked from commit 88368cefaa)
2023-08-06 00:52:20 +02:00
Tobias Fella
9477e6343f Fix last active time in devices page
(cherry picked from commit ab4bb41979)
2023-08-05 20:34:00 +02:00
l10n daemon script
83241ea956 GIT_SILENT Sync po/docbooks with svn 2023-08-03 04:06:32 +00:00
l10n daemon script
f054467878 GIT_SILENT made messages (after extraction) 2023-08-03 03:11:57 +00:00
l10n daemon script
fb7154b492 GIT_SILENT Sync po/docbooks with svn 2023-08-02 03:20:51 +00:00
l10n daemon script
973a75128c 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"
2023-08-02 03:13:39 +00:00
l10n daemon script
9ea70d7eac GIT_SILENT made messages (after extraction) 2023-08-02 02:35:56 +00:00
l10n daemon script
7f8285037c GIT_SILENT Sync po/docbooks with svn 2023-08-01 03:26:38 +00:00
Carl Schwan
c5f19f12e5 Redesign timeline
Remove border von bubbles and only hilight the bubble on hover

(cherry picked from commit 7f459cb90f)
2023-07-31 21:51:12 +02:00
Carl Schwan
ed6379ff85 Fix opening account menu on right click
(cherry picked from commit 5f41b7b4c1)
2023-07-31 09:03:01 +02:00
l10n daemon script
9750df90e0 GIT_SILENT Sync po/docbooks with svn 2023-07-31 04:06:19 +00:00
l10n daemon script
bd90658668 GIT_SILENT made messages (after extraction) 2023-07-31 03:12:56 +00:00
l10n daemon script
f78b634720 GIT_SILENT Sync po/docbooks with svn 2023-07-30 03:13:52 +00:00
Tobias Fella
250476f77c Html-escape display names in state delegates
(cherry picked from commit 163c1ef407)
2023-07-29 22:31:46 +02:00
Tobias Fella
e293d1f644 Fix room list icon size in compact room list
BUG: 472682
(cherry picked from commit 3bd639775a)
2023-07-29 22:31:14 +02:00
l10n daemon script
cde50588cb GIT_SILENT Sync po/docbooks with svn 2023-07-29 03:09:59 +00:00
l10n daemon script
3972dab7b9 GIT_SILENT made messages (after extraction) 2023-07-29 02:26:29 +00:00
Carl Schwan
7c1b43bcad Fix compilation with e2ee disabled 2023-07-28 13:01:54 +02:00
l10n daemon script
c22c74f735 GIT_SILENT Sync po/docbooks with svn 2023-07-28 03:18:59 +00:00
l10n daemon script
9c42b3c1a7 GIT_SILENT Sync po/docbooks with svn 2023-07-27 03:12:00 +00:00
l10n daemon script
d45cd5d9c9 GIT_SILENT made messages (after extraction) 2023-07-27 02:26:28 +00:00
Joshua Goins
8c503b8258 Use prettier notification images
Avatars are shown rounded in the main interface, so they should look the
same in the notification tray too. On top of that, if the room is a
group then show that group's icon when applicable in the bottom right.


(cherry picked from commit 470418f14f)
2023-07-26 10:31:47 +02:00
Joshua Goins
7078caac15 Fix errors preventing the avatar from being shown when uploaded
(cherry picked from commit 807a9ee779)
2023-07-26 10:29:06 +02:00
Joshua Goins
94bf65ab43 Add an obvious "upload" button in the account editor
It's not obvious at first glance that you can click on the avatar in the
account editor to upload an image. This adds a new button when there is
no image uploaded.


(cherry picked from commit 0ac3932303)
2023-07-26 10:28:32 +02:00
Joshua Goins
244e93c926 Fix settings button tooltip
(cherry picked from commit 4f32a168cd)
2023-07-26 08:38:06 +02:00
l10n daemon script
412856e882 GIT_SILENT Sync po/docbooks with svn 2023-07-26 03:13:49 +00:00
l10n daemon script
2421f11717 GIT_SILENT Sync po/docbooks with svn 2023-07-25 03:20:17 +00:00
l10n daemon script
2d42cfedec GIT_SILENT made messages (after extraction) 2023-07-25 02:30:45 +00:00
l10n daemon script
9308c84696 GIT_SILENT Sync po/docbooks with svn 2023-07-24 11:06:34 +00:00
l10n daemon script
72fc242364 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"
2023-07-24 10:47:48 +00:00
Carl Schwan
7d3240c597 Refactor completion menu
- Use new Avatar
- Use required property in delegate


(cherry picked from commit 75cd77facb)
2023-07-24 10:46:57 +02:00
Carl Schwan
9906ba8b7d Move no connection info message to the top
(cherry picked from commit f8d3e25f8e)
2023-07-24 10:46:35 +02:00
Tobias Fella
b949092bc6 Fix clearing user search field text when switching rooms
(cherry picked from commit 9ba6b2f0a5)
2023-07-24 10:46:16 +02:00
Tobias Fella
5cce3bd692 Fix nullptr check 2023-07-23 23:12:01 +02:00
Carl Schwan
ef5d67e5bf Add back some spacing around the avatar in the timeline
(cherry picked from commit b486cb905c)
2023-07-22 22:32:28 +02:00
Carl Schwan
4711b954c5 Fix accessibility of StartChatPage and port to new components
(cherry picked from commit cdd5c9f484)
2023-07-22 22:32:27 +02:00
Carl Schwan
1688b00f48 Port Avatar usage in Settings KirigamiAddons
(cherry picked from commit 3e6c426397)
2023-07-22 22:32:27 +02:00
Carl Schwan
410befa4bf Port most Avatar usage to new KirigamiAddons Avatar
(cherry picked from commit 847f41e1ad)
2023-07-22 22:32:27 +02:00
Carl Schwan
b380c74b0e Remove hover effect on timeline events 2023-07-22 22:32:20 +02:00
Carl Schwan
da8227931f Remove duplicated code in QuickSwitcher for RoomDelegate 2023-07-22 22:31:42 +02:00
Carl Schwan
fdc45ec5c8 Redesign room list
Use KirigamiAddons.Delegated.RoundedItemDelegate
2023-07-22 22:31:38 +02:00
Carl Schwan
94dd69ea02 Scroll to top of RoomDrawer on loading of header
(cherry picked from commit c8b4da2b96)
2023-07-22 17:53:06 +00:00
Carl Schwan
80c3253a6e Discard wrong avatar urls
(cherry picked from commit ed5bb270ff)
2023-07-22 17:51:46 +00:00
l10n daemon script
c5f6a6607e GIT_SILENT Sync po/docbooks with svn 2023-07-21 03:39:31 +00:00
l10n daemon script
a10d5cbe75 GIT_SILENT Sync po/docbooks with svn 2023-07-20 03:31:32 +00:00
l10n daemon script
584cad19b1 GIT_SILENT made messages (after extraction) 2023-07-20 02:45:39 +00:00
Carl Schwan
3745414635 Port to KirigamAddons.Banner
(cherry picked from commit 3263a69880)
2023-07-19 22:48:56 +02:00
l10n daemon script
147ce42c04 GIT_SILENT Sync po/docbooks with svn 2023-07-19 05:18:38 +00:00
l10n daemon script
928feeca82 GIT_SILENT made messages (after extraction) 2023-07-18 08:31:37 +00:00
Tobias Fella
fc04af536d Fix opening user mentions
(cherry picked from commit 646c8ba8fe)
2023-07-18 08:06:16 +02:00
Tobias Fella
12b949d6cb Fix image loading in room avatars
(cherry picked from commit 918e805718)
2023-07-18 05:26:04 +00:00
l10n daemon script
6aaaabf159 GIT_SILENT Sync po/docbooks with svn 2023-07-18 04:13:52 +00:00
l10n daemon script
fe45ef85a6 GIT_SILENT made messages (after extraction) 2023-07-18 02:55:30 +00:00
Albert Astals Cid
13e38ed982 GIT_SILENT Upgrade release service version to 23.07.80. 2023-07-17 11:25:34 +02:00
108 changed files with 14490 additions and 13949 deletions

View File

@@ -8,8 +8,8 @@ cmake_minimum_required(VERSION 3.16)
# KDE Applications version, managed by release script.
set(RELEASE_SERVICE_VERSION_MAJOR "23")
set(RELEASE_SERVICE_VERSION_MINOR "07")
set(RELEASE_SERVICE_VERSION_MICRO "70")
set(RELEASE_SERVICE_VERSION_MINOR "08")
set(RELEASE_SERVICE_VERSION_MICRO "2")
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
@@ -141,6 +141,7 @@ set_package_properties(cmark PROPERTIES
ecm_find_qmlmodule(org.kde.kquickimageeditor 1.0)
ecm_find_qmlmodule(org.kde.kitemmodels 1.0)
ecm_find_qmlmodule(org.kde.quickcharts 1.0)
ecm_find_qmlmodule(QtLocation ${QTLOCATION_MODULE_QML_VERSION})
find_package(KQuickImageEditor COMPONENTS)
set_package_properties(KQuickImageEditor PROPERTIES

View File

@@ -60,7 +60,7 @@
<summary xml:lang="eu">Matrix, deszentralizatutako komunikazio protokolorako bezero bat</summary>
<summary xml:lang="fi">Asiakas Matrixille, hajautetulle viestintäyhteyskäytännölle</summary>
<summary xml:lang="fr">Un client pour « Matrix », le protocole décentralisé de communications.</summary>
<summary xml:lang="gl">Un cliente para Matrix, o protocolo de comunicación descentralizada</summary>
<summary xml:lang="gl">Un cliente para Matrix, o protocolo de comunicación descentralizada.</summary>
<summary xml:lang="hu">Kliens a matrixhoz, a decentralizált kommunikációs protokollhoz</summary>
<summary xml:lang="ia">Un cliente per Matrix, le protocollo de communication decentralisate</summary>
<summary xml:lang="id">Klien untuk matrix, protokol komunikasi terdesentralisasi</summary>
@@ -92,17 +92,20 @@ to provide a convergent experience across multiple platforms.</p>
<p xml:lang="en-GB">NeoChat is a client for Matrix, the decentralised communication protocol for instant messaging. It allows you to send text messages, videos and audio files to your family, colleagues and friends. It uses KDE frameworks and most notably Kirigami to provide a convergent experience across multiple platforms.</p>
<p xml:lang="eo">NeoChat estas kliento por Matrix, la malcentra komunikoprotokolo por tuja mesaĝado. Ĝi ebligas al vi sendi tekstmesaĝojn, filmetojn kaj sondosierojn al via familio, kolegoj kaj amikoj. Ĝi uzas KDE-framojn kaj precipe Kirigami por disponigi konverĝan sperton tra pluraj platformoj.</p>
<p xml:lang="es">NeoChat es un cliente para Matrix, el protocolo de comunicaciones descentralizado para mensajería instantánea. Le permite enviar mensajes de texto, vídeos y archivos de sonido a su familia, compañeros de trabajo y amigos. Usa la infraestructura de KDE y, en particular, Kirigami para proporcionar una experiencia convergente en muchas plataformas.</p>
<p xml:lang="eu">NeoChat «Matrix»erako, bat-bateko mezularitzarako komunikazio deszentralizatuko protokolorako, bezero bat da. Zure sendiari, kide eta lagunei testu mezuak, bideo eta audio fitxategiak bidaltzeko aukera ematen dizu. «KDE Frameworks» eta bereziki «Kirigami» erabiltzen ditu plataforma anitzen artean esperientzia konbergente bat eskaintzeko.</p>
<p xml:lang="fi">NeoChat on asiakassovellus Matrixille, hajautetulle pikaviestinyhteyskäytännölle. Sillä voi lähettää teksti-, video- ja ääniviestejä perheelle, tutuille ja ystäville. Se käyttää KDE-kehystä ja erityisesti Kirigamia tuottaakseen mukautuvan monialustaisen käyttökokemuksen.</p>
<p xml:lang="fr">NeoChat est un client pour le protocole Matrix, un protocole décentralisé de communications pour messagerie instantané. Il vous permet d'envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos amis. Il utilise les environnements de développement et plus précisément Kirigami pour fournir une expérience convergente sur plusieurs plate-formes. </p>
<p xml:lang="gl">NeoChat é un cliente para Matrix, o protocolo de comunicación descentralizada para mensaxería instantánea. Podes enviar mensaxes de texto, vídeos e ficheiros de son á túa familia, colegas e amizades. Usas infraestruturas de KDE e principalmente Kirigami para proporcionar unha experiencia de uso converxente para varias plataformas.</p>
<p xml:lang="gl">NeoChat é un cliente para Matrix, o protocolo de comunicación descentralizada para mensaxaría instantánea. Podes enviar mensaxes de texto, vídeos e ficheiros de son á túa familia, colegas e amizades. Usas infraestruturas de KDE e principalmente Kirigami para proporcionar unha experiencia de uso converxente para varias plataformas.</p>
<p xml:lang="ia">NeoChat es un cliente per Matrix, le protocollo de communication decentralisate per messager instantanee. Illo te permitte inviar messager de texto, files de video e audio a tu familia, collegas e amicos usante. Illo usa KDE frameworks e super toto Kirigamii forni un experientia convergente trans platteforme multiple.</p>
<p xml:lang="it">NeoChat è un client per Matrix, il protocollo di comunicazione decentralizzato per la messaggistica istantanea. Ti consente di inviare messaggi di testo, video e file audio a familiari, colleghi e amici. Utilizza i framework KDE e in particolare Kirigami per fornire un'esperienza convergente su più piattaforme.</p>
<p xml:lang="ka">NeoChat არის Matrix კლიენტი. ის საშუალებას გაძლევთ გაგზავნოთ ტექსტური შეტყობინებები, ვიდეოები და აუდიო ფაილები თქვენს ოჯახს, კოლეგებსა და მეგობრებს მატრიქსის პროტოკოლის გამოყენებით.</p>
<p xml:lang="ko">NeoChat은 분산형 인스턴트 메시징 통신 프로토콜인 Matrix 클라이언트입니다. 가족, 동료, 친구에게 텍스트 메시지, 동영상, 오디오 파일을 전송할 수 있습니다. KDE 프레임워크와 Kirigami를 사용하여 다양한 플랫폼에서 일관적인 사용자 경험을 제공합니다.</p>
<p xml:lang="nl">NeoChat is een client voor Matrix, het gedecentraliseerde communicatieprotocol voor instant messages. Het biedt u het verzenden van tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden. Het gebruik KDE frameworks en het meest opmerkelijk Kirigami om een convergente ervaring te leveren op meerdere platforms.</p>
<p xml:lang="nn">NeoChat er ein klient for Matrix, ein protokoll for desentralisert kommunikasjon. Du kan utveksla tekst, lyd og videoar med kollegaar, vennar og familie. Programmet brukar KDE Frameworks og Kirigami for å gje ei brukarflate tilpassa ulike plattformer.</p>
<p xml:lang="pl">NeoChat jest programem do Matriksa, protokołu rozproszonego porozumiewania się w czasie rzeczywistym. Umożliwia wysyłanie wiadomości tekstowych, filmów oraz dźwięku do twojej rodziny, znajomych oraz przyjaciół. Używa szkieletów KDE i głównie Kirigami, aby zapewnić spójne wrażenia na wielu platformach</p>
<p xml:lang="pt">O NeoChat é um cliente do Matrix. O mesmo permite-lhe enviar mensagens de texto, ficheiros de vídeo e áudio para a sua família, colegas e amigos com o protocolo Matrix. Usa as plataformas do KDE, e principalmente o Kirigami, para oferecer uma experiência convergente entre várias plataformas.</p>
<p xml:lang="sl">Neochat je odjemalec za Matrix, decentralizirani komunikacijski protokol za takojšnje sporočanje. Omogoča vam pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek svoji družini, sodelavcem in prijateljem. Uporablja okvire ogrodje KDE frameworks in predvsem Kirigami za zagotavljanje konvergentne izkušnje na več platformah.</p>
<p xml:lang="sv">NeoChat är en klient för Matrix, det decentraliserade kommunikationsprotokollet för direktmeddelanden. Den låter dig skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner. Den använder KDE Ramverk, i synnerhet Kirigami, för att tillhandahålla en konvergent upplevelse på flera plattformar.</p>
<p xml:lang="tr">NeoChat, anlık iletileşme için merkezi olmayan iletişim protokolü olan Matrix için bir istemcidir. Ailenize, iş arkadaşlarınıza ve arkadaşlarınıza metin iletiler, videolar ve ses dosyaları göndermenize olanak tanır. Birden çok platformda yakınsak bir deneyim sağlamak için KDE Frameworks ve en önemlilerinden Kirigami'yi kullanır.</p>
<p xml:lang="uk">NeoChat — клієнт Matrix, децентралізованого протоколу спілкування для миттєвого обміну повідомленнями. За його допомогою ви можете надсилати текстові повідомлення, відео та звукові файли вашій родин, колегами та друзям. У програмі використано бібліотеки KDE, зокрема Kirigami, для надання однорідного середовища на декількох програмних та апаратних платформах.</p>
<p xml:lang="x-test">xxNeoChat is a client for Matrix, the decentralized communication protocol for instant messaging. It allows you to send text messages, videos and audio files to your family, colleagues and friends. It uses KDE frameworks and most notably Kirigami to provide a convergent experience across multiple platforms.xx</p>
@@ -112,17 +115,20 @@ to provide a convergent experience across multiple platforms.</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 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="en-GB">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="es">NeoChat pretende ser una aplicación con todas las funciones para la especificación de Matrix. Como tal, admite todo en la especificación estable actual, con las notables excepciones de VoIP, subprocesos y algunas funciones de cifrado de extremo a extremo. Existen algunas omisiones menos importantes debido al hecho de que la especificación de Matrix está en constante evolución, pero el objetivo sigue siendo brindar compatibilidad final con toda la especificación.</p>
<p xml:lang="eu">«NeoChat»ek «Matrix» zehaztapenaren ezaugarri guztiak eskaintzen dituen aplikazio bat izan nahi du. Beraz, egungo zehaztapen egonkorrean dagoen guztiaren euskarria du, VoIP, hariak eta muturren artean zifratzeko salbuespen nabarmenekin. Badira beste ez-betetze txikiago batzuk, «Matrix»en zehaztapena etengabe eboluzioan dagoelako, baina azken helburua zehaztapen osoaren euskarria ematea izaten jarraitzen du.</p>
<p xml:lang="fi">NeoChat pyrkii olemaan Matrix-määritelmän täysominaisuuksinen sovellus, joten se tukee kaikkea nykyisessä vakaassa määritelmässä muutamaa huomattavaa poikkeusta lukuun ottamatta (VoIP, säikeet ja jotkin piirteet päästä päähän -salauksessa). Joitakin pienempiäkin puutteita on Matrix-määritelmän jatkuvan kehityksen vuoksi, mutta lopputavoitteena on tarjota määritelmän täysi tuki.</p>
<p xml:lang="fr">L'objectif de NeoChat est d'être une application complète pour le protocole Matrix. En tant que tel, tout dans la spécification stable actuelle avec les exceptions notables de VoIP, les processus et certains aspects du chiffrement de bout en bout sont pris en charge. Il y a quelques autres petites omissions en raison du fait que la spécification du protocole Matrix est en constante évolution. Cependant, l'objectif reste de fournir un soutien éventuel pour l'ensemble de la spécification.</p>
<p xml:lang="gl">NeoChat pretende ser unha aplicación completa para a especificación de Matrix. Coas excepcións de VoIP, conversas fiadas e algúns aspectos da cifraxe de extremo a extremo, a versión estábel segue as especificacións. Existen algunhas outras pequenas omisións debido ao feito de que Matrix está en continua evolución pero a intención é implementar a especificación completa.</p>
<p xml:lang="ia">NeoChat aspira a esser un application plenemente eminente per le specification de Matrix. Tal como omne cosas in le specification currentemente stabile con le exceptiones notabile de VOIP, threads e alcun aspectos del cryptation End-to-End es supportate. Il ha ltere pauc omissiones, debite al facto que le specification de Matrix es in evolution constante ma le aspiration remane a fornir supporto eventual per le integre specification.</p>
<p xml:lang="it">NeoChat mira ad essere un'applicazione completa per le specifiche Matrix. Pertanto, sono supportati tutti gli elementi dell'attuale specifica stabile con le notevoli eccezioni di VoIP, conversazioni e alcuni aspetti della cifratura end-to-end. Ci sono alcune altre piccole omissioni dovute al fatto che le specifiche Matrix sono in continua evoluzione, ma l'obiettivo rimane quello di fornire un eventuale supporto per l'intera specifica.</p>
<p xml:lang="ka">NeoChat-ი მიზნად ისახავს Matrix სპეციფიკაციის სრული განხორციელება ჰქონდეს. როგორც ასეთი, ყველაფერი მიმდინარე სპეციფიკაციიდან, VoIP-ის, ძაფებისა და გამჭოლი დაშიფვრის ზოგიერთი ასპექტის გარდა, მხარდაჭერილია. შეძლება ასევე იყოს მცირე ლაფსუსებიც იმის გამო, რომ Matrix-ის სპეციფიკაცია მუდმივად ვითარგდება, მაგრამ ჩვენი მიზანი მისი სრული მხარდაჭერაა.</p>
<p xml:lang="ko">NeoChat은 Matrix 표준을 따르는 프로그램을 목표로 합니다. 현재 안정 버전의 표준에서 제공하는 기능의 대부분을 지원하며, VoIP, 스레드, 일부 종단간 암호화와 같은 기능은 아직 지원하지 않습니다. Matrix 표준은 계속하여 진화 중이기 때문에 일부 기능이 빠져 있을 수도 있지만 장기적으로는 전체 표준을 지원하는 것이 목표입니다.</p>
<p xml:lang="nl">NeoChat richt zich op het volledig bieden van alle mogelijkheden van de Matrix-specificatie. Alles in de huidige stabiele specificatie met merkbare uitzondering van VoIP, gekoppelde discussies en sommige aspecten van eind-tot-eind versleuteling worden ondersteund. Er zijn een paar andere kleinere omissies vanwege het feit dat de Matrix specificatie constant evolueert maar het doel blijft het eventueel bieden van ondersteuning van de gehele specificatie.</p>
<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="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 Şifreleme'nin 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>
@@ -132,17 +138,21 @@ to provide a convergent experience across multiple platforms.</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="en-GB">Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:</p>
<p xml:lang="es">Debido a la naturaleza del desarrollo de la especificación de Matrix, NeoChat también permite numerosas funciones no estables, como:</p>
<p xml:lang="eu">«Matrix» zehaztapenaren garapenaren izaeragatik, «Neo¢hat»ek ezaugarri ezegonkor ugari ere onartzen ditu. Gaur egun hauek:</p>
<p xml:lang="fi">Matrix-määritelmän kehittyessä NeoChat tukee myös monia epävakaita ominaisuuksia. Tällä hetkellä näitä ovat:</p>
<p xml:lang="fr">En raison de la nature du développement des spécifications du protocole Matrix, NeoChat prend également en charge de nombreuses fonctionnalités instables. Actuellement, ce sont :</p>
<p xml:lang="gl">Debido á natureza do desenvolvemento da especificación de Matrix, NeoChat tamén inclúe varias funcionalidades non estábeis:</p>
<p xml:lang="ia">Debite al natura del disveloppamento de specification de Matrix NeoChat tamben supporta numerose characteristicas instabile. Currentemente istes es:</p>
<p xml:lang="it">A causa della natura dello sviluppo delle specifiche Matrix, NeoChat supporta anche numerose funzionalità instabili. Attualmente queste sono:</p>
<p xml:lang="ka">Matrix-ის სპეციფიკაციის განვითარების ბუნების გამო NeoChat-ს ასევე აქვს უამრავი არასტაბილური ფუნქციაც. ახლა ისინია:</p>
<p xml:lang="ko">Matrix 표준 개발의 특징으로 인하여 NeoChat은 일부 실험적인 기능을 지원합니다. 현재 지원하는 기능은 다음과 같습니다.</p>
<p xml:lang="nl">Vanwege de aard van de ontwikkeling van de Matrix specificatie ondersteunt NeoChat ook talloze onstabiele mogelijkheden. Dit zijn nu:</p>
<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="sl">Zaradi narave razvoja specifikacije Matrixa NeoChat podpira tudi številne nestabilne zmožnosti. Trenutno so to:</p>
<p xml:lang="sv">På grund av sättet Matrix-specifikationens utvecklas, stöder NeoChat också ett stor antal instabila funktioner. För närvarande är de:</p>
<p xml:lang="ta">மேட்ரிக்ஸு நெறிமுறை வரையறுக்கப்படும் வித‍த்தின் காரணமாக, பல நிலையற்ற அம்சங்களையும் நியோச்சாட் ஆதரிக்கிறது. தற்போது ஆதரிக்கப்படுபவை:</p>
<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>
@@ -153,16 +163,20 @@ to provide a convergent experience across multiple platforms.</p>
<li xml:lang="ca-valencia">Enquestes - MSC3381</li>
<li xml:lang="en-GB">Polls - MSC3381</li>
<li xml:lang="es">Encuestas - MSC3381</li>
<li xml:lang="eu">Polls - MSC3381</li>
<li xml:lang="fi">Kyselyt MSC3381</li>
<li xml:lang="fr">Sondages - MSC3381</li>
<li xml:lang="gl">Enquisas - MSC3381</li>
<li xml:lang="gl">Enquisas MSC3381</li>
<li xml:lang="ia">Inquestas - MSC3381</li>
<li xml:lang="it">Sondaggi - MSC3381</li>
<li xml:lang="ka">Polls - MSC3381</li>
<li xml:lang="ko">투표 - MSC3381</li>
<li xml:lang="nl">Polls - MSC3381</li>
<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="sl">Polls - MSC3381</li>
<li xml:lang="sv">Polls - MSC3381</li>
<li xml:lang="ta">வாக்கெடுப்புகள் - MSC3381</li>
<li xml:lang="tr">Anketler - MSC3381</li>
<li xml:lang="uk">Опитування - MSC3381</li>
@@ -173,16 +187,20 @@ to provide a convergent experience across multiple platforms.</p>
<li xml:lang="ca-valencia">Paquets d'adhesius - MSC2545</li>
<li xml:lang="en-GB">Sticker Packs - MSC2545</li>
<li xml:lang="es">Paquetes de pegatinas - MSC2545</li>
<li xml:lang="eu">Eranskailu paketeak - MSC2545</li>
<li xml:lang="fi">Tarrapakkaukset MSC2545</li>
<li xml:lang="fr">Paquets d'auto-collants - MSC2545</li>
<li xml:lang="gl">Paquetes de adhesivos - MSC2545</li>
<li xml:lang="gl">Paquetes de adhesivos MSC2545</li>
<li xml:lang="ia">Etiquetta gummate (sticker) -MSC2545</li>
<li xml:lang="it">Pacchetti di adesivi - MSC2545</li>
<li xml:lang="ka">სტიკერების პაკეტები - MSC2545</li>
<li xml:lang="ko">스티커 팩 - MSC2545</li>
<li xml:lang="nl">Sticker Packs - MSC2545</li>
<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="sl">Sticker Packs - MSC2545</li>
<li xml:lang="sv">Sticker Packs - MSC2545</li>
<li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li>
<li xml:lang="tr">Yapışkan Paketleri - MSC2545</li>
<li xml:lang="uk">Пакунки наліпок - MSC2545</li>
@@ -193,16 +211,20 @@ to provide a convergent experience across multiple platforms.</p>
<li xml:lang="ca-valencia">Esdeveniments d'ubicació - MSC3488</li>
<li xml:lang="en-GB">Location Events - MSC3488</li>
<li xml:lang="es">Eventos de ubicación - MSC3488</li>
<li xml:lang="eu">Kokaleku-gertaerak - MSC3488</li>
<li xml:lang="fi">Sijaintitapahtumat MSC3488</li>
<li xml:lang="fr">Événements de lieu - MSC3488</li>
<li xml:lang="gl">Localización de eventos - MSC3488</li>
<li xml:lang="gl">Localización de eventos MSC3488</li>
<li xml:lang="ia">Eventos de Location - MSC3488</li>
<li xml:lang="it">Località eventi - MSC3488</li>
<li xml:lang="ka">მდებარეობის მოვლენები - MSC3488</li>
<li xml:lang="ko">위치 이벤트 - MSC3488</li>
<li xml:lang="nl">Locatie gebeurtenissen - MSC3488</li>
<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="sl">Location Events - MSC3488</li>
<li xml:lang="sv">Location Events - MSC3488</li>
<li xml:lang="ta">இட நிகழ்வுகள் - MSC3488</li>
<li xml:lang="tr">Konum Etkinlikleri - MSC3488</li>
<li xml:lang="uk">Місцеві зустрічі - MSC3488</li>
@@ -261,32 +283,6 @@ to provide a convergent experience across multiple platforms.</p>
<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::windows_store::screenshots::1::image">https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</value>
<value key="KDE::windows_store::screenshots::1::caption">Main view with room list, chat, and room information</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ka">მთავარი ხედი სურათების სიით, ჩატით და ოთახის ინფორმაციით</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="nl">Hoofdweergave met lijst met rooms, chat en roominformatie</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="tr">Oda listesini, sohbet penceresini ve oda bilgisini gösteren ana görünüm</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</value>
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="x-test">xxMain view with room list, chat, and room informationxx</value>
<value key="KDE::windows_store::screenshots::2::image">https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Login.png</value>
<value key="KDE::windows_store::screenshots::2::caption">Login screen</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ca">Pantalla d'inici de sessió</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ca-valencia">Pantalla d'inici de sessió</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="es">Pantalla de inicio de sesión</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="fr">Écran de connexion</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ka">შესვლის ეკრანი</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="nl">Aanmeldscherm</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="pt">Ecrã de autenticação</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="sl">Prijavni zaslon</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="tr">Oturum açma ekranı</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="uk">Вікно входу</value>
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="x-test">xxLogin screenxx</value>
</custom>
<launchable type="desktop-id">org.kde.neochat.desktop</launchable>
<screenshots>
@@ -296,15 +292,80 @@ to provide a convergent experience across multiple platforms.</p>
<screenshot type="default">
<image>https://cdn.kde.org/screenshots/neochat/application.png</image>
</screenshot>
<screenshot x-kde-os="windows">
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</image>
<caption>Main view with room list, chat, and room information</caption>
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
<caption xml:lang="fi">Päänäkymä, jossa huoneluettelo, keskustelu ja huoneen tiedot</caption>
<caption xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</caption>
<caption xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</caption>
<caption xml:lang="ia">Vista principal con lista de sala, chat e information de sala</caption>
<caption xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</caption>
<caption xml:lang="ka">მთავარი ხედი სურათების სიით, ჩატით და ოთახის ინფორმაციით</caption>
<caption xml:lang="ko">대화방 목록, 채팅, 대화방 정보가 표시된 주 보기</caption>
<caption xml:lang="nl">Hoofdweergave met lijst met rooms, chat en roominformatie</caption>
<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="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
<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>
</screenshot>
<screenshot x-kde-os="windows">
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Login.png</image>
<caption>Login screen</caption>
<caption xml:lang="ar">شاشة الدخول</caption>
<caption xml:lang="ca">Pantalla d'inici de sessió</caption>
<caption xml:lang="ca-valencia">Pantalla d'inici de sessió</caption>
<caption xml:lang="es">Pantalla de inicio de sesión</caption>
<caption xml:lang="eu">Saio-hasteko pantaila</caption>
<caption xml:lang="fi">Kirjautumisnäkymä</caption>
<caption xml:lang="fr">Écran de connexion</caption>
<caption xml:lang="gl">Pantalla de identificación.</caption>
<caption xml:lang="ia">Schermo de accesso</caption>
<caption xml:lang="it">Schermata di accesso</caption>
<caption xml:lang="ka">შესვლის ეკრანი</caption>
<caption xml:lang="ko">로그인 화면</caption>
<caption xml:lang="nl">Aanmeldscherm</caption>
<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="sl">Prijavni zaslon</caption>
<caption xml:lang="sv">Inloggningsfönster</caption>
<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>
</screenshot>
</screenshots>
<content_rating type="oars-1.1">
<content_attribute id="social-chat">intense</content_attribute>
</content_rating>
<releases>
<release version="23.08.2" date="2023-10-12"/>
<release version="23.08.0" date="2023-08-24">
<url>https://kde.org/announcements/gear/23.08.0/#neochathttpsappskdeorgneochat</url>
<description>
<p>Apart from a visual overhaul, NeoChat can now display location events and also a map with the location of all the users currently broadcasting their location using Itineray's Matrix integration. Great for locating where your friends are.</p>
</description>
</release>
<release version="23.04.3" date="2023-07-06"/>
<release version="23.04.2" date="2023-06-08"/>
<release version="23.04.1" date="2023-05-11"/>
<release version="23.04.0" date="2023-04-20">
<url>https://kde.org/announcements/gear/23.04.0/#neochathttpsappskdeorgneochat</url>
<description>
<p>NeoChat improves its design with tweaks that provide a more compact layout and a simpler menu which works better for the collapsed room list.</p>
<p>We have also improved the video controls, added a new command /knock &lt;room-id&gt; to send a knock event to a room, and you can now edit a prior message inline, within the chat pane.</p>
<p>Other usability improvements include an overhaul of the keyboard navigation and shortcuts like Ctrl+PgUp/PgDn that allow you to skip from room to room.</p>
</description>
<artifacts>
<artifact type="binary" platform="x86_64-windows-msvc">
<location>https://download.kde.org/stable/release-service/23.04.0/windows/neochat-23.04.0-512-windows-cl-msvc2019-x86_64.exe</location>

View File

@@ -93,7 +93,7 @@ Comment[es]=Cliente para el protocolo Matrix
Comment[eu]=Matrix protokolorako bezeroa
Comment[fi]=Asiakas Matrix-yhteyskäytännölle
Comment[fr]=Client pour le protocole « Matrix »
Comment[gl]=Cliente para o protocolo Matrix
Comment[gl]=Cliente para o protocolo Matrix.
Comment[hu]=Kliens a Matrix protokollhoz
Comment[ia]=Cliente per le protocollo de Matrix
Comment[id]=Klien untuk protokol 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

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -218,8 +218,8 @@ void ChatDocumentHandler::setRoom(NeoChatRoom *room)
void ChatDocumentHandler::complete(int index)
{
if (m_completionModel->autoCompletionType() == CompletionModel::User) {
auto name = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Text).toString();
auto id = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Subtitle).toString();
auto name = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::DisplayNameRole).toString();
auto id = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::SubtitleRole).toString();
auto text = getText();
auto at = text.lastIndexOf(QLatin1Char('@'), cursorPosition() - 1);
QTextCursor cursor(document()->textDocument());
@@ -232,7 +232,7 @@ void ChatDocumentHandler::complete(int index)
pushMention({cursor, name, 0, 0, id});
m_highlighter->rehighlight();
} else if (m_completionModel->autoCompletionType() == CompletionModel::Command) {
auto command = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedText).toString();
auto command = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedTextRole).toString();
auto text = getText();
auto at = text.lastIndexOf(QLatin1Char('/'));
QTextCursor cursor(document()->textDocument());
@@ -240,7 +240,7 @@ void ChatDocumentHandler::complete(int index)
cursor.setPosition(cursorPosition(), QTextCursor::KeepAnchor);
cursor.insertText(QStringLiteral("/%1 ").arg(command));
} else if (m_completionModel->autoCompletionType() == CompletionModel::Room) {
auto alias = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Subtitle).toString();
auto alias = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::SubtitleRole).toString();
auto text = getText();
auto at = text.lastIndexOf(QLatin1Char('#'), cursorPosition() - 1);
QTextCursor cursor(document()->textDocument());
@@ -253,7 +253,7 @@ void ChatDocumentHandler::complete(int index)
pushMention({cursor, alias, 0, 0, alias});
m_highlighter->rehighlight();
} else if (m_completionModel->autoCompletionType() == CompletionModel::Emoji) {
auto shortcode = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedText).toString();
auto shortcode = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedTextRole).toString();
auto text = getText();
auto at = text.lastIndexOf(QLatin1Char(':'));
QTextCursor cursor(document()->textDocument());

View File

@@ -185,8 +185,10 @@ int main(int argc, char *argv[])
initLogging();
#if Quotient_VERSION_MINOR == 8
#ifdef Quotient_E2EE_ENABLED
Connection::setEncryptionDefault(true);
#endif
#endif
#ifdef NEOCHAT_FLATPAK
// Copy over the included FontConfig configuration to the

View File

@@ -32,11 +32,17 @@ ThumbnailResponse::ThumbnailResponse(QString id, QSize size)
requestedSize.setWidth(100);
}
if (mediaId.count('/') != 1) {
errorStr = i18n("Media id '%1' doesn't follow server/mediaId pattern", mediaId);
Q_EMIT finished();
return;
if (mediaId.startsWith(QLatin1Char('/'))) {
mediaId = mediaId.mid(1);
} else {
errorStr = i18n("Media id '%1' doesn't follow server/mediaId pattern", mediaId);
Q_EMIT finished();
return;
}
}
mediaId = mediaId.split(QLatin1Char('?'))[0];
QImage cachedImage;
if (cachedImage.load(localFile)) {
image = cachedImage;

View File

@@ -34,7 +34,7 @@ private Q_SLOTS:
void prepareResult();
private:
const QString mediaId;
QString mediaId;
QSize requestedSize;
const QString localFile;
Quotient::MediaThumbnailJob *job = nullptr;

View File

@@ -81,7 +81,7 @@ QString CollapseStateProxyModel::aggregateEventToString(int sourceRow) const
: QStringLiteral("<a href=\"https://matrix.to/#/%1\" style=\"color: %2\">%3</a> ")
.arg(uniqueAuthors[0].toMap()["id"].toString(),
uniqueAuthors[0].toMap()["color"].toString(),
uniqueAuthors[0].toMap()["displayName"].toString());
uniqueAuthors[0].toMap()["displayName"].toString().toHtmlEscaped());
text += userText;
text += chunks.takeFirst();

View File

@@ -53,54 +53,54 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
}
auto filterIndex = m_filterModel->index(index.row(), 0);
if (m_autoCompletionType == User) {
if (role == Text) {
if (role == DisplayNameRole) {
return m_filterModel->data(filterIndex, UserListModel::DisplayNameRole);
}
if (role == Subtitle) {
if (role == SubtitleRole) {
return m_filterModel->data(filterIndex, UserListModel::UserIdRole);
}
if (role == Icon) {
if (role == IconNameRole) {
return m_filterModel->data(filterIndex, UserListModel::AvatarRole);
}
}
if (m_autoCompletionType == Command) {
if (role == Text) {
if (role == DisplayNameRole) {
return m_filterModel->data(filterIndex, ActionsModel::Prefix).toString() + QStringLiteral(" ")
+ m_filterModel->data(filterIndex, ActionsModel::Parameters).toString();
}
if (role == Subtitle) {
if (role == SubtitleRole) {
return m_filterModel->data(filterIndex, ActionsModel::Description);
}
if (role == Icon) {
if (role == IconNameRole) {
return QStringLiteral("invalid");
}
if (role == ReplacedText) {
if (role == ReplacedTextRole) {
return m_filterModel->data(filterIndex, ActionsModel::Prefix);
}
}
if (m_autoCompletionType == Room) {
if (role == Text) {
if (role == DisplayNameRole) {
return m_filterModel->data(filterIndex, RoomListModel::DisplayNameRole);
}
if (role == Subtitle) {
if (role == SubtitleRole) {
return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
}
if (role == Icon) {
if (role == IconNameRole) {
return m_filterModel->data(filterIndex, RoomListModel::AvatarRole);
}
}
if (m_autoCompletionType == Emoji) {
if (role == Text) {
if (role == DisplayNameRole) {
return m_filterModel->data(filterIndex, CustomEmojiModel::DisplayRole);
}
if (role == Icon) {
if (role == IconNameRole) {
return m_filterModel->data(filterIndex, CustomEmojiModel::MxcUrl);
}
if (role == ReplacedText) {
if (role == ReplacedTextRole) {
return m_filterModel->data(filterIndex, CustomEmojiModel::ReplacedTextRole);
}
if (role == Subtitle) {
if (role == SubtitleRole) {
return m_filterModel->data(filterIndex, EmojiModel::DescriptionRole);
}
}
@@ -111,10 +111,10 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
QHash<int, QByteArray> CompletionModel::roleNames() const
{
return {
{Text, "text"},
{Subtitle, "subtitle"},
{Icon, "icon"},
{ReplacedText, "replacedText"},
{DisplayNameRole, "displayName"},
{SubtitleRole, "subtitle"},
{IconNameRole, "iconName"},
{ReplacedTextRole, "replacedText"},
};
}

View File

@@ -64,10 +64,10 @@ public:
* @brief Defines the model roles.
*/
enum Roles {
Text = Qt::DisplayRole, /**< The main text to show. */
Subtitle, /**< The subtitle text to show. */
Icon, /**< The icon to show. */
ReplacedText, /**< The text to replace the input text with for the completion. */
DisplayNameRole = Qt::DisplayRole, /**< The main text to show. */
SubtitleRole, /**< The subtitle text to show. */
IconNameRole, /**< The icon to show. */
ReplacedTextRole, /**< The text to replace the input text with for the completion. */
};
Q_ENUM(Roles)

View File

@@ -5,6 +5,9 @@
#include "controller.h"
#include <QDateTime>
#include <QLocale>
#include <KLocalizedString>
#include <Quotient/csapi/device_management.h>
@@ -52,10 +55,17 @@ QVariant DevicesModel::data(const QModelIndex &index, int role) const
} else {
return false;
}
case TimestampString:
if (device.lastSeenTs) {
return QDateTime::fromMSecsSinceEpoch(*device.lastSeenTs).toString(QLocale().dateTimeFormat(QLocale::ShortFormat));
} else {
return false;
}
case Type:
if (device.deviceId == m_connection->deviceId()) {
return This;
}
#ifdef Quotient_E2EE_ENABLED
if (!m_connection->isKnownE2eeCapableDevice(m_connection->userId(), device.deviceId)) {
return Unencrypted;
}
@@ -64,6 +74,9 @@ QVariant DevicesModel::data(const QModelIndex &index, int role) const
} else {
return Unverified;
}
#else
return Unverified;
#endif
}
return {};
}
@@ -81,6 +94,7 @@ QHash<int, QByteArray> DevicesModel::roleNames() const
{DisplayName, "displayName"},
{LastIp, "lastIp"},
{LastTimestamp, "lastTimestamp"},
{TimestampString, "timestamp"},
{Type, "type"},
};
}
@@ -147,6 +161,7 @@ void DevicesModel::setConnection(Connection *connection)
Q_EMIT connectionChanged();
fetchDevices();
#ifdef Quotient_E2EE_ENABLED
connect(m_connection, &Connection::sessionVerified, this, [this](const QString &userId, const QString &deviceId) {
Q_UNUSED(deviceId);
if (userId == Controller::instance().activeConnection()->userId()) {
@@ -156,6 +171,7 @@ void DevicesModel::setConnection(Connection *connection)
connect(m_connection, &Connection::finishedQueryingKeys, this, [this]() {
fetchDevices();
});
#endif
}
#include "moc_devicesmodel.cpp"

View File

@@ -40,6 +40,7 @@ public:
DisplayName, /**< Display name set by the user for this device. */
LastIp, /**< The IP address where this device was last seen. */
LastTimestamp, /**< The timestamp when this devices was last seen. */
TimestampString, /**< String for the timestamp when this devices was last seen. */
Type, /**< The category to sort this device into. */
};
Q_ENUM(Roles)

View File

@@ -338,7 +338,7 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const
if (role == AvatarImageRole) {
return room->avatar(128);
}
if (role == IdRole) {
if (role == RoomIdRole) {
return room->id();
}
if (role == IsSpaceRole) {
@@ -379,7 +379,7 @@ QHash<int, QByteArray> RoomListModel::roleNames() const
roles[CategoryVisibleRole] = "categoryVisible";
roles[SubtitleTextRole] = "subtitleText";
roles[IsSpaceRole] = "isSpace";
roles[IdRole] = "id";
roles[RoomIdRole] = "roomId";
roles[IsChildSpaceRole] = "isChildSpace";
return roles;
}

View File

@@ -72,7 +72,7 @@ public:
CategoryVisibleRole, /**< If the room's category is visible. */
SubtitleTextRole, /**< The text to show as the room subtitle. */
AvatarImageRole, /**< The room avatar as an image. */
IdRole, /**< The room matrix ID. */
RoomIdRole, /**< The room matrix ID. */
IsSpaceRole, /**< Whether the room is a space. */
IsChildSpaceRole, /**< Whether this space is a child of a different space. */
};

View File

@@ -87,7 +87,8 @@ bool SortFilterRoomListModel::filterAcceptsRow(int source_row, const QModelIndex
return acceptRoom;
} else {
const auto &rooms = SpaceHierarchyCache::instance().getRoomListForSpace(m_activeSpaceId, false);
return std::find(rooms.begin(), rooms.end(), sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::IdRole).toString()) != rooms.end()
return std::find(rooms.begin(), rooms.end(), sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::RoomIdRole).toString())
!= rooms.end()
&& acceptRoom;
}
}

View File

@@ -8,7 +8,7 @@
SortFilterSpaceListModel::SortFilterSpaceListModel(QObject *parent)
: QSortFilterProxyModel{parent}
{
setSortRole(RoomListModel::IdRole);
setSortRole(RoomListModel::RoomIdRole);
sort(0);
invalidateFilter();
connect(this, &QAbstractProxyModel::sourceModelChanged, this, [this]() {
@@ -33,8 +33,8 @@ bool SortFilterSpaceListModel::filterAcceptsRow(int source_row, const QModelInde
bool SortFilterSpaceListModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
const auto idLeft = sourceModel()->data(source_left, RoomListModel::IdRole).toString();
const auto idRight = sourceModel()->data(source_right, RoomListModel::IdRole).toString();
const auto idLeft = sourceModel()->data(source_left, RoomListModel::RoomIdRole).toString();
const auto idRight = sourceModel()->data(source_right, RoomListModel::RoomIdRole).toString();
return idLeft < idRight;
}

View File

@@ -109,7 +109,7 @@ void StickerModel::setRoom(NeoChatRoom *room)
void StickerModel::postSticker(int index)
{
const auto &image = m_images[index];
const auto &body = image.body ? *image.body : QString();
const auto &body = image.body ? *image.body : image.shortcode;
QJsonObject infoJson;
if (image.info) {
infoJson["w"] = image.info->imageSize.width();

View File

@@ -144,7 +144,7 @@ QVariant UserDirectoryListModel::data(const QModelIndex &index, int role) const
auto avatarUrl = user.avatarUrl;
if (avatarUrl.isEmpty()) {
return "";
return QString();
}
return avatarUrl.url().remove(0, 6);
}
@@ -153,7 +153,7 @@ QVariant UserDirectoryListModel::data(const QModelIndex &index, int role) const
}
if (role == DirectChatsRole) {
if (!m_connection) {
return {};
return QStringList();
};
auto userObj = m_connection->user(user.userId);
@@ -165,6 +165,8 @@ QVariant UserDirectoryListModel::data(const QModelIndex &index, int role) const
return QVariant::fromValue(directChatsForUser);
}
}
return QStringList();
}
return {};

View File

@@ -54,7 +54,7 @@ Comment[es]=Un cliente para Matrix, el protocolo de comunicaciones descentraliza
Comment[eu]=Matrix, deszentralizatutako komunikazio protokolorako, bezero bat
Comment[fi]=Hajautetun Matrix-viestintäyhteyskäytännön asiakasohjelma
Comment[fr]=Un client pour « Matrix », le protocole décentralisé de communications.
Comment[gl]=Un cliente para Matrix, o protocolo de comunicación descentralizada
Comment[gl]=Un cliente para Matrix, o protocolo de comunicación descentralizada.
Comment[hu]=Kliens a matrixhoz, a decentralizált kommunikációs protokollhoz
Comment[ia]=Un cliente per Matrix, le protocollo de communication decentralisate
Comment[id]=Sebuah klien untuk matrix, protokol komunikasi terdecentralisasi
@@ -133,7 +133,7 @@ Comment[es]=Hay un mensaje nuevo
Comment[eu]=Mezu berri bat dago
Comment[fi]=Saapui uusi viesti
Comment[fr]=Il y a un nouveau message
Comment[gl]=Hai unha nova mensaxe
Comment[gl]=Hai unha nova mensaxe.
Comment[hu]=Új üzenet érkezett
Comment[ia]=Il ha un nove message
Comment[id]=Ada pesan baru
@@ -209,7 +209,7 @@ Comment[es]=Hay una nueva invitación a una sala
Comment[eu]=Gela baterako gonbidapen berri bat dago
Comment[fi]=Uusi kutsu huoneeseen
Comment[fr]=Il y a une nouvelle invitation dans un salon.
Comment[gl]=Tes un novo convite para unha sala
Comment[gl]=Tes un novo convite para unha sala.
Comment[ia]=Il ha un nove invitation a un sala
Comment[id]=Ada undangan baru ke sebuah ruangan
Comment[ie]=Vu have un nov invitation a un chambre

View File

@@ -993,7 +993,7 @@ void NeoChatRoom::deleteMessagesByUser(const QString &user, const QString &reaso
QString NeoChatRoom::joinRule() const
{
auto joinRulesEvent = currentState().get<JoinRulesEvent>();
if (joinRulesEvent) {
if (!joinRulesEvent) {
return {};
}
return joinRulesEvent->joinRule();
@@ -1941,7 +1941,7 @@ QByteArray NeoChatRoom::roomAcountDataJson(const QString &eventType)
QUrl NeoChatRoom::avatarForMember(NeoChatUser *user) const
{
const auto &url = memberAvatarUrl(user->id());
if (url.isEmpty()) {
if (url.isEmpty() || url.scheme() != "mxc"_ls) {
return {};
}
auto avatar = connection()->makeMediaUrl(url);

View File

@@ -11,6 +11,7 @@
#include <KNotification>
#include <KNotificationReplyAction>
#include <QPainter>
#include <Quotient/accountregistry.h>
#include <Quotient/connection.h>
#include <Quotient/csapi/pushrules.h>
@@ -203,7 +204,7 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
}
notification->setText(notification->text() + '\n' + entry);
notification->setPixmap(QPixmap::fromImage(icon));
notification->setPixmap(createNotificationImage(icon, room));
notification->setDefaultAction(i18n("Open NeoChat in this room"));
connect(notification, &KNotification::defaultActivated, this, [notification, room]() {
@@ -239,7 +240,7 @@ void NotificationsManager::postInviteNotification(NeoChatRoom *room, const QStri
KNotification *notification = new KNotification("invite");
notification->setText(i18n("%1 invited you to a room", sender));
notification->setTitle(title);
notification->setPixmap(img);
notification->setPixmap(createNotificationImage(icon, nullptr));
notification->setFlags(KNotification::Persistent);
notification->setDefaultAction(i18n("Open this invitation in NeoChat"));
connect(notification, &KNotification::defaultActivated, this, [notification, room]() {
@@ -282,4 +283,41 @@ void NotificationsManager::clearInvitationNotification(const QString &roomId)
}
}
QPixmap NotificationsManager::createNotificationImage(const QImage &icon, NeoChatRoom *room)
{
// Handle avatars that are lopsided in one dimension
const int biggestDimension = std::max(icon.width(), icon.height());
const QRect imageRect{0, 0, biggestDimension, biggestDimension};
QImage roundedImage(imageRect.size(), QImage::Format_ARGB32);
roundedImage.fill(Qt::transparent);
QPainter painter(&roundedImage);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setPen(Qt::NoPen);
// Fill background for transparent avatars
painter.setBrush(Qt::white);
painter.drawRoundedRect(imageRect, imageRect.width(), imageRect.height());
QBrush brush(icon.scaledToHeight(biggestDimension));
painter.setBrush(brush);
painter.drawRoundedRect(imageRect, imageRect.width(), imageRect.height());
if (room != nullptr) {
const QImage roomAvatar = room->avatar(imageRect.width(), imageRect.height());
if (icon != roomAvatar) {
const QRect lowerQuarter{imageRect.center(), imageRect.size() / 2};
painter.setBrush(Qt::white);
painter.drawRoundedRect(lowerQuarter, lowerQuarter.width(), lowerQuarter.height());
painter.setBrush(roomAvatar.scaled(lowerQuarter.size()));
painter.drawRoundedRect(lowerQuarter, lowerQuarter.width(), lowerQuarter.height());
}
}
return QPixmap::fromImage(roundedImage);
}
#include "moc_notificationsmanager.cpp"

View File

@@ -97,4 +97,7 @@ private:
private Q_SLOTS:
void processNotificationJob(QPointer<Quotient::Connection> connection, Quotient::GetNotificationsJob *job, bool initialization);
private:
QPixmap createNotificationImage(const QImage &icon, NeoChatRoom *room);
};

View File

@@ -53,7 +53,7 @@ Comment[es]=Buscar salas en NeoChat
Comment[eu]=Bilatu gelak NeoChat-en
Comment[fi]=Etsi huoneita NeoChatissä
Comment[fr]=Trouver des salons dans NeoChat
Comment[gl]=Atopa salas en NeoChat
Comment[gl]=Atopa salas en NeoChat.
Comment[ia]=Trova salas in NeoChat
Comment[id]=Cari ruangan di NeoChat
Comment[ie]=Trovar chambres in NeoChat

View File

@@ -6,185 +6,35 @@ import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Templates 2.15 as T
import org.kde.kirigami 2.19 as Kirigami
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
T.TabButton {
id: control
Delegates.RoundedItemDelegate {
id: root
/**
* @brief This property specifies the index of this tab within the tab bar.
*/
readonly property int tabIndex: {
let tabIdx = 0
for (let i = 0; i < parent.children.length; ++i) {
if (parent.children[i] === this) {
return tabIdx
}
// Checking for AbstractButtons because any AbstractButton can act as a tab
if (parent.children[i] instanceof T.AbstractButton) {
++tabIdx
}
}
return -1
required property url source
signal contextMenuRequested()
padding: Kirigami.Units.largeSpacing
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: text
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
onPressAndHold: root.contextMenuRequested()
TapHandler {
acceptedButtons: Qt.RightButton
acceptedDevices: PointerDevice.Mouse
grabPermissions: PointerHandler.TakeOverForbidden
gesturePolicy: TapHandler.WithinBounds
onTapped: root.contextMenuRequested()
}
/**
* @brief This property sets whether the icon colors should be masked with a single color.
*
* default: ``true``
*
* @since KDE Frameworks 5.96
*/
property bool recolorIcon: true
property color foregroundColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.85)
property color highlightForegroundColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.85)
property color highlightBarColor: Kirigami.Theme.highlightColor
property color pressedColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.3)
property color hoverSelectColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.2)
property color checkedBorderColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.7)
property color pressedBorderColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.9)
property url source
property string name
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
display: T.AbstractButton.TextUnderIcon
Kirigami.Theme.colorSet: Kirigami.Theme.Window
Kirigami.Theme.inherit: false
// not using the hover handler built into control, since it seems to misbehave and
// permanently report hovered after a touch event
HoverHandler {
id: hoverHandler
}
padding: Kirigami.Units.smallSpacing
spacing: Kirigami.Units.smallSpacing
icon.height: control.display === T.AbstractButton.TextBesideIcon ? Kirigami.Units.iconSizes.small : Kirigami.Units.iconSizes.smallMedium
icon.width: control.display === T.AbstractButton.TextBesideIcon ? Kirigami.Units.iconSizes.small : Kirigami.Units.iconSizes.smallMedium
icon.color: control.checked ? control.highlightForegroundColor : control.foregroundColor
background: Rectangle {
Kirigami.Theme.colorSet: Kirigami.Theme.Button
Kirigami.Theme.inherit: false
implicitHeight: (control.display === T.AbstractButton.TextBesideIcon) ? 0 : (Kirigami.Units.gridUnit * 3 + Kirigami.Units.smallSpacing * 2)
color: "transparent"
Rectangle {
width: parent.width - Kirigami.Units.largeSpacing
height: parent.height - Kirigami.Units.largeSpacing
anchors.centerIn: parent
radius: Kirigami.Units.smallSpacing
color: control.down ? pressedColor : (control.checked || hoverHandler.hovered ? hoverSelectColor : "transparent")
border.color: control.checked ? checkedBorderColor : (control.down ? pressedBorderColor : color)
border.width: 1
Behavior on color { ColorAnimation { duration: Kirigami.Units.shortDuration } }
Behavior on border.color { ColorAnimation { duration: Kirigami.Units.shortDuration } }
}
}
contentItem: GridLayout {
id: gridLayout
columnSpacing: 0
rowSpacing: (label.visible && label.lineCount > 1) ? 0 : control.spacing
// if this is a row or a column
columns: control.display !== T.AbstractButton.TextBesideIcon ? 1 : 2
property real verticalMargins: (control.display === T.AbstractButton.TextBesideIcon) ? Kirigami.Units.largeSpacing : 0
Kirigami.Avatar {
id: icon
source: control.source
name: control.name
Layout.topMargin: gridLayout.verticalMargins
Layout.bottomMargin: gridLayout.verticalMargins
Layout.leftMargin: (control.display === T.AbstractButton.TextBesideIcon) ? Kirigami.Units.gridUnit : 0
Layout.rightMargin: (control.display === T.AbstractButton.TextBesideIcon) ? Kirigami.Units.gridUnit : 0
Layout.alignment: {
if (control.display === T.AbstractButton.TextBesideIcon) {
// row layout
return Qt.AlignVCenter | Qt.AlignRight;
} else {
// column layout
return Qt.AlignHCenter | ((!label.visible || label.lineCount > 1) ? Qt.AlignVCenter : Qt.AlignBottom);
}
}
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
}
QQC2.Label {
id: label
Kirigami.MnemonicData.enabled: control.enabled && control.visible
Kirigami.MnemonicData.controlType: Kirigami.MnemonicData.MenuItem
Kirigami.MnemonicData.label: control.text
text: Kirigami.MnemonicData.richTextLabel
horizontalAlignment: (control.display === T.AbstractButton.TextBesideIcon) ? Text.AlignLeft : Text.AlignHCenter
visible: control.display !== T.AbstractButton.IconOnly
wrapMode: Text.Wrap
elide: Text.ElideMiddle
color: control.checked ? control.highlightForegroundColor : control.foregroundColor
font.bold: control.checked
font.family: Kirigami.Theme.smallFont.family
font.pointSize: {
if (control.display === T.AbstractButton.TextBesideIcon) {
// row layout
return Kirigami.Theme.defaultFont.pointSize;
} else {
// column layout
return icon.visible ? Kirigami.Theme.smallFont.pointSize : Kirigami.Theme.defaultFont.pointSize * 1.20; // 1.20 is equivalent to level 2 heading
}
}
Behavior on color { ColorAnimation {} }
Behavior on opacity { NumberAnimation {} }
Layout.topMargin: gridLayout.verticalMargins
Layout.bottomMargin: gridLayout.verticalMargins
Layout.alignment: {
if (control.display === T.AbstractButton.TextBesideIcon) {
// row layout
return Qt.AlignVCenter | Qt.AlignLeft;
} else {
// column layout
return icon.visible ? Qt.AlignHCenter | Qt.AlignTop : Qt.AlignCenter;
}
}
// Work around bold text changing implicit size
Layout.preferredWidth: boldMetrics.implicitWidth
Layout.preferredHeight: boldMetrics.implicitHeight * label.lineCount
Layout.fillWidth: true
QQC2.Label {
id: boldMetrics
visible: false
text: parent.text
font.bold: true
font.family: Kirigami.Theme.smallFont.family
font.pointSize: Kirigami.Theme.smallFont.pointSize
horizontalAlignment: Text.AlignHCenter
wrapMode: QQC2.Label.Wrap
elide: Text.ElideMiddle
}
}
contentItem: KirigamiComponents.Avatar {
source: root.source
name: root.text
}
}

View File

@@ -97,6 +97,7 @@ QQC2.Control {
emojiDialog.open()
}
}
tooltip: text
},
Kirigami.Action {
id: mapButton
@@ -108,6 +109,7 @@ QQC2.Control {
onTriggered: {
locationChooserComponent.createObject(QQC2.ApplicationWindow.overlay, {room: currentRoom}).open()
}
tooltip: text
},
Kirigami.Action {
id: sendAction
@@ -235,9 +237,9 @@ QQC2.Control {
completionMenu.complete()
}
}
Keys.onPressed: {
Keys.onPressed: (event) => {
if (event.key === Qt.Key_V && event.modifiers & Qt.ControlModifier) {
root.pasteImage();
event.accepted = root.pasteImage();
} else if (event.key === Qt.Key_Up && event.modifiers & Qt.ControlModifier) {
currentRoom.replyLastMessage();
} else if (event.key === Qt.Key_Up && textField.text.length === 0) {
@@ -382,6 +384,7 @@ QQC2.Control {
QQC2.ToolTip.visible: modelData.tooltip !== "" && hoverHandler.hovered
QQC2.ToolTip.text: modelData.tooltip
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
HoverHandler { id: hoverHandler }
PieProgressBar {
@@ -464,9 +467,10 @@ QQC2.Control {
function pasteImage() {
let localPath = Clipboard.saveImage();
if (localPath.length === 0) {
return;
return false;
}
currentRoom.chatBoxAttachmentPath = localPath
root.currentRoom.chatBoxAttachmentPath = localPath;
return true;
}
function postMessage() {

View File

@@ -56,15 +56,6 @@ ColumnLayout {
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
Kirigami.InlineMessage {
Layout.fillWidth: true
Layout.leftMargin: 1 // So we can see the border
Layout.rightMargin: 1 // So we can see the border
text: i18n("NeoChat is offline. Please check your network connection.")
visible: !Controller.isOnline
}
Kirigami.Separator {
Layout.fillWidth: true
}

View File

@@ -8,6 +8,8 @@ import QtQuick.Controls 2.15 as QQC2
import Qt.labs.qmlmodels 1.0
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -43,6 +45,7 @@ QQC2.Popup {
rightPadding: 0
topPadding: 0
bottomPadding: 0
implicitHeight: Math.min(completions.contentHeight, Kirigami.Units.gridUnit * 10)
contentItem: ListView {
@@ -53,23 +56,35 @@ QQC2.Popup {
currentIndex: 0
keyNavigationWraps: true
highlightMoveDuration: 100
delegate: Kirigami.BasicListItem {
text: model.text
subtitle: model.subtitle ?? ""
labelItem.textFormat: Text.PlainText
subtitleItem.textFormat: Text.PlainText
leading: RowLayout {
Kirigami.Avatar {
visible: model.icon !== "invalid"
Layout.preferredWidth: height
Layout.fillHeight: true
source: model.icon === "invalid" ? "" : ("image://mxc/" + model.icon)
name: model.text
delegate: Delegates.RoundedItemDelegate {
id: completionDelegate
required property int index
required property string displayName
required property string subtitle
required property string iconName
text: displayName
contentItem: RowLayout {
KirigamiComponents.Avatar {
visible: completionDelegate.iconName !== "invalid"
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
source: completionDelegate.iconName === "invalid" ? "" : ("image://" + completionDelegate.iconName)
name: completionDelegate.text
}
Delegates.SubtitleContentItem {
itemDelegate: completionDelegate
labelItem.textFormat: Text.PlainText
subtitle: completionDelegate.subtitle ?? ""
subtitleItem.textFormat: Text.PlainText
}
}
onClicked: completionMenu.chatDocumentHandler.complete(model.index)
onClicked: completionMenu.chatDocumentHandler.complete(completionDelegate.index)
}
}
background: Rectangle {
color: Kirigami.Theme.backgroundColor
}

View File

@@ -6,7 +6,8 @@ import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 as QQC2
import org.kde.kirigami 2.14 as Kirigami
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -40,7 +41,7 @@ GridLayout {
implicitWidth: Kirigami.Units.smallSpacing
color: userColor
}
Kirigami.Avatar {
KirigamiComponents.Avatar {
id: replyAvatar
implicitWidth: Kirigami.Units.iconSizes.small

View File

@@ -26,14 +26,20 @@ QQC2.Popup {
padding: 2
modal: true
dim: true
clip: false
onOpened: x = Math.min(parent.mapFromGlobal(QQC2.Overlay.overlay.width - tones.width, 0).x, -(width - parent.width) / 2)
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
shadow.size: Kirigami.Units.smallSpacing
shadow.color: Qt.rgba(0.0, 0.0, 0.0, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 1
radius: Kirigami.Units.mediumSpacing
shadow {
size: Kirigami.Units.largeSpacing
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)
yOffset: 2
}
border {
color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
width: 1
}
}
ListView {

View File

@@ -9,6 +9,7 @@ import QtLocation 5.15
import QtPositioning 5.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -44,7 +45,7 @@ MapQuickItem {
isMask: true
color: parent.color
}
Kirigami.Avatar {
KirigamiComponents.Avatar {
anchors.centerIn: parent
anchors.verticalCenterOffset: -parent.height / 8
visible: root.asset === "m.self"

View File

@@ -56,7 +56,7 @@ Components.AlbumMaximizeComponent {
}
leading: RowLayout {
Kirigami.Avatar {
Components.Avatar {
id: userAvatar
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium

View File

@@ -6,9 +6,11 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
import org.kde.kitemmodels 1.0
import org.kde.neochat 1.0
import './RoomList' as RoomList
QQC2.Dialog {
id: root
@@ -86,48 +88,23 @@ QQC2.Dialog {
connection: Controller.activeConnection
}
}
delegate: Kirigami.BasicListItem {
id: roomListItem
required property NeoChatRoom currentRoom
required property string displayName
required property int index
required property int notificationCount
required property string subtitleText
required property string avatar
delegate: RoomList.RoomDelegate {
filterText: searchField.text
topPadding: Kirigami.Units.largeSpacing
bottomPadding: Kirigami.Units.largeSpacing
highlighted: roomList.currentIndex === roomListItem.index
focus: true
icon: undefined
onClicked: {
RoomManager.enterRoom(roomListItem.currentRoom);
RoomManager.enterRoom(currentRoom);
root.close()
}
Keys.onEnterPressed: {
RoomManager.enterRoom(roomListItem.currentRoom);
RoomManager.enterRoom(currentRoom);
root.close();
}
Keys.onReturnPressed: {
RoomManager.enterRoom(roomListItem.currentRoom);
root.close();
}
@BASICLISTITEM_BOLD@: roomListItem.notificationCount > 0
label: roomListItem.displayName ?? ""
labelItem.textFormat: Text.PlainText
subtitle: roomListItem.subtitleText
subtitleItem.textFormat: Text.PlainText
onPressAndHold: {
createRoomListContextMenu()
}
leading: Kirigami.Avatar {
source: roomListItem.avatar ? "image://mxc/" + roomListItem.avatar : ""
name: roomListItem.displayName
implicitWidth: height
sourceSize.width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
sourceSize.height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
Keys.onReturnPressed: {
RoomManager.enterRoom(currentRoom);
root.close();
}
}
}

View File

@@ -5,6 +5,7 @@ import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
Flow {
id: root
@@ -17,11 +18,11 @@ Flow {
spacing: -avatarSize / 2
Repeater {
id: avatarFlowRepeater
delegate: Kirigami.Avatar {
topInset: Kirigami.Units.smallSpacing / 2
topPadding: Kirigami.Units.smallSpacing / 2
implicitWidth: avatarSize
implicitHeight: avatarSize + Kirigami.Units.smallSpacing / 2
delegate: KirigamiComponents.Avatar {
required property var modelData
implicitWidth: root.avatarSize
implicitHeight: root.avatarSize
name: modelData.displayName
source: modelData.avatarSource

View File

@@ -50,10 +50,10 @@ Flow {
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.View
radius: height / 2
shadow.size: Kirigami.Units.smallSpacing
shadow.color: !model.hasLocalUser ? Qt.rgba(0.0, 0.0, 0.0, 0.10) : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 1
shadow {
size: Kirigami.Units.smallSpacing
color: !model.hasLocalUser ? Qt.rgba(0.0, 0.0, 0.0, 0.10) : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
}
}
onClicked: reactionClicked(model.reaction)

View File

@@ -7,6 +7,7 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -93,7 +94,7 @@ Item {
implicitWidth: Kirigami.Units.smallSpacing
color: root.author.color
}
Kirigami.Avatar {
KirigamiComponents.Avatar {
id: replyAvatar
implicitWidth: Kirigami.Units.iconSizes.small

View File

@@ -27,7 +27,12 @@ TextEdit {
/**
* @brief Regex for detecting a message with a single emoji.
*/
readonly property var isEmoji: /^(<span style='.*'>)?(\u00a9|\u00ae|[\u20D0-\u2fff]|[\u3190-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])+(<\/span>)?$/
readonly property var isEmojiRegex: /^(<span style='.*'>)?(\u00a9|\u00ae|[\u20D0-\u2fff]|[\u3190-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])+(<\/span>)?$/
/**
* @brief Whether the message is an emoji
*/
readonly property var isEmoji: isEmojiRegex.test(textMessage)
/**
* @brief Regex for detecting a message with a spoiler.
@@ -85,7 +90,10 @@ a{
color: Kirigami.Theme.textColor
selectedTextColor: Kirigami.Theme.highlightedTextColor
selectionColor: Kirigami.Theme.highlightColor
font.pointSize: !root.isReply && isEmoji.test(textMessage) ? Kirigami.Theme.defaultFont.pointSize * 4 : Kirigami.Theme.defaultFont.pointSize
font {
pointSize: !root.isReply && root.isEmoji ? Kirigami.Theme.defaultFont.pointSize * 4 : Kirigami.Theme.defaultFont.pointSize
family: root.isEmoji ? 'emoji' : Kirigami.Theme.defaultFont.family
}
selectByMouse: !Kirigami.Settings.isMobile
readOnly: true
wrapMode: Text.Wrap

View File

@@ -6,6 +6,7 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -21,14 +22,23 @@ RowLayout {
implicitHeight: Math.max(label.contentHeight, stateAvatar.implicitHeight)
Kirigami.Avatar {
KirigamiComponents.Avatar {
id: stateAvatar
Layout.preferredWidth: Kirigami.Units.iconSizes.small
Layout.preferredHeight: Kirigami.Units.iconSizes.small
name: root.name
color: root.color
Rectangle {
radius: height
height: 4
width: 4
color: root.color
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor

View File

@@ -6,6 +6,7 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -71,34 +72,61 @@ QQC2.Control {
Flow {
visible: columnLayout.folded
spacing: -Kirigami.Units.iconSizes.small / 2
Repeater {
model: authorList
delegate: Kirigami.Avatar {
topInset: Kirigami.Units.smallSpacing / 2
topPadding: Kirigami.Units.smallSpacing / 2
delegate: Item {
id: avatarDelegate
required property var modelData
implicitWidth: Kirigami.Units.iconSizes.small
implicitHeight: Kirigami.Units.iconSizes.small + Kirigami.Units.smallSpacing / 2
name: modelData.displayName
source: modelData.avatarSource
color: modelData.color
KirigamiComponents.Avatar {
y: Kirigami.Units.smallSpacing / 2
implicitWidth: Kirigami.Units.iconSizes.small
implicitHeight: Kirigami.Units.iconSizes.small
name: parent.modelData.displayName
source: parent.modelData.avatarSource
color: parent.modelData.color
Rectangle {
radius: height
height: 4
width: 4
color: avatarDelegate.modelData.color
anchors.centerIn: parent
}
}
}
}
QQC2.Label {
id: excessAuthorsLabel
text: model.excessAuthors
visible: model.excessAuthors !== ""
color: Kirigami.Theme.textColor
horizontalAlignment: Text.AlignHCenter
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.View
color: Kirigami.Theme.backgroundColor
radius: height / 2
shadow.size: Kirigami.Units.smallSpacing
shadow.color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 1
shadow {
size: Kirigami.Units.smallSpacing
color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
}
border {
color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
width: 1
}
}
height: Kirigami.Units.iconSizes.small + Kirigami.Units.smallSpacing
@@ -125,13 +153,13 @@ QQC2.Control {
visible: !columnLayout.folded
}
QQC2.ToolButton {
icon.name: (!columnLayout.folded ? "go-up" : "go-down")
icon.width: Kirigami.Units.iconSizes.small
icon.height: Kirigami.Units.iconSizes.small
onClicked: {
columnLayout.toggleFolded()
icon {
name: (!columnLayout.folded ? "go-up" : "go-down")
width: Kirigami.Units.iconSizes.small
height: Kirigami.Units.iconSizes.small
}
onClicked: columnLayout.toggleFolded()
}
}
Repeater {

View File

@@ -6,6 +6,7 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -353,18 +354,15 @@ ColumnLayout {
}
}
Kirigami.Avatar {
KirigamiComponents.Avatar {
id: avatar
width: visible || Config.showAvatarInTimeline ? Kirigami.Units.gridUnit * 2 + Kirigami.Units.smallSpacing * 2 : 0
width: visible || Config.showAvatarInTimeline ? Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2: 0
height: width
padding: Kirigami.Units.smallSpacing
topInset: Kirigami.Units.smallSpacing
bottomInset: Kirigami.Units.smallSpacing
leftInset: Kirigami.Units.smallSpacing
rightInset: Kirigami.Units.smallSpacing
anchors {
left: parent.left
leftMargin: Kirigami.Units.smallSpacing
top: parent.top
topMargin: Kirigami.Units.smallSpacing
}
visible: root.showAuthor &&
@@ -395,7 +393,8 @@ ColumnLayout {
hoverEnabled: true
anchors {
leftMargin: Kirigami.Units.smallSpacing
left: avatar.right
leftMargin: Kirigami.Units.largeSpacing
rightMargin: Kirigami.Units.largeSpacing
}
// HACK: anchoring didn't reset anchors.right when switching from parent.right to undefined reliably
@@ -519,31 +518,29 @@ ColumnLayout {
visible: cardBackground && !Config.compactLayout
anchors.fill: parent
Kirigami.Theme.colorSet: Kirigami.Theme.View
color: {
if (root.author.isLocalUser) {
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.15)
} else if (root.showHighlight) {
return Kirigami.Theme.positiveBackgroundColor
} else {
return Kirigami.Theme.backgroundColor
}
Kirigami.Theme.inherit: false
color: if (root.author.isLocalUser) {
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.15)
} else if (root.showHighlight) {
return Kirigami.Theme.positiveBackgroundColor
} else {
return Kirigami.Theme.backgroundColor
}
radius: Kirigami.Units.smallSpacing
shadow.size: Kirigami.Units.smallSpacing
shadow.color: root.showHighlight ? Qt.rgba(0.0, 0.0, 0.0, 0.10) : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 1
shadow {
size: Kirigami.Units.smallSpacing
color: root.isHighlighted ? Qt.rgba(0.0, 0.0, 0.0, 0.10) : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
}
Behavior on color {
enabled: isTemporaryHighlighted
ColorAnimation {target: bubbleBackground; duration: Kirigami.Units.veryLongDuration; easing.type: Easing.InOutCubic}
ColorAnimation { duration: Kirigami.Units.shortDuration }
}
}
}
}
background: Rectangle {
visible: mainContainer.hovered
visible: mainContainer.hovered && Config.compactLayout
color: Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.15)
radius: Kirigami.Units.smallSpacing
}

View File

@@ -308,7 +308,7 @@ QQC2.ScrollView {
x: delegate ? delegate.x + delegate.bubbleX : 0
y: delegate ? delegate.mapToItem(parent, 0, 0).y + delegate.bubbleY - height + Kirigami.Units.smallSpacing : 0
width: delegate.bubbleWidth
width: delegate ? delegate.bubbleWidth : Kirigami.Units.gridUnit * 4
showActions: delegate && delegate.hovered
verified: delegate && delegate.verified
@@ -420,13 +420,6 @@ QQC2.ScrollView {
popup.open()
}
function showUserDetail(user) {
userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
room: root.currentRoom,
user: root.currentRoom.getUser(user.id),
}).open();
}
function goToLastMessage() {
root.currentRoom.markAllMessagesAsRead()
// scroll to the very end, i.e to messageListView.YEnd
@@ -496,4 +489,11 @@ QQC2.ScrollView {
function positionViewAtBeginning() {
messageListView.positionViewAtBeginning()
}
function showUserDetail(user) {
userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
room: root.currentRoom,
user: root.currentRoom.getUser(user.id),
}).open();
}
}

View File

@@ -34,15 +34,21 @@ QQC2.Popup {
background: Kirigami.ShadowedRectangle {
Kirigami.Theme.colorSet: Kirigami.Theme.View
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
shadow.size: Kirigami.Units.smallSpacing
shadow.color: Qt.rgba(0.0, 0.0, 0.0, 0.10)
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
border.width: 2
radius: Kirigami.Units.mediumSpacing
shadow {
size: Kirigami.Units.largeSpacing
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)
yOffset: 2
}
border {
color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
width: 2
}
}
modal: true
focus: true
clip: false
closePolicy: QQC2.Popup.CloseOnEscape | QQC2.Popup.CloseOnPressOutsideParent
margins: 0
padding: 2

View File

@@ -7,6 +7,7 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -37,7 +38,7 @@ Kirigami.OverlaySheet {
Layout.bottomMargin: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.largeSpacing
Kirigami.Avatar {
KirigamiComponents.Avatar {
Layout.preferredWidth: Kirigami.Units.iconSizes.huge
Layout.preferredHeight: Kirigami.Units.iconSizes.huge
@@ -57,6 +58,7 @@ Kirigami.OverlaySheet {
elide: Text.ElideRight
wrapMode: Text.NoWrap
text: user.displayName
textFormat: Text.PlainText
}
Kirigami.SelectableLabel {

View File

@@ -24,7 +24,9 @@ Labs.MenuBar {
text: i18nc("menu", "Configure NeoChat...")
shortcut: StandardKey.Preferences
onTriggered: pageStack.pushDialogLayer("qrc:/SettingsPage.qml", {}, {
onTriggered: pageStack.pushDialogLayer("qrc:/SettingsPage.qml", {
connection: Controller.activeConnection
}, {
title: i18n("Configure")
})
}

View File

@@ -7,6 +7,8 @@ import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.neochat 1.0
Kirigami.Page {
id: banSheet

View File

@@ -6,6 +6,7 @@ import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -222,11 +223,11 @@ Loader {
Layout.fillWidth: true
Layout.margins: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.largeSpacing
Kirigami.Avatar {
KirigamiComponents.Avatar {
id: avatar
source: author.avatarSource
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
Layout.alignment: Qt.AlignTop
}
ColumnLayout {

View File

@@ -7,6 +7,8 @@ import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.neochat 1.0
Kirigami.Page {
id: reportSheet

View File

@@ -7,6 +7,7 @@ import QtQuick.Layouts 1.15
import Qt.labs.platform 1.1 as Platform
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.kquickimageeditor 1.0 as KQuickImageEditor
Kirigami.Page {
@@ -170,7 +171,7 @@ Kirigami.Page {
}
}
footer: Kirigami.InlineMessage {
footer: KirigamiComponents.Banner {
id: msg
type: Kirigami.MessageType.Error
showCloseButton: true

View File

@@ -6,6 +6,8 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -68,38 +70,51 @@ Kirigami.ScrollablePage {
text: i18n("No users available")
}
delegate: Kirigami.BasicListItem {
delegate: Delegates.RoundedItemDelegate {
id: delegate
required property string userID
required property string name
required property string avatar
property bool inRoom: room && room.containsUser(userID)
label: model.name
subtitle: model.userID
text: name
leading: Kirigami.Avatar {
implicitWidth: height
source: model.avatar ? ("image://mxc/" + model.avatar) : ""
name: model.name
}
trailing: QQC2.ToolButton {
id: inviteButton
icon.name: "document-send"
text: i18n("Send invitation")
checkable: true
checked: inRoom
opacity: inRoom ? 0.5 : 1
onToggled: {
if (inRoom) {
checked = true
} else {
room.inviteToRoom(model.userID);
applicationWindow().pageStack.layers.pop();
}
contentItem: RowLayout {
KirigamiComponents.Avatar {
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
source: delegate.avatar ? ("image://mxc/" + delegate.avatar) : ""
name: delegate.name
}
QQC2.ToolTip.text: !inRoom ? text : i18n("User is either already a member or has been invited")
QQC2.ToolTip.visible: inviteButton.hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
Delegates.SubtitleContentItem {
itemDelegate: delegate
subtitle: delegate.userID
}
QQC2.ToolButton {
id: inviteButton
icon.name: "document-send"
text: i18n("Send invitation")
checkable: true
checked: inRoom
opacity: inRoom ? 0.5 : 1
onToggled: {
if (inRoom) {
checked = true
} else {
room.inviteToRoom(delegate.userID);
applicationWindow().pageStack.layers.pop();
}
}
QQC2.ToolTip.text: !inRoom ? text : i18n("User is either already a member or has been invited")
QQC2.ToolTip.visible: inviteButton.hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
}
}
}

View File

@@ -8,6 +8,7 @@ import QtQuick.Layouts 1.15
import Qt.labs.qmlmodels 1.0
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -202,7 +203,7 @@ Kirigami.ScrollablePage {
applicationWindow().pageStack.layers.pop();
}
contentItem: RowLayout {
Kirigami.Avatar {
KirigamiComponents.Avatar {
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: Kirigami.Units.gridUnit * 2

View File

@@ -7,6 +7,7 @@ import QtQuick.Layouts 1.15
import QtQml.Models 2.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.kitemmodels 1.0
import org.kde.neochat 1.0
@@ -32,7 +33,7 @@ QQC2.ItemDelegate {
visible: root.categoryVisible || filterText.length > 0 || Config.mergeRoomList
contentItem: Kirigami.Avatar {
contentItem: KirigamiComponents.Avatar {
source: root.avatar ? `image://mxc/${root.avatar}` : ""
name: root.displayName

View File

@@ -7,6 +7,7 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.19 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -157,7 +158,7 @@ Loader {
Layout.fillWidth: true
Layout.margins: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.largeSpacing
Kirigami.Avatar {
KirigamiComponents.Avatar {
id: avatar
source: room.avatarMediaId ? ("image://mxc/" + room.avatarMediaId) : ""
name: room.displayName

View File

@@ -240,6 +240,15 @@ Kirigami.Page {
RoomList.RoomDelegate {
filterText: sortFilterRoomListModel.filterText
height: visible ? implicitHeight : 0
visible: categoryVisible || filterText.length > 0 || Config.mergeRoomList
onClicked: RoomManager.enterRoom(currentRoom)
Keys.onEnterPressed: RoomManager.enterRoom(currentRoom)
Keys.onReturnPressed: RoomManager.enterRoom(currentRoom)
}
}
}

View File

@@ -7,13 +7,15 @@ import QtQuick.Layouts 1.15
import QtQml.Models 2.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
import org.kde.kirigamiaddons.labs.components 1.0 as Components
import org.kde.kitemmodels 1.0
import org.kde.neochat 1.0
import './' as RoomList
Kirigami.BasicListItem {
Delegates.RoundedItemDelegate {
id: root
required property int index
@@ -29,48 +31,61 @@ Kirigami.BasicListItem {
readonly property bool hasNotifications: notificationCount > 0
topPadding: Kirigami.Units.largeSpacing
bottomPadding: Kirigami.Units.largeSpacing
visible: root.categoryVisible || root.filterText.length > 0 || Config.mergeRoomList
highlighted: ListView.view.currentIndex === index
focus: true
icon: undefined
@BASICLISTITEM_BOLD@: root.hasNotifications
label: root.displayName
labelItem.textFormat: Text.PlainText
subtitle: root.subtitleText
subtitleItem {
textFormat: Text.PlainText
visible: !Config.compactRoomList
}
onClicked: RoomManager.enterRoom(root.currentRoom)
onPressAndHold: createRoomListContextMenu()
Keys.onEnterPressed: RoomManager.enterRoom(root.currentRoom)
Keys.onReturnPressed: RoomManager.enterRoom(root.currentRoom)
TapHandler {
acceptedButtons: Qt.RightButton
acceptedDevices: PointerDevice.Mouse
onTapped: createRoomListContextMenu()
}
leading: Kirigami.Avatar {
source: root.avatar ? `image://mxc/${root.avatar}` : ""
name: root.displayName
implicitWidth: visible ? height : 0
visible: Config.showAvatarInRoomDrawer
sourceSize {
width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
}
}
contentItem: RowLayout {
spacing: Kirigami.Units.largeSpacing
Components.Avatar {
source: root.avatar ? "image://mxc/" + root.avatar : ""
name: root.displayName
visible: Config.showAvatarInRoomDrawer
implicitHeight: Kirigami.Units.gridUnit + (Config.compactRoomList ? 0 : Kirigami.Units.largeSpacing * 2)
implicitWidth: visible ? implicitHeight : 0
Layout.fillHeight: true
Layout.preferredWidth: height
}
ColumnLayout {
spacing: 0
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
QQC2.Label {
id: label
text: root.displayName
elide: Text.ElideRight
font.weight: root.hasNotifications ? Font.Bold : Font.Normal
textFormat: Text.PlainText
Layout.fillWidth: true
Layout.alignment: subtitle.visible ? Qt.AlignLeft | Qt.AlignBottom : Qt.AlignLeft | Qt.AlignVCenter
}
QQC2.Label {
id: subtitle
text: root.subtitleText
elide: Text.ElideRight
font: Kirigami.Theme.smallFont
opacity: root.hasNotifications ? 0.9 : 0.7
visible: !Config.compactRoomList
textFormat: Text.PlainText
Layout.fillWidth: true
Layout.alignment: visible ? Qt.AlignLeft | Qt.AlignTop : Qt.AlignLeft | Qt.AlignVCenter
}
}
trailing: RowLayout {
Kirigami.Icon {
source: "notifications-disabled"
enabled: false
@@ -80,10 +95,12 @@ Kirigami.BasicListItem {
Accessible.name: i18n("Muted room")
Layout.rightMargin: Kirigami.Units.smallSpacing
}
QQC2.Label {
id: notificationCountLabel
text: notificationCount
visible: hasNotifications
text: root.notificationCount
visible: root.hasNotifications
color: Kirigami.Theme.textColor
horizontalAlignment: Text.AlignHCenter
background: Rectangle {
@@ -103,6 +120,7 @@ Kirigami.BasicListItem {
text: notificationCountLabel.text
}
}
QQC2.Button {
id: configButton
visible: root.hovered && !Kirigami.Settings.isMobile && !Config.compactRoomList

View File

@@ -7,6 +7,7 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
import '.'
import org.kde.neochat 1.0
@@ -15,12 +16,8 @@ QQC2.Control {
id: root
readonly property real pinnedWidth: Kirigami.Units.gridUnit * 6
readonly property int buttonDisplayMode: Kirigami.NavigationTabButton.IconOnly
property bool drawerEnabled: true
Kirigami.Theme.colorSet: Kirigami.Theme.Window
Kirigami.Theme.inherit: false
leftPadding: 0
rightPadding: 0
topPadding: 0
@@ -28,12 +25,6 @@ QQC2.Control {
property string selectedSpaceId
background: Rectangle {
color: Kirigami.Theme.backgroundColor
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
}
contentItem: Loader {
id: sidebarColumn
active: root.drawerEnabled
@@ -56,17 +47,23 @@ QQC2.Control {
width: scrollView.width
spacing: 0
Kirigami.NavigationTabButton {
AvatarTabButton {
id: allRoomButton
Layout.fillWidth: true
Layout.preferredHeight: width
display: Kirigami.NavigationTabButton.IconOnly
Layout.preferredHeight: width - Kirigami.Units.smallSpacing
Layout.maximumHeight: width - Kirigami.Units.smallSpacing
Layout.topMargin: Kirigami.Units.smallSpacing
text: i18n("All Rooms")
icon.name: "globe"
checked: true
source: "globe"
contentItem: Kirigami.Icon {
source: "globe"
}
checked: root.selectedSpaceId === ""
onClicked: root.selectedSpaceId = ""
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: text
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
Repeater {
@@ -75,27 +72,32 @@ QQC2.Control {
connection: Controller.activeConnection
}
}
onCountChanged: root.enabled = count > 0
onCountChanged: {
root.enabled = count > 0
if (!Controller.activeConnection.room(root.selectedSpaceId)) {
root.selectedSpaceId = ""
}
}
Component.onCompleted: root.enabled = count > 0
delegate: AvatarTabButton {
Layout.fillWidth: true
Layout.preferredHeight: width
display: Kirigami.NavigationTabButton.IconOnly
text: model.displayName
source: model.avatar ? ("image://mxc/" + model.avatar) : ""
name: model.displayName
onClicked: root.selectedSpaceId = model.id
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: text
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
onPressAndHold: root.createContextMenu(model.currentRoom)
id: spaceDelegate
TapHandler {
acceptedButtons: Qt.RightButton
acceptedDevices: PointerDevice.Mouse
onTapped: root.createContextMenu(model.currentRoom)
}
required property string displayName
required property string avatar
required property string roomId
required property var currentRoom
Layout.fillWidth: true
Layout.preferredHeight: width - Kirigami.Units.smallSpacing
Layout.maximumHeight: width - Kirigami.Units.smallSpacing
text: displayName
source: avatar ? ("image://mxc/" + avatar) : ""
onClicked: root.selectedSpaceId = roomId
checked: root.selectedSpaceId === roomId
onContextMenuRequested: root.createContextMenu(currentRoom)
}
}
}

View File

@@ -7,6 +7,7 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.19 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -23,11 +24,13 @@ Loader {
QQC2.Menu {
QQC2.MenuItem {
text: i18nc("'Space' is a matrix space", "View Space")
icon.name: "view-list-details"
onTriggered: RoomManager.enterRoom(room);
}
QQC2.MenuItem {
text: i18nc("@action:inmenu", "Copy Address to Clipboard")
icon.name: "edit-copy"
onTriggered: if (room.canonicalAlias.length === 0) {
Clipboard.saveText(room.id)
} else {
@@ -37,6 +40,7 @@ Loader {
QQC2.MenuItem {
text: i18nc("'Space' is a matrix space", "Space Settings")
icon.name: 'settings-configure'
onTriggered: QQC2.ApplicationWindow.window.pageStack.pushDialogLayer('qrc:/Categories.qml', {room: room}, { title: i18n("Space Settings") })
}
@@ -44,12 +48,13 @@ Loader {
QQC2.MenuItem {
text: i18nc("'Space' is a matrix space", "Leave Space")
icon.name: "go-previous"
onTriggered: RoomManager.leaveRoom(room)
}
onClosed: {
root.closed()
destroy()
regularMenu.destroy()
}
}
}
@@ -78,7 +83,7 @@ Loader {
Layout.fillWidth: true
Layout.margins: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.largeSpacing
Kirigami.Avatar {
KirigamiComponents.Avatar {
id: avatar
source: room.avatarMediaId ? ("image://mxc/" + room.avatarMediaId) : ""
Layout.preferredWidth: Kirigami.Units.gridUnit * 3

View File

@@ -5,6 +5,8 @@ import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
import org.kde.neochat 1.0
@@ -27,34 +29,28 @@ QQC2.ToolBar {
header: Kirigami.Separator {}
footer: Kirigami.BasicListItem {
footer: Delegates.RoundedItemDelegate {
id: addButton
width: parent.width
highlighted: focus
background: Rectangle {
id: background
color: addAccount.backgroundColor
Rectangle {
anchors.fill: parent
visible: !Kirigami.Settings.tabletMode && addAccount.hoverEnabled
color: addAccount.activeBackgroundColor
opacity: {
if ((addAccount.highlighted || addAccount.ListView.isCurrentItem) && !addAccount.pressed) {
return .6
} else if (addAccount.hovered && !addAccount.pressed) {
return .3
} else {
return 0
}
}
}
}
highlighted: focus || (addAccount.highlighted || addAccount.ListView.isCurrentItem) && !addAccount.pressed
Component.onCompleted: userInfo.addAccount = this
icon: "list-add"
icon {
name: "list-add"
width: Kirigami.Units.iconSizes.smallMedium
height: Kirigami.Units.iconSizes.smallMedium
}
text: i18n("Add Account")
subtitle: i18n("Log in to an existing account")
contentItem: Delegates.SubtitleContentItem {
itemDelegate: parent
subtitle: i18n("Log in to an existing account")
labelItem.textFormat: Text.PlainText
subtitleItem.textFormat: Text.PlainText
}
onClicked: {
pageStack.pushDialogLayer("qrc:/WelcomePage.qml", {}, {title: i18nc("@title:window", "Login")})
pageStack.pushDialogLayer("qrc:/WelcomePage.qml", {}, {
title: i18nc("@title:window", "Login"),
});
if (switchUserButton.checked) {
switchUserButton.checked = false
}
@@ -99,28 +95,38 @@ QQC2.ToolBar {
}
}
width: parent.width
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
delegate: Kirigami.BasicListItem {
leftPadding: topPadding
leading: Kirigami.Avatar {
implicitWidth: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
implicitHeight: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
sourceSize {
width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
}
source: model.connection.localUser.avatarMediaId ? ("image://mxc/" + model.connection.localUser.avatarMediaId) : ""
name: model.connection.localUser.displayName ?? model.connection.localUser.id
}
delegate: Delegates.RoundedItemDelegate {
id: userDelegate
required property var connection
width: parent.width
text: model.connection.localUser.displayName
labelItem.textFormat: Text.PlainText
subtitleItem.textFormat: Text.PlainText
subtitle: model.connection.localUser.id
text: connection.localUser.displayName
contentItem: RowLayout {
KirigamiComponents.Avatar {
implicitWidth: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
implicitHeight: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
sourceSize {
width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
}
source: userDelegate.connection.localUser.avatarMediaId ? ("image://mxc/" + userDelegate.connection.localUser.avatarMediaId) : ""
name: userDelegate.connection.localUser.displayName ?? userDelegate.connection.localUser.id
}
Delegates.SubtitleContentItem {
itemDelegate: userDelegate
subtitle: userDelegate.connection.localUser.id
labelItem.textFormat: Text.PlainText
subtitleItem.textFormat: Text.PlainText
}
}
onClicked: {
Controller.activeConnection = model.connection
Controller.activeConnection = userDelegate.connection
if (switchUserButton.checked) {
switchUserButton.checked = false
}
@@ -139,28 +145,40 @@ QQC2.ToolBar {
Layout.bottomMargin: Kirigami.Units.smallSpacing
Layout.minimumHeight: Kirigami.Units.gridUnit * 2 - 2 // HACK: -2 here is to ensure the ChatBox and the UserInfo have the same height
Kirigami.Avatar {
readonly property string mediaId: Controller.activeConnection.localUser.avatarMediaId
QQC2.AbstractButton {
id: accountButton
Layout.preferredWidth: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
Layout.preferredHeight: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
Layout.leftMargin: Kirigami.Units.largeSpacing
source: mediaId ? ("image://mxc/" + mediaId) : ""
name: Controller.activeConnection.localUser.displayName ?? Controller.activeConnection.localUser.id
actions.main: Kirigami.Action {
text: i18n("Edit this account")
icon.name: "document-edit"
onTriggered: pageStack.pushDialogLayer(Qt.resolvedUrl('qrc:/AccountEditorPage.qml'), {
connection: Controller.activeConnection
}, {
title: i18n("Account editor")
});
}
TapHandler {
acceptedButtons: Qt.RightButton
acceptedDevices: PointerDevice.Mouse
onTapped: accountMenu.open()
acceptedButtons: Qt.RightButton | Qt.LeftButton
acceptedDevices: PointerDevice.Mouse
onTapped: (eventPoint, button) => {
// TODO Qt6 remove
if (!button) {
button = eventPoint.event.button;
}
if (button == Qt.RightButton) {
accountMenu.open();
} else {
pageStack.pushDialogLayer(Qt.resolvedUrl('qrc:/AccountEditorPage.qml'), {
connection: Controller.activeConnection
}, {
title: i18n("Account editor")
});
}
}
}
text: i18n("Edit this account")
contentItem: KirigamiComponents.Avatar {
readonly property string mediaId: Controller.activeConnection.localUser.avatarMediaId
source: mediaId ? ("image://mxc/" + mediaId) : ""
name: Controller.activeConnection.localUser.displayName ?? Controller.activeConnection.localUser.id
}
}
@@ -220,7 +238,7 @@ QQC2.ToolBar {
Layout.minimumWidth: Layout.preferredWidth
Layout.alignment: Qt.AlignRight
Layout.rightMargin: Kirigami.Units.largeSpacing
QQC2.ToolTip.text: parent.text
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}

View File

@@ -7,6 +7,7 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.kirigami 2.19 as Kirigami
import org.kde.kitemmodels 1.0
@@ -42,16 +43,26 @@ Kirigami.Page {
}
}
header: QQC2.Control {
height: visible ? implicitHeight : 0
visible: false
padding: Kirigami.Units.smallSpacing
contentItem: Kirigami.InlineMessage {
showCloseButton: true
visible: true
Connections {
target: Controller
function onIsOnlineChanged() {
if (!Controller.isOnline) {
banner.text = i18n("NeoChat is offline. Please check your network connection.");
banner.visible = true;
banner.type = Kirigami.MessageType.Error;
} else {
banner.visible = false;
}
}
}
header: KirigamiComponents.Banner {
id: banner
showCloseButton: true
visible: false
}
Loader {
id: timelineViewLoader
anchors.fill: parent
@@ -166,15 +177,19 @@ Kirigami.Page {
Connections {
target: currentRoom
function onShowMessage(messageType, message) {
root.header.contentItem.text = message;
root.header.contentItem.type = messageType === ActionsHandler.Error ? Kirigami.MessageType.Error : messageType === ActionsHandler.Positive ? Kirigami.MessageType.Positive : Kirigami.MessageType.Information;
root.header.visible = true;
banner.text = message;
banner.type = messageType === ActionsHandler.Error ? Kirigami.MessageType.Error : messageType === ActionsHandler.Positive ? Kirigami.MessageType.Positive : Kirigami.MessageType.Information;
banner.visible = true;
}
}
function warning(title, message) {
root.header.contentItem.text = `${title}<br />${message}`;
root.header.contentItem.type = Kirigami.MessageType.Warning;
root.header.visible = true;
banner.text = `${title}<br />${message}`;
banner.type = Kirigami.MessageType.Warning;
banner.visible = true;
}
function showUserDetail(user) {
timelineViewLoader.item.showUserDetail(user)
}
}

View File

@@ -7,6 +7,8 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -60,69 +62,68 @@ Kirigami.ScrollablePage {
keyword: identifierField.text
}
delegate: Kirigami.AbstractListItem {
width: userDictListView.width
delegate: Delegates.RoundedItemDelegate {
id: delegate
required property string userID
required property string avatar
required property string name
required property var directChats
text: name
contentItem: RowLayout {
spacing: Kirigami.Units.largeSpacing
Kirigami.Avatar {
Layout.preferredWidth: height
Layout.fillHeight: true
source: model.avatar ? ("image://mxc/" + model.avatar) : ""
name: model.name
KirigamiComponents.Avatar {
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
source: delegate.avatar ? ("image://mxc/" + delegate.avatar) : ""
name: delegate.name
}
ColumnLayout {
Delegates.SubtitleContentItem {
itemDelegate: delegate
subtitle: delegate.userID
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 0
Kirigami.Heading {
Layout.fillWidth: true
Layout.fillHeight: true
text: name
textFormat: Text.PlainText
elide: Text.ElideRight
wrapMode: Text.NoWrap
}
QQC2.Label {
Layout.fillWidth: true
Layout.fillHeight: true
text: userID
textFormat: Text.PlainText
elide: Text.ElideRight
wrapMode: Text.NoWrap
}
}
QQC2.Button {
id: joinChatButton
Layout.alignment: Qt.AlignRight
visible: directChats && directChats.length > 0
visible: delegate.directChats && delegate.directChats.length > 0
text: i18n("Join existing chat")
display: QQC2.Button.IconOnly
icon.name: "document-send"
onClicked: {
connection.requestDirectChat(userID);
connection.requestDirectChat(delegate.userID);
applicationWindow().pageStack.layers.pop();
}
Layout.alignment: Qt.AlignRight
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
QQC2.Button {
Layout.alignment: Qt.AlignRight
icon.name: "irc-join-channel"
// We wants to make sure an user can't start more than one
// chat with someone.
visible: !joinChatButton.visible
text: i18n("Create new chat")
display: QQC2.Button.IconOnly
onClicked: {
connection.requestDirectChat(userID);
connection.requestDirectChat(delegate.userID);
applicationWindow().pageStack.layers.pop();
}
Layout.alignment: Qt.AlignRight
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
}
}

View File

@@ -6,6 +6,7 @@ import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -18,43 +19,45 @@ ColumnLayout {
Layout.fillWidth: true
Layout.preferredHeight: Kirigami.Units.largeSpacing * 2
}
Kirigami.Avatar {
QQC2.AbstractButton {
Layout.preferredWidth: Math.round(Kirigami.Units.gridUnit * 3.5)
Layout.preferredHeight: Math.round(Kirigami.Units.gridUnit * 3.5)
Layout.alignment: Qt.AlignHCenter
name: room ? room.displayName : ""
source: room ? ("image://mxc/" + room.avatarMediaId) : ""
Rectangle {
visible: room.usesEncryption
color: Kirigami.Theme.backgroundColor
width: Kirigami.Units.gridUnit
height: Kirigami.Units.gridUnit
anchors.bottom: parent.bottom
anchors.right: parent.right
radius: Math.round(width / 2)
Kirigami.Icon {
source: "channel-secure-symbolic"
anchors.fill: parent
onClicked: {
const popup = userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
room: room,
user: room.getUser(room.directChatRemoteUser.id),
})
popup.closed.connect(() => {
userListItem.highlighted = false
})
if (roomDrawer.modal) {
roomDrawer.close()
}
popup.open()
}
actions.main: Kirigami.Action {
onTriggered: {
const popup = userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
room: room,
user: room.getUser(room.directChatRemoteUser.id),
})
popup.closed.connect(() => {
userListItem.highlighted = false
})
if (roomDrawer.modal) {
roomDrawer.close()
contentItem: KirigamiComponents.Avatar {
name: room ? room.displayName : ""
source: room ? ("image://mxc/" + room.avatarMediaId) : ""
Rectangle {
visible: room.usesEncryption
color: Kirigami.Theme.backgroundColor
width: Kirigami.Units.gridUnit
height: Kirigami.Units.gridUnit
anchors.bottom: parent.bottom
anchors.right: parent.right
radius: Math.round(width / 2)
Kirigami.Icon {
source: "channel-secure-symbolic"
anchors.fill: parent
}
popup.open()
}
}
}

View File

@@ -6,6 +6,7 @@ import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.neochat 1.0
@@ -17,11 +18,14 @@ ColumnLayout {
RowLayout {
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.topMargin: Kirigami.Units.largeSpacing
Layout.bottomMargin: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.largeSpacing
Kirigami.Avatar {
Layout.preferredWidth: Kirigami.Units.gridUnit * 3.5
Layout.preferredHeight: Kirigami.Units.gridUnit * 3.5
KirigamiComponents.Avatar {
Layout.preferredWidth: Kirigami.Units.iconSizes.large
Layout.preferredHeight: Kirigami.Units.iconSizes.large
name: room ? room.displayName : ""
source: room && room.avatarMediaId ? ("image://mxc/" + room.avatarMediaId) : ""
@@ -47,6 +51,7 @@ ColumnLayout {
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
@@ -54,14 +59,14 @@ ColumnLayout {
Kirigami.Heading {
Layout.fillWidth: true
type: Kirigami.Heading.Type.Primary
wrapMode: QQC2.Label.Wrap
text: room ? room.displayName : i18n("No name")
textFormat: Text.PlainText
wrapMode: Text.Wrap
}
Kirigami.SelectableLabel {
Layout.fillWidth: true
font: Kirigami.Theme.smallFont
textFormat: TextEdit.PlainText
text: room && room.canonicalAlias ? room.canonicalAlias : i18n("No Canonical Alias")
}

View File

@@ -7,6 +7,8 @@ import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
import org.kde.kitemmodels 1.0
import org.kde.neochat 1.0
@@ -73,11 +75,15 @@ Kirigami.OverlayDrawer {
active: roomDrawer.drawerOpen
sourceComponent: ColumnLayout {
readonly property string userSearchText: userListView.headerItem.userListSearchField.text
readonly property string userSearchText: userListView.headerItem ? userListView.headerItem.userListSearchField.text : ''
property alias highlightedUser: userListView.currentIndex
spacing: 0
function clearSearch() {
userListView.headerItem.userListSearchField.text = ""
}
QQC2.ToolBar {
Layout.fillWidth: true
@@ -120,7 +126,7 @@ Kirigami.OverlayDrawer {
property alias userListSearchField: userListSearchField
spacing: Kirigami.Units.largeSpacing
spacing: 0
width: userListView.width
Loader {
@@ -128,31 +134,41 @@ Kirigami.OverlayDrawer {
Layout.fillWidth: true
Layout.topMargin: Kirigami.Units.smallSpacing
sourceComponent: room.isDirectChat() ? directChatDrawerHeader : groupChatDrawerHeader
onItemChanged: if (item) {
userListView.positionViewAtBeginning();
}
}
Kirigami.ListSectionHeader {
label: i18n("Options")
activeFocusOnTab: false
Layout.fillWidth: true
}
Kirigami.BasicListItem {
Delegates.RoundedItemDelegate {
id: devtoolsButton
icon: "tools"
icon.name: "tools"
text: i18n("Open developer tools")
visible: Config.developerTools
Layout.fillWidth: true
onClicked: {
applicationWindow().pageStack.layers.push("qrc:/DevtoolsPage.qml", {room: room}, {title: i18n("Developer Tools")})
roomDrawer.close();
}
}
Kirigami.BasicListItem {
Delegates.RoundedItemDelegate {
id: searchButton
icon: "search"
icon.name: "search"
text: i18n("Search in this room")
Layout.fillWidth: true
onClicked: {
pageStack.pushDialogLayer("qrc:/SearchPage.qml", {
currentRoom: room
@@ -161,19 +177,22 @@ Kirigami.OverlayDrawer {
})
}
}
Kirigami.BasicListItem {
Delegates.RoundedItemDelegate {
id: favouriteButton
icon: room && room.isFavourite ? "rating" : "rating-unrated"
icon.name: room && room.isFavourite ? "rating" : "rating-unrated"
text: room && room.isFavourite ? i18n("Remove room from favorites") : i18n("Make room favorite")
onClicked: room.isFavourite ? room.removeTag("m.favourite") : room.addTag("m.favourite", 1.0)
Layout.fillWidth: true
}
Kirigami.BasicListItem {
Delegates.RoundedItemDelegate {
id: locationsButton
icon: "map-flat"
icon.name: "map-flat"
text: i18n("Show locations for this room")
onClicked: pageStack.pushDialogLayer("qrc:/LocationsPage.qml", {
@@ -181,6 +200,8 @@ Kirigami.OverlayDrawer {
}, {
title: i18nc("Locations on a map", "Locations")
})
Layout.fillWidth: true
}
Kirigami.ListSectionHeader {
@@ -189,6 +210,8 @@ Kirigami.OverlayDrawer {
spacing: 0
visible: !room.isDirectChat()
Layout.fillWidth: true
QQC2.ToolButton {
id: memberSearchToggle
checkable: true
@@ -255,44 +278,62 @@ Kirigami.OverlayDrawer {
clip: true
activeFocusOnTab: true
delegate: Kirigami.BasicListItem {
id: userListItem
delegate: Delegates.RoundedItemDelegate {
id: userDelegate
required property string name
required property string userId
required property string avatar
required property int powerLevel
required property string powerLevelString
implicitHeight: Kirigami.Units.gridUnit * 2
leftPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
label: name
labelItem.textFormat: Text.PlainText
text: name
onClicked: {
userDelegate.highlighted = true;
const popup = userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
room: room,
user: room.getUser(user.id)
})
popup.closed.connect(function() {
userListItem.highlighted = false
})
user: room.getUser(userDelegate.userId)
});
popup.closed.connect(() => {
userDelegate.highlighted = false;
});
if (roomDrawer.modal) {
roomDrawer.close()
roomDrawer.close();
}
popup.open()
popup.open();
}
leading: Kirigami.Avatar {
implicitWidth: height
sourceSize.height: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 2.5
sourceSize.width: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 2.5
source: avatar
name: model.userId
}
contentItem: RowLayout {
KirigamiComponents.Avatar {
implicitWidth: height
sourceSize {
height: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 2.5
width: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 2.5
}
source: userDelegate.avatar
name: userDelegate.userId
trailing: QQC2.Label {
visible: powerLevel > 0
Layout.fillHeight: true
}
text: powerLevelString
color: Kirigami.Theme.disabledTextColor
textFormat: Text.PlainText
wrapMode: Text.NoWrap
QQC2.Label {
text: userDelegate.name
textFormat: Text.PlainText
elide: Text.ElideRight
Layout.fillWidth: true
}
QQC2.Label {
visible: userDelegate.powerLevel > 0
text: userDelegate.powerLevelString
color: Kirigami.Theme.disabledTextColor
textFormat: Text.PlainText
}
}
}
}
@@ -302,7 +343,7 @@ Kirigami.OverlayDrawer {
onRoomChanged: {
if (loader.active) {
loader.item.userSearchText = ""
loader.item.clearSearch()
loader.item.highlightedUser = -1
}
if (room == null) {

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