From 1994ea634eab69478cfdf1da37cbb9de62dbe595 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Wed, 31 May 2023 03:59:07 +0200 Subject: [PATCH 001/128] Show custom reactions in reaction history fixes #1467 --- resources/qml/MessageView.qml | 55 +++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index 206b9a17..d0ec3214 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -106,21 +106,66 @@ Item { Repeater { model: Settings.recentReactions + visible: room ? room.permissions.canSend(MtxEvent.Reaction) : false + + delegate: AbstractButton { + id: button - delegate: TextButton { required property string modelData - visible: room ? room.permissions.canSend(MtxEvent.Reaction) : false + property color highlightColor: Nheko.colors.highlight + property color buttonTextColor: Nheko.colors.buttonText + property bool showImage: modelData.startsWith("mxc://") + + //Layout.preferredHeight: fontMetrics.height + Layout.alignment: Qt.AlignBottom + + focusPolicy: Qt.NoFocus + width: showImage ? 16 : buttonText.implicitWidth + height: showImage ? 16 : buttonText.implicitHeight + implicitWidth: showImage ? 16 : buttonText.implicitWidth + implicitHeight: showImage ? 16 : buttonText.implicitHeight + + Label { + id: buttonText - Layout.preferredHeight: fontMetrics.height - font.family: Settings.emojiFont + visible: !button.showImage + + anchors.centerIn: parent + padding: 0 + text: button.modelData + color: button.hovered ? button.highlightColor : button.buttonTextColor + font.family: Settings.emojiFont + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + } + + Image { + id: buttonImg + + // Workaround, can't get icon.source working for now... + anchors.fill: parent + source: button.showImage ? (button.modelData.replace("mxc://", "image://MxcImage/") + "?scale") : "" + sourceSize.height: button.height + sourceSize.width: button.width + fillMode: Image.PreserveAspectFit + } + + CursorShape { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + } + + Ripple { + color: Qt.rgba(buttonTextColor.r, buttonTextColor.g, buttonTextColor.b, 0.5) + } - text: modelData onClicked: { room.input.reaction(row.model.eventId, modelData); TimelineManager.focusMessageInput(); } } + } ImageButton { From 76bf255d4b8879ac8739311d35dba647dd4736d2 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 1 Jun 2023 21:26:02 +0200 Subject: [PATCH 002/128] Don't delete uncached messages after edit fixes #1469 --- src/timeline/EventStore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index 84b6dcd4..5cdb372a 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -264,7 +264,8 @@ EventStore::EventStore(std::string room_id, QObject *) auto idx = idToIndex(pending_event_id); events_by_id_.remove({room_id_, pending_event_id}); - events_.remove({room_id_, toInternalIdx(*idx)}); + if (idx) + events_.remove({room_id_, toInternalIdx(*idx)}); } } From eb9a2766b86d9c2a126c149a2981aeeb36383643 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:30 +0000 Subject: [PATCH 003/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_eo.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_eo.ts b/resources/langs/nheko_eo.ts index 704da4a2..c87e169a 100644 --- a/resources/langs/nheko_eo.ts +++ b/resources/langs/nheko_eo.ts @@ -1394,11 +1394,6 @@ Vi povas aldoni noton, pri kial oni akceptu vian frapadon: InputBar - - - Select a file - Elektu dosieron - All Files (*) From d386b3b87461fe64fceb62385cd11fb5d16b4b20 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:30 +0000 Subject: [PATCH 004/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_es.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_es.ts b/resources/langs/nheko_es.ts index 1f88c958..d5585db7 100644 --- a/resources/langs/nheko_es.ts +++ b/resources/langs/nheko_es.ts @@ -1392,11 +1392,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - Seleccionar un archivo - All Files (*) From b16867e33710072e15fec9259437a0fbbaa0b248 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:30 +0000 Subject: [PATCH 005/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_et.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_et.ts b/resources/langs/nheko_et.ts index 2221d7ed..d8080eb7 100644 --- a/resources/langs/nheko_et.ts +++ b/resources/langs/nheko_et.ts @@ -1393,11 +1393,6 @@ Kui soovid, siis võid lisada ka selgituse, miks peaks sinu koputusele reageerim InputBar - - - Select a file - Vali fail - All Files (*) From 9d8275f5185e80caf24a2a0f3ad1e1db9273861f Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:30 +0000 Subject: [PATCH 006/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_nl.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_nl.ts b/resources/langs/nheko_nl.ts index 8b78215a..49dadbb3 100644 --- a/resources/langs/nheko_nl.ts +++ b/resources/langs/nheko_nl.ts @@ -1393,11 +1393,6 @@ Je kan optioneel hier een reden invoeren dat je aanklopt: InputBar - - - Select a file - Selecteer een bestand - All Files (*) From efff9149d355e1fcabf866049f9fbef696370504 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:30 +0000 Subject: [PATCH 007/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_fi.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_fi.ts b/resources/langs/nheko_fi.ts index 1213d13c..08c88899 100644 --- a/resources/langs/nheko_fi.ts +++ b/resources/langs/nheko_fi.ts @@ -1393,11 +1393,6 @@ Voit antaa valinnaisen syyn muiden hyväksyäkseen koputuksesi: InputBar - - - Select a file - Valitse tiedosto - All Files (*) From fd734f7e654a79624176520d9c07a1e979d3a010 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:30 +0000 Subject: [PATCH 008/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Translated using Weblate (French) Currently translated at 70.0% (660 of 942 strings) Translated using Weblate (French) Currently translated at 70.0% (660 of 942 strings) Translated using Weblate (French) Currently translated at 70.0% (660 of 942 strings) Translated using Weblate (French) Currently translated at 70.0% (660 of 942 strings) Co-authored-by: CB Co-authored-by: Mayeul Cantan Co-authored-by: Mohamad Damaj Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 89 ++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index 2d71d13b..ca74be81 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -96,7 +96,7 @@ Add - Ajouter + Ajouter @@ -229,7 +229,7 @@ Confirm logout - + Confirmer la déconnexion @@ -239,7 +239,7 @@ Failed to open database, logging out! - Impossible d'ouvrir la base de données, déconnexion ! + Impossible d'ouvrir la base de données, déconnexion ! @@ -249,7 +249,7 @@ Do you really want to knock on %1? You may optionally provide a reason for others to accept your knock: - Voulez-vous vraiment toquer à %1 ? Vous pouvez fournir une raison aux autres de l'accepter : + Voulez-vous vraiment frapper à %1 ? Vous pouvez donner une raison aux membres actuels de vous accepter : @@ -275,7 +275,7 @@ Do you really want to invite %1 (%2)? - Voulez-vous vraiment inviter %1 (%2) ? + Voulez-vous vraiment inviter %1 (%2) ? @@ -305,7 +305,7 @@ Do you really want to unban %1 (%2)? - Voulez-vous vraiment annuler le bannissement de %1 (%2) ? + Voulez-vous vraiment annuler le bannissement de %1 (%2) ? @@ -325,14 +325,16 @@ Cache migration failed! - Échec de la migration du cache ! + Échec de la migration du cache ! Because of the following reason Nheko wants to drop you to the login page: %1 If you think this is a mistake, you can close Nheko instead to possibly recover your encryption keys. After you have been dropped to the login page, you can sign in again using your usual methods. - + Nheko veut vous renvoyer à la page de connexion pour cette raison : +%1 +Si vous pensez qu'il s'agit d'une erreur, vous pouvez plutôt fermer Nheko pour essayer de récupérer vos clés de chiffrement. De retour à la page de connexion, vous pourrez vous reconnecter par vos méthodes habituelles. @@ -381,7 +383,7 @@ You may optionally provide a reason for others to accept your knock: Failed to remove invite: %1 - Impossible de supprimer l'invitation : %1 + Impossible de supprimer l'invitation : %1 @@ -406,7 +408,7 @@ You may optionally provide a reason for others to accept your knock: Failed to kick %1 from %2: %3 - Échec de l'expulsion de %1 de %2  : %3 + Échec de l'expulsion de %1 de %2  : %3 @@ -804,7 +806,7 @@ You may optionally provide a reason for others to accept your knock: %n member(s) - + %n membre %n membres @@ -964,17 +966,17 @@ You may optionally provide a reason for others to accept your knock: Please verify the following digits. You should see the same numbers on both sides. If they differ, please press 'They do not match!' to abort verification! - Veuillez vérifier les chiffres suivants. Vous devriez voir les mêmes chiffres des deux côtés. Si ceux-ci diffèrent, veuillez choisir « Ils sont différents ! » pour annuler la vérification ! + Veuillez vérifier les chiffres suivants. Vous devriez voir les mêmes chiffres des deux côtés. Si ceux-ci diffèrent, veuillez choisir « Ils sont différents ! » pour annuler la vérification ! They do not match! - Ils sont différents ! + Ils sont différents ! They match! - Ils sont identiques ! + Ils sont identiques ! @@ -1035,7 +1037,7 @@ You may optionally provide a reason for others to accept your knock: Please verify the following emoji. You should see the same emoji on both sides. If they differ, please press 'They do not match!' to abort verification! - Veuillez vérifier les émoji suivants. Vous devriez voir les mêmes émoji des deux côtés. S'ils diffèrent, veuillez choisir « Ils sont différents ! » pour annuler la vérification ! + Veuillez vérifier les émoji suivants. Vous devriez voir les mêmes émoji des deux côtés. S'ils diffèrent, veuillez choisir « Ils sont différents ! » pour annuler la vérification ! @@ -1045,12 +1047,12 @@ You may optionally provide a reason for others to accept your knock: They do not match! - Ils sont différents ! + Ils sont différents ! They match! - Ils sont identiques ! + Ils sont identiques ! @@ -1114,7 +1116,7 @@ You may optionally provide a reason for others to accept your knock: This message is not encrypted! - Ce message n'est pas chiffré ! + Ce message n'est pas chiffré ! @@ -1147,7 +1149,7 @@ You may optionally provide a reason for others to accept your knock: Key mismatch detected! - Clés non correspondantes détectées ! + Clés non correspondantes détectées ! @@ -1162,7 +1164,7 @@ You may optionally provide a reason for others to accept your knock: Verification messages received out of order! - Messages de vérification reçus dans le désordre ! + Messages de vérification reçus dans le désordre ! @@ -1390,11 +1392,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - Sélectionnez un fichier - All Files (*) @@ -1543,7 +1540,7 @@ Example: https://server.my:8787 You have entered an invalid Matrix ID e.g @joe:matrix.org - Vous avez entré un identifiant Matrix invalide exemple correct : @moi:monserveur.example.com) + Vous avez entré un identifiant Matrix invalide exemple correct : @moi:monserveur.example.com) @@ -1626,12 +1623,12 @@ Example: https://server.my:8787 A call is in progress. Log out? - Un appel est en cours. Se déconnecter ? + Un appel est en cours. Se déconnecter ? Are you sure you want to log out? - Êtes-vous certain de vouloir vous déconnecter ? + Êtes-vous certain de vouloir vous déconnecter ? @@ -2041,7 +2038,7 @@ Example: https://server.my:8787 Place a call to %1? - Appeler %1 ? + Appeler %1 ? @@ -3174,17 +3171,17 @@ Veuillez noter qu'il ne pourra plus être désactivé par la suite. Share desktop with %1? - Partager le bureau avec %1  ? + Partager le bureau avec %1  ? Window: - Fenêtre : + Fenêtre : Frame rate: - Fréquence d'images : + Fréquence d'images : @@ -3233,7 +3230,7 @@ Veuillez noter qu'il ne pourra plus être désactivé par la suite. Nheko could not connect to the secure storage to save encryption secrets to. This can have multiple reasons. Check if your D-Bus service is running and you have configured a service like KWallet, Gnome Keyring, KeePassXC or the equivalent for your platform. If you are having trouble, feel free to open an issue here: https://github.com/Nheko-Reborn/nheko/issues - Nheko n'a pas pu se connecter au stockage sécurisé afin d'y sauvegarder les clés de chiffrement. Cela peut avoir différentes causes. Vérifiez si votre service D-Bus est lancé, et si vous avez configuré un service tel que KWallet ; Gnome Keyring ; KeePassXC ou l'équivalent pour votre système. Si vous n'arrivez pas à résoudre le problème, n'hésitez pas à nous en faire part ici : https ://github.com/Nheko-Reborn/nheko/issues + Nheko n'a pas pu se connecter au stockage sécurisé afin d'y sauvegarder les clés de chiffrement. Cela peut avoir différentes causes. Vérifiez si votre service D-Bus est lancé, et si vous avez configuré un service tel que KWallet ; Gnome Keyring ; KeePassXC ou l'équivalent pour votre système. Si vous n'arrivez pas à résoudre le problème, n'hésitez pas à nous en faire part ici : https ://github.com/Nheko-Reborn/nheko/issues @@ -3241,7 +3238,7 @@ Veuillez noter qu'il ne pourra plus être désactivé par la suite. This is your recovery key. You will need it to restore access to your encrypted messages and verification keys. Keep this safe. Don't share it with anyone and don't lose it! Do not pass go! Do not collect $200! - Ceci est votre clé de récupération. Vous en aurez besoin afin de restaurer l'accès à vos messages chiffrés et à vos clés de vérification. Gardez cette clé en sûreté. Ne la partagez pas avec qui que ce soit et ne la perdez pas ! Ne passez pas par la case départ et ne recevez pas 20 000 francs ! + Ceci est votre clé de récupération. Vous en aurez besoin afin de restaurer l'accès à vos messages chiffrés et à vos clés de vérification. Gardez cette clé en sûreté. Ne la partagez pas avec qui que ce soit et ne la perdez pas ! Ne passez pas par la case départ et ne recevez pas 20 000 francs ! @@ -3262,8 +3259,8 @@ Veuillez noter qu'il ne pourra plus être désactivé par la suite. Hello and welcome to Matrix! It seems like you are new. Before you can securely encrypt your messages, we need to setup a few small things. You can either press accept immediately or adjust a few basic options. We also try to explain a few of the basics. You can skip those parts, but they might prove to be helpful! - Bonjour et bienvenue sur le réseau Matrix ! -Il semblerait que ce soit votre première fois ici. Avant de pouvoir chiffrer vos messages de manière sécurisée, nous devons configurer quelques détails. Vous pouvez soit accepter immédiatement, soit ajuster quelques options basiques. Nous essayons également d'expliquer le fonctionnement de certains mécanismes. Vous pouvez sauter ces étapes, mais celles-ci pourraient se montrer utiles par la suite ! + Bonjour et bienvenue sur le réseau Matrix ! +Il semblerait que ce soit votre première fois ici. Avant de pouvoir chiffrer vos messages de manière sécurisée, nous devons configurer quelques détails. Vous pouvez soit accepter immédiatement, soit ajuster quelques options basiques. Nous essayons également d'expliquer le fonctionnement de certains mécanismes. Vous pouvez sauter ces étapes, mais celles-ci pourraient se montrer utiles par la suite ! @@ -3293,17 +3290,17 @@ Si vous choisissez de vérifier, vous aurez besoin de l'autre appareil. Si Failed to create keys for cross-signing! - Échec de la création des clés pour l'auto-vérification (cross-signing) ! + Échec de la création des clés pour l'auto-vérification (cross-signing) ! Failed to create keys for online key backup! - Échec de la création de clés pour la sauvegarde en ligne ! + Échec de la création de clés pour la sauvegarde en ligne ! Failed to create keys for secure server side secret storage! - Échec de la création des clés pour le stockage sécurisé côté serveur ! + Échec de la création des clés pour le stockage sécurisé côté serveur ! @@ -3313,7 +3310,7 @@ Si vous choisissez de vérifier, vous aurez besoin de l'autre appareil. Si Encryption setup failed: %1 - Échec de la configuration du chiffrement : %1 + Échec de la configuration du chiffrement : %1 @@ -3426,7 +3423,7 @@ Si vous choisissez de vérifier, vous aurez besoin de l'autre appareil. Si Verification successful! Both sides verified their devices! - Vérification réussie ! Les deux côtés ont vérifié leur appareil ! + Vérification réussie ! Les deux côtés ont vérifié leur appareil ! @@ -3446,7 +3443,7 @@ Si vous choisissez de vérifier, vous aurez besoin de l'autre appareil. Si Failed to encrypt event, sending aborted! - Échec du chiffrement de l'évènement, envoi abandonné ! + Échec du chiffrement de l'évènement, envoi abandonné ! @@ -3826,7 +3823,7 @@ Raison : %4 %1 left after having already left! This is a leave event after the user already left and shouldn't happen apart from state resets - %1 a quitté le salon après l'avoir déjà quitté ! + %1 a quitté le salon après l'avoir déjà quitté ! @@ -4863,17 +4860,17 @@ This setting will take effect upon restart. Waiting for other side to accept the verification request. - Attente que le correspondant accepte la demande de vérification. + Attente d'acceptation de la demande de vérification par le correspondant. Waiting for other side to continue the verification process. - Attente que le correspondant poursuive le processus de vérification. + Attente de la poursuite du processus de vérification par le correspondant. Waiting for other side to complete the verification process. - Attente que le correspondant termine le processus de vérification. + Attente de la fin du processus de vérification par le correspondant. From 35521714a661d2e2430129f44c600b56ea53945d Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 009/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_hu.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_hu.ts b/resources/langs/nheko_hu.ts index d1a3f5e7..803dc2fe 100644 --- a/resources/langs/nheko_hu.ts +++ b/resources/langs/nheko_hu.ts @@ -1388,11 +1388,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - Fájl kiválasztása - All Files (*) From 4ddd6f799dd1873a1cd2e48bd744a51ce214f889 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 010/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_pl.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_pl.ts b/resources/langs/nheko_pl.ts index cfd22a8f..435cfe24 100644 --- a/resources/langs/nheko_pl.ts +++ b/resources/langs/nheko_pl.ts @@ -1392,11 +1392,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - Wybierz plik - All Files (*) From 656a5c1e88ef954b236d56cc57f42be0f0b40221 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 011/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_id.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_id.ts b/resources/langs/nheko_id.ts index 2b6dcd2c..2906a3c9 100644 --- a/resources/langs/nheko_id.ts +++ b/resources/langs/nheko_id.ts @@ -1391,11 +1391,6 @@ Kamu dapat memberikan alasan untuk orang lain untuk menerima ketukanmu: InputBar - - - Select a file - Pilih sebuah file - All Files (*) From 4a825b00ad4e33346140e7d81db22fa43d93291e Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 012/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_pt_BR.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_pt_BR.ts b/resources/langs/nheko_pt_BR.ts index 53a9b9f1..43ae3f0b 100644 --- a/resources/langs/nheko_pt_BR.ts +++ b/resources/langs/nheko_pt_BR.ts @@ -1390,11 +1390,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - - All Files (*) From c6079bcf3bbca4550cd77940f95aed5d4d11fc46 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 013/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_pt_PT.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_pt_PT.ts b/resources/langs/nheko_pt_PT.ts index 59221684..e1b86e2c 100644 --- a/resources/langs/nheko_pt_PT.ts +++ b/resources/langs/nheko_pt_PT.ts @@ -1390,11 +1390,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - Selecionar um ficheiro - All Files (*) From 621f70e4dfc3ef844f28cab7fab697f7171d8451 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 014/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_ro.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_ro.ts b/resources/langs/nheko_ro.ts index a90dfda7..59702740 100644 --- a/resources/langs/nheko_ro.ts +++ b/resources/langs/nheko_ro.ts @@ -1392,11 +1392,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - - All Files (*) From 03f61a4437aaa672624965fef440057554ca4d26 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 015/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_ie.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_ie.ts b/resources/langs/nheko_ie.ts index c22fbb0e..4358c218 100644 --- a/resources/langs/nheko_ie.ts +++ b/resources/langs/nheko_ie.ts @@ -1390,11 +1390,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - - All Files (*) From d04c89e87f9c43ae7724a2486c8e360dfa95197a Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 016/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_it.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_it.ts b/resources/langs/nheko_it.ts index d2144e3b..c6710f2a 100644 --- a/resources/langs/nheko_it.ts +++ b/resources/langs/nheko_it.ts @@ -1390,11 +1390,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - Seleziona un file - All Files (*) From 8a37bed6e117b3e270407fa4414b81af2425fc52 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 017/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_ru.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_ru.ts b/resources/langs/nheko_ru.ts index 27192dd3..444a6f38 100644 --- a/resources/langs/nheko_ru.ts +++ b/resources/langs/nheko_ru.ts @@ -1392,11 +1392,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - Выберите файл - All Files (*) From 567ef806aa1901285b8af11a0417396da9eef4ca Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 018/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_ja.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_ja.ts b/resources/langs/nheko_ja.ts index 60f80848..55cf649f 100644 --- a/resources/langs/nheko_ja.ts +++ b/resources/langs/nheko_ja.ts @@ -1388,11 +1388,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - ファイルを選択 - All Files (*) From 9a5b1b9219ac37c3f4799c73da4db3256eda3044 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:31 +0000 Subject: [PATCH 019/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_ml.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_ml.ts b/resources/langs/nheko_ml.ts index ece960ad..0a912b3a 100644 --- a/resources/langs/nheko_ml.ts +++ b/resources/langs/nheko_ml.ts @@ -1390,11 +1390,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - ഒരു ഫയൽ തിരഞ്ഞെടുക്കുക - All Files (*) From 81d74f41be65506197f51c99e5bdcd0b35f76108 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 020/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_si.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_si.ts b/resources/langs/nheko_si.ts index e4ba7628..2254bf24 100644 --- a/resources/langs/nheko_si.ts +++ b/resources/langs/nheko_si.ts @@ -1390,11 +1390,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - - All Files (*) From 98237908701531712cb67ebbbcff008ceca87224 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 021/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_sr_Latn.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_sr_Latn.ts b/resources/langs/nheko_sr_Latn.ts index c8b54d06..c77ee762 100644 --- a/resources/langs/nheko_sr_Latn.ts +++ b/resources/langs/nheko_sr_Latn.ts @@ -1392,11 +1392,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - - All Files (*) From d886b5d52dd7be537de7514a3a9f4f55a7571532 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 022/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_sv.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_sv.ts b/resources/langs/nheko_sv.ts index 9319efa4..ddb64aef 100644 --- a/resources/langs/nheko_sv.ts +++ b/resources/langs/nheko_sv.ts @@ -1390,11 +1390,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - Välj en fil - All Files (*) From ba33827c0b5e7146ffcb0d61cd3d204204836f73 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 023/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_ca.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_ca.ts b/resources/langs/nheko_ca.ts index 035978f3..8de8ee24 100644 --- a/resources/langs/nheko_ca.ts +++ b/resources/langs/nheko_ca.ts @@ -1390,11 +1390,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - - All Files (*) From 185be17166be3c577b4d5cb8b8f75423f940445a Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 024/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_uk.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_uk.ts b/resources/langs/nheko_uk.ts index 99315c8a..72ff3953 100644 --- a/resources/langs/nheko_uk.ts +++ b/resources/langs/nheko_uk.ts @@ -1395,11 +1395,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - Виберіть файл - All Files (*) From e1f61d14e76bcfa04997594484046caeb45cab5f Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 025/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_vi.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_vi.ts b/resources/langs/nheko_vi.ts index 6d419b3b..f1525f92 100644 --- a/resources/langs/nheko_vi.ts +++ b/resources/langs/nheko_vi.ts @@ -1388,11 +1388,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - - All Files (*) From 1da48a587dfe956ef4658b69989f24e2ac0317e8 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 026/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_cs.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_cs.ts b/resources/langs/nheko_cs.ts index 9c4af145..87ea404f 100644 --- a/resources/langs/nheko_cs.ts +++ b/resources/langs/nheko_cs.ts @@ -1392,11 +1392,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - - All Files (*) From 9c55cb222beabfc2c6ecb57511259fe6d21d976b Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 027/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_de.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_de.ts b/resources/langs/nheko_de.ts index 24cd3f7b..c60c97e9 100644 --- a/resources/langs/nheko_de.ts +++ b/resources/langs/nheko_de.ts @@ -1393,11 +1393,6 @@ Du kannst zusätzlich einen Grund angeben, warum die anderen dein Anklopfen anne InputBar - - - Select a file - Datei auswählen - All Files (*) From a9d88951adc80ff3a7377c41cd756552677a3ae9 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 028/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_el.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_el.ts b/resources/langs/nheko_el.ts index 07c89a3e..b3e33751 100644 --- a/resources/langs/nheko_el.ts +++ b/resources/langs/nheko_el.ts @@ -1390,11 +1390,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - Διάλεξε ένα αρχείο - All Files (*) From a7f1e31979ce13fa172e3d78905e7b023afdf5f8 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 029/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_tr.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_tr.ts b/resources/langs/nheko_tr.ts index 71fa01a2..573ff38c 100644 --- a/resources/langs/nheko_tr.ts +++ b/resources/langs/nheko_tr.ts @@ -1393,11 +1393,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - - All Files (*) From 326e6c2d933b1fd719b892347234444891fdc938 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:08:32 +0000 Subject: [PATCH 030/128] Update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Weblate Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ Translation: Nheko/nheko --- resources/langs/nheko_zh_CN.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/resources/langs/nheko_zh_CN.ts b/resources/langs/nheko_zh_CN.ts index e6c3d4be..f392c51f 100644 --- a/resources/langs/nheko_zh_CN.ts +++ b/resources/langs/nheko_zh_CN.ts @@ -1391,11 +1391,6 @@ You may optionally provide a reason for others to accept your knock: InputBar - - - Select a file - 选择一个文件 - All Files (*) From 075b865a099902adaae9028cf9cab96dcf154c17 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:12:04 +0000 Subject: [PATCH 031/128] Translated using Weblate (French) Currently translated at 70.0% (660 of 942 strings) Co-authored-by: CB Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index ca74be81..1afeb5d7 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -339,7 +339,7 @@ Si vous pensez qu'il s'agit d'une erreur, vous pouvez plutôt fer Migrating the cache to the current version failed. This can have different reasons. Please open an issue at https://github.com/Nheko-Reborn/nheko and try to use an older version in the meantime. Alternatively you can try deleting the cache manually. - + La migration du cache vers la nouvelle version a échoué. Cela peut être pour diverses raisons. Merci d'ouvrir un rapport de bug à https://github.com/Nheko-Reborn/nheko et essayez d'utiliser une version précédente entretemps. Une autre option est d'effacer manuellement le cache. From cb18bccbcce00b1c555bef12ab9df07c8af68dea Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:18:55 +0000 Subject: [PATCH 032/128] Translated using Weblate (French) Currently translated at 70.8% (667 of 942 strings) Translated using Weblate (French) Currently translated at 70.8% (667 of 942 strings) Co-authored-by: CB Co-authored-by: Mayeul Cantan Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index 1afeb5d7..c55434b9 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -339,7 +339,7 @@ Si vous pensez qu'il s'agit d'une erreur, vous pouvez plutôt fer Migrating the cache to the current version failed. This can have different reasons. Please open an issue at https://github.com/Nheko-Reborn/nheko and try to use an older version in the meantime. Alternatively you can try deleting the cache manually. - La migration du cache vers la nouvelle version a échoué. Cela peut être pour diverses raisons. Merci d'ouvrir un rapport de bug à https://github.com/Nheko-Reborn/nheko et essayez d'utiliser une version précédente entretemps. Une autre option est d'effacer manuellement le cache. + La migration du cache vers la version actuelle a échoué. Plusieurs causes sont possibles. Merci d'ouvrir un rapport d'anomalie sur https://github.com/Nheko-Reborn/nheko et essayez d'utiliser une version antérieure entretemps. Vous pouvez également tenter d'effacer le cache manuellement. @@ -373,7 +373,8 @@ Si vous pensez qu'il s'agit d'une erreur, vous pouvez plutôt fer You failed to join %1. You can try to knock so that others can invite you in. Do you want to do so? You may optionally provide a reason for others to accept your knock: - + Vous n'avez pas pu rejoindre %1. Vous pouvez essayer de frapper au salon afin que les autres membres vous invitent. Voulez-vous le faire ? +Vous pouvez éventuellement fournir une raison afin que les membres acceptent votre requête : @@ -431,27 +432,27 @@ You may optionally provide a reason for others to accept your knock: /me <message> - + /me <message> /react <text> - + /react <texte> /part [reason] - + /part [raison] /leave [reason] - + /leave [raison] /roomnick <displayname> - + /roomnick <nomaffiché> @@ -567,7 +568,7 @@ You may optionally provide a reason for others to accept your knock: Leave a room. Reason is optional. - + Quitte un salon. La raison est optionnelle. From 8185d4bc2c7d949373ffb0834811bf8791411b77 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:20:29 +0000 Subject: [PATCH 033/128] Translated using Weblate (French) Currently translated at 70.9% (668 of 942 strings) Co-authored-by: CB Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index c55434b9..45750083 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -573,7 +573,7 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Invite a user into the current room. Reason is optional. - + Invite un utilisateur au salon courant. La raison est optionnelle. From 79c00c8c5adff66f94a744cb84e3021be007cda7 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:21:01 +0000 Subject: [PATCH 034/128] Translated using Weblate (French) Currently translated at 71.0% (669 of 942 strings) Translated using Weblate (French) Currently translated at 71.0% (669 of 942 strings) Co-authored-by: CB Co-authored-by: Mayeul Cantan Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index 45750083..4695b4ac 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -573,12 +573,12 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Invite a user into the current room. Reason is optional. - Invite un utilisateur au salon courant. La raison est optionnelle. + Invite un utilisateur dans le salon actuel. La raison est optionnelle. Kick a user from the current room. Reason is optional. - + Exclue un utilisateur du salon courant. La raison est optionnelle. From 6deded09e2f3c55a71495f4f9e97ef6d370e0bbd Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:21:54 +0000 Subject: [PATCH 035/128] Translated using Weblate (French) Currently translated at 71.1% (670 of 942 strings) Translated using Weblate (French) Currently translated at 71.1% (670 of 942 strings) Co-authored-by: CB Co-authored-by: Mayeul Cantan Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index 4695b4ac..06c063c7 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -578,12 +578,12 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Kick a user from the current room. Reason is optional. - Exclue un utilisateur du salon courant. La raison est optionnelle. + Expulse un utilisateur du salon actuel. La raison est optionnelle. Ban a user from the current room. Reason is optional. - + Banni un utilisateur du salon courant. La raison est optionnelle. From 02519ccd405895c2dab973bfb6c2f06309b05b5f Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:22:50 +0000 Subject: [PATCH 036/128] Translated using Weblate (French) Currently translated at 71.2% (671 of 942 strings) Translated using Weblate (French) Currently translated at 71.2% (671 of 942 strings) Co-authored-by: CB Co-authored-by: Mayeul Cantan Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index 06c063c7..d194bd8c 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -583,12 +583,12 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Ban a user from the current room. Reason is optional. - Banni un utilisateur du salon courant. La raison est optionnelle. + Bannit un utilisateur du salon actuel. La raison est optionnelle. Unban a user in the current room. Reason is optional. - + Annule le bannissement d'un utilisateur du salon courant. La raison est optionnelle. From 27f3cfa2a008747a7b0bac75bf43c5d384391542 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:25:41 +0000 Subject: [PATCH 037/128] Translated using Weblate (French) Currently translated at 71.3% (672 of 942 strings) Translated using Weblate (French) Currently translated at 71.3% (672 of 942 strings) Co-authored-by: CB Co-authored-by: Mayeul Cantan Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index d194bd8c..88dccc1c 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -588,12 +588,12 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Unban a user in the current room. Reason is optional. - Annule le bannissement d'un utilisateur du salon courant. La raison est optionnelle. + Dé-bannit un utilisateur du salon actuel. La raison est optionnelle. Redact an event or all locally cached messages of a user. - + Retire un évènement ou tous les messages en cache d'un utilisateur. From fb3a050dd0970ee587aa8249ebdd8b679b4305ef Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:29:41 +0000 Subject: [PATCH 038/128] Translated using Weblate (French) Currently translated at 72.1% (680 of 942 strings) Translated using Weblate (French) Currently translated at 72.1% (680 of 942 strings) Co-authored-by: CB Co-authored-by: Mayeul Cantan Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index 88dccc1c..3f680163 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -593,32 +593,32 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Redact an event or all locally cached messages of a user. - Retire un évènement ou tous les messages en cache d'un utilisateur. + Efface un évènement ou tous les messages connus (présents dans la base de données locale) d'un utilisateur. Change your displayname in this room. - + Change votre nom affiché dans ce salon. ¯\_(ツ)_/¯ with an optional message. - + ¯\_(ツ)_/¯ avec un message optionnel. (╯°□°)╯︵ ┻━┻ - + (╯°□°)╯︵ ┻━┻ ┯━┯╭( º _ º╭) - + ┯━┯╭( º _ º╭) ノ┬─┬ノ ︵ ( \o°o)\ - + ノ┬─┬ノ ︵ ( \o°o)\ @@ -653,17 +653,17 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Send a message in rainbow colors. - + Envoie un message aux couleurs de l'arc-en-ciel. Send /me in rainbow colors. - + Envoie /me aux couleurs de l'arc-en-ciel. Send a bot message. - + Envoie un message de robot. From 296efbe518b9710550175e080a5e14fef0f71cbd Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:31:44 +0000 Subject: [PATCH 039/128] Translated using Weblate (French) Currently translated at 72.7% (685 of 942 strings) Translated using Weblate (French) Currently translated at 72.7% (685 of 942 strings) Co-authored-by: CB Co-authored-by: Mayeul Cantan Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index 3f680163..c9028a4b 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -668,17 +668,17 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Send a bot message in rainbow colors. - + Envoie un message de robot aux couleurs de l'arc-en-ciel. Send a message with confetti. - + Envoie un message avec des confettis. Send a message in rainbow colors with confetti. - + Envoie des confettis avec un message aux couleurs de l'arc-en-ciel. @@ -701,12 +701,12 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Do not show notification counts for this community or tag. - + Ne pas afficher le compteur de notifications pour cette communauté ou cette étiquette. Hide rooms with this tag or from this community by default. - + Cache par défaut les salons avec ce label ou provenant de cette communauté. From d95d2fcaa9e3b8ab47275d2bf56e5a7ebddd37e7 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jun 2023 19:33:58 +0000 Subject: [PATCH 040/128] Translated using Weblate (French) Currently translated at 72.8% (686 of 942 strings) Translated using Weblate (French) Currently translated at 72.8% (686 of 942 strings) Co-authored-by: CB Co-authored-by: Mayeul Cantan Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index c9028a4b..cb11e3d3 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -706,7 +706,7 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Hide rooms with this tag or from this community by default. - Cache par défaut les salons avec ce label ou provenant de cette communauté. + Cache par défaut les salons avec cette étiquette ou provenant de cette communauté. @@ -774,7 +774,7 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Failed to update community: %1 - + Echec de mise à jour de la communauté : %1 From 0ac46ea2099ac64e96a6f5b7f62802e1163b0d31 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 1 Jun 2023 22:09:54 +0200 Subject: [PATCH 041/128] Select Qt6 in cmake --- CMakeLists.txt | 51 ++++++++++++++++++++-------------------- cmake/Translations.cmake | 8 +++---- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7c02ffb..a9478c97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ option(USE_BUNDLED_OPENSSL "Use the bundled version of OpenSSL." OFF) option(USE_BUNDLED_MTXCLIENT "Use the bundled version of the Matrix Client library." ${HUNTER_ENABLED}) option(USE_BUNDLED_LMDB "Use the bundled version of lmdb." ${HUNTER_ENABLED}) option(USE_BUNDLED_LMDBXX "Use the bundled version of lmdb++." ${HUNTER_ENABLED}) -option(USE_BUNDLED_QTKEYCHAIN "Use the bundled version of Qt5Keychain." ${HUNTER_ENABLED}) +option(USE_BUNDLED_QTKEYCHAIN "Use the bundled version of Qt6Keychain." ${HUNTER_ENABLED}) option(USE_BUNDLED_COEURL "Use a bundled version of the Curl wrapper" ${HUNTER_ENABLED}) option(USE_BUNDLED_LIBEVENT "Use the bundled version of libevent." ${HUNTER_ENABLED}) @@ -239,16 +239,17 @@ endif() # # Discover Qt dependencies. # -find_package(Qt5 5.15 COMPONENTS Core Widgets LinguistTools Concurrent Svg Multimedia Qml QuickControls2 QuickWidgets REQUIRED) -find_package(Qt5QuickCompiler) -find_package(Qt5DBus) +find_package(Qt6 6.5 COMPONENTS Core Widgets LinguistTools Svg Multimedia Qml QuickControls2 REQUIRED) +#find_package(Qt6QuickCompiler) +find_package(Qt6DBus) if (USE_BUNDLED_QTKEYCHAIN) include(FetchContent) + set(BUILD_WITH_QT6 ON) FetchContent_Declare( - qt5keychain + qt6keychain GIT_REPOSITORY https://github.com/frankosterfeld/qtkeychain.git - GIT_TAG v0.13.1 + GIT_TAG v0.14.0 ) if (BUILD_SHARED_LIBS) set(QTKEYCHAIN_STATIC OFF CACHE INTERNAL "") @@ -256,21 +257,21 @@ if (USE_BUNDLED_QTKEYCHAIN) set(QTKEYCHAIN_STATIC ON CACHE INTERNAL "") endif() set(BUILD_TEST_APPLICATION OFF CACHE INTERNAL "") - FetchContent_MakeAvailable(qt5keychain) + FetchContent_MakeAvailable(qt6keychain) else() - find_package(Qt5Keychain REQUIRED) + find_package(Qt6Keychain REQUIRED) endif() if (APPLE) - find_package(Qt5MacExtras REQUIRED) + find_package(Qt6MacExtras REQUIRED) endif(APPLE) -if (Qt5Widgets_FOUND) - if (Qt5Widgets_VERSION VERSION_LESS 5.15.0) - message(STATUS "Qt version ${Qt5Widgets_VERSION}") - message(WARNING "Minimum supported Qt5 version is 5.15!") +if (Qt6Widgets_FOUND) + if (Qt6Widgets_VERSION VERSION_LESS 6.5.0) + message(STATUS "Qt version ${Qt6Widgets_VERSION}") + message(WARNING "Minimum supported Qt6 version is 6.5!") endif() -endif(Qt5Widgets_FOUND) +endif(Qt6Widgets_FOUND) set(CMAKE_INCLUDE_CURRENT_DIR ON) if(NOT MSVC) @@ -690,15 +691,15 @@ set_target_properties(nheko AUTOMOC ON) if(APPLE) - target_link_libraries (nheko PRIVATE Qt5::MacExtras) + target_link_libraries (nheko PRIVATE Qt6::MacExtras) elseif(WIN32) target_compile_definitions(nheko PRIVATE WIN32_LEAN_AND_MEAN) - target_link_libraries (nheko PRIVATE ${NTDLIB} Qt5::WinMain) + target_link_libraries (nheko PRIVATE ${NTDLIB} Qt6::WinMain) if(MSVC) target_compile_options(nheko PUBLIC "/Zc:__cplusplus") endif() else() - target_link_libraries (nheko PRIVATE Qt5::DBus) + target_link_libraries (nheko PRIVATE Qt6::DBus) if (FLATPAK) target_compile_definitions(nheko PRIVATE NHEKO_FLATPAK) endif() @@ -729,7 +730,7 @@ endif() # Fixup bundled keychain include dirs if (USE_BUNDLED_QTKEYCHAIN) - target_include_directories(nheko PRIVATE ${qt5keychain_SOURCE_DIR} ${qt5keychain_BINARY_DIR}) + target_include_directories(nheko PRIVATE ${qt6keychain_SOURCE_DIR} ${qt6keychain_BINARY_DIR}) endif() if (NOT JSON_ImplicitConversions) @@ -744,14 +745,12 @@ target_link_libraries(nheko PRIVATE MatrixClient::MatrixClient cmark::cmark spdlog::spdlog - Qt5::Widgets - Qt5::Svg - Qt5::Concurrent - Qt5::Multimedia - Qt5::Qml - Qt5::QuickControls2 - Qt5::QuickWidgets - qt5keychain + Qt::Widgets + Qt::Svg + Qt::Multimedia + Qt::Qml + Qt::QuickControls2 + qt6keychain nlohmann_json::nlohmann_json lmdbxx::lmdbxx liblmdb::lmdb diff --git a/cmake/Translations.cmake b/cmake/Translations.cmake index 887697a8..9422570d 100644 --- a/cmake/Translations.cmake +++ b/cmake/Translations.cmake @@ -4,8 +4,8 @@ file(GLOB LANG_TS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/resources/langs/*.ts") -qt5_add_translation(QM_SRC ${LANG_TS_SRC}) -qt5_create_translation(${QM_SRC}) +qt_add_translation(QM_SRC ${LANG_TS_SRC}) +qt_create_translation(${QM_SRC}) add_custom_target(LANG_QRC ALL DEPENDS ${QM_SRC}) # Generate a qrc file for the translations @@ -20,9 +20,9 @@ if(NOT EXISTS ${_qrc}) file(APPEND ${_qrc} " \n\n") endif() -qt5_add_resources(LANG_QRC ${_qrc}) +qt_add_resources(LANG_QRC ${_qrc}) if(Qt5QuickCompiler_FOUND AND COMPILE_QML) qtquick_compiler_add_resources(QRC resources/res.qrc) else() - qt5_add_resources(QRC resources/res.qrc) + qt_add_resources(QRC resources/res.qrc) endif() From b518f6902e909b22e1623f96249a3ab1424ced59 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 00:24:26 +0200 Subject: [PATCH 042/128] Make Nheko compile on Qt6 --- CMakeLists.txt | 3 +- src/Cache.cpp | 15 +---- src/ChatPage.cpp | 12 ---- src/CompletionProxyModel.cpp | 2 +- src/GridImagePackModel.cpp | 10 +--- src/InviteesModel.h | 2 +- src/JdenticonProvider.h | 6 +- src/LoginPage.cpp | 7 --- src/MainWindow.cpp | 33 +---------- src/MatrixClient.cpp | 23 -------- src/MxcImageProvider.cpp | 8 +-- src/MxcImageProvider.h | 6 +- src/SingleImagePackModel.cpp | 2 - src/UserSettingsPage.cpp | 20 +++---- src/Utils.cpp | 2 +- src/dbus/NhekoDBusApi.h | 1 - src/emoji/Provider.h | 1 - src/main.cpp | 14 ++--- src/timeline/CommunitiesModel.cpp | 3 - src/timeline/DelegateChooser.cpp | 4 +- src/timeline/DelegateChooser.h | 4 +- src/timeline/EventStore.cpp | 14 ++--- src/timeline/EventStore.h | 9 ++- src/timeline/InputBar.cpp | 86 ++++++---------------------- src/timeline/InputBar.h | 20 ------- src/timeline/RoomlistModel.cpp | 3 +- src/timeline/TimelineModel.cpp | 1 - src/timeline/TimelineModel.h | 4 +- src/timeline/TimelineViewManager.cpp | 2 +- src/timeline/TimelineViewManager.h | 8 --- src/ui/MxcAnimatedImage.cpp | 4 +- src/ui/MxcAnimatedImage.h | 2 +- src/ui/MxcMediaProxy.cpp | 65 +++------------------ src/ui/MxcMediaProxy.h | 13 ++--- src/ui/NhekoGlobalObject.cpp | 28 ++++++--- src/ui/Theme.cpp | 2 - src/voip/CallManager.cpp | 27 +++------ src/voip/ScreenCastPortal.cpp | 1 - src/voip/WebRTCSession.cpp | 6 -- 39 files changed, 110 insertions(+), 363 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9478c97..87eb8474 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,7 +239,7 @@ endif() # # Discover Qt dependencies. # -find_package(Qt6 6.5 COMPONENTS Core Widgets LinguistTools Svg Multimedia Qml QuickControls2 REQUIRED) +find_package(Qt6 6.5 COMPONENTS Core Widgets Gui LinguistTools Svg Multimedia Qml QuickControls2 REQUIRED) #find_package(Qt6QuickCompiler) find_package(Qt6DBus) @@ -747,6 +747,7 @@ target_link_libraries(nheko PRIVATE spdlog::spdlog Qt::Widgets Qt::Svg + Qt::Gui Qt::Multimedia Qt::Qml Qt::QuickControls2 diff --git a/src/Cache.cpp b/src/Cache.cpp index 44f2ecb0..1c29d530 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -93,11 +93,6 @@ static constexpr auto MEGOLM_SESSIONS_DATA_DB("megolm_sessions_data_db"); using CachedReceipts = std::multimap>; using Receipts = std::map>; -Q_DECLARE_METATYPE(RoomMember) -Q_DECLARE_METATYPE(mtx::responses::Timeline) -Q_DECLARE_METATYPE(RoomInfo) -Q_DECLARE_METATYPE(mtx::responses::QueryKeys) - namespace { std::unique_ptr instance_ = nullptr; } @@ -4429,7 +4424,8 @@ Cache::displayName(const QString &room_id, const QString &user_id) static bool isDisplaynameSafe(const std::string &s) { - for (QChar c : QString::fromStdString(s).toStdU32String()) { + for (std::uint32_t cc : QString::fromStdString(s).toStdU32String()) { + auto c = QChar(cc); if (c.isPrint() && !c.isSpace()) return false; } @@ -5293,13 +5289,6 @@ namespace cache { void init(const QString &user_id) { - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType>(); - qRegisterMetaType>(); - qRegisterMetaType>(); - qRegisterMetaType(); - instance_ = std::make_unique(user_id); } diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 8feabfd0..c305a54a 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -36,12 +36,6 @@ static constexpr int CHECK_CONNECTIVITY_INTERVAL = 15'000; static constexpr int RETRY_TIMEOUT = 5'000; static constexpr size_t MAX_ONETIME_KEYS = 50; -Q_DECLARE_METATYPE(std::optional) -Q_DECLARE_METATYPE(std::optional) -Q_DECLARE_METATYPE(mtx::presence::PresenceState) -Q_DECLARE_METATYPE(mtx::secret_storage::AesHmacSha2KeyDescription) -Q_DECLARE_METATYPE(SecretsToDecrypt) - ChatPage::ChatPage(QSharedPointer userSettings, QObject *parent) : QObject(parent) , isConnected_(true) @@ -53,12 +47,6 @@ ChatPage::ChatPage(QSharedPointer userSettings, QObject *parent) instance_ = this; - qRegisterMetaType>(); - qRegisterMetaType>(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - view_manager_ = new TimelineViewManager(callManager_, this); connect(this, diff --git a/src/CompletionProxyModel.cpp b/src/CompletionProxyModel.cpp index 638b5fb4..eea1e6aa 100644 --- a/src/CompletionProxyModel.cpp +++ b/src/CompletionProxyModel.cpp @@ -29,7 +29,7 @@ CompletionProxyModel::CompletionProxyModel(QAbstractItemModel *model, finder.toNextBoundary(); auto end = finder.position(); - auto ref = str.midRef(start, end - start).trimmed(); + auto ref = QStringView(str).mid(start, end - start).trimmed(); if (!ref.isEmpty()) trie_.insert(ref.toUcs4(), id); } while (finder.position() < str.size()); diff --git a/src/GridImagePackModel.cpp b/src/GridImagePackModel.cpp index bd39405e..4260b6d6 100644 --- a/src/GridImagePackModel.cpp +++ b/src/GridImagePackModel.cpp @@ -13,10 +13,6 @@ #include "Cache_p.h" #include "emoji/Provider.h" -Q_DECLARE_METATYPE(StickerImage) -Q_DECLARE_METATYPE(TextEmoji) -Q_DECLARE_METATYPE(SectionDescription) -Q_DECLARE_METATYPE(QList) QString emoji::categoryToName(emoji::Emoji::Category cat) @@ -73,10 +69,6 @@ GridImagePackModel::GridImagePackModel(const std::string &roomId, bool stickers, , room_id(roomId) , columns(stickers ? 3 : 7) { - [[maybe_unused]] static auto id = qRegisterMetaType(); - [[maybe_unused]] static auto id2 = qRegisterMetaType(); - [[maybe_unused]] static auto id3 = qRegisterMetaType(); - [[maybe_unused]] static auto id4 = qRegisterMetaType>(); if (!stickers) { for (const auto &category : { @@ -144,7 +136,7 @@ GridImagePackModel::GridImagePackModel(const std::string &roomId, bool stickers, finder.toNextBoundary(); auto end = finder.position(); - auto ref = str.midRef(start, end - start).trimmed(); + auto ref = QStringView(str).mid(start, end - start).trimmed(); if (!ref.isEmpty()) trie_.insert(ref.toUcs4(), id); } while (finder.position() < str.size()); diff --git a/src/InviteesModel.h b/src/InviteesModel.h index ab8fbdb4..3f417bd1 100644 --- a/src/InviteesModel.h +++ b/src/InviteesModel.h @@ -8,7 +8,7 @@ #include #include -class TimelineModel; +#include "timeline/TimelineModel.h" class Invitee final : public QObject { diff --git a/src/JdenticonProvider.h b/src/JdenticonProvider.h index 5a475ded..b4a9ba62 100644 --- a/src/JdenticonProvider.h +++ b/src/JdenticonProvider.h @@ -54,10 +54,6 @@ public: class JdenticonProvider : -#if QT_VERSION < 0x60000 - public QObject - , -#endif public QQuickAsyncImageProvider { Q_OBJECT @@ -77,7 +73,7 @@ public slots: if (queryStart != -1) { id_ = id.left(queryStart); auto query = id.mid(queryStart + 1); - auto queryBits = query.splitRef('&'); + auto queryBits = QStringView(query).split('&'); for (const auto &b : queryBits) { if (b.startsWith(QStringView(u"radius="))) { diff --git a/src/LoginPage.cpp b/src/LoginPage.cpp index 95b46d04..8d6a69cf 100644 --- a/src/LoginPage.cpp +++ b/src/LoginPage.cpp @@ -19,19 +19,12 @@ #include "SSOHandler.h" #include "UserSettingsPage.h" -Q_DECLARE_METATYPE(LoginPage::LoginMethod) -Q_DECLARE_METATYPE(SSOProvider) - using namespace mtx::identifiers; LoginPage::LoginPage(QObject *parent) : QObject(parent) , inferredServerAddress_() { - [[maybe_unused]] static auto ignored = - qRegisterMetaType("LoginPage::LoginMethod"); - [[maybe_unused]] static auto ignored2 = qRegisterMetaType(); - connect(this, &LoginPage::versionOkCb, this, &LoginPage::versionOk, Qt::QueuedConnection); connect(this, &LoginPage::versionErrorCb, this, &LoginPage::versionError, Qt::QueuedConnection); connect( diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index a8cc66b7..4159006e 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "AliasEditModel.h" #include "BlurhashProvider.h" @@ -63,13 +64,6 @@ #include "dbus/NhekoDBusApi.h" #endif -Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents) -Q_DECLARE_METATYPE(std::vector) -Q_DECLARE_METATYPE(std::vector) -Q_DECLARE_METATYPE(mtx::responses::PublicRoom) -Q_DECLARE_METATYPE(mtx::responses::Profile) -Q_DECLARE_METATYPE(mtx::responses::User) - MainWindow *MainWindow::instance_ = nullptr; MainWindow::MainWindow(QWindow *parent) @@ -138,27 +132,8 @@ MainWindow::MainWindow(QWindow *parent) void MainWindow::registerQmlTypes() { - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType>(); - - qRegisterMetaType>(); - qRegisterMetaType>(); - - qRegisterMetaType(); + + qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject, "im.nheko", 1, @@ -278,8 +253,6 @@ MainWindow::registerQmlTypes() qmlRegisterSingletonInstance("im.nheko", 1, 0, "Settings", userSettings_.data()); - qRegisterMetaType(); - qRegisterMetaType>(); qmlRegisterUncreatableType( "im.nheko", diff --git a/src/MatrixClient.cpp b/src/MatrixClient.cpp index 1452257a..55542a75 100644 --- a/src/MatrixClient.cpp +++ b/src/MatrixClient.cpp @@ -15,18 +15,7 @@ #include "nlohmann/json.hpp" #include -Q_DECLARE_METATYPE(mtx::responses::Login) -Q_DECLARE_METATYPE(mtx::responses::Messages) -Q_DECLARE_METATYPE(mtx::responses::Notifications) -Q_DECLARE_METATYPE(mtx::responses::Rooms) -Q_DECLARE_METATYPE(mtx::responses::Sync) -Q_DECLARE_METATYPE(mtx::responses::StateEvents) -// Q_DECLARE_METATYPE(nlohmann::json) -Q_DECLARE_METATYPE(std::string) -Q_DECLARE_METATYPE(std::vector) -Q_DECLARE_METATYPE(std::vector) -Q_DECLARE_METATYPE(std::set) namespace http { @@ -52,18 +41,6 @@ is_logged_in() void init() { - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - qRegisterMetaType(); - // qRegisterMetaType(); - qRegisterMetaType>(); - qRegisterMetaType>(); - qRegisterMetaType>("std::map"); - qRegisterMetaType>(); } } // namespace http diff --git a/src/MxcImageProvider.cpp b/src/MxcImageProvider.cpp index cb21fa0d..47e0344f 100644 --- a/src/MxcImageProvider.cpp +++ b/src/MxcImageProvider.cpp @@ -24,12 +24,8 @@ QHash infos; -MxcImageProvider::MxcImageProvider(QObject *parent) -#if QT_VERSION < 0x60000 - : QObject(parent) -#else - : QQuickAsyncImageProvider(parent) -#endif +MxcImageProvider::MxcImageProvider() + : QQuickAsyncImageProvider() { auto timer = new QTimer(this); timer->setInterval(std::chrono::hours(1)); diff --git a/src/MxcImageProvider.h b/src/MxcImageProvider.h index 8096a7dc..b67e2f8d 100644 --- a/src/MxcImageProvider.h +++ b/src/MxcImageProvider.h @@ -72,16 +72,12 @@ public: class MxcImageProvider : -#if QT_VERSION < 0x60000 - public QObject - , -#endif public QQuickAsyncImageProvider { Q_OBJECT public: - MxcImageProvider(QObject *parent = nullptr); + MxcImageProvider(); public slots: QQuickImageResponse * diff --git a/src/SingleImagePackModel.cpp b/src/SingleImagePackModel.cpp index 99338f2e..47e11f0e 100644 --- a/src/SingleImagePackModel.cpp +++ b/src/SingleImagePackModel.cpp @@ -20,7 +20,6 @@ #include "timeline/Permissions.h" #include "timeline/TimelineModel.h" -Q_DECLARE_METATYPE(mtx::common::ImageInfo) SingleImagePackModel::SingleImagePackModel(ImagePackInfo pack_, QObject *parent) : QAbstractListModel(parent) @@ -30,7 +29,6 @@ SingleImagePackModel::SingleImagePackModel(ImagePackInfo pack_, QObject *parent) , pack(std::move(pack_.pack)) , fromSpace_(pack_.from_space) { - [[maybe_unused]] static auto imageInfoType = qRegisterMetaType(); if (!pack.pack) pack.pack = mtx::events::msc2545::ImagePack::PackDescription{}; diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index d5b7289c..7e7cead3 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -1585,8 +1585,6 @@ UserSettingsModel::data(const QModelIndex &index, int role) const l.push_back(QString::fromStdString(d)); return l; }; - static QFontDatabase fontDb; - switch (index.row()) { case Theme: return QStringList{ @@ -1605,9 +1603,9 @@ UserSettingsModel::data(const QModelIndex &index, int role) const i->camera().toStdString(), i->cameraResolution().toStdString())); case Font: - return fontDb.families(); + return QFontDatabase::families(); case EmojiFont: - return fontDb.families(QFontDatabase::WritingSystem::Symbol); + return QFontDatabase::families(QFontDatabase::WritingSystem::Symbol); case Ringtone: { QStringList l{ QStringLiteral("Mute"), @@ -1651,8 +1649,6 @@ UserSettingsModel::data(const QModelIndex &index, int role) const bool UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int role) { - static QFontDatabase fontDb; - auto i = UserSettings::instance(); if (role == Value) { switch (index.row()) { @@ -1677,7 +1673,7 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int return false; } case ScaleFactor: { - if (value.canConvert(QMetaType::Double)) { + if (value.canConvert(QMetaType::fromType())) { utils::setScaleFactor(static_cast(value.toDouble())); return true; } else @@ -1782,7 +1778,7 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int return false; } case TimelineMaxWidth: { - if (value.canConvert(QMetaType::Int)) { + if (value.canConvert(QMetaType::fromType())) { i->setTimelineMaxWidth(value.toInt()); return true; } else @@ -1880,7 +1876,7 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int return false; } case PrivacyScreenTimeout: { - if (value.canConvert(QMetaType::Int)) { + if (value.canConvert(QMetaType::fromType())) { i->setPrivacyScreenTimeout(value.toInt()); return true; } else @@ -1894,7 +1890,7 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int return false; } case FontSize: { - if (value.canConvert(QMetaType::Double)) { + if (value.canConvert(QMetaType::fromType())) { i->setFontSize(value.toDouble()); return true; } else @@ -1902,7 +1898,7 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int } case Font: { if (value.userType() == QMetaType::Int) { - i->setFontFamily(fontDb.families().at(value.toInt())); + i->setFontFamily(QFontDatabase::families().at(value.toInt())); return true; } else return false; @@ -1910,7 +1906,7 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int case EmojiFont: { if (value.userType() == QMetaType::Int) { i->setEmojiFontFamily( - fontDb.families(QFontDatabase::WritingSystem::Symbol).at(value.toInt())); + QFontDatabase::families(QFontDatabase::WritingSystem::Symbol).at(value.toInt())); return true; } else return false; diff --git a/src/Utils.cpp b/src/Utils.cpp index c9a6fb55..2249379d 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -290,7 +290,7 @@ utils::firstChar(const QString &input) return QString::fromUcs4(&c, 1).toUpper(); } - return QString::fromUcs4(&input.toUcs4().at(0), 1).toUpper(); + return QString::fromUcs4(&input.toStdU32String().at(0), 1).toUpper(); } QString diff --git a/src/dbus/NhekoDBusApi.h b/src/dbus/NhekoDBusApi.h index 5a34f0b7..ce265a17 100644 --- a/src/dbus/NhekoDBusApi.h +++ b/src/dbus/NhekoDBusApi.h @@ -92,7 +92,6 @@ operator<<(QDBusArgument &arg, const RoomInfoItem &item); const QDBusArgument & operator>>(const QDBusArgument &arg, RoomInfoItem &item); } // nheko::dbus -Q_DECLARE_METATYPE(nheko::dbus::RoomInfoItem) QDBusArgument & operator<<(QDBusArgument &arg, const QImage &image); diff --git a/src/emoji/Provider.h b/src/emoji/Provider.h index 5d8000a4..d0441ad3 100644 --- a/src/emoji/Provider.h +++ b/src/emoji/Provider.h @@ -94,4 +94,3 @@ public: QString categoryToName(emoji::Emoji::Category cat); } // namespace emoji -Q_DECLARE_METATYPE(emoji::Emoji) diff --git a/src/main.cpp b/src/main.cpp index 90e1cb4c..99e11bf9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -154,8 +154,6 @@ main(int argc, char *argv[]) QCoreApplication::setApplicationVersion(nheko::version); QCoreApplication::setOrganizationName(QStringLiteral("nheko")); QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // Disable the qml disk cache by default to prevent crashes on updates. See // https://github.com/Nheko-Reborn/nheko/issues/1383 @@ -332,16 +330,16 @@ main(int argc, char *argv[]) QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedKingdom)); QTranslator qtTranslator; - qtTranslator.load(QLocale(), + if(qtTranslator.load(QLocale(), QStringLiteral("qt"), QStringLiteral("_"), - QLibraryInfo::location(QLibraryInfo::TranslationsPath)); - app.installTranslator(&qtTranslator); + QLibraryInfo::path(QLibraryInfo::TranslationsPath))) + app.installTranslator(&qtTranslator); QTranslator appTranslator; - appTranslator.load( - QLocale(), QStringLiteral("nheko"), QStringLiteral("_"), QStringLiteral(":/translations")); - app.installTranslator(&appTranslator); + if(appTranslator.load( + QLocale(), QStringLiteral("nheko"), QStringLiteral("_"), QStringLiteral(":/translations"))) + app.installTranslator(&appTranslator); MainWindow w; // QQuickView w; diff --git a/src/timeline/CommunitiesModel.cpp b/src/timeline/CommunitiesModel.cpp index c563639b..dc09a95e 100644 --- a/src/timeline/CommunitiesModel.cpp +++ b/src/timeline/CommunitiesModel.cpp @@ -17,15 +17,12 @@ #include "Utils.h" #include "timeline/TimelineModel.h" -Q_DECLARE_METATYPE(SpaceItem) CommunitiesModel::CommunitiesModel(QObject *parent) : QAbstractListModel(parent) , hiddenTagIds_{UserSettings::instance()->hiddenTags()} , mutedTagIds_{UserSettings::instance()->mutedTags()} { - static auto ignore = qRegisterMetaType(); - (void)ignore; } QHash diff --git a/src/timeline/DelegateChooser.cpp b/src/timeline/DelegateChooser.cpp index 7f80d5f6..91b2194b 100644 --- a/src/timeline/DelegateChooser.cpp +++ b/src/timeline/DelegateChooser.cpp @@ -77,13 +77,13 @@ DelegateChooser::appendChoice(QQmlListProperty *p, DelegateChoic dc->choices_.append(c); } -int +qsizetype DelegateChooser::choiceCount(QQmlListProperty *p) { return static_cast(p->object)->choices_.count(); } DelegateChoice * -DelegateChooser::choice(QQmlListProperty *p, int index) +DelegateChooser::choice(QQmlListProperty *p, qsizetype index) { return static_cast(p->object)->choices_.at(index); } diff --git a/src/timeline/DelegateChooser.h b/src/timeline/DelegateChooser.h index 8f72e73b..c27f2c43 100644 --- a/src/timeline/DelegateChooser.h +++ b/src/timeline/DelegateChooser.h @@ -86,7 +86,7 @@ private: DelegateIncubator incubator{*this}; static void appendChoice(QQmlListProperty *, DelegateChoice *); - static int choiceCount(QQmlListProperty *); - static DelegateChoice *choice(QQmlListProperty *, int index); + static qsizetype choiceCount(QQmlListProperty *); + static DelegateChoice *choice(QQmlListProperty *, qsizetype index); static void clearChoices(QQmlListProperty *); }; diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index 5cdb372a..d373cf55 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -15,11 +15,9 @@ #include "EventAccessors.h" #include "Logging.h" #include "MatrixClient.h" -#include "TimelineModel.h" #include "UserSettingsPage.h" #include "Utils.h" -Q_DECLARE_METATYPE(Reaction) QCache EventStore::decryptedEvents_{1000}; QCache EventStore::events_by_id_{ @@ -29,8 +27,6 @@ QCache EventStore:: EventStore::EventStore(std::string room_id, QObject *) : room_id_(std::move(room_id)) { - static auto reactionType = qRegisterMetaType(); - (void)reactionType; auto range = cache::client()->getTimelineRange(room_id_); @@ -293,12 +289,12 @@ EventStore::EventStore(std::string room_id, QObject *) } void -EventStore::addPending(mtx::events::collections::TimelineEvents event) +EventStore::addPending(const mtx::events::collections::TimelineEvents& event) { if (this->thread() != QThread::currentThread()) nhlog::db()->warn("{} called from a different thread!", __func__); - cache::client()->savePendingMessage(this->room_id_, {event}); + cache::client()->savePendingMessage(this->room_id_, event); mtx::responses::Timeline events; events.limited = false; events.events.emplace_back(event); @@ -761,11 +757,11 @@ EventStore::decryptEvent(const IdIndex &idx, } void -EventStore::refetchOnlineKeyBackupKeys(TimelineModel *room) +EventStore::refetchOnlineKeyBackupKeys() { - for (const auto &[session_id, request] : room->events.pending_key_requests) { + for (const auto &[session_id, request] : this->pending_key_requests) { (void)request; - olm::lookup_keybackup(room->events.room_id_, session_id); + olm::lookup_keybackup(this->room_id_, session_id); } } diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h index bf905fc6..f2f9e2d7 100644 --- a/src/timeline/EventStore.h +++ b/src/timeline/EventStore.h @@ -14,12 +14,11 @@ #include #include #include +#include #include "Reaction.h" #include "encryption/Olm.h" -class TimelineModel; - class EventStore final : public QObject { Q_OBJECT @@ -27,7 +26,7 @@ class EventStore final : public QObject public: EventStore(std::string room_id, QObject *parent); - static void refetchOnlineKeyBackupKeys(TimelineModel *room); + void refetchOnlineKeyBackupKeys(); // taken from QtPrivate::QHashCombine static uint hashCombine(uint hash, uint seed) @@ -108,7 +107,7 @@ signals: void newEncryptedImage(mtx::crypto::EncryptedFile encryptionInfo); void eventFetched(std::string id, std::string relatedTo, - mtx::events::collections::TimelineEvents timeline); + const mtx::events::collections::TimelineEvents& timeline); void oldMessagesRetrieved(const mtx::responses::Messages &); void fetchedMore(); @@ -120,7 +119,7 @@ signals: void updateFlowEventId(std::string event_id); public slots: - void addPending(mtx::events::collections::TimelineEvents event); + void addPending(const mtx::events::collections::TimelineEvents& event); void receivedSessionKey(const std::string &session_id); void clearTimeline(); void enableKeyRequests(bool suppressKeyRequests_); diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 0c2e3752..2fd2d21a 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -74,55 +76,6 @@ MediaUpload::thumbnailDataUrl() const return QString("data:image/png;base64,") + base64; } -bool -InputVideoSurface::present(const QVideoFrame &frame) -{ - QImage::Format format = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()); - - if (format == QImage::Format_Invalid) { - emit newImage({}); - return false; - } else { - QVideoFrame frametodraw(frame); - - if (!frametodraw.map(QAbstractVideoBuffer::ReadOnly)) { - emit newImage({}); - return false; - } - - // this is a shallow operation. it just refer the frame buffer - QImage image(qAsConst(frametodraw).bits(), - frametodraw.width(), - frametodraw.height(), - frametodraw.bytesPerLine(), - format); - image.detach(); - - frametodraw.unmap(); - - emit newImage(std::move(image)); - return true; - } -} - -QList -InputVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const -{ - if (type == QAbstractVideoBuffer::NoHandle) { - return { - QVideoFrame::Format_ARGB32, - QVideoFrame::Format_ARGB32_Premultiplied, - QVideoFrame::Format_RGB24, - QVideoFrame::Format_BGR24, - QVideoFrame::Format_RGB32, - QVideoFrame::Format_RGB565, - QVideoFrame::Format_RGB555, - }; - } else { - return {}; - } -} - bool InputBar::tryPasteAttachment(bool fromMouse) { @@ -536,7 +489,7 @@ InputBar::message(const QString &msg, MarkdownOverride useMarkdown, bool rainbow if (!related.quoted_user.startsWith("@room:")) { QString body; bool firstLine = true; - auto lines = related.quoted_body.splitRef(u'\n'); + auto lines = QStringView(related.quoted_body).split(u'\n'); for (auto line : qAsConst(lines)) { if (firstLine) { firstLine = false; @@ -1036,21 +989,20 @@ MediaUpload::MediaUpload(std::unique_ptr source_, blurhash_ = QString::fromStdString(blurhash::encode(data_.data(), img.width(), img.height(), 4, 3)); } else if (mimeClass_ == u"video" || mimeClass_ == u"audio") { - auto mediaPlayer = new QMediaPlayer( - this, - mimeClass_ == u"video" ? QFlags{QMediaPlayer::VideoSurface} : QMediaPlayer::Flags{}); - mediaPlayer->setMuted(true); + auto mediaPlayer = new QMediaPlayer( this); + mediaPlayer->setAudioOutput(nullptr); if (mimeClass_ == u"video") { - auto newSurface = new InputVideoSurface(this); + auto newSurface = new QVideoSink(this); connect( - newSurface, &InputVideoSurface::newImage, this, [this, mediaPlayer](QImage img) { + newSurface, &QVideoSink::videoFrameChanged, this, [this, mediaPlayer](const QVideoFrame& frame) { + QImage img = frame.toImage(); if (img.size().isEmpty()) return; mediaPlayer->stop(); - auto orientation = mediaPlayer->metaData(QMediaMetaData::Orientation).toInt(); + auto orientation = mediaPlayer->metaData().value(QMediaMetaData::Orientation).toInt(); if (orientation == 90 || orientation == 270 || orientation == 180) { img = img.transformed(QTransform().rotate(orientation), Qt::SmoothTransformation); @@ -1081,11 +1033,11 @@ MediaUpload::MediaUpload(std::unique_ptr source_, } connect(mediaPlayer, - qOverload(&QMediaPlayer::error), +&QMediaPlayer::error, this, - [mediaPlayer](QMediaPlayer::Error error) { + [mediaPlayer]() { nhlog::ui()->debug("Media player error {} and errorStr {}", - error, + mediaPlayer->error(), mediaPlayer->errorString().toStdString()); }); connect(mediaPlayer, @@ -1095,19 +1047,19 @@ MediaUpload::MediaUpload(std::unique_ptr source_, "Media player status {} and error {}", status, mediaPlayer->error()); }); connect(mediaPlayer, - qOverload(&QMediaPlayer::metaDataChanged), +&QMediaPlayer::metaDataChanged, this, - [this, mediaPlayer](const QString &t, const QVariant &) { - nhlog::ui()->debug("Got metadata {}", t.toStdString()); + [this, mediaPlayer]() { + nhlog::ui()->debug("Got metadata {}"); if (mediaPlayer->duration() > 0) this->duration_ = mediaPlayer->duration(); - auto dimensions = mediaPlayer->metaData(QMediaMetaData::Resolution).toSize(); + auto dimensions = mediaPlayer->metaData().value(QMediaMetaData::Resolution).toSize(); if (!dimensions.isEmpty()) { dimensions_ = dimensions; auto orientation = - mediaPlayer->metaData(QMediaMetaData::Orientation).toInt(); + mediaPlayer->metaData().value(QMediaMetaData::Orientation).toInt(); if (orientation == 90 || orientation == 270) { dimensions_.transpose(); } @@ -1125,8 +1077,8 @@ MediaUpload::MediaUpload(std::unique_ptr source_, auto originalFile = qobject_cast(source.get()); - mediaPlayer->setMedia( - QMediaContent(originalFile ? originalFile->fileName() : originalFilename_), source.get()); + mediaPlayer->setSourceDevice(source.get(), + QUrl(originalFile ? originalFile->fileName() : originalFilename_)); mediaPlayer->play(); } diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index 1f1d6fe1..f03e6019 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include #include @@ -41,25 +40,6 @@ enum class MarkdownOverride CMARK, }; -class InputVideoSurface final : public QAbstractVideoSurface -{ - Q_OBJECT - -public: - InputVideoSurface(QObject *parent) - : QAbstractVideoSurface(parent) - { - } - - bool present(const QVideoFrame &frame) override; - - QList - supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const override; - -signals: - void newImage(QImage img); -}; - class MediaUpload final : public QObject { Q_OBJECT diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp index 6bd02a17..b55cbabd 100644 --- a/src/timeline/RoomlistModel.cpp +++ b/src/timeline/RoomlistModel.cpp @@ -28,7 +28,6 @@ RoomlistModel::RoomlistModel(TimelineViewManager *parent) : QAbstractListModel(parent) , manager(parent) { - [[maybe_unused]] static auto id = qRegisterMetaType(); connect(ChatPage::instance(), &ChatPage::decryptSidebarChanged, this, [this]() { auto decrypt = ChatPage::instance()->userSettings()->decryptSidebar(); @@ -819,7 +818,7 @@ RoomlistModel::refetchOnlineKeyBackupKeys() auto ptr = i.value(); if (!ptr.isNull()) { - EventStore::refetchOnlineKeyBackupKeys(ptr.data()); + ptr->refetchOnlineKeyBackupKeys(); } } } diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 5996bea8..a4659f33 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -31,7 +31,6 @@ #include "Utils.h" #include "encryption/Olm.h" -Q_DECLARE_METATYPE(QModelIndex) namespace std { inline uint // clazy:exclude=qhash-namespace diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index b0d81441..02a5ee80 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -374,6 +374,8 @@ public: return std::nullopt; } + void refetchOnlineKeyBackupKeys() { events.refetchOnlineKeyBackupKeys(); }; + public slots: void setCurrentIndex(int index); int currentIndex() const { return idToIndex(currentId); } @@ -537,8 +539,6 @@ private: std::unique_ptr parentSummary = nullptr; bool parentChecked = false; - - friend void EventStore::refetchOnlineKeyBackupKeys(TimelineModel *room); }; Q_DECLARE_OPERATORS_FOR_FLAGS(TimelineModel::SpecialEffects) diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index e062dde2..a3b91ce7 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -280,7 +280,7 @@ TimelineViewManager::saveMedia(QString mxcUrl) { const QString downloadsFolder = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); - const QString openLocation = downloadsFolder + "/" + mxcUrl.splitRef(u'/').constLast(); + const QString openLocation = downloadsFolder + "/" + mxcUrl.split(u'/').constLast(); const QString filename = QFileDialog::getSaveFileName(nullptr, {}, openLocation); diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index e3279e21..303e2af2 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -131,11 +131,3 @@ private: QHash, QColor> userColors; }; -Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationAccept) -Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationCancel) -Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationDone) -Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationKey) -Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationMac) -Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationReady) -Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationRequest) -Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationStart) diff --git a/src/ui/MxcAnimatedImage.cpp b/src/ui/MxcAnimatedImage.cpp index 7544537d..14f5dbd8 100644 --- a/src/ui/MxcAnimatedImage.cpp +++ b/src/ui/MxcAnimatedImage.cpp @@ -152,9 +152,9 @@ MxcAnimatedImage::startDownload() } void -MxcAnimatedImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +MxcAnimatedImage::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) { - QQuickItem::geometryChanged(newGeometry, oldGeometry); + QQuickItem::geometryChange(newGeometry, oldGeometry); if (newGeometry.size() != oldGeometry.size()) { if (height() != 0 && width() != 0) { diff --git a/src/ui/MxcAnimatedImage.h b/src/ui/MxcAnimatedImage.h index a32de6ee..bc53e711 100644 --- a/src/ui/MxcAnimatedImage.h +++ b/src/ui/MxcAnimatedImage.h @@ -59,7 +59,7 @@ public: } } - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override; diff --git a/src/ui/MxcMediaProxy.cpp b/src/ui/MxcMediaProxy.cpp index 9a439c30..e10cb846 100644 --- a/src/ui/MxcMediaProxy.cpp +++ b/src/ui/MxcMediaProxy.cpp @@ -8,17 +8,11 @@ #include #include #include -#include #include #include #include #include -#if defined(Q_OS_MACOS) -// TODO (red_sky): Remove for Qt6. See other ifdef below -#include -#endif - #include "ChatPage.h" #include "EventAccessors.h" #include "Logging.h" @@ -32,19 +26,18 @@ MxcMediaProxy::MxcMediaProxy(QObject *parent) connect(this, &MxcMediaProxy::eventIdChanged, &MxcMediaProxy::startDownload); connect(this, &MxcMediaProxy::roomChanged, &MxcMediaProxy::startDownload); connect(this, - qOverload(&MxcMediaProxy::error), - [this](QMediaPlayer::Error error) { + &MxcMediaProxy::error, + [this]() { nhlog::ui()->info("Media player error {} and errorStr {}", - error, + error(), this->errorString().toStdString()); }); connect(this, &MxcMediaProxy::mediaStatusChanged, [this](QMediaPlayer::MediaStatus status) { nhlog::ui()->info("Media player status {} and error {}", status, this->error()); }); connect(this, - qOverload(&MxcMediaProxy::metaDataChanged), - [this](const QString &t, const QVariant &) { - if (t == QMediaMetaData::Orientation) + &MxcMediaProxy::metaDataChanged, + [this]() { emit orientationChanged(); }); @@ -53,28 +46,12 @@ MxcMediaProxy::MxcMediaProxy(QObject *parent) this, &MxcMediaProxy::pause); } -void -MxcMediaProxy::setVideoSurface(QAbstractVideoSurface *surface) -{ - if (surface != m_surface) { - qDebug() << "Changing surface"; - m_surface = surface; - setVideoOutput(m_surface); - emit videoSurfaceChanged(); - } -} - -QAbstractVideoSurface * -MxcMediaProxy::getVideoSurface() -{ - return m_surface; -} int MxcMediaProxy::orientation() const { - nhlog::ui()->debug("metadata: {}", availableMetaData().join(QStringLiteral(",")).toStdString()); - auto orientation = metaData(QMediaMetaData::Orientation).toInt(); + //nhlog::ui()->debug("metadata: {}", availableMetaData().join(QStringLiteral(",")).toStdString()); + auto orientation = metaData().value(QMediaMetaData::Orientation).toInt(); nhlog::ui()->debug("Video orientation: {}", orientation); return orientation; } @@ -135,34 +112,10 @@ MxcMediaProxy::startDownload() buffer.open(QIODevice::ReadOnly); buffer.reset(); - QTimer::singleShot(0, this, [this, filename, suffix, encryptionInfo] { -#if defined(Q_OS_MACOS) - if (encryptionInfo) { - // macOS has issues reading from a buffer in setMedia for whatever reason. - // Instead, write the buffer to a temporary file and read from that. - // This should be fixed in Qt6, so update this when we do that! - // TODO: REMOVE IN QT6 - QTemporaryFile tempFile; - tempFile.setFileTemplate(tempFile.fileTemplate() + QLatin1Char('.') + suffix); - tempFile.open(); - tempFile.write(buffer.data()); - tempFile.close(); - nhlog::ui()->debug("Playing media from temp buffer file: {}. Remove in QT6!", - filename.filePath().toStdString()); - this->setMedia(QUrl::fromLocalFile(tempFile.fileName())); - } else { - nhlog::ui()->info( - "Playing buffer with size: {}, {}", buffer.bytesAvailable(), buffer.isOpen()); - this->setMedia(QUrl::fromLocalFile(filename.filePath())); - } -#else - Q_UNUSED(suffix) - Q_UNUSED(encryptionInfo) - + QTimer::singleShot(0, this, [this, filename] { nhlog::ui()->info( "Playing buffer with size: {}, {}", buffer.bytesAvailable(), buffer.isOpen()); - this->setMedia(QMediaContent(filename.fileName()), &buffer); -#endif + this->setSourceDevice(&buffer, QUrl(filename.fileName())); emit loadedChanged(); }); }; diff --git a/src/ui/MxcMediaProxy.h b/src/ui/MxcMediaProxy.h index 48de5a4f..7b7947e9 100644 --- a/src/ui/MxcMediaProxy.h +++ b/src/ui/MxcMediaProxy.h @@ -4,9 +4,9 @@ #pragma once -#include +#include #include -#include +#include #include #include #include @@ -23,8 +23,6 @@ class MxcMediaProxy : public QMediaPlayer Q_OBJECT Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED) Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged) - Q_PROPERTY(QAbstractVideoSurface *videoSurface READ getVideoSurface WRITE setVideoSurface NOTIFY - videoSurfaceChanged) Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) Q_PROPERTY(int orientation READ orientation NOTIFY orientationChanged) @@ -44,16 +42,13 @@ public: room_ = room; emit roomChanged(); } - void setVideoSurface(QAbstractVideoSurface *surface); - QAbstractVideoSurface *getVideoSurface(); - int orientation() const; signals: void roomChanged(); void eventIdChanged(); void loadedChanged(); - void newBuffer(QMediaContent, QIODevice *buf); + void newBuffer(QUrl, QIODevice *buf); void orientationChanged(); void videoSurfaceChanged(); @@ -66,5 +61,5 @@ private: QString eventId_; QString filename_; QBuffer buffer; - QAbstractVideoSurface *m_surface = nullptr; + QObject *m_surface = nullptr; }; diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp index a6f9abe7..8f410dae 100644 --- a/src/ui/NhekoGlobalObject.cpp +++ b/src/ui/NhekoGlobalObject.cpp @@ -5,16 +5,12 @@ #include "NhekoGlobalObject.h" #include +#include #include #include #include #include -// for some reason that is not installed in our macOS env... -#ifndef Q_OS_MAC -#include -#endif - #include "Cache_p.h" #include "ChatPage.h" #include "Logging.h" @@ -22,6 +18,8 @@ #include "Utils.h" #include "voip/WebRTCSession.h" +#include + Nheko::Nheko() { connect( @@ -186,7 +184,21 @@ Nheko::createRoom(bool space, void Nheko::setWindowRole([[maybe_unused]] QWindow *win, [[maybe_unused]] QString newRole) const { -#ifndef Q_OS_MAC - QXcbWindowFunctions::setWmWindowRole(win, newRole.toUtf8()); -#endif + const QNativeInterface::QX11Application *x11Interface = qGuiApp->nativeInterface(); + + if (!x11Interface) return; + + auto connection = x11Interface->connection(); + + auto role = newRole.toStdString(); + + char WM_WINDOW_ROLE[] = "WM_WINDOW_ROLE"; + auto cookie = xcb_intern_atom(connection, false, std::size(WM_WINDOW_ROLE) - 1, WM_WINDOW_ROLE); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, nullptr); + auto atom = reply ->atom; + free(reply); + + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, win->winId(), + atom, XCB_ATOM_STRING, 8, + role.size(), role.data()); } diff --git a/src/ui/Theme.cpp b/src/ui/Theme.cpp index 48cb8bce..8cf38548 100644 --- a/src/ui/Theme.cpp +++ b/src/ui/Theme.cpp @@ -4,12 +4,10 @@ #include "Theme.h" -Q_DECLARE_METATYPE(Theme) QPalette Theme::paletteFromTheme(QStringView theme) { - [[maybe_unused]] static auto meta = qRegisterMetaType("Theme"); static QPalette original; if (theme == u"light") { static QPalette lightActive = [] { diff --git a/src/voip/CallManager.cpp b/src/voip/CallManager.cpp index 993937f0..0ef14db9 100644 --- a/src/voip/CallManager.cpp +++ b/src/voip/CallManager.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include "Cache.h" @@ -42,9 +41,6 @@ extern "C" } #endif -Q_DECLARE_METATYPE(std::vector) -Q_DECLARE_METATYPE(mtx::events::voip::CallCandidates::Candidate) -Q_DECLARE_METATYPE(mtx::responses::TurnServer) using namespace mtx::events; using namespace mtx::events::voip; @@ -64,9 +60,6 @@ CallManager::CallManager(QObject *parent) , session_(WebRTCSession::instance()) , turnServerTimer_(this) { - qRegisterMetaType>(); - qRegisterMetaType(); - qRegisterMetaType(); #ifdef GSTREAMER_AVAILABLE std::string errorMessage; @@ -180,11 +173,11 @@ CallManager::CallManager(QObject *parent) }); connect(&player_, - QOverload::of(&QMediaPlayer::error), + &QMediaPlayer::error, this, - [this](QMediaPlayer::Error error) { + [this]() { stopRingtone(); - switch (error) { + switch (player_.error()) { case QMediaPlayer::FormatError: case QMediaPlayer::ResourceError: nhlog::ui()->error("WebRTC: valid ringtone file not found"); @@ -827,19 +820,17 @@ CallManager::retrieveTurnServer() void CallManager::playRingtone(const QUrl &ringtone, bool repeat) { - static QMediaPlaylist playlist; - playlist.clear(); - playlist.setPlaybackMode(repeat ? QMediaPlaylist::CurrentItemInLoop - : QMediaPlaylist::CurrentItemOnce); - playlist.addMedia(ringtone); - player_.setVolume(100); - player_.setPlaylist(&playlist); + player_.setLoops(repeat ? QMediaPlayer::Infinite : + 1); + player_.setSource(ringtone); + //player_.audioOutput()->setVolume(100); + player_.play(); } void CallManager::stopRingtone() { - player_.setPlaylist(nullptr); + player_.stop(); } bool diff --git a/src/voip/ScreenCastPortal.cpp b/src/voip/ScreenCastPortal.cpp index 31cddba0..e0433387 100644 --- a/src/voip/ScreenCastPortal.cpp +++ b/src/voip/ScreenCastPortal.cpp @@ -438,7 +438,6 @@ struct PipeWireStream QVariantMap map; }; -Q_DECLARE_METATYPE(PipeWireStream) const QDBusArgument & operator>>(const QDBusArgument &argument, PipeWireStream &stream) diff --git a/src/voip/WebRTCSession.cpp b/src/voip/WebRTCSession.cpp index c0cab4ac..c8bc9cb5 100644 --- a/src/voip/WebRTCSession.cpp +++ b/src/voip/WebRTCSession.cpp @@ -41,9 +41,6 @@ extern "C" // https://github.com/vector-im/riot-web/issues/10173 #define STUN_SERVER "stun://turn.matrix.org:3478" -Q_DECLARE_METATYPE(webrtc::CallType) -Q_DECLARE_METATYPE(webrtc::ScreenShareType) -Q_DECLARE_METATYPE(webrtc::State) using webrtc::CallType; using webrtc::ScreenShareType; @@ -52,7 +49,6 @@ using webrtc::State; WebRTCSession::WebRTCSession() : devices_(CallDevices::instance()) { - qRegisterMetaType(); qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject, "im.nheko", 1, @@ -60,7 +56,6 @@ WebRTCSession::WebRTCSession() "CallType", QStringLiteral("Can't instantiate enum")); - qRegisterMetaType(); qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject, "im.nheko", 1, @@ -68,7 +63,6 @@ WebRTCSession::WebRTCSession() "ScreenShareType", QStringLiteral("Can't instantiate enum")); - qRegisterMetaType(); qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject, "im.nheko", 1, From e85a1d4aeb464f155cf026d33cab120f07724e70 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 00:43:38 +0200 Subject: [PATCH 043/128] First runnable qt6 Nheko --- resources/qml/PrivacyScreen.qml | 15 +++++++----- resources/qml/components/FlatButton.qml | 23 +++++++++---------- .../qml/delegates/PlayableMediaMessage.qml | 22 ++++++++---------- resources/qml/emoji/StickerPicker.qml | 11 ++++----- resources/qml/ui/Ripple.qml | 5 ++-- resources/qml/ui/Spinner.qml | 12 +++++----- .../qml/ui/animations/BlinkAnimation.qml | 3 +-- src/LoginPage.cpp | 2 ++ 8 files changed, 46 insertions(+), 47 deletions(-) diff --git a/resources/qml/PrivacyScreen.qml b/resources/qml/PrivacyScreen.qml index 5967f25d..da196667 100644 --- a/resources/qml/PrivacyScreen.qml +++ b/resources/qml/PrivacyScreen.qml @@ -2,10 +2,10 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -import QtGraphicalEffects 1.0 -import QtQuick 2.12 -import QtQuick.Window 2.2 -import im.nheko 1.0 +import QtQuick +import QtQuick.Window +import im.nheko +import QtQuick.Effects Item { id: privacyScreen @@ -100,12 +100,15 @@ Item { } ] - FastBlur { + MultiEffect { id: blur + blurEnabled: true + anchors.fill: parent source: timelineRoot - radius: 50 + blur: 1.0 + blurMax: 32 } } diff --git a/resources/qml/components/FlatButton.qml b/resources/qml/components/FlatButton.qml index ec4b306a..a3dedf35 100644 --- a/resources/qml/components/FlatButton.qml +++ b/resources/qml/components/FlatButton.qml @@ -2,11 +2,11 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -import QtGraphicalEffects 1.12 -import QtQuick 2.9 -import QtQuick.Controls 2.5 -import QtQuick.Layouts 1.2 -import im.nheko 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Effects +import im.nheko // FIXME(Nico): Don't use hardcoded colors. Button { @@ -18,14 +18,13 @@ Button { property string iconImage: "" - DropShadow { + MultiEffect { anchors.fill: control.background - horizontalOffset: 3 - verticalOffset: 3 - radius: 8 - samples: 17 - cached: true - color: "#80000000" + shadowHorizontalOffset: 3 + shadowVerticalOffset: 3 + shadowBlur: 8 + shadowEnabled: true + shadowColor: "#80000000" source: control.background } diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml index 741369d2..1131856f 100644 --- a/resources/qml/delegates/PlayableMediaMessage.qml +++ b/resources/qml/delegates/PlayableMediaMessage.qml @@ -4,11 +4,11 @@ import "../" import "../ui/media" -import QtMultimedia 5.15 -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import im.nheko 1.0 +import QtMultimedia +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import im.nheko Item { id: content @@ -36,12 +36,12 @@ Item { id: mxcmedia // TODO: Show error in overlay or so? - onError: console.log(error) roomm: room - // desiredVolume is a float from 0.0 -> 1.0, MediaPlayer volume is an int from 0 to 100 - // this value automatically gets clamped for us between these two values. - volume: mediaControls.desiredVolume * 100 - muted: mediaControls.muted + audioOutput: AudioOutput { + muted: mediaControls.muted + volume: mediaControls.desiredVolume + } + videoOutput: videoOutput } Rectangle { @@ -68,8 +68,6 @@ Item { clip: true anchors.fill: parent fillMode: VideoOutput.PreserveAspectFit - source: mxcmedia - flushMode: VideoOutput.FirstFrame orientation: mxcmedia.orientation } diff --git a/resources/qml/emoji/StickerPicker.qml b/resources/qml/emoji/StickerPicker.qml index 38788899..9a5cd6d1 100644 --- a/resources/qml/emoji/StickerPicker.qml +++ b/resources/qml/emoji/StickerPicker.qml @@ -3,12 +3,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later import "../" -import QtGraphicalEffects 1.0 -import QtQuick 2.9 -import QtQuick.Controls 2.3 -import QtQuick.Layouts 1.3 -import im.nheko 1.0 -import im.nheko.EmojiModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import im.nheko +import im.nheko.EmojiModel Menu { id: stickerPopup diff --git a/resources/qml/ui/Ripple.qml b/resources/qml/ui/Ripple.qml index 192909b2..73d8520f 100644 --- a/resources/qml/ui/Ripple.qml +++ b/resources/qml/ui/Ripple.qml @@ -2,9 +2,8 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -import QtGraphicalEffects 1.0 -import QtQuick 2.15 -import QtQuick.Controls 2.15 +import QtQuick +import QtQuick.Controls Item { id: ripple diff --git a/resources/qml/ui/Spinner.qml b/resources/qml/ui/Spinner.qml index a88318c6..9c0c8a31 100644 --- a/resources/qml/ui/Spinner.qml +++ b/resources/qml/ui/Spinner.qml @@ -3,8 +3,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later import "./animations" -import QtGraphicalEffects 1.12 -import QtQuick 2.12 +import QtQuick +import QtQuick.Effects Item { id: spinner @@ -139,11 +139,11 @@ Item { } - Glow { + MultiEffect { anchors.fill: row - radius: 14 - samples: 17 - color: spinner.foreground + shadowBlur: 14 + shadowEnabled: true + shadowColor: spinner.foreground source: row transform: Matrix4x4 { diff --git a/resources/qml/ui/animations/BlinkAnimation.qml b/resources/qml/ui/animations/BlinkAnimation.qml index ae730452..de2a11d8 100644 --- a/resources/qml/ui/animations/BlinkAnimation.qml +++ b/resources/qml/ui/animations/BlinkAnimation.qml @@ -2,8 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -import QtGraphicalEffects 1.12 -import QtQuick 2.12 +import QtQuick SequentialAnimation { property alias target: numberAnimation.target diff --git a/src/LoginPage.cpp b/src/LoginPage.cpp index 8d6a69cf..55487502 100644 --- a/src/LoginPage.cpp +++ b/src/LoginPage.cpp @@ -25,6 +25,8 @@ LoginPage::LoginPage(QObject *parent) : QObject(parent) , inferredServerAddress_() { + [[maybe_unused]] static auto ignored = qRegisterMetaType(); + connect(this, &LoginPage::versionOkCb, this, &LoginPage::versionOk, Qt::QueuedConnection); connect(this, &LoginPage::versionErrorCb, this, &LoginPage::versionError, Qt::QueuedConnection); connect( From 54e2295c214874a316d22eaedaf5c2db17b59df0 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 01:29:05 +0200 Subject: [PATCH 044/128] Fix palette access and QMediaPlayer errors --- resources/qml/Avatar.qml | 6 +-- resources/qml/ChatPage.qml | 2 +- resources/qml/CommunitiesList.qml | 30 ++++++------ resources/qml/Completer.qml | 30 ++++++------ resources/qml/ElidedLabel.qml | 2 +- resources/qml/EncryptionIndicator.qml | 2 +- resources/qml/ForwardCompleter.qml | 11 ++--- resources/qml/ImageButton.qml | 4 +- resources/qml/MatrixText.qml | 2 +- resources/qml/MatrixTextField.qml | 10 ++-- resources/qml/MessageInput.qml | 15 +++--- resources/qml/MessageInputWarning.qml | 3 +- resources/qml/MessageView.qml | 30 ++++++------ resources/qml/QuickSwitcher.qml | 3 +- resources/qml/Reactions.qml | 14 +++--- resources/qml/ReplyPopup.qml | 8 +-- resources/qml/RoomList.qml | 49 +++++++++---------- resources/qml/Root.qml | 1 - resources/qml/SelfVerificationCheck.qml | 22 ++++----- resources/qml/TimelineRow.qml | 22 ++++----- resources/qml/TimelineView.qml | 14 ++---- resources/qml/ToggleButton.qml | 4 +- resources/qml/TopBar.qml | 18 +++---- resources/qml/TypingIndicator.qml | 6 +-- resources/qml/UploadBox.qml | 6 +-- resources/qml/components/AvatarListTile.qml | 30 ++++++------ resources/qml/components/FlatButton.qml | 4 +- resources/qml/components/MainWindowDialog.qml | 2 +- resources/qml/components/NhekoTabButton.qml | 6 +-- .../qml/components/ReorderableListview.qml | 4 +- resources/qml/components/TextButton.qml | 4 +- resources/qml/components/UserListRow.qml | 4 +- resources/qml/delegates/Encrypted.qml | 5 +- resources/qml/delegates/EncryptionEnabled.qml | 6 +-- resources/qml/delegates/FileMessage.qml | 8 +-- resources/qml/delegates/ImageMessage.qml | 12 ++--- resources/qml/delegates/MessageDelegate.qml | 8 ++- resources/qml/delegates/NoticeMessage.qml | 2 +- resources/qml/delegates/Pill.qml | 4 +- resources/qml/delegates/Placeholder.qml | 2 +- .../qml/delegates/PlayableMediaMessage.qml | 8 +-- resources/qml/delegates/Redacted.qml | 6 +-- resources/qml/delegates/Reply.qml | 6 +-- resources/qml/delegates/TextMessage.qml | 14 +++--- .../DeviceVerification.qml | 5 +- .../device-verification/DigitVerification.qml | 8 +-- .../device-verification/EmojiVerification.qml | 8 +-- resources/qml/device-verification/Failed.qml | 2 +- .../NewVerificationRequest.qml | 2 +- resources/qml/device-verification/Success.qml | 2 +- resources/qml/device-verification/Waiting.qml | 4 +- resources/qml/dialogs/AliasEditor.qml | 16 +++--- .../dialogs/AllowedRoomsSettingsDialog.qml | 11 ++--- .../qml/dialogs/ConfirmJoinRoomDialog.qml | 13 +++-- resources/qml/dialogs/CreateDirect.qml | 6 +-- resources/qml/dialogs/CreateRoom.qml | 10 ++-- .../qml/dialogs/ImagePackEditorDialog.qml | 18 +++---- .../qml/dialogs/ImagePackSettingsDialog.qml | 19 +++---- resources/qml/dialogs/InputDialog.qml | 2 +- resources/qml/dialogs/InviteDialog.qml | 19 ++++--- resources/qml/dialogs/JoinRoomDialog.qml | 5 +- .../qml/dialogs/PhoneNumberInputDialog.qml | 2 +- resources/qml/dialogs/PowerLevelEditor.qml | 29 ++++++----- .../dialogs/PowerLevelSpacesApplyDialog.qml | 13 +++-- resources/qml/dialogs/RawMessageDialog.qml | 8 ++- resources/qml/dialogs/ReadReceipts.qml | 12 ++--- resources/qml/dialogs/RoomDirectory.qml | 15 +++--- resources/qml/dialogs/RoomMembers.qml | 12 ++--- resources/qml/dialogs/RoomSettings.qml | 45 +++++++++-------- resources/qml/dialogs/UserProfile.qml | 18 +++---- resources/qml/emoji/StickerPicker.qml | 19 +++---- resources/qml/pages/LoginPage.qml | 5 +- resources/qml/pages/RegisterPage.qml | 7 ++- resources/qml/pages/UserSettingsPage.qml | 9 ++-- resources/qml/pages/WelcomePage.qml | 6 +-- resources/qml/ui/NhekoSlider.qml | 4 +- resources/qml/ui/Ripple.qml | 2 +- resources/qml/ui/Snackbar.qml | 4 +- resources/qml/ui/media/MediaControls.qml | 8 +-- resources/qml/voip/CallDevices.qml | 9 ++-- resources/qml/voip/CallInvite.qml | 15 +++--- resources/qml/voip/CallInviteBar.qml | 2 - resources/qml/voip/DeviceError.qml | 8 +-- resources/qml/voip/PlaceCall.qml | 11 ++--- resources/qml/voip/ScreenShare.qml | 13 +++-- src/timeline/InputBar.cpp | 8 +-- src/ui/MxcMediaProxy.cpp | 15 +++--- src/voip/CallManager.cpp | 8 +-- 88 files changed, 426 insertions(+), 480 deletions(-) diff --git a/resources/qml/Avatar.qml b/resources/qml/Avatar.qml index 4951a9fb..8302f8fa 100644 --- a/resources/qml/Avatar.qml +++ b/resources/qml/Avatar.qml @@ -24,7 +24,7 @@ AbstractButton { background: Rectangle { id: bg radius: Settings.avatarCircles ? height / 2 : height / 8 - color: Nheko.colors.alternateBase + color: palette.alternateBase } Label { @@ -39,7 +39,7 @@ AbstractButton { verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter visible: img.status != Image.Ready && !Settings.useIdenticon - color: Nheko.colors.text + color: palette.text } Image { @@ -109,7 +109,7 @@ AbstractButton { } Ripple { - color: Qt.rgba(Nheko.colors.alternateBase.r, Nheko.colors.alternateBase.g, Nheko.colors.alternateBase.b, 0.5) + color: Qt.rgba(palette.alternateBase.r, palette.alternateBase.g, palette.alternateBase.b, 0.5) } } diff --git a/resources/qml/ChatPage.qml b/resources/qml/ChatPage.qml index d4d2b845..564c093d 100644 --- a/resources/qml/ChatPage.qml +++ b/resources/qml/ChatPage.qml @@ -14,7 +14,7 @@ import QtQml 2.15 Rectangle { id: chatPage - color: Nheko.colors.window + color: palette.window ColumnLayout { spacing: 0 diff --git a/resources/qml/CommunitiesList.qml b/resources/qml/CommunitiesList.qml index ee49ae2d..5bf239a6 100644 --- a/resources/qml/CommunitiesList.qml +++ b/resources/qml/CommunitiesList.qml @@ -78,11 +78,11 @@ Page { delegate: ItemDelegate { id: communityItem - property color backgroundColor: Nheko.colors.window - property color importantText: Nheko.colors.text - property color unimportantText: Nheko.colors.buttonText - property color bubbleBackground: Nheko.colors.highlight - property color bubbleText: Nheko.colors.highlightedText + property color backgroundColor: palette.window + property color importantText: palette.text + property color unimportantText: palette.buttonText + property color bubbleBackground: palette.highlight + property color bubbleText: palette.highlightedText required property var model height: avatarSize + 2 * Nheko.paddingMedium @@ -100,11 +100,11 @@ Page { PropertyChanges { target: communityItem - backgroundColor: Nheko.colors.dark - importantText: Nheko.colors.brightText - unimportantText: Nheko.colors.brightText - bubbleBackground: Nheko.colors.highlight - bubbleText: Nheko.colors.highlightedText + backgroundColor: palette.dark + importantText: palette.brightText + unimportantText: palette.brightText + bubbleBackground: palette.highlight + bubbleText: palette.highlightedText } }, @@ -114,11 +114,11 @@ Page { PropertyChanges { target: communityItem - backgroundColor: Nheko.colors.highlight - importantText: Nheko.colors.highlightedText - unimportantText: Nheko.colors.highlightedText - bubbleBackground: Nheko.colors.highlightedText - bubbleText: Nheko.colors.highlight + backgroundColor: palette.highlight + importantText: palette.highlightedText + unimportantText: palette.highlightedText + bubbleBackground: palette.highlightedText + bubbleText: palette.highlight } } diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml index 0a9c41ed..95bebc1b 100644 --- a/resources/qml/Completer.qml +++ b/resources/qml/Completer.qml @@ -127,8 +127,8 @@ Control { ListView.delayRemove: true - color: model.index == popup.currentIndex ? Nheko.colors.highlight : Nheko.colors.base - height: chooser.child.implicitHeight + 2 * popup.rowMargin + color: model.index == popup.currentIndex ? palette.highlight : palette.base + height: (chooser.child?.implicitHeight ?? 0) + 2 * popup.rowMargin implicitWidth: fullWidth ? ListView.view.width : chooser.child.implicitWidth + 4 MouseArea { @@ -146,7 +146,7 @@ Control { } } Ripple { - color: Qt.rgba(Nheko.colors.base.r, Nheko.colors.base.g, Nheko.colors.base.b, 0.5) + color: Qt.rgba(palette.base.r, palette.base.g, palette.base.b, 0.5) } DelegateChooser { @@ -177,12 +177,12 @@ Control { Label { text: model.displayName - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text + color: model.index == popup.currentIndex ? palette.highlightedText : palette.text } Label { text: "(" + model.userid + ")" - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.buttonText + color: model.index == popup.currentIndex ? palette.highlightedText : palette.buttonText } } @@ -201,7 +201,7 @@ Control { Label { visible: !!model.unicode text: model.unicode - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text + color: model.index == popup.currentIndex ? palette.highlightedText : palette.text font: Settings.emojiFont } @@ -220,12 +220,12 @@ Control { Layout.leftMargin: Nheko.paddingSmall Layout.rightMargin: Nheko.paddingSmall text: model.shortcode - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text + color: model.index == popup.currentIndex ? palette.highlightedText : palette.text } Label { text: "(" + model.packname + ")" - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.buttonText + color: model.index == popup.currentIndex ? palette.highlightedText : palette.buttonText } } @@ -243,13 +243,13 @@ Control { Label { text: model.name - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text + color: model.index == popup.currentIndex ? palette.highlightedText : palette.text font.bold: true } Label { text: model.description - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.buttonText + color: model.index == popup.currentIndex ? palette.highlightedText : palette.buttonText } } @@ -277,7 +277,7 @@ Control { Label { text: model.roomName font.pixelSize: popup.avatarHeight * 0.5 - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text + color: model.index == popup.currentIndex ? palette.highlightedText : palette.text font.italic: model.isTombstoned textFormat: Text.RichText } @@ -306,14 +306,14 @@ Control { Label { text: model.roomName - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.text + color: model.index == popup.currentIndex ? palette.highlightedText : palette.text font.italic: model.isTombstoned textFormat: Text.RichText } Label { text: "(" + model.roomAlias + ")" - color: model.index == popup.currentIndex ? Nheko.colors.highlightedText : Nheko.colors.buttonText + color: model.index == popup.currentIndex ? palette.highlightedText : palette.buttonText textFormat: Text.RichText } @@ -329,8 +329,8 @@ Control { background: Rectangle { - color: Nheko.colors.base - border.color: Nheko.colors.mid + color: palette.base + border.color: palette.mid } } diff --git a/resources/qml/ElidedLabel.qml b/resources/qml/ElidedLabel.qml index 180259b1..2d53faff 100644 --- a/resources/qml/ElidedLabel.qml +++ b/resources/qml/ElidedLabel.qml @@ -13,7 +13,7 @@ Label { property alias elideWidth: metrics.elideWidth property int fullTextWidth: Math.ceil(metrics.advanceWidth) - color: Nheko.colors.text + color: palette.text text: (textFormat == Text.PlainText) ? metrics.elidedText : TimelineManager.escapeEmoji(metrics.elidedText) maximumLineCount: 1 elide: Text.ElideRight diff --git a/resources/qml/EncryptionIndicator.qml b/resources/qml/EncryptionIndicator.qml index 5338b6be..c675fb52 100644 --- a/resources/qml/EncryptionIndicator.qml +++ b/resources/qml/EncryptionIndicator.qml @@ -43,7 +43,7 @@ Image { case Crypto.Verified: return sourceUrl + Nheko.theme.green; case Crypto.TOFU: - return sourceUrl + Nheko.colors.buttonText; + return sourceUrl + palette.buttonText; default: return sourceUrl + Nheko.theme.error; } diff --git a/resources/qml/ForwardCompleter.qml b/resources/qml/ForwardCompleter.qml index 4ab23a4f..a5787189 100644 --- a/resources/qml/ForwardCompleter.qml +++ b/resources/qml/ForwardCompleter.qml @@ -19,7 +19,6 @@ Popup { x: Math.round(parent.width / 2 - width / 2) y: Math.round(parent.height / 4) modal: true - palette: Nheko.colors parent: Overlay.overlay width: timelineRoot.width * 0.8 leftPadding: 10 @@ -39,7 +38,7 @@ Popup { text: qsTr("Forward Message") font.bold: true bottomPadding: 10 - color: Nheko.colors.text + color: palette.text } Reply { @@ -50,7 +49,7 @@ Popup { width: parent.width - userColor: TimelineManager.userColor(modelData.userId, Nheko.colors.window) + userColor: TimelineManager.userColor(modelData.userId, palette.window) blurhash: modelData.blurhash ?? "" body: modelData.body ?? "" formattedBody: modelData.formattedBody ?? "" @@ -72,7 +71,7 @@ Popup { id: roomTextInput width: forwardMessagePopup.width - forwardMessagePopup.leftPadding * 2 - color: Nheko.colors.text + color: palette.text onTextEdited: { completerPopup.completer.searchString = text; } @@ -123,11 +122,11 @@ Popup { } background: Rectangle { - color: Nheko.colors.window + color: palette.window } Overlay.modal: Rectangle { - color: Qt.rgba(Nheko.colors.window.r, Nheko.colors.window.g, Nheko.colors.window.b, 0.7) + color: Qt.rgba(palette.window.r, palette.window.g, palette.window.b, 0.7) } } diff --git a/resources/qml/ImageButton.qml b/resources/qml/ImageButton.qml index 547b4a12..ecb402c7 100644 --- a/resources/qml/ImageButton.qml +++ b/resources/qml/ImageButton.qml @@ -12,8 +12,8 @@ AbstractButton { property alias cursor: mouseArea.cursorShape property string image: undefined - property color highlightColor: Nheko.colors.highlight - property color buttonTextColor: Nheko.colors.buttonText + property color highlightColor: palette.highlight + property color buttonTextColor: palette.buttonText property bool changeColorOnHover: true property bool ripple: true diff --git a/resources/qml/MatrixText.qml b/resources/qml/MatrixText.qml index 7956f0b6..96303a2b 100644 --- a/resources/qml/MatrixText.qml +++ b/resources/qml/MatrixText.qml @@ -18,7 +18,7 @@ TextEdit { selectByMouse: !Settings.mobileMode // this always has to be enabled, otherwise you can't click links anymore! //enabled: selectByMouse - color: Nheko.colors.text + color: palette.text onLinkActivated: Nheko.openLink(link) ToolTip.visible: hoveredLink || false ToolTip.text: hoveredLink diff --git a/resources/qml/MatrixTextField.qml b/resources/qml/MatrixTextField.qml index 74cacf33..f1ff2836 100644 --- a/resources/qml/MatrixTextField.qml +++ b/resources/qml/MatrixTextField.qml @@ -10,7 +10,7 @@ import im.nheko 1.0 ColumnLayout { id: c - property color backgroundColor: Nheko.colors.base + property color backgroundColor: palette.base property alias color: labelC.color property alias textPadding: input.padding property alias text: input.text @@ -61,8 +61,7 @@ ColumnLayout { y: contentHeight + input.padding + Nheko.paddingSmall enabled: false - palette: Nheko.colors - color: Nheko.colors.text + color: palette.text font.pixelSize: input.font.pixelSize font.weight: Font.DemiBold font.letterSpacing: input.font.pixelSize * 0.02 @@ -114,7 +113,6 @@ ColumnLayout { id: input Layout.fillWidth: true - palette: Nheko.colors color: labelC.color opacity: labelC.text ? 0 : 1 focus: true @@ -156,7 +154,7 @@ ColumnLayout { Layout.fillWidth: true - color: Nheko.colors.highlight + color: palette.highlight height: 1 Rectangle { @@ -166,7 +164,7 @@ ColumnLayout { anchors.horizontalCenter: parent.horizontalCenter height: parent.height*2 width: 0 - color: Nheko.colors.text + color: palette.text states: State { name: "focused" diff --git a/resources/qml/MessageInput.qml b/resources/qml/MessageInput.qml index 8e72f458..6220249b 100644 --- a/resources/qml/MessageInput.qml +++ b/resources/qml/MessageInput.qml @@ -16,7 +16,7 @@ Rectangle { readonly property string text: messageInput.text - color: Nheko.colors.window + color: palette.window Layout.fillWidth: true Layout.preferredHeight: row.implicitHeight Layout.minimumHeight: 40 @@ -90,7 +90,7 @@ Rectangle { Rectangle { anchors.fill: parent - color: Nheko.colors.window + color: palette.window visible: room && room.input.uploading Spinner { @@ -144,8 +144,8 @@ Rectangle { selectByMouse: true placeholderText: qsTr("Write a message...") - placeholderTextColor: Nheko.colors.buttonText - color: Nheko.colors.text + placeholderTextColor: palette.buttonText + color: palette.text width: textInput.width verticalAlignment: TextEdit.AlignVCenter wrapMode: TextEdit.Wrap @@ -192,8 +192,8 @@ Rectangle { onSelectionStartChanged: room.input.updateState(selectionStart, selectionEnd, cursorPosition, text) onSelectionEndChanged: room.input.updateState(selectionStart, selectionEnd, cursorPosition, text) // Ensure that we get escape key press events first. - Keys.onShortcutOverride: event.accepted = (popup.opened && (event.key === Qt.Key_Escape || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter || event.key === Qt.Key_Space)) - Keys.onPressed: { + Keys.onShortcutOverride: (event) => event.accepted = (popup.opened && (event.key === Qt.Key_Escape || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter || event.key === Qt.Key_Space)) + Keys.onPressed: (event) => { if (event.matches(StandardKey.Paste)) { event.accepted = room.input.tryPasteAttachment(false); } else if (event.key == Qt.Key_Space) { @@ -438,7 +438,6 @@ Rectangle { StickerPicker { id: stickerPopup - colors: Nheko.colors emoji: false } @@ -463,7 +462,6 @@ Rectangle { StickerPicker { id: emojiPopup - colors: Nheko.colors emoji: true } } @@ -489,7 +487,6 @@ Rectangle { anchors.centerIn: parent visible: room ? (!room.permissions.canSend(MtxEvent.TextMessage)) : false text: qsTr("You don't have permission to send messages in this room") - color: Nheko.colors.text } } diff --git a/resources/qml/MessageInputWarning.qml b/resources/qml/MessageInputWarning.qml index 9b0b0907..be73df2a 100644 --- a/resources/qml/MessageInputWarning.qml +++ b/resources/qml/MessageInputWarning.qml @@ -16,7 +16,7 @@ Rectangle { implicitHeight: visible ? warningDisplay.implicitHeight + 4 * Nheko.paddingSmall : 0 height: implicitHeight Layout.fillWidth: true - color: Nheko.colors.window // required to hide the timeline behind this warning + color: palette.window // required to hide the timeline behind this warning Rectangle { id: warningRect @@ -37,7 +37,6 @@ Rectangle { anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter anchors.margins: Nheko.paddingSmall - color: Nheko.colors.text text: warningRoot.text textFormat: Text.PlainText } diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index d0ec3214..b35db9ac 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -91,8 +91,8 @@ Item { z: 10 background: Rectangle { - color: Nheko.colors.window - border.color: Nheko.colors.buttonText + color: palette.window + border.color: palette.buttonText border.width: 1 radius: padding } @@ -113,8 +113,8 @@ Item { required property string modelData - property color highlightColor: Nheko.colors.highlight - property color buttonTextColor: Nheko.colors.buttonText + property color highlightColor: palette.highlight + property color buttonTextColor: palette.buttonText property bool showImage: modelData.startsWith("mxc://") //Layout.preferredHeight: fontMetrics.height @@ -170,7 +170,7 @@ Item { ImageButton { visible: !!row.model && row.model.isEditable - buttonTextColor: Nheko.colors.buttonText + buttonTextColor: palette.buttonText width: 16 hoverEnabled: true image: ":/icons/icons/ui/edit.svg" @@ -223,7 +223,7 @@ Item { ImageButton { visible: !!row.model && filteredTimeline.filterByContent - buttonTextColor: Nheko.colors.buttonText + buttonTextColor: palette.buttonText width: 16 hoverEnabled: true image: ":/icons/icons/ui/go-to.svg" @@ -354,7 +354,7 @@ Item { anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined visible: room && previousMessageDay !== day text: room ? room.formatDateSeparator(timestamp) : "" - color: Nheko.colors.text + color: palette.text height: Math.round(fontMetrics.height * 1.4) width: contentWidth * 1.2 horizontalAlignment: Text.AlignHCenter @@ -362,7 +362,7 @@ Item { background: Rectangle { radius: parent.height / 2 - color: Nheko.colors.window + color: palette.window } } @@ -404,7 +404,7 @@ Item { contentItem: ElidedLabel { id: userName_ fullText: userName - color: TimelineManager.userColor(userId, Nheko.colors.base) + color: TimelineManager.userColor(userId, palette.base) textFormat: Text.RichText elideWidth: Math.min(userInfo.remainingWidth-Math.min(statusMsg.implicitWidth,userInfo.remainingWidth/3), userName_.fullTextWidth) } @@ -427,7 +427,7 @@ Item { Label { id: statusMsg anchors.baseline: userNameButton.baseline - color: Nheko.colors.buttonText + color: palette.buttonText text: userStatus.replace(/\n/g, " ") textFormat: Text.PlainText elide: Text.ElideRight @@ -580,7 +580,7 @@ Item { visible: true z: 1 enabled: false - color: Nheko.colors.highlight + color: palette.highlight states: State { name: "revealed" @@ -646,7 +646,7 @@ Item { anchors.centerIn: parent anchors.margins: Nheko.paddingLarge running: (room && room.paginationInProgress) || chat.filteringInProgress - foreground: Nheko.colors.mid + foreground: palette.mid z: 3 } @@ -892,9 +892,9 @@ Item { hoverEnabled: true background: Rectangle { - color: toEndButton.down ? Nheko.colors.highlight : Nheko.colors.button + color: toEndButton.down ? palette.highlight : palette.button opacity: enabled ? 1 : 0.3 - border.color: toEndButton.hovered ? Nheko.colors.highlight : Nheko.colors.buttonText + border.color: toEndButton.hovered ? palette.highlight : palette.buttonText border.width: 1 radius: toEndButton.radius } @@ -915,7 +915,7 @@ Item { id: buttonImg anchors.fill: parent anchors.margins: Nheko.paddingMedium - source: "image://colorimage/:/icons/icons/ui/download.svg?" + (toEndButton.down ? Nheko.colors.highlightedText : Nheko.colors.buttonText) + source: "image://colorimage/:/icons/icons/ui/download.svg?" + (toEndButton.down ? palette.highlightedText : palette.buttonText) fillMode: Image.PreserveAspectFit } diff --git a/resources/qml/QuickSwitcher.qml b/resources/qml/QuickSwitcher.qml index 916a4cee..5878b391 100644 --- a/resources/qml/QuickSwitcher.qml +++ b/resources/qml/QuickSwitcher.qml @@ -19,7 +19,6 @@ Popup { modal: true closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside parent: Overlay.overlay - palette: Nheko.colors onOpened: { roomTextInput.forceActiveFocus(); } @@ -35,7 +34,7 @@ Popup { width: parent.width font.pixelSize: Math.ceil(quickSwitcher.textHeight * 0.6) - color: Nheko.colors.text + color: palette.text onTextEdited: { completerPopup.completer.searchString = text; } diff --git a/resources/qml/Reactions.qml b/resources/qml/Reactions.qml index cce8720a..caee708e 100644 --- a/resources/qml/Reactions.qml +++ b/resources/qml/Reactions.qml @@ -12,8 +12,8 @@ Flow { id: reactionFlow // lower-contrast colors to avoid distracting from text & to enhance hover effect - property color gentleHighlight: Qt.hsla(Nheko.colors.highlight.hslHue, Nheko.colors.highlight.hslSaturation, Nheko.colors.highlight.hslLightness, 0.8) - property color gentleText: Qt.hsla(Nheko.colors.text.hslHue, Nheko.colors.text.hslSaturation, Nheko.colors.text.hslLightness, 0.6) + property color gentleHighlight: Qt.hsla(palette.highlight.hslHue, palette.highlight.hslSaturation, palette.highlight.hslLightness, 0.8) + property color gentleText: Qt.hsla(palette.text.hslHue, palette.text.hslSaturation, palette.text.hslLightness, 0.6) property string eventId property alias reactions: repeater.model @@ -69,7 +69,7 @@ Flow { return textMetrics.elidedText; } font.family: Settings.emojiFont - color: (reaction.hovered || modelData.selfReactedEvent !== '') ? Nheko.colors.highlightedText: Nheko.colors.text + color: (reaction.hovered || modelData.selfReactedEvent !== '') ? palette.highlightedText: palette.text maximumLineCount: 1 visible: !modelData.key.startsWith("mxc://") } @@ -87,7 +87,7 @@ Flow { height: Math.floor(reactionCounter.implicitHeight * 1.4) width: 1 - color: reaction.hovered ? Nheko.colors.text: gentleText + color: reaction.hovered ? palette.text: gentleText } Text { @@ -96,7 +96,7 @@ Flow { anchors.verticalCenter: divider.verticalCenter text: modelData.count font: reaction.font - color: (reaction.hovered || modelData.selfReactedEvent !== '') ? Nheko.colors.highlightedText: Nheko.colors.windowText + color: (reaction.hovered || modelData.selfReactedEvent !== '') ? palette.highlightedText: palette.windowText } } @@ -105,8 +105,8 @@ Flow { anchors.centerIn: parent implicitWidth: reaction.implicitWidth implicitHeight: reaction.implicitHeight - border.color: reaction.hovered ? Nheko.colors.text: gentleText - color: reaction.hovered ? Nheko.colors.highlight : (modelData.selfReactedEvent !== '' ? gentleHighlight : Nheko.colors.window) + border.color: reaction.hovered ? palette.text: gentleText + color: reaction.hovered ? palette.highlight : (modelData.selfReactedEvent !== '' ? gentleHighlight : palette.window) border.width: 1 radius: reaction.height / 2 } diff --git a/resources/qml/ReplyPopup.qml b/resources/qml/ReplyPopup.qml index 365c5bff..6fceb4e5 100644 --- a/resources/qml/ReplyPopup.qml +++ b/resources/qml/ReplyPopup.qml @@ -15,7 +15,7 @@ Rectangle { visible: room && (room.reply || room.edit || room.thread) // Height of child, plus margins, plus border implicitHeight: (room && room.reply ? replyPreview.height : Math.max(closeEditButton.height, closeThreadButton.height)) + Nheko.paddingSmall - color: Nheko.colors.window + color: palette.window z: 3 Reply { @@ -31,7 +31,7 @@ Rectangle { anchors.rightMargin: replyPopup.width < 450? 2*(22+16) : 3*(22+16) anchors.top: parent.top anchors.topMargin: Nheko.paddingSmall - userColor: TimelineManager.userColor(modelData.userId, Nheko.colors.window) + userColor: TimelineManager.userColor(modelData.userId, palette.window) blurhash: modelData.blurhash ?? "" body: modelData.body ?? "" formattedBody: modelData.formattedBody ?? "" @@ -46,7 +46,7 @@ Rectangle { isOnlyEmoji: modelData.isOnlyEmoji ?? false userId: modelData.userId ?? "" userName: modelData.userName ?? "" - encryptionError: modelData.encryptionError ?? "" + encryptionError: modelData.encryptionError ?? 0 width: parent.width } @@ -90,7 +90,7 @@ Rectangle { anchors.margins: 8 anchors.top: parent.top hoverEnabled: true - buttonTextColor: room ? TimelineManager.userColor(room.thread, Nheko.colors.base) : Nheko.colors.buttonText + buttonTextColor: room ? TimelineManager.userColor(room.thread, palette.base) : palette.buttonText image: ":/icons/icons/ui/dismiss_thread.svg" width: 22 height: 22 diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index 49a36d8f..733063f9 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -97,8 +97,7 @@ Page { width: 420 minimumWidth: 150 minimumHeight: 150 - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window title: room.plainRoomName //flags: Qt.Window | Qt.WindowCloseButtonHint | Qt.WindowTitleHint @@ -197,8 +196,8 @@ Page { Instantiator { model: Communities.tagsWithDefault - onObjectAdded: tagsMenu.insertItem(index, object) - onObjectRemoved: tagsMenu.removeItem(object) + onObjectAdded: (index, object) => tagsMenu.insertItem(index, object) + onObjectRemoved: (index, object) => tagsMenu.removeItem(object) delegate: Platform.MenuItem { property string t: modelData @@ -241,11 +240,11 @@ Page { delegate: ItemDelegate { id: roomItem - property color backgroundColor: Nheko.colors.window - property color importantText: Nheko.colors.text - property color unimportantText: Nheko.colors.buttonText - property color bubbleBackground: Nheko.colors.highlight - property color bubbleText: Nheko.colors.highlightedText + property color backgroundColor: palette.window + property color importantText: palette.text + property color unimportantText: palette.buttonText + property color bubbleBackground: palette.highlight + property color bubbleText: palette.highlightedText required property string roomName required property string roomId required property string avatarUrl @@ -261,7 +260,7 @@ Page { required property string directChatOtherUserId Ripple { - color: Qt.rgba(Nheko.colors.dark.r, Nheko.colors.dark.g, Nheko.colors.dark.b, 0.5) + color: Qt.rgba(palette.dark.r, palette.dark.g, palette.dark.b, 0.5) } height: avatarSize + 2 * Nheko.paddingMedium @@ -290,11 +289,11 @@ Page { PropertyChanges { target: roomItem - backgroundColor: Nheko.colors.dark - importantText: Nheko.colors.brightText - unimportantText: Nheko.colors.brightText - bubbleBackground: Nheko.colors.highlight - bubbleText: Nheko.colors.highlightedText + backgroundColor: palette.dark + importantText: palette.brightText + unimportantText: palette.brightText + bubbleBackground: palette.highlight + bubbleText: palette.highlightedText } }, @@ -304,11 +303,11 @@ Page { PropertyChanges { target: roomItem - backgroundColor: Nheko.colors.highlight - importantText: Nheko.colors.highlightedText - unimportantText: Nheko.colors.highlightedText - bubbleBackground: Nheko.colors.highlightedText - bubbleText: Nheko.colors.highlight + backgroundColor: palette.highlight + importantText: palette.highlightedText + unimportantText: palette.highlightedText + bubbleBackground: palette.highlightedText + bubbleText: palette.highlight } } @@ -450,7 +449,7 @@ Page { anchors.verticalCenter: parent.verticalCenter height: parent.height - Nheko.paddingSmall * 2 width: 3 - color: Nheko.colors.highlight + color: palette.highlight visible: hasUnreadMessages } @@ -491,7 +490,7 @@ Page { padding: Nheko.paddingMedium Layout.minimumHeight: 40 - background: Rectangle {color: Nheko.colors.window} + background: Rectangle {color: palette.window} InputDialog { id: statusDialog @@ -572,7 +571,7 @@ Page { ElidedLabel { Layout.alignment: Qt.AlignTop - color: Nheko.colors.buttonText + color: palette.buttonText font.pointSize: fontMetrics.font.pointSize * 0.9 elideWidth: col.width fullText: userInfoGrid.profile ? userInfoGrid.profile.userid : "" @@ -627,7 +626,7 @@ Page { Layout.margins: Nheko.paddingMedium Layout.rightMargin: Nheko.paddingSmall - color: Nheko.colors.buttonText + color: palette.buttonText Layout.fillWidth: true text: { switch (SelfVerificationStatus.status) { @@ -711,7 +710,7 @@ Page { horizontalPadding: Nheko.paddingMedium verticalPadding: 0 - background: Rectangle {color: Nheko.colors.window} + background: Rectangle {color: palette.window} contentItem: RowLayout { id: buttonRow diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml index 4b71af37..01fde18e 100644 --- a/resources/qml/Root.qml +++ b/resources/qml/Root.qml @@ -20,7 +20,6 @@ import im.nheko.EmojiModel 1.0 Pane { id: timelineRoot - palette: Nheko.colors background: null padding: 0 diff --git a/resources/qml/SelfVerificationCheck.qml b/resources/qml/SelfVerificationCheck.qml index 4f2d9202..bb7ea5f0 100644 --- a/resources/qml/SelfVerificationCheck.qml +++ b/resources/qml/SelfVerificationCheck.qml @@ -37,7 +37,7 @@ Item { Layout.maximumWidth: (Overlay.overlay ? Overlay.overlay.width : 400) - Nheko.paddingMedium * 4 Layout.fillWidth: true text: qsTr("This is your recovery key. You will need it to restore access to your encrypted messages and verification keys. Keep this safe. Don't share it with anyone and don't lose it! Do not pass go! Do not collect $200!") - color: Nheko.colors.text + color: palette.text wrapMode: Text.Wrap } @@ -49,7 +49,7 @@ Item { readOnly: true selectByMouse: true text: showRecoverKeyDialog.recoveryKey - color: Nheko.colors.text + color: palette.text font.bold: true wrapMode: TextEdit.Wrap } @@ -57,7 +57,7 @@ Item { } background: Rectangle { - color: Nheko.colors.window + color: palette.window border.color: Nheko.theme.separator border.width: 1 radius: Nheko.paddingSmall @@ -101,7 +101,7 @@ Item { Layout.columnSpan: 2 font.pointSize: fontMetrics.font.pointSize * 2 text: qsTr("Setup Encryption") - color: Nheko.colors.text + color: palette.text wrapMode: Text.Wrap } @@ -111,7 +111,7 @@ Item { Layout.columnSpan: 2 Layout.maximumWidth: grid.width - Nheko.paddingMedium * 2 text: qsTr("Hello and welcome to Matrix!\nIt seems like you are new. Before you can securely encrypt your messages, we need to setup a few small things. You can either press accept immediately or adjust a few basic options. We also try to explain a few of the basics. You can skip those parts, but they might prove to be helpful!") - color: Nheko.colors.text + color: palette.text wrapMode: Text.Wrap } @@ -121,7 +121,7 @@ Item { Layout.columnSpan: 1 Layout.maximumWidth: Math.floor(grid.width / 2) - Nheko.paddingMedium * 2 text: "Store secrets online.\nYou have a few secrets to make all the encryption magic work. While you can keep them stored only locally, we recommend storing them encrypted on the server. Otherwise it will be painful to recover them. Only disable this if you are paranoid and like losing your data!" - color: Nheko.colors.text + color: palette.text wrapMode: Text.Wrap } @@ -148,7 +148,7 @@ Item { Layout.maximumWidth: Math.floor(grid.width / 2) - Nheko.paddingMedium * 2 visible: storeSecretsOnline.checked text: "Set an online backup password.\nWe recommend you DON'T set a password and instead only rely on the recovery key. You will get a recovery key in any case when storing the cross-signing secrets online, but passwords are usually not very random, so they are easier to attack than a completely random recovery key. If you choose to use a password, DON'T make it the same as your login password, otherwise your server can read all your encrypted messages. (You don't want that.)" - color: Nheko.colors.text + color: palette.text wrapMode: Text.Wrap } @@ -187,7 +187,7 @@ Item { Layout.columnSpan: 1 Layout.maximumWidth: Math.floor(grid.width / 2) - Nheko.paddingMedium * 2 text: "Use online key backup.\nStore the keys for your messages securely encrypted online. In general you do want this, because it protects your messages from becoming unreadable, if you log out by accident. It does however carry a small security risk, if you ever share your recovery key by accident. Currently this also has some other weaknesses, that might allow the server to insert new keys into your backup. The server will however never be able to read your messages." - color: Nheko.colors.text + color: palette.text wrapMode: Text.Wrap } @@ -209,7 +209,7 @@ Item { } background: Rectangle { - color: Nheko.colors.window + color: palette.window border.color: Nheko.theme.separator border.width: 1 radius: Nheko.paddingSmall @@ -235,7 +235,7 @@ Item { //Layout.columnSpan: 2 font.pointSize: fontMetrics.font.pointSize * 2 text: qsTr("Activate Encryption") - color: Nheko.colors.text + color: palette.text wrapMode: Text.Wrap } @@ -245,7 +245,7 @@ Item { //Layout.columnSpan: 2 Layout.maximumWidth: grid.width - Nheko.paddingMedium * 2 text: qsTr("It seems like you have encryption already configured for this account. To be able to access your encrypted messages and make this device appear as trusted, you can either verify an existing device or (if you have one) enter your recovery passphrase. Please select one of the options below.\nIf you choose verify, you need to have the other device available. If you choose \"enter passphrase\", you will need your recovery key or passphrase. If you click cancel, you can choose to verify yourself at a later point.") - color: Nheko.colors.text + color: palette.text wrapMode: Text.Wrap } diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml index d9deefa0..07cb5ce2 100644 --- a/resources/qml/TimelineRow.qml +++ b/resources/qml/TimelineRow.qml @@ -54,7 +54,7 @@ AbstractButton { height: row.height+(reactionRow.height > 0 ? reactionRow.height-2 : 0 )+unreadRow.height Rectangle { - color: (Settings.messageHoverHighlight && hovered) ? Nheko.colors.alternateBase : "transparent" + color: (Settings.messageHoverHighlight && hovered) ? palette.alternateBase : "transparent" anchors.fill: parent // this looks better without margins TapHandler { @@ -112,7 +112,7 @@ AbstractButton { Rectangle { id: threadLine - color: TimelineManager.userColor(threadId, Nheko.colors.base) + color: TimelineManager.userColor(threadId, palette.base) anchors.fill: parent } @@ -133,8 +133,8 @@ AbstractButton { width: Settings.bubbles? Math.min(maxWidth,Math.max(reply.implicitWidth+8,contentItem.implicitWidth+metadata.width+20)) : maxWidth height: msg.height+msg.anchors.margins*2 - property color userColor: TimelineManager.userColor(userId, Nheko.colors.base) - property color bgColor: Nheko.colors.base + property color userColor: TimelineManager.userColor(userId, palette.base) + property color bgColor: palette.base color: (Settings.bubbles && !isStateEvent) ? Qt.tint(bgColor, Qt.hsla(userColor.hslHue, 0.5, userColor.hslLightness, 0.2)) : "#00000000" radius: 4 border.width: r.notificationlevel == MtxEvent.Highlight ? 1 : 0 @@ -169,7 +169,7 @@ AbstractButton { return replyTo != "" ? room.dataById(replyTo, role, r.eventId) : null; } visible: replyTo - userColor: r.relatedEventCacheBuster, TimelineManager.userColor(userId, Nheko.colors.base) + userColor: r.relatedEventCacheBuster, TimelineManager.userColor(userId, palette.base) blurhash: r.relatedEventCacheBuster, fromModel(Room.Blurhash) ?? "" body: r.relatedEventCacheBuster, fromModel(Room.Body) ?? "" formattedBody: r.relatedEventCacheBuster, fromModel(Room.FormattedBody) ?? "" @@ -186,11 +186,11 @@ AbstractButton { userId: r.relatedEventCacheBuster, fromModel(Room.UserId) ?? "" userName: r.relatedEventCacheBuster, fromModel(Room.UserName) ?? "" thumbnailUrl: r.relatedEventCacheBuster, fromModel(Room.ThumbnailUrl) ?? "" - duration: r.relatedEventCacheBuster, fromModel(Room.Duration) ?? "" + duration: r.relatedEventCacheBuster, fromModel(Room.Duration) ?? 0 roomTopic: r.relatedEventCacheBuster, fromModel(Room.RoomTopic) ?? "" roomName: r.relatedEventCacheBuster, fromModel(Room.RoomName) ?? "" callType: r.relatedEventCacheBuster, fromModel(Room.CallType) ?? "" - encryptionError: r.relatedEventCacheBuster, fromModel(Room.EncryptionError) ?? "" + encryptionError: r.relatedEventCacheBuster, fromModel(Room.EncryptionError) ?? 0 relatedEventCacheBuster: r.relatedEventCacheBuster, fromModel(Room.RelatedEventCacheBuster) ?? 0 } @@ -260,7 +260,7 @@ AbstractButton { width: parent.iconSize sourceSize.width: parent.iconSize * Screen.devicePixelRatio sourceSize.height: parent.iconSize * Screen.devicePixelRatio - source: "image://colorimage/:/icons/icons/ui/edit.svg?" + ((eventId == room.edit) ? Nheko.colors.highlight : Nheko.colors.buttonText) + source: "image://colorimage/:/icons/icons/ui/edit.svg?" + ((eventId == room.edit) ? palette.highlight : palette.buttonText) ToolTip.visible: editHovered.hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: qsTr("Edited") @@ -278,7 +278,7 @@ AbstractButton { height: parent.iconSize width: parent.iconSize image: ":/icons/icons/ui/thread.svg" - buttonTextColor: TimelineManager.userColor(threadId, Nheko.colors.base) + buttonTextColor: TimelineManager.userColor(threadId, palette.base) ToolTip.visible: hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: qsTr("Part of a thread") @@ -303,7 +303,7 @@ AbstractButton { Layout.alignment: Qt.AlignRight | Qt.AlignTop Layout.preferredWidth: implicitWidth text: timestamp.toLocaleTimeString(Locale.ShortFormat) - color: Nheko.inactiveColors.text + color: palette.inactive.text ToolTip.visible: ma.hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: Qt.formatDateTime(timestamp, Qt.DefaultLocaleLongDate) @@ -341,7 +341,7 @@ AbstractButton { left: parent.left right: parent.right } - color: Nheko.colors.highlight + color: palette.highlight visible: (r.index > 0 && (room.fullyReadEventId == r.eventId)) height: visible ? 3 : 0 diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index c8b22616..8fc567f2 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -32,12 +32,11 @@ Item { StickerPicker { id: emojiPopup - colors: Nheko.colors emoji: true } // focus message input on key press, but not on Ctrl-C and such. - Keys.onPressed: { + Keys.onPressed: (event) => { if (event.text && event.key !== Qt.Key_Enter && event.key !== Qt.Key_Return && !topBar.searchHasFocus) { TimelineManager.focusMessageInput(); room.input.setText(room.input.text + event.text); @@ -54,13 +53,12 @@ Item { anchors.centerIn: parent text: qsTr("No room open") font.pointSize: 24 - color: Nheko.colors.text } Spinner { visible: TimelineManager.isInitialSync anchors.centerIn: parent - foreground: Nheko.colors.mid + foreground: palette.mid running: TimelineManager.isInitialSync // height is somewhat arbitrary here... don't set width because width scales w/ height height: parent.height / 16 @@ -102,7 +100,7 @@ Item { Layout.fillWidth: true Layout.fillHeight: true - color: Nheko.colors.base + color: palette.base ColumnLayout { anchors.fill: parent @@ -223,7 +221,7 @@ Item { Layout.alignment: Qt.AlignHCenter MatrixText { - text: !roomPreview.isFetched ? qsTr("No preview available") : preview.roomName + text: !(roomPreview?.isFetched ?? false) ? qsTr("No preview available") : preview.roomName font.pixelSize: 24 } @@ -264,13 +262,12 @@ Item { Layout.rightMargin: Nheko.paddingLarge TextArea { - text: roomPreview.isFetched ? TimelineManager.escapeEmoji(preview.roomTopic) : qsTr("This room is possibly inaccessible. If this room is private, you should remove it from this community.") + text: (roomPreview?.isFetched ?? false) ? TimelineManager.escapeEmoji(preview.roomTopic) : qsTr("This room is possibly inaccessible. If this room is private, you should remove it from this community.") wrapMode: TextEdit.WordWrap textFormat: TextEdit.RichText readOnly: true background: null selectByMouse: true - color: Nheko.colors.text horizontalAlignment: TextEdit.AlignHCenter onLinkActivated: Nheko.openLink(link) @@ -328,7 +325,6 @@ Item { readOnly: true background: null selectByMouse: true - color: Nheko.colors.text horizontalAlignment: TextEdit.AlignHCenter } diff --git a/resources/qml/ToggleButton.qml b/resources/qml/ToggleButton.qml index 6b43bec5..66902bfd 100644 --- a/resources/qml/ToggleButton.qml +++ b/resources/qml/ToggleButton.qml @@ -32,7 +32,7 @@ Switch { PropertyChanges { target: track - border.color: Nheko.colors.highlight + border.color: palette.highlight } PropertyChanges { @@ -88,7 +88,7 @@ Switch { width: parent.height * 0.9 height: width radius: width / 2 - color: Nheko.colors.button + color: palette.button border.color: "#767676" } diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index f23645a7..eaaa38ea 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -53,7 +53,7 @@ Pane { padding: 0 background: Rectangle { - color: Nheko.colors.window + color: palette.window } TapHandler { @@ -137,7 +137,7 @@ Pane { Layout.column: 2 Layout.row: 0 Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text text: qsTr("In %1").arg(communityAvatar.displayName) maximumLineCount: 1 elide: Text.ElideRight @@ -178,7 +178,7 @@ Pane { Layout.fillWidth: true Layout.column: 2 Layout.row: 1 - color: Nheko.colors.text + color: palette.text font.pointSize: fontMetrics.font.pointSize * 1.1 font.bold: true text: roomName @@ -241,8 +241,8 @@ Pane { trust: trustlevel enabled: false unencryptedIcon: ":/icons/icons/ui/people.svg" - unencryptedColor: Nheko.colors.buttonText - unencryptedHoverColor: Nheko.colors.highlight + unencryptedColor: palette.buttonText + unencryptedHoverColor: palette.highlight hovered: parent.hovered ToolTip.delay: Nheko.tooltipDelay @@ -349,7 +349,6 @@ Pane { visible: !!room && room.pinnedMessages.length > 0 && !Settings.hiddenPins.includes(roomId) clip: true - palette: Nheko.colors ScrollBar.horizontal.visible: false ListView { @@ -372,7 +371,7 @@ Pane { Layout.fillWidth: true Layout.preferredHeight: height - userColor: TimelineManager.userColor(e.userId, Nheko.colors.window) + userColor: TimelineManager.userColor(e.userId, palette.window) blurhash: e.blurhash ?? "" body: e.body ?? "" formattedBody: e.formattedBody ?? "" @@ -387,7 +386,7 @@ Pane { isOnlyEmoji: e.isOnlyEmoji ?? false userId: e.userId ?? "" userName: e.userName ?? "" - encryptionError: e.encryptionError ?? "" + encryptionError: e.encryptionError ?? 0 keepFullText: true } @@ -430,7 +429,6 @@ Pane { visible: !!room && room.widgetLinks.length > 0 && !Settings.hiddenWidgets.includes(roomId) clip: true - palette: Nheko.colors ScrollBar.horizontal.visible: false ListView { @@ -440,7 +438,7 @@ Pane { delegate: MatrixText { required property var modelData - color: Nheko.colors.text + color: palette.text text: modelData } diff --git a/resources/qml/TypingIndicator.qml b/resources/qml/TypingIndicator.qml index 027ae5b6..704fe8ef 100644 --- a/resources/qml/TypingIndicator.qml +++ b/resources/qml/TypingIndicator.qml @@ -15,7 +15,7 @@ Item { id: typingRect visible: (room && room.typingUsers.length > 0) - color: Nheko.colors.base + color: palette.base anchors.fill: parent z: 3 @@ -27,8 +27,8 @@ Item { anchors.right: parent.right anchors.rightMargin: 10 anchors.bottom: parent.bottom - color: Nheko.colors.text - text: room ? room.formatTypingUsers(room.typingUsers, Nheko.colors.base) : "" + color: palette.text + text: room ? room.formatTypingUsers(room.typingUsers, palette.base) : "" textFormat: Text.RichText } diff --git a/resources/qml/UploadBox.qml b/resources/qml/UploadBox.qml index adb8c12b..ccec6131 100644 --- a/resources/qml/UploadBox.qml +++ b/resources/qml/UploadBox.qml @@ -40,7 +40,7 @@ Page { width: uploadPopup.availableHeight - buttons.height background: Rectangle { - color: Nheko.colors.window + color: palette.window radius: Nheko.paddingMedium } contentItem: ColumnLayout { @@ -60,7 +60,7 @@ Page { case MediaUpload.Image: return "image"; default: return "zip"; } - source: (modelData.thumbnail != "") ? modelData.thumbnail : ("image://colorimage/:/icons/icons/ui/"+typeStr+".svg?" + Nheko.colors.buttonText) + source: (modelData.thumbnail != "") ? modelData.thumbnail : ("image://colorimage/:/icons/icons/ui/"+typeStr+".svg?" + palette.buttonText) } MatrixTextField { id: namefield @@ -85,6 +85,6 @@ Page { } background: Rectangle { - color: Nheko.colors.base + color: palette.base } } diff --git a/resources/qml/components/AvatarListTile.qml b/resources/qml/components/AvatarListTile.qml index 02c92a09..dad20e52 100644 --- a/resources/qml/components/AvatarListTile.qml +++ b/resources/qml/components/AvatarListTile.qml @@ -11,11 +11,11 @@ import im.nheko 1.0 Rectangle { id: tile - property color background: Nheko.colors.window - property color importantText: Nheko.colors.text - property color unimportantText: Nheko.colors.buttonText - property color bubbleBackground: Nheko.colors.highlight - property color bubbleText: Nheko.colors.highlightedText + property color background: palette.window + property color importantText: palette.text + property color unimportantText: palette.buttonText + property color bubbleBackground: palette.highlight + property color bubbleText: palette.highlightedText property int avatarSize: Math.ceil(fontMetrics.lineSpacing * 2.3) required property string avatarUrl required property string title @@ -37,11 +37,11 @@ Rectangle { PropertyChanges { target: tile - background: Nheko.colors.dark - importantText: Nheko.colors.brightText - unimportantText: Nheko.colors.brightText - bubbleBackground: Nheko.colors.highlight - bubbleText: Nheko.colors.highlightedText + background: palette.dark + importantText: palette.brightText + unimportantText: palette.brightText + bubbleBackground: palette.highlight + bubbleText: palette.highlightedText } }, @@ -51,11 +51,11 @@ Rectangle { PropertyChanges { target: tile - background: Nheko.colors.highlight - importantText: Nheko.colors.highlightedText - unimportantText: Nheko.colors.highlightedText - bubbleBackground: Nheko.colors.highlightedText - bubbleText: Nheko.colors.highlight + background: palette.highlight + importantText: palette.highlightedText + unimportantText: palette.highlightedText + bubbleBackground: palette.highlightedText + bubbleText: palette.highlight } } diff --git a/resources/qml/components/FlatButton.qml b/resources/qml/components/FlatButton.qml index a3dedf35..0636bc04 100644 --- a/resources/qml/components/FlatButton.qml +++ b/resources/qml/components/FlatButton.qml @@ -47,7 +47,7 @@ Button { font.capitalization: Font.AllUppercase font.pointSize: Math.ceil(fontMetrics.font.pointSize * 1.5) //font.capitalization: Font.AllUppercase - color: Nheko.colors.light + color: palette.light horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter elide: Text.ElideRight @@ -58,7 +58,7 @@ Button { //height: control.contentItem.implicitHeight * 2 //width: control.contentItem.implicitWidth * 2 radius: height / 8 - color: Qt.lighter(Nheko.colors.dark, control.down ? 1.4 : (control.hovered ? 1.2 : 1)) + color: Qt.lighter(palette.dark, control.down ? 1.4 : (control.hovered ? 1.2 : 1)) } } diff --git a/resources/qml/components/MainWindowDialog.qml b/resources/qml/components/MainWindowDialog.qml index 1b063e0f..10c07aae 100644 --- a/resources/qml/components/MainWindowDialog.qml +++ b/resources/qml/components/MainWindowDialog.qml @@ -32,7 +32,7 @@ Dialog { ] background: Rectangle { - color: Nheko.colors.window + color: palette.window border.color: Nheko.theme.separator border.width: 1 radius: Nheko.paddingSmall diff --git a/resources/qml/components/NhekoTabButton.qml b/resources/qml/components/NhekoTabButton.qml index 13549068..796177e8 100644 --- a/resources/qml/components/NhekoTabButton.qml +++ b/resources/qml/components/NhekoTabButton.qml @@ -13,15 +13,15 @@ TabButton { text: control.text font: control.font opacity: enabled ? 1.0 : 0.3 - color: control.down ? Nheko.colors.highlightedText : Nheko.colors.text + color: control.down ? palette.highlightedText : palette.text horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter elide: Text.ElideRight } background: Rectangle { - border.color: control.down ? Nheko.colors.highlight : Nheko.theme.separator - color: control.checked ? Nheko.colors.highlight : Nheko.colors.base + border.color: control.down ? palette.highlight : Nheko.theme.separator + color: control.checked ? palette.highlight : palette.base border.width: 1 radius: 2 } diff --git a/resources/qml/components/ReorderableListview.qml b/resources/qml/components/ReorderableListview.qml index 137e92f8..4e67082e 100644 --- a/resources/qml/components/ReorderableListview.qml +++ b/resources/qml/components/ReorderableListview.qml @@ -47,9 +47,9 @@ Item { width: dragArea.width; height: actualDelegate.implicitHeight + 4 border.width: dragArea.enabled ? 1 : 0 - border.color: Nheko.colors.highlight + border.color: palette.highlight - color: dragArea.held ? Nheko.colors.highlight : Nheko.colors.base + color: dragArea.held ? palette.highlight : palette.base Behavior on color { ColorAnimation { duration: 100 } } radius: 2 diff --git a/resources/qml/components/TextButton.qml b/resources/qml/components/TextButton.qml index a48aee2b..0b1ac270 100644 --- a/resources/qml/components/TextButton.qml +++ b/resources/qml/components/TextButton.qml @@ -11,8 +11,8 @@ AbstractButton { id: button property alias cursor: mouseArea.cursorShape - property color highlightColor: Nheko.colors.highlight - property color buttonTextColor: Nheko.colors.buttonText + property color highlightColor: palette.highlight + property color buttonTextColor: palette.buttonText focusPolicy: Qt.NoFocus width: buttonText.implicitWidth diff --git a/resources/qml/components/UserListRow.qml b/resources/qml/components/UserListRow.qml index 316baab0..2047f700 100644 --- a/resources/qml/components/UserListRow.qml +++ b/resources/qml/components/UserListRow.qml @@ -36,7 +36,7 @@ ItemDelegate { Label { Layout.fillWidth: true text: displayName - color: TimelineManager.userColor(userid, Nheko.colors.window) + color: TimelineManager.userColor(userid, palette.window) font.pointSize: fontMetrics.font.pointSize } @@ -44,7 +44,7 @@ ItemDelegate { Layout.fillWidth: true Layout.alignment: Qt.AlignTop text: userid - color: Nheko.colors.buttonText + color: palette.buttonText font.pointSize: fontMetrics.font.pointSize * 0.9 } } diff --git a/resources/qml/delegates/Encrypted.qml b/resources/qml/delegates/Encrypted.qml index 74e1cb0d..fdfe958e 100644 --- a/resources/qml/delegates/Encrypted.qml +++ b/resources/qml/delegates/Encrypted.qml @@ -18,7 +18,7 @@ Rectangle { width: parent.width? parent.width : 0 implicitWidth: encryptedText.implicitWidth+24+Nheko.paddingMedium*3 // Column doesn't provide a useful implicitWidth, should be replaced by ColumnLayout height: contents.implicitHeight + Nheko.paddingMedium * 2 - color: Nheko.colors.alternateBase + color: palette.alternateBase RowLayout { id: contents @@ -58,12 +58,11 @@ Rectangle { return qsTr("Unknown decryption error"); } } - color: Nheko.colors.text + color: palette.text width: parent.width } Button { - palette: Nheko.colors visible: encryptionError == Olm.MissingSession || encryptionError == Olm.MissingSessionIndex text: qsTr("Request key") onClicked: room.requestKeyForEvent(eventId) diff --git a/resources/qml/delegates/EncryptionEnabled.qml b/resources/qml/delegates/EncryptionEnabled.qml index e38be4b0..c8671c84 100644 --- a/resources/qml/delegates/EncryptionEnabled.qml +++ b/resources/qml/delegates/EncryptionEnabled.qml @@ -17,7 +17,7 @@ Rectangle { width: parent.width ? Math.min(parent.width, 700) : 0 anchors.horizontalCenter: parent.horizontalCenter height: contents.implicitHeight + Nheko.paddingMedium * 2 - color: Nheko.colors.alternateBase + color: palette.alternateBase border.color: Nheko.theme.green border.width: 2 @@ -43,13 +43,13 @@ Rectangle { text: qsTr("%1 enabled end-to-end encryption").arg(r.username) font.bold: true font.pointSize: 14 - color: Nheko.colors.text + color: palette.text width: parent.width } MatrixText { text: qsTr("Encryption keeps your messages safe by only allowing the people you sent the message to to read it. For extra security, if you want to make sure you are talking to the right people, you can verify them in real life.") - color: Nheko.colors.text + color: palette.text width: parent.width } diff --git a/resources/qml/delegates/FileMessage.qml b/resources/qml/delegates/FileMessage.qml index b3c44af2..e63ca8e3 100644 --- a/resources/qml/delegates/FileMessage.qml +++ b/resources/qml/delegates/FileMessage.qml @@ -27,7 +27,7 @@ Item { Rectangle { id: button - color: Nheko.colors.light + color: palette.light radius: 22 height: 44 width: 44 @@ -67,7 +67,7 @@ Item { text: filename textFormat: Text.PlainText elide: Text.ElideRight - color: Nheko.colors.text + color: palette.text } Text { @@ -77,7 +77,7 @@ Item { text: filesize textFormat: Text.PlainText elide: Text.ElideRight - color: Nheko.colors.text + color: palette.text } } @@ -85,7 +85,7 @@ Item { } Rectangle { - color: Nheko.colors.alternateBase + color: palette.alternateBase z: -1 radius: 10 anchors.fill: parent diff --git a/resources/qml/delegates/ImageMessage.qml b/resources/qml/delegates/ImageMessage.qml index bed4b659..20d727c3 100644 --- a/resources/qml/delegates/ImageMessage.qml +++ b/resources/qml/delegates/ImageMessage.qml @@ -22,7 +22,7 @@ AbstractButton { property int tempWidth: originalWidth < 1? 400: originalWidth implicitWidth: Math.round(tempWidth*Math.min((timelineView.height/divisor)/(tempWidth*proportionalHeight), 1)) - width: Math.min(parent.width,implicitWidth) + width: Math.min(parent?.width ?? 2000,implicitWidth) height: width*proportionalHeight hoverEnabled: true @@ -106,14 +106,14 @@ AbstractButton { ] property int metadataWidth - property bool fitsMetadata: (parent.width - width) > metadataWidth+4 + property bool fitsMetadata: parent != null ? (parent.width - width) > metadataWidth+4 : false Image { id: img visible: !mxcimage.loaded anchors.fill: parent - source: url.replace("mxc://", "image://MxcImage/") + "?scale" + source: url != "" ? (url.replace("mxc://", "image://MxcImage/") + "?scale") : "" asynchronous: true fillMode: Image.PreserveAspectFit smooth: true @@ -137,7 +137,7 @@ AbstractButton { id: blurhash_ anchors.fill: parent - source: blurhash ? ("image://blurhash/" + blurhash) : ("image://colorimage/:/icons/icons/ui/image-failed.svg?" + Nheko.colors.buttonText) + source: blurhash ? ("image://blurhash/" + blurhash) : ("image://colorimage/:/icons/icons/ui/image-failed.svg?" + palette.buttonText) asynchronous: true fillMode: Image.PreserveAspectFit sourceSize.width: parent.width * Screen.devicePixelRatio @@ -158,7 +158,7 @@ AbstractButton { width: parent.width implicitHeight: imgcaption.implicitHeight anchors.bottom: overlay.bottom - color: Nheko.colors.window + color: palette.window opacity: 0.75 } @@ -171,7 +171,7 @@ AbstractButton { verticalAlignment: Text.AlignVCenter // See this MSC: https://github.com/matrix-org/matrix-doc/pull/2530 text: filename ? filename : body - color: Nheko.colors.text + color: palette.text } } diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml index c0bcec0d..cd8109b4 100644 --- a/resources/qml/delegates/MessageDelegate.qml +++ b/resources/qml/delegates/MessageDelegate.qml @@ -13,7 +13,7 @@ Item { required property bool isReply property bool keepFullText: !isReply property alias child: chooser.child - implicitWidth: (chooser.child && chooser.child.implicitWidth) ? chooser.child.implicitWidth : 0 + //implicitWidth: chooser.child?.implicitWidth ?? 0 required property double proportionalHeight required property int type required property string typeString @@ -48,7 +48,7 @@ Item { roleValue: type //anchors.fill: parent - width: parent.width? parent.width: 0 // this should get rid of "cannot read property 'width' of null" + width: parent?.width ?? 0 // this should get rid of "cannot read property 'width' of null" DelegateChoice { roleValue: MtxEvent.UnknownEvent @@ -78,7 +78,6 @@ Item { } Button { - palette: Nheko.colors Layout.alignment: Qt.AlignHCenter text: qsTr("Go to replacement room") onClicked: room.joinReplacementRoom(eventId) @@ -149,7 +148,7 @@ Item { NoticeMessage { formatted: TimelineManager.escapeEmoji(d.userName) + " " + d.formattedBody - color: TimelineManager.userColor(d.userId, Nheko.colors.base) + color: TimelineManager.userColor(d.userId, palette.base) body: d.body isOnlyEmoji: d.isOnlyEmoji isReply: d.isReply @@ -617,7 +616,6 @@ Item { Button { visible: d.relatedEventCacheBuster, room.showAcceptKnockButton(d.eventId) - palette: Nheko.colors Layout.alignment: Qt.AlignHCenter text: qsTr("Allow them in") onClicked: room.acceptKnock(eventId) diff --git a/resources/qml/delegates/NoticeMessage.qml b/resources/qml/delegates/NoticeMessage.qml index d62afb96..88efe7b7 100644 --- a/resources/qml/delegates/NoticeMessage.qml +++ b/resources/qml/delegates/NoticeMessage.qml @@ -9,7 +9,7 @@ import im.nheko 1.0 TextMessage { property bool isStateEvent font.italic: true - color: Nheko.colors.buttonText + color: palette.buttonText font.pointSize: isStateEvent? 0.8*Settings.fontSize : Settings.fontSize horizontalAlignment: isStateEvent? Text.AlignHCenter : undefined } diff --git a/resources/qml/delegates/Pill.qml b/resources/qml/delegates/Pill.qml index b60781cb..3f981d4d 100644 --- a/resources/qml/delegates/Pill.qml +++ b/resources/qml/delegates/Pill.qml @@ -8,14 +8,14 @@ import im.nheko 1.0 Label { property bool isStateEvent - color: Nheko.colors.text + color: palette.text horizontalAlignment: Text.AlignHCenter height: Math.round(fontMetrics.height * 1.4) width: contentWidth * 1.2 background: Rectangle { radius: parent.height / 2 - color: Nheko.colors.alternateBase + color: palette.alternateBase } } diff --git a/resources/qml/delegates/Placeholder.qml b/resources/qml/delegates/Placeholder.qml index 08008765..66e28c03 100644 --- a/resources/qml/delegates/Placeholder.qml +++ b/resources/qml/delegates/Placeholder.qml @@ -10,5 +10,5 @@ MatrixText { text: qsTr("unimplemented event: ") + typeString // width: parent.width - color: Nheko.inactiveColors.text + color: palette.inactive.text } diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml index 1131856f..60a61372 100644 --- a/resources/qml/delegates/PlayableMediaMessage.qml +++ b/resources/qml/delegates/PlayableMediaMessage.qml @@ -47,7 +47,7 @@ Item { Rectangle { id: videoContainer - color: type == MtxEvent.VideoMessage ? Nheko.colors.window : "transparent" + color: type == MtxEvent.VideoMessage ? palette.window : "transparent" width: parent.width height: parent.height - fileInfoLabel.height @@ -57,7 +57,7 @@ Item { Image { anchors.fill: parent - source: thumbnailUrl ? thumbnailUrl.replace("mxc://", "image://MxcImage/") + "?scale" : "image://colorimage/:/icons/icons/ui/video-file.svg?" + Nheko.colors.windowText + source: thumbnailUrl ? thumbnailUrl.replace("mxc://", "image://MxcImage/") + "?scale" : "image://colorimage/:/icons/icons/ui/video-file.svg?" + palette.windowText asynchronous: true fillMode: Image.PreserveAspectFit @@ -99,10 +99,10 @@ Item { text: body + " [" + filesize + "]" textFormat: Text.RichText elide: Text.ElideRight - color: Nheko.colors.text + color: palette.text background: Rectangle { - color: Nheko.colors.base + color: palette.base } } diff --git a/resources/qml/delegates/Redacted.qml b/resources/qml/delegates/Redacted.qml index 74d4e015..4a9700dc 100644 --- a/resources/qml/delegates/Redacted.qml +++ b/resources/qml/delegates/Redacted.qml @@ -13,7 +13,7 @@ Rectangle{ implicitWidth: redactedLayout.implicitWidth + 2 * Nheko.paddingMedium width: Math.min(parent.width,implicitWidth+1) radius: fontMetrics.lineSpacing / 2 + 2 * Nheko.paddingSmall - color: Nheko.colors.alternateBase + color: palette.alternateBase property int metadataWidth property bool fitsMetadata: parent.width - redactedLayout.width > metadataWidth + 4 @@ -28,7 +28,7 @@ Rectangle{ Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter Layout.preferredWidth: fontMetrics.font.pixelSize Layout.preferredHeight: fontMetrics.font.pixelSize - source: "image://colorimage/:/icons/icons/ui/delete.svg?" + Nheko.colors.text + source: "image://colorimage/:/icons/icons/ui/delete.svg?" + palette.text } Label { id: redactedLabel @@ -39,7 +39,7 @@ Rectangle{ property var redactedPair: room.formatRedactedEvent(eventId) text: redactedPair["first"] wrapMode: Label.WordWrap - color: Nheko.colors.text + color: palette.text ToolTip.text: redactedPair["second"] ToolTip.visible: hh.hovered diff --git a/resources/qml/delegates/Reply.qml b/resources/qml/delegates/Reply.qml index c593a4f8..94128960 100644 --- a/resources/qml/delegates/Reply.qml +++ b/resources/qml/delegates/Reply.qml @@ -54,7 +54,7 @@ AbstractButton { anchors.top: replyContainer.top anchors.bottom: replyContainer.bottom width: 4 - color: TimelineManager.userColor(userId, Nheko.colors.base) + color: TimelineManager.userColor(userId, palette.base) } onClicked: { @@ -135,8 +135,8 @@ AbstractButton { z: -1 anchors.fill: replyContainer - property color userColor: TimelineManager.userColor(userId, Nheko.colors.base) - property color bgColor: Nheko.colors.base + property color userColor: TimelineManager.userColor(userId, palette.base) + property color bgColor: palette.base color: Qt.tint(bgColor, Qt.hsla(userColor.hslHue, 0.5, userColor.hslLightness, 0.1)) } diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index eb46a9ac..39e8b1a8 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -19,15 +19,15 @@ MatrixText { // table border-collapse doesn't seem to work text: " " + formatted.replace(//g, "").replace(/<\/del>/g, "").replace(//g, "").replace(/<\/strike>/g, "") - width: parent.width + width: parent?.width ?? 0 height: !keepFullText ? Math.round(Math.min(timelineView.height / 8, implicitHeight)) : implicitHeight clip: !keepFullText selectByMouse: !Settings.mobileMode && !isReply diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index d44fd9cf..afc6fd0a 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -15,8 +15,7 @@ ApplicationWindow { onClosing: VerificationManager.removeVerificationFlow(flow) title: stack.currentItem ? (stack.currentItem.title_ || "") : "" modality: Qt.NonModal - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window //height: stack.currentItem.implicitHeight minimumHeight: stack.currentItem.implicitHeight + 2 * Nheko.paddingLarge height: stack.currentItem.implicitHeight + 2 * Nheko.paddingMedium @@ -25,7 +24,7 @@ ApplicationWindow { flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint background: Rectangle { - color: Nheko.colors.window + color: palette.window } diff --git a/resources/qml/device-verification/DigitVerification.qml b/resources/qml/device-verification/DigitVerification.qml index 10ba4c55..33cc59f4 100644 --- a/resources/qml/device-verification/DigitVerification.qml +++ b/resources/qml/device-verification/DigitVerification.qml @@ -17,7 +17,7 @@ ColumnLayout { Layout.fillWidth: true wrapMode: Text.Wrap text: qsTr("Please verify the following digits. You should see the same numbers on both sides. If they differ, please press 'They do not match!' to abort verification!") - color: Nheko.colors.text + color: palette.text verticalAlignment: Text.AlignVCenter } @@ -28,19 +28,19 @@ ColumnLayout { Label { font.pixelSize: Qt.application.font.pixelSize * 2 text: flow.sasList[0] - color: Nheko.colors.text + color: palette.text } Label { font.pixelSize: Qt.application.font.pixelSize * 2 text: flow.sasList[1] - color: Nheko.colors.text + color: palette.text } Label { font.pixelSize: Qt.application.font.pixelSize * 2 text: flow.sasList[2] - color: Nheko.colors.text + color: palette.text } } diff --git a/resources/qml/device-verification/EmojiVerification.qml b/resources/qml/device-verification/EmojiVerification.qml index a6f6ff09..0ee279cd 100644 --- a/resources/qml/device-verification/EmojiVerification.qml +++ b/resources/qml/device-verification/EmojiVerification.qml @@ -17,7 +17,7 @@ ColumnLayout { Layout.fillWidth: true wrapMode: Text.Wrap text: qsTr("Please verify the following emoji. You should see the same emoji on both sides. If they differ, please press 'They do not match!' to abort verification!") - color: Nheko.colors.text + color: palette.text verticalAlignment: Text.AlignVCenter } @@ -373,13 +373,13 @@ ColumnLayout { text: col.emoji.emoji font.pixelSize: Qt.application.font.pixelSize * 2 font.family: Settings.emojiFont - color: Nheko.colors.text + color: palette.text } Label { Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom text: col.emoji.description - color: Nheko.colors.text + color: palette.text } } @@ -396,7 +396,7 @@ ColumnLayout { Layout.fillWidth: true wrapMode: Text.Wrap text: qsTr("The displayed emoji might look different in different clients if a different font is used. Similarly they might be translated into different languages. Nonetheless they should depict one of 64 different objects or animals. For example a lion and a cat are different, but a cat is the same even if one client just shows a cat face, while another client shows a full cat body.") - color: Nheko.colors.text + color: palette.text verticalAlignment: Text.AlignVCenter } diff --git a/resources/qml/device-verification/Failed.qml b/resources/qml/device-verification/Failed.qml index fe514df0..5847894b 100644 --- a/resources/qml/device-verification/Failed.qml +++ b/resources/qml/device-verification/Failed.qml @@ -35,7 +35,7 @@ ColumnLayout { return qsTr("Unknown verification error."); } } - color: Nheko.colors.text + color: palette.text verticalAlignment: Text.AlignVCenter } diff --git a/resources/qml/device-verification/NewVerificationRequest.qml b/resources/qml/device-verification/NewVerificationRequest.qml index 84bee834..9a9ab703 100644 --- a/resources/qml/device-verification/NewVerificationRequest.qml +++ b/resources/qml/device-verification/NewVerificationRequest.qml @@ -36,7 +36,7 @@ ColumnLayout { return qsTr("Your device (%1) has requested to be verified.").arg(flow.deviceId); } } - color: Nheko.colors.text + color: palette.text verticalAlignment: Text.AlignVCenter } diff --git a/resources/qml/device-verification/Success.qml b/resources/qml/device-verification/Success.qml index 4e7bd5d1..4b60a5a3 100644 --- a/resources/qml/device-verification/Success.qml +++ b/resources/qml/device-verification/Success.qml @@ -19,7 +19,7 @@ ColumnLayout { Layout.fillWidth: true wrapMode: Text.Wrap text: qsTr("Verification successful! Both sides verified their devices!") - color: Nheko.colors.text + color: palette.text verticalAlignment: Text.AlignVCenter } diff --git a/resources/qml/device-verification/Waiting.qml b/resources/qml/device-verification/Waiting.qml index a7e68ae9..5b45fc7c 100644 --- a/resources/qml/device-verification/Waiting.qml +++ b/resources/qml/device-verification/Waiting.qml @@ -30,14 +30,14 @@ ColumnLayout { return ""; } } - color: Nheko.colors.text + color: palette.text verticalAlignment: Text.AlignVCenter } Item { Layout.fillHeight: true; } Spinner { Layout.alignment: Qt.AlignHCenter - foreground: Nheko.colors.mid + foreground: palette.mid } Item { Layout.fillHeight: true; } diff --git a/resources/qml/dialogs/AliasEditor.qml b/resources/qml/dialogs/AliasEditor.qml index 8a79f7d2..32efff22 100644 --- a/resources/qml/dialogs/AliasEditor.qml +++ b/resources/qml/dialogs/AliasEditor.qml @@ -41,7 +41,7 @@ ApplicationWindow { font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.1) Layout.fillWidth: true Layout.fillHeight: false - color: Nheko.colors.text + color: palette.text Layout.bottomMargin: Nheko.paddingMedium } @@ -69,7 +69,7 @@ ApplicationWindow { Text { Layout.fillWidth: true text: model.name - color: model.isPublished ? Nheko.colors.text : Nheko.theme.error + color: model.isPublished ? palette.text : Nheko.theme.error textFormat: Text.PlainText } @@ -78,8 +78,8 @@ ApplicationWindow { Layout.margins: 2 image: ":/icons/icons/ui/star.svg" hoverEnabled: true - buttonTextColor: model.isCanonical ? Nheko.colors.highlight : Nheko.colors.text - highlightColor: editingModel.canAdvertize ? Nheko.colors.highlight : buttonTextColor + buttonTextColor: model.isCanonical ? palette.highlight : palette.text + highlightColor: editingModel.canAdvertize ? palette.highlight : buttonTextColor ToolTip.visible: hovered ToolTip.text: model.isCanonical ? qsTr("Primary alias") : qsTr("Make primary alias") @@ -92,8 +92,8 @@ ApplicationWindow { Layout.margins: 2 image: ":/icons/icons/ui/building-shop.svg" hoverEnabled: true - buttonTextColor: model.isAdvertized ? Nheko.colors.highlight : Nheko.colors.text - highlightColor: editingModel.canAdvertize ? Nheko.colors.highlight : buttonTextColor + buttonTextColor: model.isAdvertized ? palette.highlight : palette.text + highlightColor: editingModel.canAdvertize ? palette.highlight : buttonTextColor ToolTip.visible: hovered ToolTip.text: qsTr("Advertise as an alias in this room") @@ -106,7 +106,7 @@ ApplicationWindow { Layout.margins: 2 image: ":/icons/icons/ui/room-directory.svg" hoverEnabled: true - buttonTextColor: model.isPublished ? Nheko.colors.highlight : Nheko.colors.text + buttonTextColor: model.isPublished ? palette.highlight : palette.text ToolTip.visible: hovered ToolTip.text: qsTr("Publish in room directory") @@ -139,7 +139,7 @@ ApplicationWindow { Layout.fillWidth: true selectByMouse: true font.pixelSize: fontMetrics.font.pixelSize - color: Nheko.colors.text + color: palette.text placeholderText: qsTr("#new-alias:server.tld") Component.onCompleted: forceActiveFocus() diff --git a/resources/qml/dialogs/AllowedRoomsSettingsDialog.qml b/resources/qml/dialogs/AllowedRoomsSettingsDialog.qml index d93f1f18..94ecf651 100644 --- a/resources/qml/dialogs/AllowedRoomsSettingsDialog.qml +++ b/resources/qml/dialogs/AllowedRoomsSettingsDialog.qml @@ -20,8 +20,7 @@ ApplicationWindow { minimumHeight: 450 width: 450 height: 680 - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint title: qsTr("Allowed rooms settings") @@ -42,7 +41,7 @@ ApplicationWindow { font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.1) Layout.fillWidth: true Layout.fillHeight: false - color: Nheko.colors.text + color: palette.text Layout.bottomMargin: Nheko.paddingMedium } @@ -72,14 +71,14 @@ ApplicationWindow { Text { Layout.fillWidth: true text: model.name - color: Nheko.colors.text + color: palette.text textFormat: Text.PlainText } Text { Layout.fillWidth: true text: model.isParent ? qsTr("Parent community") : qsTr("Other room") - color: Nheko.colors.buttonText + color: palette.buttonText textFormat: Text.PlainText } } @@ -122,7 +121,7 @@ ApplicationWindow { placeholderText: qsTr("Enter additional rooms not in the list yet...") - color: Nheko.colors.text + color: palette.text onTextEdited: { roomCompleter.completer.searchString = text; } diff --git a/resources/qml/dialogs/ConfirmJoinRoomDialog.qml b/resources/qml/dialogs/ConfirmJoinRoomDialog.qml index b37630c8..a3fb9831 100644 --- a/resources/qml/dialogs/ConfirmJoinRoomDialog.qml +++ b/resources/qml/dialogs/ConfirmJoinRoomDialog.qml @@ -19,8 +19,7 @@ ApplicationWindow { title: summary.isSpace ? qsTr("Confirm community join") : qsTr("Confirm room join") modality: Qt.WindowModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window width: 350 height: content.implicitHeight + Nheko.paddingLarge + footer.implicitHeight @@ -48,7 +47,7 @@ ApplicationWindow { Spinner { Layout.alignment: Qt.AlignHCenter visible: !summary.isLoaded - foreground: Nheko.colors.mid + foreground: palette.mid running: !summary.isLoaded } @@ -57,7 +56,7 @@ ApplicationWindow { textFormat: TextEdit.RichText text: summary.roomName font.pixelSize: fontMetrics.font.pixelSize * 2 - color: Nheko.colors.text + color: palette.text Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true @@ -70,7 +69,7 @@ ApplicationWindow { textFormat: TextEdit.RichText text: summary.roomid font.pixelSize: fontMetrics.font.pixelSize * 0.8 - color: Nheko.colors.text + color: palette.text Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true @@ -96,7 +95,7 @@ ApplicationWindow { readOnly: true textFormat: TextEdit.RichText text: summary.roomTopic - color: Nheko.colors.text + color: palette.text Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true @@ -109,7 +108,7 @@ ApplicationWindow { id: promptLabel text: summary.isKnockOnly ? qsTr("This room can't be joined directly. You can, however, knock on the room and room members can accept or decline this join request. You can additionally provide a reason for them to let you in below:") : qsTr("Do you want to join this room? You can optionally add a reason below:") - color: Nheko.colors.text + color: palette.text Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter wrapMode: Text.Wrap diff --git a/resources/qml/dialogs/CreateDirect.qml b/resources/qml/dialogs/CreateDirect.qml index 4ce568bb..75013970 100644 --- a/resources/qml/dialogs/CreateDirect.qml +++ b/resources/qml/dialogs/CreateDirect.qml @@ -55,14 +55,14 @@ ApplicationWindow { Label { Layout.fillWidth: true text: profile? profile.displayName : "" - color: TimelineManager.userColor(userID.text, Nheko.colors.window) + color: TimelineManager.userColor(userID.text, palette.window) font.pointSize: fontMetrics.font.pointSize } Label { Layout.fillWidth: true text: userID.text - color: Nheko.colors.buttonText + color: palette.buttonText font.pointSize: fontMetrics.font.pointSize * 0.9 } } @@ -89,7 +89,7 @@ ApplicationWindow { Layout.fillWidth: true Layout.alignment: Qt.AlignLeft text: qsTr("Encryption") - color: Nheko.colors.text + color: palette.text } ToggleButton { Layout.alignment: Qt.AlignRight diff --git a/resources/qml/dialogs/CreateRoom.qml b/resources/qml/dialogs/CreateRoom.qml index cb198bb8..2164ba50 100644 --- a/resources/qml/dialogs/CreateRoom.qml +++ b/resources/qml/dialogs/CreateRoom.qml @@ -64,7 +64,7 @@ ApplicationWindow { Label { Layout.preferredWidth: implicitWidth text: "#" - color: Nheko.colors.text + color: palette.text } MatrixTextField { id: newRoomAlias @@ -75,14 +75,14 @@ ApplicationWindow { Layout.preferredWidth: implicitWidth property string userName: userInfoGrid.profile.userid text: userName.substring(userName.indexOf(":")) - color: Nheko.colors.text + color: palette.text } } Label { Layout.preferredWidth: implicitWidth Layout.alignment: Qt.AlignLeft text: qsTr("Public") - color: Nheko.colors.text + color: palette.text HoverHandler { id: privateHover } @@ -101,7 +101,7 @@ ApplicationWindow { Layout.preferredWidth: implicitWidth Layout.alignment: Qt.AlignLeft text: qsTr("Trusted") - color: Nheko.colors.text + color: palette.text HoverHandler { id: trustedHover } @@ -122,7 +122,7 @@ ApplicationWindow { Layout.preferredWidth: implicitWidth Layout.alignment: Qt.AlignLeft text: qsTr("Encryption") - color: Nheko.colors.text + color: palette.text HoverHandler { id: encryptionHover } diff --git a/resources/qml/dialogs/ImagePackEditorDialog.qml b/resources/qml/dialogs/ImagePackEditorDialog.qml index 4f30e78a..9e848150 100644 --- a/resources/qml/dialogs/ImagePackEditorDialog.qml +++ b/resources/qml/dialogs/ImagePackEditorDialog.qml @@ -22,8 +22,7 @@ ApplicationWindow { title: qsTr("Editing image pack") height: 600 width: 600 - palette: Nheko.colors - color: Nheko.colors.base + color: palette.base modality: Qt.WindowModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint @@ -73,13 +72,12 @@ ApplicationWindow { anchors.verticalCenter: parent.verticalCenter height: parent.height - Nheko.paddingSmall * 2 width: 3 - color: Nheko.colors.highlight + color: palette.highlight } } footer: Button { - palette: Nheko.colors onClicked: addFilesDialog.open() width: ListView.view.width text: qsTr("Add images") @@ -100,11 +98,11 @@ ApplicationWindow { delegate: AvatarListTile { id: packItem - property color background: Nheko.colors.window - property color importantText: Nheko.colors.text - property color unimportantText: Nheko.colors.buttonText - property color bubbleBackground: Nheko.colors.highlight - property color bubbleText: Nheko.colors.highlightedText + property color background: palette.window + property color importantText: palette.text + property color unimportantText: palette.buttonText + property color bubbleBackground: palette.highlight + property color bubbleText: palette.highlightedText required property string shortCode required property string url required property string body @@ -129,7 +127,7 @@ ApplicationWindow { id: packinfoC Rectangle { - color: Nheko.colors.window + color: palette.window GridLayout { anchors.fill: parent diff --git a/resources/qml/dialogs/ImagePackSettingsDialog.qml b/resources/qml/dialogs/ImagePackSettingsDialog.qml index 76d84a07..31a34c94 100644 --- a/resources/qml/dialogs/ImagePackSettingsDialog.qml +++ b/resources/qml/dialogs/ImagePackSettingsDialog.qml @@ -23,8 +23,7 @@ ApplicationWindow { title: qsTr("Image pack settings") height: 600 width: 800 - palette: Nheko.colors - color: Nheko.colors.base + color: palette.base modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint @@ -64,7 +63,6 @@ ApplicationWindow { footer: ColumnLayout { Button { - palette: Nheko.colors onClicked: { var dialog = packEditor.createObject(timelineRoot, { "imagePack": packlist.newPack(false) @@ -78,7 +76,6 @@ ApplicationWindow { } Button { - palette: Nheko.colors onClicked: { var dialog = packEditor.createObject(timelineRoot, { "imagePack": packlist.newPack(true) @@ -96,11 +93,11 @@ ApplicationWindow { delegate: AvatarListTile { id: packItem - property color background: Nheko.colors.window - property color importantText: Nheko.colors.text - property color unimportantText: Nheko.colors.buttonText - property color bubbleBackground: Nheko.colors.highlight - property color bubbleText: Nheko.colors.highlightedText + property color background: palette.window + property color importantText: palette.text + property color unimportantText: palette.buttonText + property color bubbleBackground: palette.highlight + property color bubbleText: palette.highlightedText required property string displayName required property bool fromAccountData required property bool fromCurrentRoom @@ -135,7 +132,7 @@ ApplicationWindow { id: packinfoC Rectangle { - color: Nheko.colors.window + color: palette.window ColumnLayout { id: packinfo @@ -243,7 +240,7 @@ ApplicationWindow { background: Rectangle { anchors.fill: parent - color: hovered ? Nheko.colors.highlight : 'transparent' + color: hovered ? palette.highlight : 'transparent' radius: 5 } diff --git a/resources/qml/dialogs/InputDialog.qml b/resources/qml/dialogs/InputDialog.qml index a4ca1683..49becc67 100644 --- a/resources/qml/dialogs/InputDialog.qml +++ b/resources/qml/dialogs/InputDialog.qml @@ -37,7 +37,7 @@ ApplicationWindow { Label { id: promptLabel - color: Nheko.colors.text + color: palette.text } MatrixTextField { diff --git a/resources/qml/dialogs/InviteDialog.qml b/resources/qml/dialogs/InviteDialog.qml index b142818d..f5d467db 100644 --- a/resources/qml/dialogs/InviteDialog.qml +++ b/resources/qml/dialogs/InviteDialog.qml @@ -40,8 +40,7 @@ ApplicationWindow { title: qsTr("Invite users to %1").arg(invitees.room.plainRoomName) height: 380 width: 340 - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint Shortcut { @@ -74,12 +73,12 @@ ApplicationWindow { anchors.centerIn: parent id: inviteeUserid text: model.displayName != "" ? model.displayName : model.userid - color: inviteeButton.hovered ? Nheko.colors.highlightedText: Nheko.colors.text + color: inviteeButton.hovered ? palette.highlightedText: palette.text maximumLineCount: 1 } background: Rectangle { - border.color: Nheko.colors.text - color: inviteeButton.hovered ? Nheko.colors.highlight : Nheko.colors.window + border.color: palette.text + color: inviteeButton.hovered ? palette.highlight : palette.window border.width: 1 radius: inviteeButton.height / 2 } @@ -90,7 +89,7 @@ ApplicationWindow { Label { text: qsTr("Search user") Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text } RowLayout { spacing: Nheko.paddingMedium @@ -100,7 +99,7 @@ ApplicationWindow { property bool isValidMxid: text.match("@.+?:.{3,}") - backgroundColor: Nheko.colors.window + backgroundColor: palette.window placeholderText: qsTr("@joe:matrix.org", "Example user id. The name 'joe' can be localized however you want.") Layout.fillWidth: true onAccepted: { @@ -158,7 +157,7 @@ ApplicationWindow { avatarUrl: profile? profile.avatarUrl : "" userid: inviteeEntry.text onClicked: addInvite(inviteeEntry.text, displayName, avatarUrl) - bgColor: del3.hovered ? Nheko.colors.dark : inviteDialogRoot.color + bgColor: del3.hovered ? palette.dark : inviteDialogRoot.color } ListView { visible: !inviteeEntry.isValidMxid @@ -175,7 +174,7 @@ ApplicationWindow { userid: model.userid avatarUrl: model.avatarUrl onClicked: addInvite(userid, displayName, avatarUrl) - bgColor: del2.hovered ? Nheko.colors.dark : inviteDialogRoot.color + bgColor: del2.hovered ? palette.dark : inviteDialogRoot.color } } Rectangle { @@ -202,7 +201,7 @@ ApplicationWindow { userid: model.mxid avatarUrl: model.avatarUrl displayName: model.displayName - bgColor: del.hovered ? Nheko.colors.dark : inviteDialogRoot.color + bgColor: del.hovered ? palette.dark : inviteDialogRoot.color ImageButton { anchors.right: parent.right anchors.rightMargin: Nheko.paddingSmall diff --git a/resources/qml/dialogs/JoinRoomDialog.qml b/resources/qml/dialogs/JoinRoomDialog.qml index 57c7bad8..0974325a 100644 --- a/resources/qml/dialogs/JoinRoomDialog.qml +++ b/resources/qml/dialogs/JoinRoomDialog.qml @@ -14,8 +14,7 @@ ApplicationWindow { title: qsTr("Join room") modality: Qt.WindowModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window width: 350 height: fontMetrics.lineSpacing * 7 @@ -33,7 +32,7 @@ ApplicationWindow { id: promptLabel text: qsTr("Room ID or alias") - color: Nheko.colors.text + color: palette.text } MatrixTextField { diff --git a/resources/qml/dialogs/PhoneNumberInputDialog.qml b/resources/qml/dialogs/PhoneNumberInputDialog.qml index f7719800..f1b8eef8 100644 --- a/resources/qml/dialogs/PhoneNumberInputDialog.qml +++ b/resources/qml/dialogs/PhoneNumberInputDialog.qml @@ -31,7 +31,7 @@ ApplicationWindow { id: promptLabel Layout.columnSpan: 2 - color: Nheko.colors.text + color: palette.text } ComboBox { diff --git a/resources/qml/dialogs/PowerLevelEditor.qml b/resources/qml/dialogs/PowerLevelEditor.qml index 7125c712..9fc9ee15 100644 --- a/resources/qml/dialogs/PowerLevelEditor.qml +++ b/resources/qml/dialogs/PowerLevelEditor.qml @@ -41,14 +41,13 @@ ApplicationWindow { font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.1) Layout.fillWidth: true Layout.fillHeight: false - color: Nheko.colors.text + color: palette.text Layout.bottomMargin: Nheko.paddingMedium } TabBar { id: bar width: parent.width - palette: Nheko.colors NhekoTabButton { text: qsTr("Roles") @@ -60,7 +59,7 @@ ApplicationWindow { Rectangle { Layout.fillWidth: true Layout.fillHeight: true - color: Nheko.colors.alternateBase + color: palette.alternateBase border.width: 1 border.color: Nheko.theme.separator @@ -78,7 +77,7 @@ ApplicationWindow { font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.1) Layout.fillWidth: true Layout.fillHeight: false - color: Nheko.colors.text + color: palette.text } ReorderableListview { @@ -91,7 +90,7 @@ ApplicationWindow { Column { Layout.fillWidth: true - Text { visible: model.isType; text: model.displayName; color: Nheko.colors.text} + Text { visible: model.isType; text: model.displayName; color: palette.text} Text { visible: !model.isType; text: { @@ -104,7 +103,7 @@ ApplicationWindow { else return qsTr("Custom (%1)").arg(model.powerlevel) } - color: Nheko.colors.text + color: palette.text } } @@ -137,7 +136,7 @@ ApplicationWindow { z: 5 visible: false - color: Nheko.colors.text + color: palette.text Keys.onPressed: { if (typeEntry.text.includes('.') && event.matches(StandardKey.InsertParagraphSeparator)) { @@ -166,7 +165,7 @@ ApplicationWindow { anchors.fill: parent visible: false - color: Nheko.colors.alternateBase + color: palette.alternateBase RowLayout { spacing: Nheko.paddingMedium @@ -238,7 +237,7 @@ ApplicationWindow { width: parent.width //font.pixelSize: Math.ceil(quickSwitcher.textHeight * 0.6) - color: Nheko.colors.text + color: palette.text onTextEdited: { userCompleter.completer.searchString = text; } @@ -318,11 +317,11 @@ ApplicationWindow { if (model.isUser) return model.avatarUrl.replace("mxc://", "image://MxcImage/") else if (editingModel.adminLevel >= model.powerlevel) - return "image://colorimage/:/icons/icons/ui/ribbon_star.svg?" + Nheko.colors.buttonText; + return "image://colorimage/:/icons/icons/ui/ribbon_star.svg?" + palette.buttonText; else if (editingModel.moderatorLevel >= model.powerlevel) - return "image://colorimage/:/icons/icons/ui/ribbon.svg?" + Nheko.colors.buttonText; + return "image://colorimage/:/icons/icons/ui/ribbon.svg?" + palette.buttonText; else - return "image://colorimage/:/icons/icons/ui/person.svg?" + Nheko.colors.buttonText; + return "image://colorimage/:/icons/icons/ui/person.svg?" + palette.buttonText; } displayName: model.displayName enabled: false @@ -330,8 +329,8 @@ ApplicationWindow { Column { Layout.fillWidth: true - Text { visible: model.isUser; text: model.displayName; color: Nheko.colors.text} - Text { visible: model.isUser; text: model.mxid; color: Nheko.colors.text} + Text { visible: model.isUser; text: model.displayName; color: palette.text} + Text { visible: model.isUser; text: model.mxid; color: palette.text} Text { visible: !model.isUser; text: { @@ -342,7 +341,7 @@ ApplicationWindow { else return qsTr("Custom (%1)").arg(model.powerlevel) } - color: Nheko.colors.text + color: palette.text } } diff --git a/resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml b/resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml index e66f92a2..3f816143 100644 --- a/resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml +++ b/resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml @@ -21,8 +21,7 @@ ApplicationWindow { minimumHeight: 450 width: 450 height: 680 - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint title: qsTr("Apply permission changes") @@ -43,7 +42,7 @@ ApplicationWindow { font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.1) Layout.fillWidth: true Layout.fillHeight: false - color: Nheko.colors.text + color: palette.text Layout.bottomMargin: Nheko.paddingMedium } @@ -55,7 +54,7 @@ ApplicationWindow { Label { text: qsTr("Apply permissions recursively") Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text } ToggleButton { @@ -67,7 +66,7 @@ ApplicationWindow { Label { text: qsTr("Overwrite exisiting modifications in rooms") Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text } ToggleButton { @@ -103,7 +102,7 @@ ApplicationWindow { Text { Layout.fillWidth: true text: model.displayName - color: Nheko.colors.text + color: palette.text textFormat: Text.PlainText elide: Text.ElideRight } @@ -117,7 +116,7 @@ ApplicationWindow { return qsTr("Permissions synchronized with community") } elide: Text.ElideRight - color: Nheko.colors.buttonText + color: palette.buttonText textFormat: Text.PlainText } } diff --git a/resources/qml/dialogs/RawMessageDialog.qml b/resources/qml/dialogs/RawMessageDialog.qml index ef7159cb..a27d988e 100644 --- a/resources/qml/dialogs/RawMessageDialog.qml +++ b/resources/qml/dialogs/RawMessageDialog.qml @@ -13,8 +13,7 @@ ApplicationWindow { height: 420 width: 420 - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window flags: Qt.Tool | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint | Qt.WindowTitleHint Shortcut { @@ -25,14 +24,13 @@ ApplicationWindow { ScrollView { anchors.margins: Nheko.paddingMedium anchors.fill: parent - palette: Nheko.colors padding: Nheko.paddingMedium TextArea { id: rawMessageView font: Nheko.monospaceFont() - color: Nheko.colors.text + color: palette.text readOnly: true selectByMouse: !Settings.mobileMode textFormat: Text.PlainText @@ -40,7 +38,7 @@ ApplicationWindow { anchors.fill: parent background: Rectangle { - color: Nheko.colors.base + color: palette.base } } diff --git a/resources/qml/dialogs/ReadReceipts.qml b/resources/qml/dialogs/ReadReceipts.qml index 3d23a5fc..83b8b8af 100644 --- a/resources/qml/dialogs/ReadReceipts.qml +++ b/resources/qml/dialogs/ReadReceipts.qml @@ -18,8 +18,7 @@ ApplicationWindow { width: 340 minimumHeight: 380 minimumWidth: headerTitle.width + 2 * Nheko.paddingMedium - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint Shortcut { @@ -35,14 +34,13 @@ ApplicationWindow { Label { id: headerTitle - color: Nheko.colors.text + color: palette.text Layout.alignment: Qt.AlignCenter text: qsTr("Read receipts") font.pointSize: fontMetrics.font.pointSize * 1.5 } ScrollView { - palette: Nheko.colors padding: Nheko.paddingMedium ScrollBar.horizontal.visible: false Layout.fillHeight: true @@ -67,7 +65,7 @@ ApplicationWindow { ToolTip.visible: hovered ToolTip.text: model.mxid background: Rectangle { - color: del.hovered ? Nheko.colors.dark : readReceiptsRoot.color + color: del.hovered ? palette.dark : readReceiptsRoot.color } RowLayout { @@ -94,7 +92,7 @@ ApplicationWindow { ElidedLabel { text: model.displayName - color: TimelineManager.userColor(model ? model.mxid : "", Nheko.colors.window) + color: TimelineManager.userColor(model ? model.mxid : "", palette.window) font.pointSize: fontMetrics.font.pointSize elideWidth: del.width - Nheko.paddingMedium - avatar.width Layout.fillWidth: true @@ -102,7 +100,7 @@ ApplicationWindow { ElidedLabel { text: model.timestamp - color: Nheko.colors.buttonText + color: palette.buttonText font.pointSize: fontMetrics.font.pointSize * 0.9 elideWidth: del.width - Nheko.paddingMedium - avatar.width Layout.fillWidth: true diff --git a/resources/qml/dialogs/RoomDirectory.qml b/resources/qml/dialogs/RoomDirectory.qml index 85de9b45..29adb9be 100644 --- a/resources/qml/dialogs/RoomDirectory.qml +++ b/resources/qml/dialogs/RoomDirectory.qml @@ -18,8 +18,7 @@ ApplicationWindow { minimumHeight: 340 height: 420 width: 650 - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint title: qsTr("Explore Public Rooms") @@ -43,9 +42,9 @@ ApplicationWindow { delegate: Rectangle { id: roomDirDelegate - property color background: Nheko.colors.window - property color importantText: Nheko.colors.text - property color unimportantText: Nheko.colors.buttonText + property color background: palette.window + property color importantText: palette.text + property color unimportantText: palette.buttonText property int avatarSize: fontMetrics.height * 3.2 color: background @@ -143,7 +142,7 @@ ApplicationWindow { anchors.centerIn: parent anchors.margins: Nheko.paddingLarge running: visible - foreground: Nheko.colors.mid + foreground: palette.mid } } @@ -164,7 +163,7 @@ ApplicationWindow { Layout.fillWidth: true selectByMouse: true font.pixelSize: fontMetrics.font.pixelSize - color: Nheko.colors.text + color: palette.text placeholderText: qsTr("Search for public rooms") onTextChanged: searchTimer.restart() @@ -176,7 +175,7 @@ ApplicationWindow { Layout.minimumWidth: 0.3 * header.width Layout.maximumWidth: 0.3 * header.width - color: Nheko.colors.text + color: palette.text placeholderText: qsTr("Choose custom homeserver") onTextChanged: publicRooms.setMatrixServer(text) } diff --git a/resources/qml/dialogs/RoomMembers.qml b/resources/qml/dialogs/RoomMembers.qml index 1cfbe077..4952a0a9 100644 --- a/resources/qml/dialogs/RoomMembers.qml +++ b/resources/qml/dialogs/RoomMembers.qml @@ -20,8 +20,7 @@ ApplicationWindow { height: 650 width: 420 minimumHeight: 420 - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint Shortcut { @@ -77,7 +76,7 @@ ApplicationWindow { Label { text: qsTr("Sort by: ") - color: Nheko.colors.text + color: palette.text } ComboBox { @@ -94,7 +93,6 @@ ApplicationWindow { } ScrollView { - palette: Nheko.colors padding: Nheko.paddingMedium ScrollBar.horizontal.visible: false Layout.fillHeight: true @@ -123,7 +121,7 @@ ApplicationWindow { height: memberLayout.implicitHeight + Nheko.paddingSmall * 2 hoverEnabled: true background: Rectangle { - color: del.hovered ? Nheko.colors.dark : roomMembersRoot.color + color: del.hovered ? palette.dark : roomMembersRoot.color } RowLayout { @@ -158,7 +156,7 @@ ApplicationWindow { ElidedLabel { fullText: model.mxid - color: del.hovered ? Nheko.colors.brightText : Nheko.colors.buttonText + color: del.hovered ? palette.brightText : palette.buttonText font.pixelSize: Math.ceil(fontMetrics.font.pixelSize * 0.9) elideWidth: del.width - Nheko.paddingMedium * 2 - avatar.width - encryptInd.width Layout.fillWidth: true @@ -184,7 +182,7 @@ ApplicationWindow { Layout.preferredHeight: 16 sourceSize.width: width sourceSize.height: height - source: sourceUrl + (ma.hovered ? Nheko.colors.highlight : Nheko.colors.buttonText) + source: sourceUrl + (ma.hovered ? palette.highlight : palette.buttonText) ToolTip.visible: ma.hovered ToolTip.text: { if (isAdmin) diff --git a/resources/qml/dialogs/RoomSettings.qml b/resources/qml/dialogs/RoomSettings.qml index 845f4d7a..6bc24058 100644 --- a/resources/qml/dialogs/RoomSettings.qml +++ b/resources/qml/dialogs/RoomSettings.qml @@ -20,8 +20,7 @@ ApplicationWindow { minimumHeight: 450 width: 450 height: 680 - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint title: qsTr("Room Settings") @@ -79,7 +78,7 @@ ApplicationWindow { Spinner { Layout.alignment: Qt.AlignHCenter visible: roomSettings.isLoading - foreground: Nheko.colors.mid + foreground: palette.mid running: roomSettings.isLoading } @@ -130,7 +129,7 @@ ApplicationWindow { textFormat: isNameEditingAllowed ? TextEdit.PlainText : TextEdit.RichText text: isNameEditingAllowed ? roomSettings.plainRoomName : roomSettings.roomName font.pixelSize: fontMetrics.font.pixelSize * 2 - color: Nheko.colors.text + color: palette.text Layout.alignment: Qt.AlignHCenter Layout.maximumWidth: parent.width - (Nheko.paddingSmall * 2) - nameChangeButton.anchors.leftMargin - (nameChangeButton.width * 2) @@ -178,7 +177,7 @@ ApplicationWindow { Label { text: qsTr("%n member(s)", "", roomSettings.memberCount) - color: Nheko.colors.text + color: palette.text } ImageButton { @@ -213,7 +212,7 @@ ApplicationWindow { wrapMode: TextEdit.WordWrap background: null selectByMouse: !Settings.mobileMode - color: Nheko.colors.text + color: palette.text horizontalAlignment: TextEdit.AlignHCenter onLinkActivated: Nheko.openLink(link) @@ -263,7 +262,7 @@ ApplicationWindow { Label { text: qsTr("SETTINGS") font.bold: true - color: Nheko.colors.text + color: palette.text } Item { @@ -273,7 +272,7 @@ ApplicationWindow { Label { text: qsTr("Notifications") Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text } ComboBox { @@ -289,7 +288,7 @@ ApplicationWindow { Label { text: qsTr("Anyone can join") Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text } ToggleButton { @@ -303,7 +302,7 @@ ApplicationWindow { Label { text: qsTr("Allow knocking") Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text visible: knockingButton.visible } @@ -322,7 +321,7 @@ ApplicationWindow { Label { text: qsTr("Allow joining via other rooms") Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text visible: restrictedButton.visible } @@ -341,7 +340,7 @@ ApplicationWindow { Label { text: qsTr("Rooms to join via") Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text visible: allowedRoomsButton.visible } @@ -360,7 +359,7 @@ ApplicationWindow { Label { text: qsTr("Allow guests to join") Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text } ToggleButton { @@ -383,7 +382,7 @@ ApplicationWindow { Label { text: qsTr("Encryption") - color: Nheko.colors.text + color: palette.text } ToggleButton { @@ -422,7 +421,7 @@ ApplicationWindow { Label { text: qsTr("Permission") - color: Nheko.colors.text + color: palette.text } Button { @@ -434,7 +433,7 @@ ApplicationWindow { Label { text: qsTr("Aliases") - color: Nheko.colors.text + color: palette.text } Button { @@ -446,7 +445,7 @@ ApplicationWindow { Label { text: qsTr("Sticker & Emote Settings") - color: Nheko.colors.text + color: palette.text } Button { @@ -458,7 +457,7 @@ ApplicationWindow { Label { text: qsTr("Hidden events") - color: Nheko.colors.text + color: palette.text } HiddenEventsDialog { @@ -487,7 +486,7 @@ ApplicationWindow { Label { text: qsTr("INFO") font.bold: true - color: Nheko.colors.text + color: palette.text } Item { @@ -496,7 +495,7 @@ ApplicationWindow { Label { text: qsTr("Internal ID") - color: Nheko.colors.text + color: palette.text } AbstractButton { // AbstractButton does not allow setting text color @@ -507,7 +506,7 @@ ApplicationWindow { id: idLabel text: roomSettings.roomId font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 0.8) - color: Nheko.colors.text + color: palette.text width: parent.width horizontalAlignment: Text.AlignRight wrapMode: Text.WrapAnywhere @@ -531,14 +530,14 @@ ApplicationWindow { Label { text: qsTr("Room Version") - color: Nheko.colors.text + color: palette.text } Label { text: roomSettings.roomVersion font.pixelSize: fontMetrics.font.pixelSize Layout.alignment: Qt.AlignRight - color: Nheko.colors.text + color: palette.text } } diff --git a/resources/qml/dialogs/UserProfile.qml b/resources/qml/dialogs/UserProfile.qml index 95800746..dae43caa 100644 --- a/resources/qml/dialogs/UserProfile.qml +++ b/resources/qml/dialogs/UserProfile.qml @@ -22,8 +22,7 @@ ApplicationWindow { width: 420 minimumWidth: 150 minimumHeight: 150 - palette: Nheko.colors - color: Nheko.colors.window + color: palette.window title: profile.isGlobalUserProfile ? qsTr("Global User Profile") : qsTr("Room User Profile") modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint @@ -89,7 +88,7 @@ ApplicationWindow { Layout.alignment: Qt.AlignHCenter running: profile.isLoading visible: profile.isLoading - foreground: Nheko.colors.mid + foreground: palette.mid } Text { @@ -137,7 +136,7 @@ ApplicationWindow { readOnly: !isUsernameEditingAllowed text: profile.displayName font.pixelSize: 20 - color: TimelineManager.userColor(profile.userid, Nheko.colors.window) + color: TimelineManager.userColor(profile.userid, palette.window) font.bold: true Layout.alignment: Qt.AlignHCenter Layout.maximumWidth: parent.width - (Nheko.paddingSmall * 2) - usernameChangeButton.anchors.leftMargin - (usernameChangeButton.width * 2) @@ -315,7 +314,6 @@ ApplicationWindow { onCurrentIndexChanged: devicelist.selectedTab = currentIndex - palette: Nheko.colors NhekoTabButton { text: qsTr("Devices") @@ -354,7 +352,7 @@ ApplicationWindow { Layout.alignment: Qt.AlignLeft elide: Text.ElideRight font.bold: true - color: Nheko.colors.text + color: palette.text text: deviceId } @@ -400,7 +398,7 @@ ApplicationWindow { readOnly: !deviceNameRow.isEditingAllowed text: deviceName - color: Nheko.colors.text + color: palette.text Layout.alignment: Qt.AlignLeft Layout.fillWidth: true selectByMouse: true @@ -435,7 +433,7 @@ ApplicationWindow { Layout.fillWidth: true Layout.alignment: Qt.AlignLeft elide: Text.ElideRight - color: Nheko.colors.text + color: palette.text text: qsTr("Last seen %1 from %2").arg(new Date(lastTs).toLocaleString(Locale.ShortFormat)).arg(lastIp ? lastIp : "???") } @@ -504,7 +502,7 @@ ApplicationWindow { ElidedLabel { Layout.alignment: Qt.AlignVCenter - color: Nheko.colors.text + color: palette.text Layout.fillWidth: true elideWidth: width fullText: roomName @@ -527,7 +525,7 @@ ApplicationWindow { background: Rectangle { anchors.fill: parent - color: Nheko.colors.window + color: palette.window } } diff --git a/resources/qml/emoji/StickerPicker.qml b/resources/qml/emoji/StickerPicker.qml index 9a5cd6d1..b1623697 100644 --- a/resources/qml/emoji/StickerPicker.qml +++ b/resources/qml/emoji/StickerPicker.qml @@ -13,14 +13,13 @@ Menu { id: stickerPopup property var callback - property var colors property string roomid property alias model: gridView.model required property bool emoji property var textArea - property real highlightHue: Nheko.colors.highlight.hslHue - property real highlightSat: Nheko.colors.highlight.hslSaturation - property real highlightLight: Nheko.colors.highlight.hslLightness + property real highlightHue: palette.highlight.hslHue + property real highlightSat: palette.highlight.hslSaturation + property real highlightLight: palette.highlight.hslLightness readonly property int stickerDim: emoji ? 48 : 128 readonly property int stickerDimPad: stickerDim + Nheko.paddingSmall readonly property int stickersPerRow: emoji ? 7 : 3 @@ -44,7 +43,7 @@ Menu { width: sidebarAvatarSize + Nheko.paddingSmall + stickersPerRow * stickerDimPad + 20 Rectangle { - color: Nheko.colors.window + color: palette.window height: columnView.implicitHeight + Nheko.paddingSmall*2 width: sidebarAvatarSize + Nheko.paddingSmall + stickersPerRow * stickerDimPad + 20 @@ -66,10 +65,8 @@ Menu { Layout.preferredWidth: stickersPerRow * stickerDimPad + 20 - Nheko.paddingSmall Layout.row: 0 Layout.column: 1 - palette: Nheko.colors background: null - placeholderTextColor: Nheko.colors.buttonText - color: Nheko.colors.text + placeholderTextColor: palette.buttonText placeholderText: qsTr("Search") selectByMouse: true rightPadding: clearSearch.width @@ -125,7 +122,7 @@ Menu { section.delegate: Rectangle { width: gridView.width height: childrenRect.height - color: Nheko.colors.alternateBase + color: palette.alternateBase required property string section @@ -133,7 +130,6 @@ Menu { anchors.left: parent.left anchors.right: parent.right text: parent.section - color: Nheko.colors.text font.bold: true } } @@ -196,7 +192,6 @@ Menu { font.family: Settings.emojiFont font.pixelSize: 36 text: del.modelData.unicode.replace('\ufe0f', '') - color: Nheko.colors.text } } @@ -213,7 +208,7 @@ Menu { background: Rectangle { anchors.fill: parent - color: hovered ? Nheko.colors.highlight : 'transparent' + color: hovered ? palette.highlight : 'transparent' radius: 5 } diff --git a/resources/qml/pages/LoginPage.qml b/resources/qml/pages/LoginPage.qml index 4273617f..9bf4e97e 100644 --- a/resources/qml/pages/LoginPage.qml +++ b/resources/qml/pages/LoginPage.qml @@ -25,7 +25,6 @@ Item { id: scroll clip: false - palette: Nheko.colors ScrollBar.horizontal.visible: false anchors.left: parent.left anchors.right: parent.right @@ -71,7 +70,7 @@ Item { visible: running running: login.lookingUpHs - foreground: Nheko.colors.mid + foreground: palette.mid } } @@ -127,7 +126,7 @@ Item { visible: running running: login.loggingIn - foreground: Nheko.colors.mid + foreground: palette.mid } } diff --git a/resources/qml/pages/RegisterPage.qml b/resources/qml/pages/RegisterPage.qml index 8536a254..c1bc5310 100644 --- a/resources/qml/pages/RegisterPage.qml +++ b/resources/qml/pages/RegisterPage.qml @@ -25,7 +25,6 @@ Item { id: scroll clip: false - palette: Nheko.colors ScrollBar.horizontal.visible: false anchors.left: parent.left anchors.right: parent.right @@ -70,7 +69,7 @@ Item { visible: running running: regis.lookingUpHs - foreground: Nheko.colors.mid + foreground: palette.mid } } @@ -102,7 +101,7 @@ Item { visible: running running: regis.lookingUpUsername - foreground: Nheko.colors.mid + foreground: palette.mid } Image { @@ -178,7 +177,7 @@ Item { visible: running running: regis.registering - foreground: Nheko.colors.mid + foreground: palette.mid } } diff --git a/resources/qml/pages/UserSettingsPage.qml b/resources/qml/pages/UserSettingsPage.qml index 5c2ebf5f..08581ac5 100644 --- a/resources/qml/pages/UserSettingsPage.qml +++ b/resources/qml/pages/UserSettingsPage.qml @@ -16,12 +16,11 @@ Rectangle { property int collapsePoint: 600 property bool collapsed: width < collapsePoint - color: Nheko.colors.window + color: palette.window ScrollView { id: scroll - palette: Nheko.colors ScrollBar.horizontal.visible: false anchors.fill: parent anchors.topMargin: (collapsed? backButton.height : 0)+Nheko.paddingLarge @@ -51,7 +50,7 @@ Rectangle { Label { Layout.alignment: Qt.AlignLeft Layout.fillWidth: true - color: Nheko.colors.text + color: palette.text text: model.name //Layout.column: 0 Layout.columnSpan: (model.type == UserSettingsModel.SectionTitle && !userSettingsDialog.collapsed) ? 2 : 1 @@ -159,7 +158,7 @@ Rectangle { DelegateChoice { roleValue: UserSettingsModel.ReadOnlyText TextEdit { - color: Nheko.colors.text + color: palette.text text: model.value readOnly: true selectByMouse: !Settings.mobileMode @@ -176,7 +175,7 @@ Rectangle { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - color: Nheko.colors.buttonText + color: palette.buttonText height: 1 } } diff --git a/resources/qml/pages/WelcomePage.qml b/resources/qml/pages/WelcomePage.qml index 6555cc29..3acdc18f 100644 --- a/resources/qml/pages/WelcomePage.qml +++ b/resources/qml/pages/WelcomePage.qml @@ -28,7 +28,7 @@ ColumnLayout { Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true text: qsTr("Welcome to nheko! The desktop client for the Matrix protocol.") - color: Nheko.colors.text + color: palette.text font.pointSize: fontMetrics.font.pointSize*2 wrapMode: Text.Wrap horizontalAlignment: Text.AlignHCenter @@ -38,7 +38,7 @@ ColumnLayout { Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true text: qsTr("Enjoy your stay!") - color: Nheko.colors.text + color: palette.text font.pointSize: fontMetrics.font.pointSize*1.5 wrapMode: Text.Wrap horizontalAlignment: Text.AlignHCenter @@ -86,7 +86,7 @@ ColumnLayout { Layout.alignment: Qt.AlignLeft Layout.margins: Nheko.paddingLarge text: qsTr("Reduce animations") - color: Nheko.colors.text + color: palette.text HoverHandler { id: hovered diff --git a/resources/qml/ui/NhekoSlider.qml b/resources/qml/ui/NhekoSlider.qml index 724e6e48..5e3a77d8 100644 --- a/resources/qml/ui/NhekoSlider.qml +++ b/resources/qml/ui/NhekoSlider.qml @@ -9,7 +9,7 @@ import im.nheko 1.0 Slider { id: control - property color progressColor: Nheko.colors.highlight + property color progressColor: palette.highlight property bool alwaysShowSlider: true property int sliderRadius: 16 @@ -25,7 +25,7 @@ Slider { width: control.availableWidth - handle.width height: implicitHeight radius: height / 2 - color: Nheko.colors.buttonText + color: palette.buttonText Rectangle { width: control.visualPosition * parent.width diff --git a/resources/qml/ui/Ripple.qml b/resources/qml/ui/Ripple.qml index 73d8520f..911b88cf 100644 --- a/resources/qml/ui/Ripple.qml +++ b/resources/qml/ui/Ripple.qml @@ -20,7 +20,7 @@ Item { PointHandler { id: ph - onGrabChanged: { + onGrabChanged: (_, point) => { circle.centerX = point.position.x circle.centerY = point.position.y } diff --git a/resources/qml/ui/Snackbar.qml b/resources/qml/ui/Snackbar.qml index 051db70d..b3530522 100644 --- a/resources/qml/ui/Snackbar.qml +++ b/resources/qml/ui/Snackbar.qml @@ -45,7 +45,7 @@ Popup { padding: Nheko.paddingLarge contentItem: Label { - color: Nheko.colors.light + color: palette.light width: Math.max(Overlay.overlay? Overlay.overlay.width/2 : 0, 400) text: snackbar.currentMessage font.bold: true @@ -53,7 +53,7 @@ Popup { background: Rectangle { radius: Nheko.paddingLarge - color: Nheko.colors.dark + color: palette.dark opacity: 0.8 } diff --git a/resources/qml/ui/media/MediaControls.qml b/resources/qml/ui/media/MediaControls.qml index f1cb7ca1..a48f15ea 100644 --- a/resources/qml/ui/media/MediaControls.qml +++ b/resources/qml/ui/media/MediaControls.qml @@ -50,7 +50,7 @@ Rectangle { } color: { - var wc = Nheko.colors.alternateBase; + var wc = palette.alternateBase; return Qt.rgba(wc.r, wc.g, wc.b, 0.5); } opacity: control.shouldShowControls ? 1 : 0 @@ -95,7 +95,7 @@ Rectangle { id: playbackStateImage Layout.alignment: Qt.AlignLeft - buttonTextColor: Nheko.colors.text + buttonTextColor: palette.text Layout.preferredHeight: 24 Layout.preferredWidth: 24 image: { @@ -115,7 +115,7 @@ Rectangle { id: volumeButton Layout.alignment: Qt.AlignLeft - buttonTextColor: Nheko.colors.text + buttonTextColor: palette.text Layout.preferredHeight: 24 Layout.preferredWidth: 24 image: { @@ -214,7 +214,7 @@ Rectangle { Label { Layout.alignment: Qt.AlignRight text: (!control.mediaLoaded ? "-- " : durationToString(control.positionValue)) + " / " + durationToString(control.duration) - color: Nheko.colors.text + color: palette.text } Item { diff --git a/resources/qml/voip/CallDevices.qml b/resources/qml/voip/CallDevices.qml index 5a1792c9..d4c554dc 100644 --- a/resources/qml/voip/CallDevices.qml +++ b/resources/qml/voip/CallDevices.qml @@ -9,7 +9,6 @@ import im.nheko 1.0 Popup { modal: true - palette: Nheko.colors // only set the anchors on Qt 5.12 or higher // see https://doc.qt.io/qt-5/qml-qtquick-controls2-popup.html#anchors.centerIn-prop Component.onCompleted: { @@ -31,7 +30,7 @@ Popup { Image { Layout.preferredWidth: 22 Layout.preferredHeight: 22 - source: "image://colorimage/:/icons/icons/ui/microphone-unmute.svg?" + Nheko.colors.windowText + source: "image://colorimage/:/icons/icons/ui/microphone-unmute.svg?" + palette.windowText } ComboBox { @@ -49,7 +48,7 @@ Popup { Image { Layout.preferredWidth: 22 Layout.preferredHeight: 22 - source: "image://colorimage/:/icons/icons/ui/video-call.svg?" + Nheko.colors.windowText + source: "image://colorimage/:/icons/icons/ui/video-call.svg?" + palette.windowText } ComboBox { @@ -81,8 +80,8 @@ Popup { } background: Rectangle { - color: Nheko.colors.window - border.color: Nheko.colors.windowText + color: palette.window + border.color: palette.windowText } } diff --git a/resources/qml/voip/CallInvite.qml b/resources/qml/voip/CallInvite.qml index 8ffe9892..25aa0818 100644 --- a/resources/qml/voip/CallInvite.qml +++ b/resources/qml/voip/CallInvite.qml @@ -14,7 +14,6 @@ Popup { closePolicy: Popup.NoAutoClose width: parent.width height: parent.height - palette: Nheko.colors Component { id: deviceError @@ -45,7 +44,7 @@ Popup { Layout.fillWidth: true text: CallManager.callPartyDisplayName font.pointSize: fontMetrics.font.pointSize * 2 - color: Nheko.colors.windowText + color: palette.windowText horizontalAlignment: Text.AlignHCenter } @@ -68,14 +67,14 @@ Popup { Layout.alignment: Qt.AlignCenter Layout.preferredWidth: callInv.height / 10 Layout.preferredHeight: callInv.height / 10 - source: "image://colorimage/" + image + "?" + Nheko.colors.windowText + source: "image://colorimage/" + image + "?" + palette.windowText } Label { Layout.alignment: Qt.AlignCenter text: CallManager.callType == CallType.VIDEO ? qsTr("Video Call") : qsTr("Voice Call") font.pointSize: fontMetrics.font.pointSize * 2 - color: Nheko.colors.windowText + color: palette.windowText } } @@ -94,7 +93,7 @@ Popup { Image { Layout.preferredWidth: deviceCombos.imageSize Layout.preferredHeight: deviceCombos.imageSize - source: "image://colorimage/:/icons/icons/ui/microphone-unmute.svg?" + Nheko.colors.windowText + source: "image://colorimage/:/icons/icons/ui/microphone-unmute.svg?" + palette.windowText } ComboBox { @@ -113,7 +112,7 @@ Popup { Image { Layout.preferredWidth: deviceCombos.imageSize Layout.preferredHeight: deviceCombos.imageSize - source: "image://colorimage/:/icons/icons/ui/video.svg?" + Nheko.colors.windowText + source: "image://colorimage/:/icons/icons/ui/video.svg?" + palette.windowText } ComboBox { @@ -201,8 +200,8 @@ Popup { } background: Rectangle { - color: Nheko.colors.window - border.color: Nheko.colors.windowText + color: palette.window + border.color: palette.windowText } } diff --git a/resources/qml/voip/CallInviteBar.qml b/resources/qml/voip/CallInviteBar.qml index 4eaff020..3c7426cc 100644 --- a/resources/qml/voip/CallInviteBar.qml +++ b/resources/qml/voip/CallInviteBar.qml @@ -90,7 +90,6 @@ Rectangle { Layout.rightMargin: 4 icon.source: CallManager.callType == CallType.VIDEO ? "qrc:/icons/icons/ui/video.svg" : "qrc:/icons/icons/ui/place-call.svg" text: qsTr("Accept") - palette: Nheko.colors onClicked: { if (CallManager.mics.length == 0) { var dialog = deviceError.createObject(timelineRoot, { @@ -126,7 +125,6 @@ Rectangle { Layout.rightMargin: 16 icon.source: "qrc:/icons/icons/ui/end-call.svg" text: qsTr("Decline") - palette: Nheko.colors onClicked: { CallManager.rejectInvite(); } diff --git a/resources/qml/voip/DeviceError.qml b/resources/qml/voip/DeviceError.qml index 9328e385..afb70b7f 100644 --- a/resources/qml/voip/DeviceError.qml +++ b/resources/qml/voip/DeviceError.qml @@ -24,19 +24,19 @@ Popup { Image { Layout.preferredWidth: 16 Layout.preferredHeight: 16 - source: "image://colorimage/" + image + "?" + Nheko.colors.windowText + source: "image://colorimage/" + image + "?" + palette.windowText } Label { text: errorString - color: Nheko.colors.windowText + color: palette.windowText } } background: Rectangle { - color: Nheko.colors.window - border.color: Nheko.colors.windowText + color: palette.window + border.color: palette.windowText } } diff --git a/resources/qml/voip/PlaceCall.qml b/resources/qml/voip/PlaceCall.qml index c7a64342..5d9387c3 100644 --- a/resources/qml/voip/PlaceCall.qml +++ b/resources/qml/voip/PlaceCall.qml @@ -17,7 +17,6 @@ Popup { anchors.centerIn = parent; } - palette: Nheko.colors Component { id: deviceError @@ -38,7 +37,7 @@ Popup { Label { text: qsTr("Place a call to %1?").arg(room.roomName) - color: Nheko.colors.windowText + color: palette.windowText } Item { @@ -138,7 +137,7 @@ Popup { Image { Layout.preferredWidth: 22 Layout.preferredHeight: 22 - source: "image://colorimage/:/icons/icons/ui/microphone-unmute.svg?" + Nheko.colors.windowText + source: "image://colorimage/:/icons/icons/ui/microphone-unmute.svg?" + palette.windowText } ComboBox { @@ -159,7 +158,7 @@ Popup { Image { Layout.preferredWidth: 22 Layout.preferredHeight: 22 - source: "image://colorimage/:/icons/icons/ui/video.svg?" + Nheko.colors.windowText + source: "image://colorimage/:/icons/icons/ui/video.svg?" + palette.windowText } ComboBox { @@ -176,8 +175,8 @@ Popup { } background: Rectangle { - color: Nheko.colors.window - border.color: Nheko.colors.windowText + color: palette.window + border.color: palette.windowText } } diff --git a/resources/qml/voip/ScreenShare.qml b/resources/qml/voip/ScreenShare.qml index 1a82a5ce..ce998299 100644 --- a/resources/qml/voip/ScreenShare.qml +++ b/resources/qml/voip/ScreenShare.qml @@ -19,7 +19,6 @@ Popup { Component.onDestruction: { CallManager.closeScreenShare(); } - palette: Nheko.colors ColumnLayout { Label { @@ -29,7 +28,7 @@ Popup { Layout.rightMargin: 8 Layout.alignment: Qt.AlignLeft text: qsTr("Share desktop with %1?").arg(room.roomName) - color: Nheko.colors.windowText + color: palette.windowText } RowLayout { @@ -40,7 +39,7 @@ Popup { Label { Layout.alignment: Qt.AlignLeft text: qsTr("Method:") - color: Nheko.colors.windowText + color: palette.windowText } ComboBox { @@ -60,7 +59,7 @@ Popup { Label { Layout.alignment: Qt.AlignLeft text: qsTr("Window:") - color: Nheko.colors.windowText + color: palette.windowText } ComboBox { @@ -91,7 +90,7 @@ Popup { Label { Layout.alignment: Qt.AlignLeft text: qsTr("Frame rate:") - color: Nheko.colors.windowText + color: palette.windowText } ComboBox { @@ -191,8 +190,8 @@ Popup { } background: Rectangle { - color: Nheko.colors.window - border.color: Nheko.colors.windowText + color: palette.window + border.color: palette.windowText } } diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 2fd2d21a..af974592 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -1033,12 +1033,12 @@ MediaUpload::MediaUpload(std::unique_ptr source_, } connect(mediaPlayer, -&QMediaPlayer::error, +&QMediaPlayer::errorOccurred, this, - [mediaPlayer]() { + [](QMediaPlayer::Error error, QString errorString) { nhlog::ui()->debug("Media player error {} and errorStr {}", - mediaPlayer->error(), - mediaPlayer->errorString().toStdString()); + error, + errorString.toStdString()); }); connect(mediaPlayer, &QMediaPlayer::mediaStatusChanged, diff --git a/src/ui/MxcMediaProxy.cpp b/src/ui/MxcMediaProxy.cpp index e10cb846..dd5d81a9 100644 --- a/src/ui/MxcMediaProxy.cpp +++ b/src/ui/MxcMediaProxy.cpp @@ -25,13 +25,14 @@ MxcMediaProxy::MxcMediaProxy(QObject *parent) { connect(this, &MxcMediaProxy::eventIdChanged, &MxcMediaProxy::startDownload); connect(this, &MxcMediaProxy::roomChanged, &MxcMediaProxy::startDownload); - connect(this, - &MxcMediaProxy::error, - [this]() { - nhlog::ui()->info("Media player error {} and errorStr {}", - error(), - this->errorString().toStdString()); - }); + connect(this, +&QMediaPlayer::errorOccurred, + this, + [](QMediaPlayer::Error error, QString errorString) { + nhlog::ui()->debug("Media player error {} and errorStr {}", + error, + errorString.toStdString()); + }); connect(this, &MxcMediaProxy::mediaStatusChanged, [this](QMediaPlayer::MediaStatus status) { nhlog::ui()->info("Media player status {} and error {}", status, this->error()); }); diff --git a/src/voip/CallManager.cpp b/src/voip/CallManager.cpp index 0ef14db9..9a610819 100644 --- a/src/voip/CallManager.cpp +++ b/src/voip/CallManager.cpp @@ -173,11 +173,11 @@ CallManager::CallManager(QObject *parent) }); connect(&player_, - &QMediaPlayer::error, + &QMediaPlayer::errorOccurred, this, - [this]() { + [this](QMediaPlayer::Error error, QString errorString) { stopRingtone(); - switch (player_.error()) { + switch (error) { case QMediaPlayer::FormatError: case QMediaPlayer::ResourceError: nhlog::ui()->error("WebRTC: valid ringtone file not found"); @@ -186,7 +186,7 @@ CallManager::CallManager(QObject *parent) nhlog::ui()->error("WebRTC: access to ringtone file denied"); break; default: - nhlog::ui()->error("WebRTC: unable to play ringtone"); + nhlog::ui()->error("WebRTC: unable to play ringtone, {}", errorString.toStdString()); break; } }); From c25d0c6b2f30731b108e99c6ceccd925d764eb56 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 01:36:01 +0200 Subject: [PATCH 045/128] Get rid of scrollhelper --- resources/qml/CommunitiesList.qml | 6 -- resources/qml/Completer.qml | 5 - resources/qml/MessageView.qml | 5 - resources/qml/RoomList.qml | 5 - resources/qml/ScrollHelper.qml | 96 ------------------- resources/qml/TopBar.qml | 10 -- .../qml/components/ReorderableListview.qml | 4 - resources/qml/dialogs/AliasEditor.qml | 4 - .../dialogs/AllowedRoomsSettingsDialog.qml | 4 - .../qml/dialogs/ImagePackEditorDialog.qml | 5 - .../qml/dialogs/ImagePackSettingsDialog.qml | 11 +-- .../dialogs/PowerLevelSpacesApplyDialog.qml | 5 - resources/qml/dialogs/RoomDirectory.qml | 5 - resources/qml/dialogs/RoomMembers.qml | 5 - resources/qml/dialogs/RoomSettings.qml | 5 +- resources/qml/dialogs/UserProfile.qml | 6 -- resources/qml/emoji/StickerPicker.qml | 6 -- resources/res.qrc | 1 - 18 files changed, 2 insertions(+), 186 deletions(-) delete mode 100644 resources/qml/ScrollHelper.qml diff --git a/resources/qml/CommunitiesList.qml b/resources/qml/CommunitiesList.qml index 5bf239a6..a210a4bb 100644 --- a/resources/qml/CommunitiesList.qml +++ b/resources/qml/CommunitiesList.qml @@ -39,12 +39,6 @@ Page { parent: !collapsed && Settings.scrollbarsInRoomlist ? communitiesList : null } - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } - Platform.Menu { id: communityContextMenu diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml index 95bebc1b..02dccfc9 100644 --- a/resources/qml/Completer.qml +++ b/resources/qml/Completer.qml @@ -97,11 +97,6 @@ Control { // that until we find something better. Put is all together and you have the formula below! implicitHeight: Math.min(contentHeight, 6*rowSpacing + 7*(popup.avatarHeight + 2*rowMargin)) clip: true - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } Timer { id: deadTimer diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index b35db9ac..158bc236 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -252,11 +252,6 @@ Item { } - ScrollHelper { - flickable: parent - anchors.fill: parent - } - Shortcut { sequence: StandardKey.MoveToPreviousPage onActivated: { diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index 733063f9..851608b6 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -63,11 +63,6 @@ Page { parent: !collapsed && Settings.scrollbarsInRoomlist ? roomlist : null } - ScrollHelper { - flickable: parent - anchors.fill: parent - } - Connections { function onCurrentRoomChanged() { if (Rooms.currentRoom) diff --git a/resources/qml/ScrollHelper.qml b/resources/qml/ScrollHelper.qml deleted file mode 100644 index 04d060ec..00000000 --- a/resources/qml/ScrollHelper.qml +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (C) 2016 Michael Bohlender, -// Copyright (C) 2017 Christian Mollekopf, -// SPDX-FileCopyrightText: Nheko Contributors -// -// SPDX-License-Identifier: GPL-3.0-or-later - -/* -* Shamelessly stolen from: -* https://cgit.kde.org/kube.git/tree/framework/qml/ScrollHelper.qml -* -* The MouseArea + interactive: false + maximumFlickVelocity are required -* to fix scrolling for desktop systems where we don't want flicking behaviour. -* -* See also: -* ScrollView.qml in qtquickcontrols -* qquickwheelarea.cpp in qtquickcontrols -*/ - -import QtQuick 2.9 -import QtQuick.Controls 2.3 - -MouseArea { - // console.warn("Delta: ", wheel.pixelDelta.y); - // console.warn("Old position: ", flickable.contentY); - // console.warn("New position: ", newPos); - // breaks ListView's with headers... - //if (typeof (flickableItem.headerItem) !== "undefined" && flickableItem.headerItem) - // minYExtent += flickableItem.headerItem.height; - - id: root - - property Flickable flickable - property alias enabled: root.enabled - - function calculateNewPosition(flickableItem, wheel) { - //Nothing to scroll - if (flickableItem.contentHeight < flickableItem.height) - return flickableItem.contentY; - - //Ignore 0 events (happens at least with Christians trackpad) - if (wheel.pixelDelta.y == 0 && wheel.angleDelta.y == 0) - return flickableItem.contentY; - - //pixelDelta seems to be the same as angleDelta/8 - var pixelDelta = 0; - //The pixelDelta is a smaller number if both are provided, so pixelDelta can be 0 while angleDelta is still something. So we check the angleDelta - if (wheel.angleDelta.y) { - var wheelScrollLines = 3; //Default value of QApplication wheelScrollLines property - var pixelPerLine = 20; //Default value in Qt, originally comes from QTextEdit - var ticks = (wheel.angleDelta.y / 8) / 15; //Divide by 8 gives us pixels typically come in 15pixel steps. - pixelDelta = ticks * pixelPerLine * wheelScrollLines; - } else { - pixelDelta = wheel.pixelDelta.y; - } - pixelDelta = Math.round(pixelDelta); - if (!pixelDelta) - return flickableItem.contentY; - - var minYExtent = flickableItem.originY + flickableItem.topMargin; - var maxYExtent = (flickableItem.contentHeight + flickableItem.bottomMargin + flickableItem.originY) - flickableItem.height; - //Avoid overscrolling - return Math.max(minYExtent, Math.min(maxYExtent, flickableItem.contentY - pixelDelta)); - } - - propagateComposedEvents: true - //Place the mouse area under the flickable - z: -1 - onFlickableChanged: { - if (enabled) { - flickable.maximumFlickVelocity = 100000; - flickable.boundsBehavior = Flickable.StopAtBounds; - root.parent = flickable; - } - } - acceptedButtons: Qt.NoButton - onWheel: { - var newPos = calculateNewPosition(flickable, wheel); - // Show the scrollbars - flickable.flick(0, 0); - flickable.contentY = newPos; - cancelFlickStateTimer.restart(); - } - - Timer { - id: cancelFlickStateTimer - - //How long the scrollbar will remain visible - interval: 500 - // Hide the scrollbars - onTriggered: { - flickable.cancelFlick(); - flickable.movementEnded(); - } - } - -} diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index eaaa38ea..a54c5ed7 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -408,11 +408,6 @@ Pane { } - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } } } @@ -443,11 +438,6 @@ Pane { } - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } } } diff --git a/resources/qml/components/ReorderableListview.qml b/resources/qml/components/ReorderableListview.qml index 4e67082e..1e8ab7b0 100644 --- a/resources/qml/components/ReorderableListview.qml +++ b/resources/qml/components/ReorderableListview.qml @@ -105,10 +105,6 @@ Item { clip: true anchors { fill: parent; margins: 2 } - ScrollHelper { - flickable: parent - anchors.fill: parent - } model: visualModel diff --git a/resources/qml/dialogs/AliasEditor.qml b/resources/qml/dialogs/AliasEditor.qml index 32efff22..c49ad321 100644 --- a/resources/qml/dialogs/AliasEditor.qml +++ b/resources/qml/dialogs/AliasEditor.qml @@ -53,10 +53,6 @@ ApplicationWindow { clip: true - ScrollHelper { - flickable: parent - anchors.fill: parent - } model: editingModel spacing: 4 diff --git a/resources/qml/dialogs/AllowedRoomsSettingsDialog.qml b/resources/qml/dialogs/AllowedRoomsSettingsDialog.qml index 94ecf651..89ea5e04 100644 --- a/resources/qml/dialogs/AllowedRoomsSettingsDialog.qml +++ b/resources/qml/dialogs/AllowedRoomsSettingsDialog.qml @@ -53,10 +53,6 @@ ApplicationWindow { clip: true - ScrollHelper { - flickable: parent - anchors.fill: parent - } model: roomSettings.allowedRoomsModel spacing: 4 diff --git a/resources/qml/dialogs/ImagePackEditorDialog.qml b/resources/qml/dialogs/ImagePackEditorDialog.qml index 9e848150..4cb2c1f6 100644 --- a/resources/qml/dialogs/ImagePackEditorDialog.qml +++ b/resources/qml/dialogs/ImagePackEditorDialog.qml @@ -49,11 +49,6 @@ ApplicationWindow { model: imagePack - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } header: AvatarListTile { title: imagePack.packname diff --git a/resources/qml/dialogs/ImagePackSettingsDialog.qml b/resources/qml/dialogs/ImagePackSettingsDialog.qml index 31a34c94..b7aab2a6 100644 --- a/resources/qml/dialogs/ImagePackSettingsDialog.qml +++ b/resources/qml/dialogs/ImagePackSettingsDialog.qml @@ -55,11 +55,7 @@ ApplicationWindow { model: packlist clip: true - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } + footer: ColumnLayout { Button { @@ -217,11 +213,6 @@ ApplicationWindow { currentIndex: -1 // prevent sorting from stealing focus cacheBuffer: 500 - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } // Individual emoji delegate: AbstractButton { diff --git a/resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml b/resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml index 3f816143..01ec8b61 100644 --- a/resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml +++ b/resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml @@ -84,11 +84,6 @@ ApplicationWindow { clip: true - ScrollHelper { - flickable: parent - anchors.fill: parent - } - model: editingModel.spaces spacing: 4 cacheBuffer: 50 diff --git a/resources/qml/dialogs/RoomDirectory.qml b/resources/qml/dialogs/RoomDirectory.qml index 29adb9be..a6f53d2e 100644 --- a/resources/qml/dialogs/RoomDirectory.qml +++ b/resources/qml/dialogs/RoomDirectory.qml @@ -34,11 +34,6 @@ ApplicationWindow { anchors.fill: parent model: publicRooms - ScrollHelper { - flickable: parent - anchors.fill: parent - } - delegate: Rectangle { id: roomDirDelegate diff --git a/resources/qml/dialogs/RoomMembers.qml b/resources/qml/dialogs/RoomMembers.qml index 4952a0a9..916c6c86 100644 --- a/resources/qml/dialogs/RoomMembers.qml +++ b/resources/qml/dialogs/RoomMembers.qml @@ -106,11 +106,6 @@ ApplicationWindow { boundsBehavior: Flickable.StopAtBounds model: members - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } delegate: ItemDelegate { id: del diff --git a/resources/qml/dialogs/RoomSettings.qml b/resources/qml/dialogs/RoomSettings.qml index 6bc24058..0fa98fff 100644 --- a/resources/qml/dialogs/RoomSettings.qml +++ b/resources/qml/dialogs/RoomSettings.qml @@ -29,10 +29,7 @@ ApplicationWindow { sequence: StandardKey.Cancel onActivated: roomSettingsDialog.close() } - ScrollHelper { - flickable: flickable - anchors.fill: flickable - } + Flickable { id: flickable boundsBehavior: Flickable.StopAtBounds diff --git a/resources/qml/dialogs/UserProfile.qml b/resources/qml/dialogs/UserProfile.qml index dae43caa..b54b52a4 100644 --- a/resources/qml/dialogs/UserProfile.qml +++ b/resources/qml/dialogs/UserProfile.qml @@ -46,12 +46,6 @@ ApplicationWindow { anchors.margins: 10 footerPositioning: ListView.OverlayFooter - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } - header: ColumnLayout { id: contentL diff --git a/resources/qml/emoji/StickerPicker.qml b/resources/qml/emoji/StickerPicker.qml index b1623697..62d56a18 100644 --- a/resources/qml/emoji/StickerPicker.qml +++ b/resources/qml/emoji/StickerPicker.qml @@ -137,12 +137,6 @@ Menu { spacing: Nheko.paddingSmall - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } - // Individual emoji delegate: Row { required property var row; diff --git a/resources/res.qrc b/resources/res.qrc index bcef8841..841f956e 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -116,7 +116,6 @@ qml/PrivacyScreen.qml qml/Reactions.qml qml/ReplyPopup.qml - qml/ScrollHelper.qml qml/StatusIndicator.qml qml/TimelineRow.qml qml/TopBar.qml From de8522a185f9d62eaefb37d0f1a5e2e77c73c175 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 01:37:53 +0200 Subject: [PATCH 046/128] lint --- src/GridImagePackModel.cpp | 2 - src/JdenticonProvider.h | 4 +- src/MainWindow.cpp | 5 +- src/MatrixClient.cpp | 2 - src/MxcImageProvider.h | 4 +- src/SingleImagePackModel.cpp | 2 - src/main.cpp | 14 ++-- src/timeline/CommunitiesModel.cpp | 1 - src/timeline/EventStore.cpp | 4 +- src/timeline/EventStore.h | 6 +- src/timeline/InputBar.cpp | 109 +++++++++++++++--------------- src/timeline/RoomlistModel.cpp | 1 - src/timeline/TimelineModel.cpp | 1 - src/ui/MxcMediaProxy.cpp | 22 +++--- src/ui/MxcMediaProxy.h | 4 +- src/ui/NhekoGlobalObject.cpp | 21 ++++-- src/ui/Theme.cpp | 1 - src/voip/CallManager.cpp | 10 ++- src/voip/ScreenCastPortal.cpp | 1 - src/voip/WebRTCSession.cpp | 1 - 20 files changed, 97 insertions(+), 118 deletions(-) diff --git a/src/GridImagePackModel.cpp b/src/GridImagePackModel.cpp index 4260b6d6..2d5960a4 100644 --- a/src/GridImagePackModel.cpp +++ b/src/GridImagePackModel.cpp @@ -13,7 +13,6 @@ #include "Cache_p.h" #include "emoji/Provider.h" - QString emoji::categoryToName(emoji::Emoji::Category cat) { @@ -69,7 +68,6 @@ GridImagePackModel::GridImagePackModel(const std::string &roomId, bool stickers, , room_id(roomId) , columns(stickers ? 3 : 7) { - if (!stickers) { for (const auto &category : { emoji::Emoji::Category::People, diff --git a/src/JdenticonProvider.h b/src/JdenticonProvider.h index b4a9ba62..da4d73e1 100644 --- a/src/JdenticonProvider.h +++ b/src/JdenticonProvider.h @@ -52,9 +52,7 @@ public: QImage m_pixmap; }; -class JdenticonProvider - : - public QQuickAsyncImageProvider +class JdenticonProvider : public QQuickAsyncImageProvider { Q_OBJECT diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 4159006e..ecb5ffd0 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -5,9 +5,9 @@ #include #include +#include #include #include -#include #include "AliasEditModel.h" #include "BlurhashProvider.h" @@ -132,8 +132,6 @@ MainWindow::MainWindow(QWindow *parent) void MainWindow::registerQmlTypes() { - - qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject, "im.nheko", 1, @@ -253,7 +251,6 @@ MainWindow::registerQmlTypes() qmlRegisterSingletonInstance("im.nheko", 1, 0, "Settings", userSettings_.data()); - qmlRegisterUncreatableType( "im.nheko", 1, diff --git a/src/MatrixClient.cpp b/src/MatrixClient.cpp index 55542a75..2fd2eac9 100644 --- a/src/MatrixClient.cpp +++ b/src/MatrixClient.cpp @@ -15,8 +15,6 @@ #include "nlohmann/json.hpp" #include - - namespace http { mtx::http::Client * diff --git a/src/MxcImageProvider.h b/src/MxcImageProvider.h index b67e2f8d..5c3e5c58 100644 --- a/src/MxcImageProvider.h +++ b/src/MxcImageProvider.h @@ -70,9 +70,7 @@ public: QImage m_image; }; -class MxcImageProvider - : - public QQuickAsyncImageProvider +class MxcImageProvider : public QQuickAsyncImageProvider { Q_OBJECT diff --git a/src/SingleImagePackModel.cpp b/src/SingleImagePackModel.cpp index 47e11f0e..686184da 100644 --- a/src/SingleImagePackModel.cpp +++ b/src/SingleImagePackModel.cpp @@ -20,7 +20,6 @@ #include "timeline/Permissions.h" #include "timeline/TimelineModel.h" - SingleImagePackModel::SingleImagePackModel(ImagePackInfo pack_, QObject *parent) : QAbstractListModel(parent) , roomid_(std::move(pack_.source_room)) @@ -29,7 +28,6 @@ SingleImagePackModel::SingleImagePackModel(ImagePackInfo pack_, QObject *parent) , pack(std::move(pack_.pack)) , fromSpace_(pack_.from_space) { - if (!pack.pack) pack.pack = mtx::events::msc2545::ImagePack::PackDescription{}; diff --git a/src/main.cpp b/src/main.cpp index 99e11bf9..1a7843db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -330,15 +330,17 @@ main(int argc, char *argv[]) QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedKingdom)); QTranslator qtTranslator; - if(qtTranslator.load(QLocale(), - QStringLiteral("qt"), - QStringLiteral("_"), - QLibraryInfo::path(QLibraryInfo::TranslationsPath))) + if (qtTranslator.load(QLocale(), + QStringLiteral("qt"), + QStringLiteral("_"), + QLibraryInfo::path(QLibraryInfo::TranslationsPath))) app.installTranslator(&qtTranslator); QTranslator appTranslator; - if(appTranslator.load( - QLocale(), QStringLiteral("nheko"), QStringLiteral("_"), QStringLiteral(":/translations"))) + if (appTranslator.load(QLocale(), + QStringLiteral("nheko"), + QStringLiteral("_"), + QStringLiteral(":/translations"))) app.installTranslator(&appTranslator); MainWindow w; diff --git a/src/timeline/CommunitiesModel.cpp b/src/timeline/CommunitiesModel.cpp index dc09a95e..b04fd7a9 100644 --- a/src/timeline/CommunitiesModel.cpp +++ b/src/timeline/CommunitiesModel.cpp @@ -17,7 +17,6 @@ #include "Utils.h" #include "timeline/TimelineModel.h" - CommunitiesModel::CommunitiesModel(QObject *parent) : QAbstractListModel(parent) , hiddenTagIds_{UserSettings::instance()->hiddenTags()} diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index d373cf55..63b67474 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -18,7 +18,6 @@ #include "UserSettingsPage.h" #include "Utils.h" - QCache EventStore::decryptedEvents_{1000}; QCache EventStore::events_by_id_{ 1000}; @@ -27,7 +26,6 @@ QCache EventStore:: EventStore::EventStore(std::string room_id, QObject *) : room_id_(std::move(room_id)) { - auto range = cache::client()->getTimelineRange(room_id_); if (range) { @@ -289,7 +287,7 @@ EventStore::EventStore(std::string room_id, QObject *) } void -EventStore::addPending(const mtx::events::collections::TimelineEvents& event) +EventStore::addPending(const mtx::events::collections::TimelineEvents &event) { if (this->thread() != QThread::currentThread()) nhlog::db()->warn("{} called from a different thread!", __func__); diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h index f2f9e2d7..ee92a795 100644 --- a/src/timeline/EventStore.h +++ b/src/timeline/EventStore.h @@ -11,10 +11,10 @@ #include #include +#include #include #include #include -#include #include "Reaction.h" #include "encryption/Olm.h" @@ -107,7 +107,7 @@ signals: void newEncryptedImage(mtx::crypto::EncryptedFile encryptionInfo); void eventFetched(std::string id, std::string relatedTo, - const mtx::events::collections::TimelineEvents& timeline); + const mtx::events::collections::TimelineEvents &timeline); void oldMessagesRetrieved(const mtx::responses::Messages &); void fetchedMore(); @@ -119,7 +119,7 @@ signals: void updateFlowEventId(std::string event_id); public slots: - void addPending(const mtx::events::collections::TimelineEvents& event); + void addPending(const mtx::events::collections::TimelineEvents &event); void receivedSessionKey(const std::string &session_id); void clearTimeline(); void enableKeyRequests(bool suppressKeyRequests_); diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index af974592..6980c364 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -989,56 +989,58 @@ MediaUpload::MediaUpload(std::unique_ptr source_, blurhash_ = QString::fromStdString(blurhash::encode(data_.data(), img.width(), img.height(), 4, 3)); } else if (mimeClass_ == u"video" || mimeClass_ == u"audio") { - auto mediaPlayer = new QMediaPlayer( this); + auto mediaPlayer = new QMediaPlayer(this); mediaPlayer->setAudioOutput(nullptr); if (mimeClass_ == u"video") { auto newSurface = new QVideoSink(this); - connect( - newSurface, &QVideoSink::videoFrameChanged, this, [this, mediaPlayer](const QVideoFrame& frame) { - QImage img = frame.toImage(); - if (img.size().isEmpty()) - return; + connect(newSurface, + &QVideoSink::videoFrameChanged, + this, + [this, mediaPlayer](const QVideoFrame &frame) { + QImage img = frame.toImage(); + if (img.size().isEmpty()) + return; - mediaPlayer->stop(); + mediaPlayer->stop(); - auto orientation = mediaPlayer->metaData().value(QMediaMetaData::Orientation).toInt(); - if (orientation == 90 || orientation == 270 || orientation == 180) { - img = - img.transformed(QTransform().rotate(orientation), Qt::SmoothTransformation); - } + auto orientation = + mediaPlayer->metaData().value(QMediaMetaData::Orientation).toInt(); + if (orientation == 90 || orientation == 270 || orientation == 180) { + img = img.transformed(QTransform().rotate(orientation), + Qt::SmoothTransformation); + } - nhlog::ui()->debug("Got image {}x{}", img.width(), img.height()); + nhlog::ui()->debug("Got image {}x{}", img.width(), img.height()); - this->setThumbnail(img); + this->setThumbnail(img); - if (!dimensions_.isValid()) - this->dimensions_ = img.size(); + if (!dimensions_.isValid()) + this->dimensions_ = img.size(); - if (img.height() > 200 && img.width() > 360) - img = img.scaled(360, 200, Qt::KeepAspectRatioByExpanding); - std::vector data_; - for (int y = 0; y < img.height(); y++) { - for (int x = 0; x < img.width(); x++) { - auto p = img.pixel(x, y); - data_.push_back(static_cast(qRed(p))); - data_.push_back(static_cast(qGreen(p))); - data_.push_back(static_cast(qBlue(p))); - } - } - blurhash_ = QString::fromStdString( - blurhash::encode(data_.data(), img.width(), img.height(), 4, 3)); - }); + if (img.height() > 200 && img.width() > 360) + img = img.scaled(360, 200, Qt::KeepAspectRatioByExpanding); + std::vector data_; + for (int y = 0; y < img.height(); y++) { + for (int x = 0; x < img.width(); x++) { + auto p = img.pixel(x, y); + data_.push_back(static_cast(qRed(p))); + data_.push_back(static_cast(qGreen(p))); + data_.push_back(static_cast(qBlue(p))); + } + } + blurhash_ = QString::fromStdString( + blurhash::encode(data_.data(), img.width(), img.height(), 4, 3)); + }); mediaPlayer->setVideoOutput(newSurface); } connect(mediaPlayer, -&QMediaPlayer::errorOccurred, + &QMediaPlayer::errorOccurred, this, [](QMediaPlayer::Error error, QString errorString) { - nhlog::ui()->debug("Media player error {} and errorStr {}", - error, - errorString.toStdString()); + nhlog::ui()->debug( + "Media player error {} and errorStr {}", error, errorString.toStdString()); }); connect(mediaPlayer, &QMediaPlayer::mediaStatusChanged, @@ -1046,25 +1048,22 @@ MediaUpload::MediaUpload(std::unique_ptr source_, nhlog::ui()->debug( "Media player status {} and error {}", status, mediaPlayer->error()); }); - connect(mediaPlayer, -&QMediaPlayer::metaDataChanged, - this, - [this, mediaPlayer]() { - nhlog::ui()->debug("Got metadata {}"); - - if (mediaPlayer->duration() > 0) - this->duration_ = mediaPlayer->duration(); - - auto dimensions = mediaPlayer->metaData().value(QMediaMetaData::Resolution).toSize(); - if (!dimensions.isEmpty()) { - dimensions_ = dimensions; - auto orientation = - mediaPlayer->metaData().value(QMediaMetaData::Orientation).toInt(); - if (orientation == 90 || orientation == 270) { - dimensions_.transpose(); - } - } - }); + connect(mediaPlayer, &QMediaPlayer::metaDataChanged, this, [this, mediaPlayer]() { + nhlog::ui()->debug("Got metadata {}"); + + if (mediaPlayer->duration() > 0) + this->duration_ = mediaPlayer->duration(); + + auto dimensions = mediaPlayer->metaData().value(QMediaMetaData::Resolution).toSize(); + if (!dimensions.isEmpty()) { + dimensions_ = dimensions; + auto orientation = + mediaPlayer->metaData().value(QMediaMetaData::Orientation).toInt(); + if (orientation == 90 || orientation == 270) { + dimensions_.transpose(); + } + } + }); connect( mediaPlayer, &QMediaPlayer::durationChanged, this, [this, mediaPlayer](qint64 duration) { if (duration > 0) { @@ -1077,8 +1076,8 @@ MediaUpload::MediaUpload(std::unique_ptr source_, auto originalFile = qobject_cast(source.get()); - mediaPlayer->setSourceDevice(source.get(), - QUrl(originalFile ? originalFile->fileName() : originalFilename_)); + mediaPlayer->setSourceDevice( + source.get(), QUrl(originalFile ? originalFile->fileName() : originalFilename_)); mediaPlayer->play(); } diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp index b55cbabd..35507cbd 100644 --- a/src/timeline/RoomlistModel.cpp +++ b/src/timeline/RoomlistModel.cpp @@ -28,7 +28,6 @@ RoomlistModel::RoomlistModel(TimelineViewManager *parent) : QAbstractListModel(parent) , manager(parent) { - connect(ChatPage::instance(), &ChatPage::decryptSidebarChanged, this, [this]() { auto decrypt = ChatPage::instance()->userSettings()->decryptSidebar(); QHash>::iterator i; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index a4659f33..0e99e7e1 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -31,7 +31,6 @@ #include "Utils.h" #include "encryption/Olm.h" - namespace std { inline uint // clazy:exclude=qhash-namespace qHash(const std::string &key, uint seed = 0) diff --git a/src/ui/MxcMediaProxy.cpp b/src/ui/MxcMediaProxy.cpp index dd5d81a9..2adf2538 100644 --- a/src/ui/MxcMediaProxy.cpp +++ b/src/ui/MxcMediaProxy.cpp @@ -25,22 +25,15 @@ MxcMediaProxy::MxcMediaProxy(QObject *parent) { connect(this, &MxcMediaProxy::eventIdChanged, &MxcMediaProxy::startDownload); connect(this, &MxcMediaProxy::roomChanged, &MxcMediaProxy::startDownload); - connect(this, -&QMediaPlayer::errorOccurred, - this, - [](QMediaPlayer::Error error, QString errorString) { - nhlog::ui()->debug("Media player error {} and errorStr {}", - error, - errorString.toStdString()); - }); + connect( + this, &QMediaPlayer::errorOccurred, this, [](QMediaPlayer::Error error, QString errorString) { + nhlog::ui()->debug( + "Media player error {} and errorStr {}", error, errorString.toStdString()); + }); connect(this, &MxcMediaProxy::mediaStatusChanged, [this](QMediaPlayer::MediaStatus status) { nhlog::ui()->info("Media player status {} and error {}", status, this->error()); }); - connect(this, - &MxcMediaProxy::metaDataChanged, - [this]() { - emit orientationChanged(); - }); + connect(this, &MxcMediaProxy::metaDataChanged, [this]() { emit orientationChanged(); }); connect(ChatPage::instance()->timelineManager()->rooms(), &RoomlistModel::currentRoomChanged, @@ -51,7 +44,8 @@ MxcMediaProxy::MxcMediaProxy(QObject *parent) int MxcMediaProxy::orientation() const { - //nhlog::ui()->debug("metadata: {}", availableMetaData().join(QStringLiteral(",")).toStdString()); + // nhlog::ui()->debug("metadata: {}", + // availableMetaData().join(QStringLiteral(",")).toStdString()); auto orientation = metaData().value(QMediaMetaData::Orientation).toInt(); nhlog::ui()->debug("Video orientation: {}", orientation); return orientation; diff --git a/src/ui/MxcMediaProxy.h b/src/ui/MxcMediaProxy.h index 7b7947e9..5c2eac33 100644 --- a/src/ui/MxcMediaProxy.h +++ b/src/ui/MxcMediaProxy.h @@ -4,13 +4,13 @@ #pragma once -#include #include -#include #include #include #include #include +#include +#include #include "Logging.h" diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp index 8f410dae..0bdb45f4 100644 --- a/src/ui/NhekoGlobalObject.cpp +++ b/src/ui/NhekoGlobalObject.cpp @@ -5,8 +5,8 @@ #include "NhekoGlobalObject.h" #include -#include #include +#include #include #include #include @@ -184,9 +184,11 @@ Nheko::createRoom(bool space, void Nheko::setWindowRole([[maybe_unused]] QWindow *win, [[maybe_unused]] QString newRole) const { - const QNativeInterface::QX11Application *x11Interface = qGuiApp->nativeInterface(); + const QNativeInterface::QX11Application *x11Interface = + qGuiApp->nativeInterface(); - if (!x11Interface) return; + if (!x11Interface) + return; auto connection = x11Interface->connection(); @@ -195,10 +197,15 @@ Nheko::setWindowRole([[maybe_unused]] QWindow *win, [[maybe_unused]] QString new char WM_WINDOW_ROLE[] = "WM_WINDOW_ROLE"; auto cookie = xcb_intern_atom(connection, false, std::size(WM_WINDOW_ROLE) - 1, WM_WINDOW_ROLE); xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, nullptr); - auto atom = reply ->atom; + auto atom = reply->atom; free(reply); - xcb_change_property(connection, XCB_PROP_MODE_REPLACE, win->winId(), - atom, XCB_ATOM_STRING, 8, - role.size(), role.data()); + xcb_change_property(connection, + XCB_PROP_MODE_REPLACE, + win->winId(), + atom, + XCB_ATOM_STRING, + 8, + role.size(), + role.data()); } diff --git a/src/ui/Theme.cpp b/src/ui/Theme.cpp index 8cf38548..159fc2ae 100644 --- a/src/ui/Theme.cpp +++ b/src/ui/Theme.cpp @@ -4,7 +4,6 @@ #include "Theme.h" - QPalette Theme::paletteFromTheme(QStringView theme) { diff --git a/src/voip/CallManager.cpp b/src/voip/CallManager.cpp index 9a610819..feb06835 100644 --- a/src/voip/CallManager.cpp +++ b/src/voip/CallManager.cpp @@ -41,7 +41,6 @@ extern "C" } #endif - using namespace mtx::events; using namespace mtx::events::voip; @@ -60,7 +59,6 @@ CallManager::CallManager(QObject *parent) , session_(WebRTCSession::instance()) , turnServerTimer_(this) { - #ifdef GSTREAMER_AVAILABLE std::string errorMessage; if (session_.havePlugins(true, true, ScreenShareType::XDP, &errorMessage)) { @@ -186,7 +184,8 @@ CallManager::CallManager(QObject *parent) nhlog::ui()->error("WebRTC: access to ringtone file denied"); break; default: - nhlog::ui()->error("WebRTC: unable to play ringtone, {}", errorString.toStdString()); + nhlog::ui()->error("WebRTC: unable to play ringtone, {}", + errorString.toStdString()); break; } }); @@ -820,10 +819,9 @@ CallManager::retrieveTurnServer() void CallManager::playRingtone(const QUrl &ringtone, bool repeat) { - player_.setLoops(repeat ? QMediaPlayer::Infinite : - 1); + player_.setLoops(repeat ? QMediaPlayer::Infinite : 1); player_.setSource(ringtone); - //player_.audioOutput()->setVolume(100); + // player_.audioOutput()->setVolume(100); player_.play(); } diff --git a/src/voip/ScreenCastPortal.cpp b/src/voip/ScreenCastPortal.cpp index e0433387..6cd91e51 100644 --- a/src/voip/ScreenCastPortal.cpp +++ b/src/voip/ScreenCastPortal.cpp @@ -438,7 +438,6 @@ struct PipeWireStream QVariantMap map; }; - const QDBusArgument & operator>>(const QDBusArgument &argument, PipeWireStream &stream) { diff --git a/src/voip/WebRTCSession.cpp b/src/voip/WebRTCSession.cpp index c8bc9cb5..c40b39a4 100644 --- a/src/voip/WebRTCSession.cpp +++ b/src/voip/WebRTCSession.cpp @@ -41,7 +41,6 @@ extern "C" // https://github.com/vector-im/riot-web/issues/10173 #define STUN_SERVER "stun://turn.matrix.org:3478" - using webrtc::CallType; using webrtc::ScreenShareType; using webrtc::State; From 5aee8d609a3fcca63bb9a0f983a77b45eebfefe7 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 01:45:24 +0200 Subject: [PATCH 047/128] Format qml --- .qmlformat.ini | 7 + resources/qml/Avatar.qml | 61 +- resources/qml/ChatPage.qml | 70 +- resources/qml/CommunitiesList.qml | 172 ++-- resources/qml/Completer.qml | 212 ++--- resources/qml/ElidedLabel.qml | 9 +- resources/qml/EncryptionIndicator.qml | 55 +- resources/qml/ForwardCompleter.qml | 69 +- resources/qml/ImageButton.qml | 15 +- resources/qml/MatrixText.qml | 18 +- resources/qml/MatrixTextField.qml | 124 ++- resources/qml/MessageInput.qml | 279 +++--- resources/qml/MessageInputWarning.qml | 20 +- resources/qml/MessageView.qml | 947 +++++++++---------- resources/qml/PrivacyScreen.qml | 36 +- resources/qml/QuickSwitcher.qml | 55 +- resources/qml/Reactions.qml | 76 +- resources/qml/ReplyPopup.qml | 64 +- resources/qml/RoomList.qml | 1155 +++++++++++------------ resources/qml/Root.qml | 392 ++++---- resources/qml/SelfVerificationCheck.qml | 166 ++-- resources/qml/StatusIndicator.qml | 24 +- resources/qml/TimelineRow.qml | 358 +++---- resources/qml/TimelineView.qml | 275 +++--- resources/qml/ToggleButton.qml | 79 +- resources/qml/TopBar.qml | 382 ++++---- resources/qml/TypingIndicator.qml | 10 +- resources/qml/UploadBox.qml | 67 +- 28 files changed, 2433 insertions(+), 2764 deletions(-) create mode 100644 .qmlformat.ini diff --git a/.qmlformat.ini b/.qmlformat.ini new file mode 100644 index 00000000..c136c23b --- /dev/null +++ b/.qmlformat.ini @@ -0,0 +1,7 @@ +[General] +FunctionsSpacing= +IndentWidth=4 +NewlineType=native +NormalizeOrder=true +ObjectsSpacing= +UseTabs=false diff --git a/resources/qml/Avatar.qml b/resources/qml/Avatar.qml index 8302f8fa..53124f28 100644 --- a/resources/qml/Avatar.qml +++ b/resources/qml/Avatar.qml @@ -11,45 +11,44 @@ import im.nheko 1.0 AbstractButton { id: avatar - property string url - property string userid - property string roomid + property alias color: bg.color + property bool crop: true property string displayName + property string roomid property alias textColor: label.color - property bool crop: true - property alias color: bg.color + property string url + property string userid - width: 48 height: 48 + width: 48 + background: Rectangle { id: bg - radius: Settings.avatarCircles ? height / 2 : height / 8 + color: palette.alternateBase + radius: Settings.avatarCircles ? height / 2 : height / 8 } Label { id: label - enabled: false - anchors.fill: parent + color: palette.text + enabled: false + font.pixelSize: avatar.height / 2 + horizontalAlignment: Text.AlignHCenter text: TimelineManager.escapeEmoji(displayName ? String.fromCodePoint(displayName.codePointAt(0)) : "") textFormat: Text.RichText - font.pixelSize: avatar.height / 2 verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter visible: img.status != Image.Ready && !Settings.useIdenticon - color: palette.text } - Image { id: identicon anchors.fill: parent - visible: Settings.useIdenticon && img.status != Image.Ready source: Settings.useIdenticon ? ("image://jdenticon/" + (userid !== "" ? userid : roomid) + "?radius=" + (Settings.avatarCircles ? 100 : 25)) : "" + visible: Settings.useIdenticon && img.status != Image.Ready } - Image { id: img @@ -58,8 +57,6 @@ AbstractButton { fillMode: avatar.crop ? Image.PreserveAspectCrop : Image.PreserveAspectFit mipmap: true smooth: true - sourceSize.width: avatar.width * Screen.devicePixelRatio - sourceSize.height: avatar.height * Screen.devicePixelRatio source: if (avatar.url.startsWith('image://')) { return avatar.url + "?radius=" + (Settings.avatarCircles ? 100 : 25) + ((avatar.crop) ? "" : "&scale"); } else if (avatar.url.startsWith(':/')) { @@ -67,20 +64,12 @@ AbstractButton { } else { return ""; } - + sourceSize.height: avatar.height * Screen.devicePixelRatio + sourceSize.width: avatar.width * Screen.devicePixelRatio } - Rectangle { id: onlineIndicator - anchors.bottom: avatar.bottom - anchors.right: avatar.right - visible: !!userid - height: avatar.height / 6 - width: height - radius: Settings.avatarCircles ? height / 2 : height / 8 - color: updatePresence() - function updatePresence() { switch (Presence.userPresence(userid)) { case "online": @@ -94,22 +83,28 @@ AbstractButton { } } - Connections { - target: Presence + anchors.bottom: avatar.bottom + anchors.right: avatar.right + color: updatePresence() + height: avatar.height / 6 + radius: Settings.avatarCircles ? height / 2 : height / 8 + visible: !!userid + width: height + Connections { function onPresenceChanged(id) { - if (id == userid) onlineIndicator.color = onlineIndicator.updatePresence(); + if (id == userid) + onlineIndicator.color = onlineIndicator.updatePresence(); } + + target: Presence } } - CursorShape { anchors.fill: parent cursorShape: Qt.PointingHandCursor } - Ripple { color: Qt.rgba(palette.alternateBase.r, palette.alternateBase.g, palette.alternateBase.b, 0.5) } - } diff --git a/resources/qml/ChatPage.qml b/resources/qml/ChatPage.qml index 564c093d..2803e97d 100644 --- a/resources/qml/ChatPage.qml +++ b/resources/qml/ChatPage.qml @@ -17,16 +17,16 @@ Rectangle { color: palette.window ColumnLayout { - spacing: 0 anchors.fill: parent + spacing: 0 Rectangle { id: offlineIndicator + Layout.fillWidth: true + Layout.preferredHeight: offlineLabel.height + Nheko.paddingMedium color: Nheko.theme.error visible: !TimelineManager.isConnected - Layout.preferredHeight: offlineLabel.height + Nheko.paddingMedium - Layout.fillWidth: true z: 1 Label { @@ -36,18 +36,9 @@ Rectangle { text: qsTr("No network connection") } } - AdaptiveLayout { id: adaptiveView - Layout.fillWidth: true - Layout.fillHeight: true - singlePageMode: communityListC.preferredWidth + roomListC.preferredWidth + timlineViewC.minimumWidth > width - pageIndex: 1 - - Component.onCompleted: initializePageIndex() - onSinglePageModeChanged: initializePageIndex() - function initializePageIndex() { if (!singlePageMode) adaptiveView.pageIndex = 0; @@ -57,67 +48,67 @@ Rectangle { adaptiveView.pageIndex = 1; } + Layout.fillHeight: true + Layout.fillWidth: true + pageIndex: 1 + singlePageMode: communityListC.preferredWidth + roomListC.preferredWidth + timlineViewC.minimumWidth > width + + Component.onCompleted: initializePageIndex() + onSinglePageModeChanged: initializePageIndex() + Connections { - target: Rooms function onCurrentRoomChanged() { adaptiveView.initializePageIndex(); } - } + target: Rooms + } AdaptiveLayoutElement { id: communityListC - visible: Settings.groupView - minimumWidth: communitiesList.avatarSize * 4 + Nheko.paddingMedium * 2 collapsedWidth: communitiesList.avatarSize + 2 * Nheko.paddingMedium - preferredWidth: Settings.communityListWidth >= minimumWidth ? Settings.communityListWidth : collapsedWidth maximumWidth: communitiesList.avatarSize * 10 + 2 * Nheko.paddingMedium + minimumWidth: communitiesList.avatarSize * 4 + Nheko.paddingMedium * 2 + preferredWidth: Settings.communityListWidth >= minimumWidth ? Settings.communityListWidth : collapsedWidth + visible: Settings.groupView CommunitiesList { id: communitiesList collapsed: parent.collapsed } - Binding { - target: Settings + delayed: true property: 'communityListWidth' + restoreMode: Binding.RestoreBindingOrValue + target: Settings value: communityListC.preferredWidth when: !adaptiveView.singlePageMode - delayed: true - restoreMode: Binding.RestoreBindingOrValue } - } - AdaptiveLayoutElement { id: roomListC - minimumWidth: roomlist.avatarSize * 4 + Nheko.paddingSmall * 2 - preferredWidth: (Settings.roomListWidth == - 1) - ? (roomlist.avatarSize * 5 + Nheko.paddingSmall * 2) - : (Settings.roomListWidth >= minimumWidth ? Settings.roomListWidth : collapsedWidth) - maximumWidth: roomlist.avatarSize * 10 + Nheko.paddingSmall * 2 collapsedWidth: roomlist.avatarSize + 2 * Nheko.paddingMedium + maximumWidth: roomlist.avatarSize * 10 + Nheko.paddingSmall * 2 + minimumWidth: roomlist.avatarSize * 4 + Nheko.paddingSmall * 2 + preferredWidth: (Settings.roomListWidth == -1) ? (roomlist.avatarSize * 5 + Nheko.paddingSmall * 2) : (Settings.roomListWidth >= minimumWidth ? Settings.roomListWidth : collapsedWidth) RoomList { id: roomlist - height: adaptiveView.height collapsed: parent.collapsed + height: adaptiveView.height } - Binding { - target: Settings + delayed: true property: 'roomListWidth' + restoreMode: Binding.RestoreBindingOrValue + target: Settings value: roomListC.preferredWidth when: !adaptiveView.singlePageMode - delayed: true - restoreMode: Binding.RestoreBindingOrValue } - } - AdaptiveLayoutElement { id: timlineViewC @@ -127,25 +118,20 @@ Rectangle { id: timeline privacyScreen: privacyScreen - showBackButton: adaptiveView.singlePageMode room: Rooms.currentRoom roomPreview: Rooms.currentRoomPreview.roomid ? Rooms.currentRoomPreview : null + showBackButton: adaptiveView.singlePageMode } - } - } - } - PrivacyScreen { id: privacyScreen anchors.fill: parent - visible: Settings.privacyScreen screenTimeout: Settings.privacyScreenTimeout timelineRoot: adaptiveView + visible: Settings.privacyScreen windowTarget: MainWindow } - } diff --git a/resources/qml/CommunitiesList.qml b/resources/qml/CommunitiesList.qml index a210a4bb..62a29a2d 100644 --- a/resources/qml/CommunitiesList.qml +++ b/resources/qml/CommunitiesList.qml @@ -13,19 +13,24 @@ import im.nheko 1.0 Page { id: communitySidebar + //leftPadding: Nheko.paddingSmall //rightPadding: Nheko.paddingSmall property int avatarSize: Math.ceil(fontMetrics.lineSpacing * 1.6) property bool collapsed: false + background: Rectangle { + color: Nheko.theme.sidebarBackground + } + // HACK: https://bugreports.qt.io/browse/QTBUG-83972, qtwayland cannot auto hide menu Connections { function onHideMenu() { - communityContextMenu.close() + communityContextMenu.close(); } + target: MainWindow } - ListView { id: communitiesList @@ -36,195 +41,180 @@ Page { ScrollBar.vertical: ScrollBar { id: scrollbar - parent: !collapsed && Settings.scrollbarsInRoomlist ? communitiesList : null - } - - Platform.Menu { - id: communityContextMenu - - property string tagId - property bool hidden - property bool muted - - function show(id_, hidden_, muted_) { - tagId = id_; - hidden = hidden_; - muted = muted_; - open(); - } - - Platform.MenuItem { - text: qsTr("Do not show notification counts for this community or tag.") - checkable: true - checked: communityContextMenu.muted - onTriggered: Communities.toggleTagMute(communityContextMenu.tagId) - } - - Platform.MenuItem { - text: qsTr("Hide rooms with this tag or from this community by default.") - checkable: true - checked: communityContextMenu.hidden - onTriggered: Communities.toggleTagId(communityContextMenu.tagId) - } + parent: !collapsed && Settings.scrollbarsInRoomlist ? communitiesList : null } - delegate: ItemDelegate { id: communityItem property color backgroundColor: palette.window - property color importantText: palette.text - property color unimportantText: palette.buttonText property color bubbleBackground: palette.highlight property color bubbleText: palette.highlightedText + property color importantText: palette.text required property var model + property color unimportantText: palette.buttonText + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: model.tooltip + ToolTip.visible: hovered && collapsed height: avatarSize + 2 * Nheko.paddingMedium - width: ListView.view.width - ((scrollbar.interactive && scrollbar.visible && scrollbar.parent) ? scrollbar.width : 0) state: "normal" - ToolTip.visible: hovered && collapsed - ToolTip.text: model.tooltip - ToolTip.delay: Nheko.tooltipDelay - onClicked: Communities.setCurrentTagId(model.id) - onPressAndHold: communityContextMenu.show(model.id, model.hidden, model.muted) + width: ListView.view.width - ((scrollbar.interactive && scrollbar.visible && scrollbar.parent) ? scrollbar.width : 0) + + background: Rectangle { + color: communityItem.backgroundColor + } states: [ State { name: "highlight" when: (communityItem.hovered || model.hidden) && !(Communities.currentTagId === model.id) PropertyChanges { - target: communityItem backgroundColor: palette.dark - importantText: palette.brightText - unimportantText: palette.brightText bubbleBackground: palette.highlight bubbleText: palette.highlightedText + importantText: palette.brightText + target: communityItem + unimportantText: palette.brightText } - }, State { name: "selected" when: Communities.currentTagId == model.id PropertyChanges { - target: communityItem backgroundColor: palette.highlight - importantText: palette.highlightedText - unimportantText: palette.highlightedText bubbleBackground: palette.highlightedText bubbleText: palette.highlight + importantText: palette.highlightedText + target: communityItem + unimportantText: palette.highlightedText } - } ] + onClicked: Communities.setCurrentTagId(model.id) + onPressAndHold: communityContextMenu.show(model.id, model.hidden, model.muted) + Item { anchors.fill: parent TapHandler { acceptedButtons: Qt.RightButton - onSingleTapped: communityContextMenu.show(model.id, model.hidden, model.muted) - gesturePolicy: TapHandler.ReleaseWithinBounds acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad - } + gesturePolicy: TapHandler.ReleaseWithinBounds + onSingleTapped: communityContextMenu.show(model.id, model.hidden, model.muted) + } } - RowLayout { id: r - spacing: Nheko.paddingMedium + anchors.fill: parent - anchors.margins: Nheko.paddingMedium anchors.leftMargin: Nheko.paddingMedium + (communitySidebar.collapsed ? 0 : (fontMetrics.lineSpacing * model.depth)) + anchors.margins: Nheko.paddingMedium + spacing: Nheko.paddingMedium ImageButton { - visible: !communitySidebar.collapsed && model.collapsible + Layout.alignment: Qt.AlignVCenter Layout.preferredHeight: fontMetrics.lineSpacing Layout.preferredWidth: fontMetrics.lineSpacing - Layout.alignment: Qt.AlignVCenter - height: fontMetrics.lineSpacing - width: fontMetrics.lineSpacing - image: model.collapsed ? ":/icons/icons/ui/collapsed.svg" : ":/icons/icons/ui/expanded.svg" - ToolTip.visible: hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: model.collapsed ? qsTr("Expand") : qsTr("Collapse") + ToolTip.visible: hovered + height: fontMetrics.lineSpacing hoverEnabled: true + image: model.collapsed ? ":/icons/icons/ui/collapsed.svg" : ":/icons/icons/ui/expanded.svg" + visible: !communitySidebar.collapsed && model.collapsible + width: fontMetrics.lineSpacing onClicked: model.collapsed = !model.collapsed } - Item { Layout.preferredWidth: fontMetrics.lineSpacing visible: !communitySidebar.collapsed && !model.collapsible && Communities.containsSubspaces } - Avatar { id: avatar - enabled: false Layout.alignment: Qt.AlignVCenter + color: communityItem.backgroundColor + displayName: model.displayName + enabled: false height: avatarSize - width: avatarSize + roomid: model.id url: { if (model.avatarUrl.startsWith("mxc://")) return model.avatarUrl.replace("mxc://", "image://MxcImage/"); else return "image://colorimage/" + model.avatarUrl + "?" + communityItem.unimportantText; } - roomid: model.id - displayName: model.displayName - color: communityItem.backgroundColor + width: avatarSize NotificationBubble { - notificationCount: model.unreadMessages - hasLoudNotification: model.hasLoudNotification + anchors.bottom: avatar.bottom + anchors.margins: -Nheko.paddingSmall + anchors.right: avatar.right bubbleBackgroundColor: communityItem.bubbleBackground bubbleTextColor: communityItem.bubbleText font.pixelSize: fontMetrics.font.pixelSize * 0.6 + hasLoudNotification: model.hasLoudNotification mayBeVisible: communitySidebar.collapsed && !model.muted && Settings.spaceNotifications - anchors.right: avatar.right - anchors.bottom: avatar.bottom - anchors.margins: -Nheko.paddingSmall + notificationCount: model.unreadMessages } - } - ElidedLabel { - visible: !communitySidebar.collapsed Layout.alignment: Qt.AlignVCenter - color: communityItem.importantText Layout.fillWidth: true + color: communityItem.importantText elideWidth: width fullText: model.displayName textFormat: Text.PlainText + visible: !communitySidebar.collapsed } - Item { Layout.fillWidth: true } - NotificationBubble { - notificationCount: model.unreadMessages - hasLoudNotification: model.hasLoudNotification + Layout.alignment: Qt.AlignRight + Layout.leftMargin: Nheko.paddingSmall bubbleBackgroundColor: communityItem.bubbleBackground bubbleTextColor: communityItem.bubbleText + hasLoudNotification: model.hasLoudNotification mayBeVisible: !communitySidebar.collapsed && !model.muted && Settings.spaceNotifications - Layout.alignment: Qt.AlignRight - Layout.leftMargin: Nheko.paddingSmall + notificationCount: model.unreadMessages } - } + } - background: Rectangle { - color: communityItem.backgroundColor + Platform.Menu { + id: communityContextMenu + + property bool hidden + property bool muted + property string tagId + + function show(id_, hidden_, muted_) { + tagId = id_; + hidden = hidden_; + muted = muted_; + open(); } - } + Platform.MenuItem { + checkable: true + checked: communityContextMenu.muted + text: qsTr("Do not show notification counts for this community or tag.") - } + onTriggered: Communities.toggleTagMute(communityContextMenu.tagId) + } + Platform.MenuItem { + checkable: true + checked: communityContextMenu.hidden + text: qsTr("Hide rooms with this tag or from this community by default.") - background: Rectangle { - color: Nheko.theme.sidebarBackground + onTriggered: Communities.toggleTagId(communityContextMenu.tagId) + } + } } - } diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml index 02dccfc9..00141d4d 100644 --- a/resources/qml/Completer.qml +++ b/resources/qml/Completer.qml @@ -11,117 +11,102 @@ import im.nheko 1.0 Control { id: popup - property alias currentIndex: listView.currentIndex - property string roomId - property string completerName - property var completer - property bool bottomToTop: true - property bool fullWidth: false - property bool centerRowContent: true property int avatarHeight: 24 property int avatarWidth: 24 + property bool bottomToTop: true + property bool centerRowContent: true + property var completer + property string completerName + property alias count: listView.count + property alias currentIndex: listView.currentIndex + property bool fullWidth: false + property string roomId property int rowMargin: 0 property int rowSpacing: Nheko.paddingSmall - property alias count: listView.count signal completionClicked(string completion) signal completionSelected(string id) - function up() { - if (bottomToTop) - down_(); + function changeCompleter() { + if (completerName) { + completer = TimelineManager.completerFor(completerName, completerName == "room" ? "" : (popup.roomId != "" ? popup.roomId : room.roomId)); + completer.setSearchString(""); + } else { + completer = undefined; + } + currentIndex = -1; + } + function currentCompletion() { + if (currentIndex > -1 && currentIndex < listView.count) + return completer.completionAt(currentIndex); else - up_(); + return null; } - function down() { if (bottomToTop) up_(); else down_(); } - - function up_() { - currentIndex = currentIndex - 1; - if (currentIndex == -2) - currentIndex = listView.count - 1; - - } - function down_() { currentIndex = currentIndex + 1; if (currentIndex >= listView.count) currentIndex = -1; - - } - - function currentCompletion() { - if (currentIndex > -1 && currentIndex < listView.count) - return completer.completionAt(currentIndex); - else - return null; } - function finishCompletion() { if (popup.completerName == "room") popup.completionSelected(listView.itemAtIndex(currentIndex).modelData.roomid); else if (popup.completerName == "user") popup.completionSelected(listView.itemAtIndex(currentIndex).modelData.userid); - } - - function changeCompleter() { - if (completerName) { - completer = TimelineManager.completerFor(completerName, completerName == "room" ? "" : (popup.roomId != "" ? popup.roomId : room.roomId)); - completer.setSearchString(""); - } else { - completer = undefined; - } - currentIndex = -1 + function up() { + if (bottomToTop) + down_(); + else + up_(); + } + function up_() { + currentIndex = currentIndex - 1; + if (currentIndex == -2) + currentIndex = listView.count - 1; } - onCompleterNameChanged: changeCompleter() - onRoomIdChanged: changeCompleter() bottomPadding: 1 leftPadding: 1 - topPadding: 1 rightPadding: 1 + topPadding: 1 + background: Rectangle { + border.color: palette.mid + color: palette.base + } contentItem: ListView { id: listView - // If we have fewer than 7 items, just use the list view's content height. + clip: true + displayMarginBeginning: height / 2 + displayMarginEnd: height / 2 + highlightFollowsCurrentItem: true + + // If we have fewer than 7 items, just use the list view's content height. // Otherwise, we want to show 7 items. Each item consists of row spacing between rows, row margins // on each side of a row, 1px of padding above the first item and below the last item, and nominally // some kind of content height. avatarHeight is used for just about every delegate, so we're using // that until we find something better. Put is all together and you have the formula below! - implicitHeight: Math.min(contentHeight, 6*rowSpacing + 7*(popup.avatarHeight + 2*rowMargin)) - clip: true - - Timer { - id: deadTimer - interval: 50 - } - - onContentYChanged: deadTimer.restart() + implicitHeight: Math.min(contentHeight, 6 * rowSpacing + 7 * (popup.avatarHeight + 2 * rowMargin)) // Broken, see https://bugreports.qt.io/browse/QTBUG-102811 //reuseItems: true implicitWidth: listView.contentItem.childrenRect.width model: completer - verticalLayoutDirection: popup.bottomToTop ? ListView.BottomToTop : ListView.TopToBottom - spacing: rowSpacing pixelAligned: true - highlightFollowsCurrentItem: true - - displayMarginBeginning: height / 2 - displayMarginEnd: height / 2 + spacing: rowSpacing + verticalLayoutDirection: popup.bottomToTop ? ListView.BottomToTop : ListView.TopToBottom delegate: Rectangle { property variant modelData: model ListView.delayRemove: true - color: model.index == popup.currentIndex ? palette.highlight : palette.base height: (chooser.child?.implicitHeight ?? 0) + 2 * popup.rowMargin implicitWidth: fullWidth ? ListView.view.width : chooser.child.implicitWidth + 4 @@ -131,26 +116,27 @@ Control { anchors.fill: parent hoverEnabled: true - onPositionChanged: if (!listView.moving && !deadTimer.running) popup.currentIndex = model.index + onClicked: { - popup.completionClicked(completer.completionAt(model.index)); - if (popup.completerName == "room") - popup.completionSelected(model.roomid); - else if (popup.completerName == "user") - popup.completionSelected(model.userid); + popup.completionClicked(completer.completionAt(model.index)); + if (popup.completerName == "room") + popup.completionSelected(model.roomid); + else if (popup.completerName == "user") + popup.completionSelected(model.userid); } + onPositionChanged: if (!listView.moving && !deadTimer.running) + popup.currentIndex = model.index } Ripple { color: Qt.rgba(palette.base.r, palette.base.g, palette.base.b, 0.5) } - DelegateChooser { id: chooser - roleValue: popup.completerName anchors.fill: parent anchors.margins: popup.rowMargin enabled: false + roleValue: popup.completerName DelegateChoice { roleValue: "user" @@ -162,28 +148,23 @@ Control { spacing: rowSpacing Avatar { - height: popup.avatarHeight - width: popup.avatarWidth displayName: model.displayName - userid: model.userid - url: model.avatarUrl.replace("mxc://", "image://MxcImage/") enabled: false + height: popup.avatarHeight + url: model.avatarUrl.replace("mxc://", "image://MxcImage/") + userid: model.userid + width: popup.avatarWidth } - Label { - text: model.displayName color: model.index == popup.currentIndex ? palette.highlightedText : palette.text + text: model.displayName } - Label { - text: "(" + model.userid + ")" color: model.index == popup.currentIndex ? palette.highlightedText : palette.buttonText + text: "(" + model.userid + ")" } - } - } - DelegateChoice { roleValue: "emoji" @@ -194,39 +175,33 @@ Control { spacing: rowSpacing Label { - visible: !!model.unicode - text: model.unicode color: model.index == popup.currentIndex ? palette.highlightedText : palette.text font: Settings.emojiFont + text: model.unicode + visible: !!model.unicode } - Avatar { - visible: !model.unicode - height: popup.avatarHeight - width: popup.avatarWidth + crop: false displayName: model.shortcode + enabled: false + height: popup.avatarHeight //userid: model.shortcode url: (model.url ? model.url : "").replace("mxc://", "image://MxcImage/") - enabled: false - crop: false + visible: !model.unicode + width: popup.avatarWidth } - Label { Layout.leftMargin: Nheko.paddingSmall Layout.rightMargin: Nheko.paddingSmall - text: model.shortcode color: model.index == popup.currentIndex ? palette.highlightedText : palette.text + text: model.shortcode } - Label { - text: "(" + model.packname + ")" color: model.index == popup.currentIndex ? palette.highlightedText : palette.buttonText + text: "(" + model.packname + ")" } - } - } - DelegateChoice { roleValue: "command" @@ -237,20 +212,16 @@ Control { spacing: rowSpacing Label { - text: model.name color: model.index == popup.currentIndex ? palette.highlightedText : palette.text font.bold: true + text: model.name } - Label { - text: model.description color: model.index == popup.currentIndex ? palette.highlightedText : palette.buttonText + text: model.description } - } - } - DelegateChoice { roleValue: "room" @@ -261,26 +232,22 @@ Control { spacing: rowSpacing Avatar { - height: popup.avatarHeight - width: popup.avatarWidth displayName: model.roomName + enabled: false + height: popup.avatarHeight roomid: model.roomid url: model.avatarUrl.replace("mxc://", "image://MxcImage/") - enabled: false + width: popup.avatarWidth } - Label { - text: model.roomName - font.pixelSize: popup.avatarHeight * 0.5 color: model.index == popup.currentIndex ? palette.highlightedText : palette.text font.italic: model.isTombstoned + font.pixelSize: popup.avatarHeight * 0.5 + text: model.roomName textFormat: Text.RichText } - } - } - DelegateChoice { roleValue: "roomAliases" @@ -291,41 +258,38 @@ Control { spacing: rowSpacing Avatar { - height: popup.avatarHeight - width: popup.avatarWidth displayName: model.roomName + enabled: false + height: popup.avatarHeight roomid: model.roomid url: model.avatarUrl.replace("mxc://", "image://MxcImage/") - enabled: false + width: popup.avatarWidth } - Label { - text: model.roomName color: model.index == popup.currentIndex ? palette.highlightedText : palette.text font.italic: model.isTombstoned + text: model.roomName textFormat: Text.RichText } - Label { - text: "(" + model.roomAlias + ")" color: model.index == popup.currentIndex ? palette.highlightedText : palette.buttonText + text: "(" + model.roomAlias + ")" textFormat: Text.RichText } - } - } - } - } - } + onContentYChanged: deadTimer.restart() + Timer { + id: deadTimer - background: Rectangle { - color: palette.base - border.color: palette.mid + interval: 50 + } } + onCompleterNameChanged: changeCompleter() + onRoomIdChanged: changeCompleter() } diff --git a/resources/qml/ElidedLabel.qml b/resources/qml/ElidedLabel.qml index 2d53faff..153d7c33 100644 --- a/resources/qml/ElidedLabel.qml +++ b/resources/qml/ElidedLabel.qml @@ -9,21 +9,20 @@ import im.nheko 1.0 Label { id: root - property alias fullText: metrics.text property alias elideWidth: metrics.elideWidth + property alias fullText: metrics.text property int fullTextWidth: Math.ceil(metrics.advanceWidth) color: palette.text - text: (textFormat == Text.PlainText) ? metrics.elidedText : TimelineManager.escapeEmoji(metrics.elidedText) - maximumLineCount: 1 elide: Text.ElideRight + maximumLineCount: 1 + text: (textFormat == Text.PlainText) ? metrics.elidedText : TimelineManager.escapeEmoji(metrics.elidedText) textFormat: Text.PlainText TextMetrics { id: metrics - font.pointSize: root.font.pointSize elide: Text.ElideRight + font.pointSize: root.font.pointSize } - } diff --git a/resources/qml/EncryptionIndicator.qml b/resources/qml/EncryptionIndicator.qml index c675fb52..fb9dc7b5 100644 --- a/resources/qml/EncryptionIndicator.qml +++ b/resources/qml/EncryptionIndicator.qml @@ -11,32 +11,40 @@ Image { id: stateImg property bool encrypted: false - property int trust: Crypto.Unverified - property string unencryptedIcon: ":/icons/icons/ui/shield-filled-cross.svg" - property color unencryptedColor: Nheko.theme.error - property color unencryptedHoverColor: unencryptedColor property bool hovered: ma.hovered - property string sourceUrl: { if (!encrypted) - return "image://colorimage/" + unencryptedIcon + "?"; - + return "image://colorimage/" + unencryptedIcon + "?"; switch (trust) { - case Crypto.Verified: + case Crypto.Verified: return "image://colorimage/:/icons/icons/ui/shield-filled-checkmark.svg?"; - case Crypto.TOFU: + case Crypto.TOFU: return "image://colorimage/:/icons/icons/ui/shield-filled.svg?"; - case Crypto.Unverified: + case Crypto.Unverified: return "image://colorimage/:/icons/icons/ui/shield-filled-exclamation-mark.svg?"; - default: + default: return "image://colorimage/:/icons/icons/ui/shield-filled-cross.svg?"; } } + property int trust: Crypto.Unverified + property color unencryptedColor: Nheko.theme.error + property color unencryptedHoverColor: unencryptedColor + property string unencryptedIcon: ":/icons/icons/ui/shield-filled-cross.svg" - width: 16 + ToolTip.text: { + if (!encrypted) + return qsTr("This message is not encrypted!"); + switch (trust) { + case Crypto.Verified: + return qsTr("Encrypted by a verified device"); + case Crypto.TOFU: + return qsTr("Encrypted by an unverified device, but you have trusted that user so far."); + default: + return qsTr("Encrypted by an unverified device or the key is from an untrusted source like the key backup."); + } + } + ToolTip.visible: stateImg.hovered height: 16 - sourceSize.height: height - sourceSize.width: width source: { if (encrypted) { switch (trust) { @@ -51,23 +59,12 @@ Image { return sourceUrl + (stateImg.hovered ? unencryptedHoverColor : unencryptedColor); } } - ToolTip.visible: stateImg.hovered - ToolTip.text: { - if (!encrypted) - return qsTr("This message is not encrypted!"); - - switch (trust) { - case Crypto.Verified: - return qsTr("Encrypted by a verified device"); - case Crypto.TOFU: - return qsTr("Encrypted by an unverified device, but you have trusted that user so far."); - default: - return qsTr("Encrypted by an unverified device or the key is from an untrusted source like the key backup."); - } - } + sourceSize.height: height + sourceSize.width: width + width: 16 HoverHandler { id: ma - } + } } diff --git a/resources/qml/ForwardCompleter.qml b/resources/qml/ForwardCompleter.qml index a5787189..cc48c46f 100644 --- a/resources/qml/ForwardCompleter.qml +++ b/resources/qml/ForwardCompleter.qml @@ -16,13 +16,21 @@ Popup { mid = mid_in; } - x: Math.round(parent.width / 2 - width / 2) - y: Math.round(parent.height / 4) + leftPadding: 10 modal: true parent: Overlay.overlay - width: timelineRoot.width * 0.8 - leftPadding: 10 rightPadding: 10 + width: timelineRoot.width * 0.8 + x: Math.round(parent.width / 2 - width / 2) + y: Math.round(parent.height / 4) + + Overlay.modal: Rectangle { + color: Qt.rgba(palette.window.r, palette.window.g, palette.window.b, 0.7) + } + background: Rectangle { + color: palette.window + } + onOpened: { roomTextInput.forceActiveFocus(); } @@ -35,46 +43,40 @@ Popup { Label { id: titleLabel - text: qsTr("Forward Message") - font.bold: true bottomPadding: 10 color: palette.text + font.bold: true + text: qsTr("Forward Message") } - Reply { id: replyPreview - property var modelData: room ? room.getDump(mid, "") : { - } + property var modelData: room ? room.getDump(mid, "") : {} - width: parent.width - - userColor: TimelineManager.userColor(modelData.userId, palette.window) blurhash: modelData.blurhash ?? "" body: modelData.body ?? "" - formattedBody: modelData.formattedBody ?? "" + encryptionError: modelData.encryptionError ?? "" eventId: modelData.eventId ?? "" filename: modelData.filename ?? "" filesize: modelData.filesize ?? "" + formattedBody: modelData.formattedBody ?? "" + isOnlyEmoji: modelData.isOnlyEmoji ?? false + originalWidth: modelData.originalWidth ?? 0 proportionalHeight: modelData.proportionalHeight ?? 1 type: modelData.type ?? MtxEvent.UnknownMessage typeString: modelData.typeString ?? "" url: modelData.url ?? "" - originalWidth: modelData.originalWidth ?? 0 - isOnlyEmoji: modelData.isOnlyEmoji ?? false + userColor: TimelineManager.userColor(modelData.userId, palette.window) userId: modelData.userId ?? "" userName: modelData.userName ?? "" - encryptionError: modelData.encryptionError ?? "" + width: parent.width } - MatrixTextField { id: roomTextInput - width: forwardMessagePopup.width - forwardMessagePopup.leftPadding * 2 color: palette.text - onTextEdited: { - completerPopup.completer.searchString = text; - } + width: forwardMessagePopup.width - forwardMessagePopup.leftPadding * 2 + Keys.onPressed: { if (event.key == Qt.Key_Up || event.key == Qt.Key_Backtab) { event.accepted = true; @@ -90,43 +92,32 @@ Popup { event.accepted = true; } } + onTextEdited: { + completerPopup.completer.searchString = text; + } } - Completer { id: completerPopup - width: forwardMessagePopup.width - forwardMessagePopup.leftPadding * 2 - completerName: "room" - fullWidth: true - centerRowContent: false avatarHeight: 24 avatarWidth: 24 bottomToTop: false + centerRowContent: false + completerName: "room" + fullWidth: true + width: forwardMessagePopup.width - forwardMessagePopup.leftPadding * 2 } - } - Connections { function onCompletionSelected(id) { room.forwardMessage(messageContextMenu.eventId, id); forwardMessagePopup.close(); } - function onCountChanged() { if (completerPopup.count > 0 && (completerPopup.currentIndex < 0 || completerPopup.currentIndex >= completerPopup.count)) completerPopup.currentIndex = 0; - } target: completerPopup } - - background: Rectangle { - color: palette.window - } - - Overlay.modal: Rectangle { - color: Qt.rgba(palette.window.r, palette.window.g, palette.window.b, 0.7) - } - } diff --git a/resources/qml/ImageButton.qml b/resources/qml/ImageButton.qml index ecb402c7..4115cd0a 100644 --- a/resources/qml/ImageButton.qml +++ b/resources/qml/ImageButton.qml @@ -10,38 +10,35 @@ import im.nheko 1.0 // for cursor shape AbstractButton { id: button - property alias cursor: mouseArea.cursorShape - property string image: undefined - property color highlightColor: palette.highlight property color buttonTextColor: palette.buttonText property bool changeColorOnHover: true + property alias cursor: mouseArea.cursorShape + property color highlightColor: palette.highlight + property string image: undefined property bool ripple: true focusPolicy: Qt.NoFocus - width: 16 height: 16 + width: 16 Image { id: buttonImg // Workaround, can't get icon.source working for now... anchors.fill: parent + fillMode: Image.PreserveAspectFit source: image != "" ? ("image://colorimage/" + image + "?" + ((button.hovered && changeColorOnHover) ? highlightColor : buttonTextColor)) : "" sourceSize.height: button.height sourceSize.width: button.width - fillMode: Image.PreserveAspectFit } - CursorShape { id: mouseArea anchors.fill: parent cursorShape: Qt.PointingHandCursor } - Ripple { - enabled: button.ripple color: Qt.rgba(buttonTextColor.r, buttonTextColor.g, buttonTextColor.b, 0.5) + enabled: button.ripple } - } diff --git a/resources/qml/MatrixText.qml b/resources/qml/MatrixText.qml index 96303a2b..057a632f 100644 --- a/resources/qml/MatrixText.qml +++ b/resources/qml/MatrixText.qml @@ -11,22 +11,23 @@ TextEdit { property alias cursorShape: cs.cursorShape - textFormat: TextEdit.RichText - readOnly: true - focus: false - wrapMode: Text.Wrap - selectByMouse: !Settings.mobileMode + ToolTip.text: hoveredLink + ToolTip.visible: hoveredLink || false // this always has to be enabled, otherwise you can't click links anymore! //enabled: selectByMouse color: palette.text - onLinkActivated: Nheko.openLink(link) - ToolTip.visible: hoveredLink || false - ToolTip.text: hoveredLink + focus: false + readOnly: true + selectByMouse: !Settings.mobileMode + textFormat: TextEdit.RichText + wrapMode: Text.Wrap + // Setting a tooltip delay makes the hover text empty .-. //ToolTip.delay: Nheko.tooltipDelay Component.onCompleted: { TimelineManager.fixImageRendering(r.textDocument, r); } + onLinkActivated: Nheko.openLink(link) CursorShape { id: cs @@ -34,5 +35,4 @@ TextEdit { anchors.fill: parent cursorShape: hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor } - } diff --git a/resources/qml/MatrixTextField.qml b/resources/qml/MatrixTextField.qml index f1ff2836..7209a5aa 100644 --- a/resources/qml/MatrixTextField.qml +++ b/resources/qml/MatrixTextField.qml @@ -7,67 +7,63 @@ import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import im.nheko 1.0 - ColumnLayout { id: c + property color backgroundColor: palette.base property alias color: labelC.color - property alias textPadding: input.padding - property alias text: input.text + property alias echoMode: input.echoMode + property alias font: input.font + property var hasClear: false property alias label: labelC.text property alias placeholderText: input.placeholderText - property alias font: input.font - property alias echoMode: input.echoMode property alias selectByMouse: input.selectByMouse - property var hasClear: false - - Timer { - id: timer - interval: 350 - onTriggered: editingFinished() - } - - onTextChanged: timer.restart() + property alias text: input.text + property alias textPadding: input.padding - signal textEdited signal accepted signal editingFinished - - function forceActiveFocus() { - input.forceActiveFocus(); - } + signal textEdited function clear() { input.clear(); } + function forceActiveFocus() { + input.forceActiveFocus(); + } ToolTip.delay: Nheko.tooltipDelay ToolTip.visible: hover.hovered - spacing: 0 + onTextChanged: timer.restart() + + Timer { + id: timer + + interval: 350 + + onTriggered: editingFinished() + } Item { + Layout.bottomMargin: Nheko.paddingSmall Layout.fillWidth: true - Layout.preferredHeight: labelC.contentHeight Layout.margins: input.padding - Layout.bottomMargin: Nheko.paddingSmall + Layout.preferredHeight: labelC.contentHeight visible: labelC.text - z: 1 Label { id: labelC - y: contentHeight + input.padding + Nheko.paddingSmall - enabled: false - color: palette.text + enabled: false + font.letterSpacing: input.font.pixelSize * 0.02 font.pixelSize: input.font.pixelSize font.weight: Font.DemiBold - font.letterSpacing: input.font.pixelSize * 0.02 - width: parent.width - state: labelC.text && (input.activeFocus == true || input.text) ? "focused" : "" + width: parent.width + y: contentHeight + input.padding + Nheko.paddingSmall states: State { name: "focused" @@ -76,50 +72,40 @@ ColumnLayout { target: labelC y: 0 } - PropertyChanges { - target: input opacity: 1 + target: input } - } - transitions: Transition { from: "" - to: "focused" reversible: true + to: "focused" NumberAnimation { - target: labelC - properties: "y" + alwaysRunToEnd: true duration: 210 easing.type: Easing.InCubic - alwaysRunToEnd: true + properties: "y" + target: labelC } - NumberAnimation { - target: input - properties: "opacity" + alwaysRunToEnd: true duration: 210 easing.type: Easing.InCubic - alwaysRunToEnd: true + properties: "opacity" + target: input } - } } } - TextField { id: input - Layout.fillWidth: true + Layout.fillWidth: true color: labelC.color - opacity: labelC.text ? 0 : 1 focus: true - - onTextEdited: c.textEdited() - onAccepted: c.accepted() - onEditingFinished: c.editingFinished() + opacity: labelC.text ? 0 : 1 background: Rectangle { id: backgroundRect @@ -127,44 +113,46 @@ ColumnLayout { color: labelC.text ? "transparent" : backgroundColor } + onAccepted: c.accepted() + onEditingFinished: c.editingFinished() + onTextEdited: c.textEdited() + ImageButton { id: clearText + focusPolicy: Qt.NoFocus + hoverEnabled: true + image: ":/icons/icons/ui/round-remove-button.svg" visible: c.hasClear && searchField.text !== '' - image: ":/icons/icons/ui/round-remove-button.svg" - focusPolicy: Qt.NoFocus onClicked: { - searchField.clear() + searchField.clear(); topBar.searchString = ""; } - hoverEnabled: true + anchors { - top: parent.top bottom: parent.bottom right: parent.right rightMargin: Nheko.paddingSmall + top: parent.top } } - } - Rectangle { id: blueBar Layout.fillWidth: true - color: palette.highlight height: 1 Rectangle { id: blackBar - anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter - height: parent.height*2 - width: 0 + anchors.top: parent.top color: palette.text + height: parent.height * 2 + width: 0 states: State { name: "focused" @@ -174,31 +162,25 @@ ColumnLayout { target: blackBar width: blueBar.width } - } - transitions: Transition { from: "" - to: "focused" reversible: true - + to: "focused" NumberAnimation { - target: blackBar - properties: "width" + alwaysRunToEnd: true duration: 310 easing.type: Easing.InCubic - alwaysRunToEnd: true + properties: "width" + target: blackBar } - } - } - } - HoverHandler { id: hover + enabled: c.ToolTip.text } } diff --git a/resources/qml/MessageInput.qml b/resources/qml/MessageInput.qml index 6220249b..e196b06d 100644 --- a/resources/qml/MessageInput.qml +++ b/resources/qml/MessageInput.qml @@ -14,60 +14,54 @@ import im.nheko 1.0 Rectangle { id: inputBar + property bool showAllButtons: width > 450 || (messageInput.length == 0 && !messageInput.inputMethodComposing) readonly property string text: messageInput.text - color: palette.window Layout.fillWidth: true - Layout.preferredHeight: row.implicitHeight Layout.minimumHeight: 40 - property bool showAllButtons: width > 450 || (messageInput.length == 0 && !messageInput.inputMethodComposing) - + Layout.preferredHeight: row.implicitHeight + color: palette.window Component { id: placeCallDialog PlaceCall { } - } - Component { id: screenShareDialog ScreenShare { } - } - RowLayout { id: row - visible: room ? room.permissions.canSend(MtxEvent.TextMessage) : false anchors.fill: parent spacing: 0 + visible: room ? room.permissions.canSend(MtxEvent.TextMessage) : false ImageButton { - visible: CallManager.callsSupported && showAllButtons - opacity: (CallManager.haveCallInvite || CallManager.isOnCallOnOtherDevice) ? 0.3 : 1 Layout.alignment: Qt.AlignBottom - hoverEnabled: true - width: 22 + Layout.margins: 8 + ToolTip.text: CallManager.isOnCall ? qsTr("Hang up") : (CallManager.isOnCallOnOtherDevice ? qsTr("Already on a call") : qsTr("Place a call")) + ToolTip.visible: hovered height: 22 + hoverEnabled: true image: CallManager.isOnCall ? ":/icons/icons/ui/end-call.svg" : ":/icons/icons/ui/place-call.svg" - ToolTip.visible: hovered - ToolTip.text: CallManager.isOnCall ? qsTr("Hang up") : (CallManager.isOnCallOnOtherDevice ? qsTr("Already on a call") : qsTr("Place a call")) - Layout.margins: 8 + opacity: (CallManager.haveCallInvite || CallManager.isOnCallOnOtherDevice) ? 0.3 : 1 + visible: CallManager.callsSupported && showAllButtons + width: 22 + onClicked: { if (room) { if (CallManager.haveCallInvite) { - return ; + return; } else if (CallManager.isOnCall) { CallManager.hangUp(); - } - else if(CallManager.isOnCallOnOtherDevice) { + } else if (CallManager.isOnCallOnOtherDevice) { return; - } - else { + } else { var dialog = placeCallDialog.createObject(timelineRoot); dialog.open(); timelineRoot.destroyOnClose(dialog); @@ -75,18 +69,18 @@ Rectangle { } } } - ImageButton { - visible: showAllButtons Layout.alignment: Qt.AlignBottom - hoverEnabled: true - width: 22 + Layout.margins: 8 + ToolTip.text: qsTr("Send a file") + ToolTip.visible: hovered height: 22 + hoverEnabled: true image: ":/icons/icons/ui/attach.svg" - Layout.margins: 8 + visible: showAllButtons + width: 22 + onClicked: room.input.openFileSelection() - ToolTip.visible: hovered - ToolTip.text: qsTr("Send a file") Rectangle { anchors.fill: parent @@ -98,112 +92,67 @@ Rectangle { height: parent.height / 2 running: parent.visible } - } - } - ScrollView { id: textInput Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true Layout.maximumHeight: Window.height / 4 Layout.minimumHeight: fontMetrics.lineSpacing Layout.preferredHeight: contentHeight - Layout.fillWidth: true - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - contentWidth: availableWidth TextArea { id: messageInput property int completerTriggeredAt: 0 + property string lastChar function insertCompletion(completion) { messageInput.remove(completerTriggeredAt, cursorPosition); messageInput.insert(cursorPosition, completion); } - function openCompleter(pos, type) { - if (popup.opened) return; + if (popup.opened) + return; completerTriggeredAt = pos; completer.completerName = type; popup.open(); - completer.completer.setSearchString(messageInput.getText(completerTriggeredAt, cursorPosition)+messageInput.preeditText); + completer.completer.setSearchString(messageInput.getText(completerTriggeredAt, cursorPosition) + messageInput.preeditText); } - function positionCursorAtEnd() { cursorPosition = messageInput.length; } - function positionCursorAtStart() { cursorPosition = 0; } - selectByMouse: true + background: null + bottomPadding: 8 + color: palette.text + focus: true + leftPadding: inputBar.showAllButtons ? 0 : 8 + padding: 0 placeholderText: qsTr("Write a message...") placeholderTextColor: palette.buttonText - color: palette.text - width: textInput.width + selectByMouse: true + topPadding: 8 verticalAlignment: TextEdit.AlignVCenter + width: textInput.width wrapMode: TextEdit.Wrap - padding: 0 - topPadding: 8 - bottomPadding: 8 - leftPadding: inputBar.showAllButtons? 0 : 8 - focus: true - property string lastChar - onTextChanged: { - if (room) - room.input.updateState(selectionStart, selectionEnd, cursorPosition, text); - forceActiveFocus(); - if (cursorPosition > 0) - lastChar = text.charAt(cursorPosition-1) - else - lastChar = '' - if (lastChar == '@') { - messageInput.openCompleter(selectionStart-1, "user"); - } else if (lastChar == ':') { - messageInput.openCompleter(selectionStart-1, "emoji"); - } else if (lastChar == '#') { - messageInput.openCompleter(selectionStart-1, "roomAliases"); - } else if (lastChar == "/" && cursorPosition == 1) { - messageInput.openCompleter(selectionStart-1, "command"); - } - } - onCursorPositionChanged: { - if (!room) - return ; - - room.input.updateState(selectionStart, selectionEnd, cursorPosition, text); - if (popup.opened && cursorPosition <= completerTriggeredAt) - popup.close(); - if (popup.opened) - completer.completer.setSearchString(messageInput.getText(completerTriggeredAt, cursorPosition)+messageInput.preeditText); - - } - onPreeditTextChanged: { - if (popup.opened) - completer.completer.setSearchString(messageInput.getText(completerTriggeredAt, cursorPosition)+messageInput.preeditText); - } - onSelectionStartChanged: room.input.updateState(selectionStart, selectionEnd, cursorPosition, text) - onSelectionEndChanged: room.input.updateState(selectionStart, selectionEnd, cursorPosition, text) - // Ensure that we get escape key press events first. - Keys.onShortcutOverride: (event) => event.accepted = (popup.opened && (event.key === Qt.Key_Escape || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter || event.key === Qt.Key_Space)) - Keys.onPressed: (event) => { + Keys.onPressed: event => { if (event.matches(StandardKey.Paste)) { event.accepted = room.input.tryPasteAttachment(false); } else if (event.key == Qt.Key_Space) { // close popup if user enters space after colon if (cursorPosition == completerTriggeredAt + 1) popup.close(); - if (popup.opened && completer.count <= 0) popup.close(); - } else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_U) { messageInput.clear(); } else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_P) { @@ -218,8 +167,8 @@ Rectangle { completer.completerName = ""; popup.close(); } else if (event.matches(StandardKey.InsertLineSeparator)) { - if (popup.opened) popup.close(); - + if (popup.opened) + popup.close(); if (Settings.invertEnterKey && (!Qt.inputMethod.visible || Qt.platform.os === "windows")) { room.input.send(); event.accepted = true; @@ -253,16 +202,16 @@ Rectangle { console.log('"' + t + '"'); if (t == '@') { messageInput.openCompleter(pos, "user"); - return ; + return; } else if (t == ' ' || t == '\t') { messageInput.openCompleter(pos + 1, "user"); - return ; + return; } else if (t == ':') { messageInput.openCompleter(pos, "emoji"); - return ; + return; } else if (t == '~') { messageInput.openCompleter(pos, "customEmoji"); - return ; + return; } pos = pos - 1; } @@ -312,21 +261,53 @@ Rectangle { } } } - background: null + // Ensure that we get escape key press events first. + Keys.onShortcutOverride: event => event.accepted = (popup.opened && (event.key === Qt.Key_Escape || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter || event.key === Qt.Key_Space)) + onCursorPositionChanged: { + if (!room) + return; + room.input.updateState(selectionStart, selectionEnd, cursorPosition, text); + if (popup.opened && cursorPosition <= completerTriggeredAt) + popup.close(); + if (popup.opened) + completer.completer.setSearchString(messageInput.getText(completerTriggeredAt, cursorPosition) + messageInput.preeditText); + } + onPreeditTextChanged: { + if (popup.opened) + completer.completer.setSearchString(messageInput.getText(completerTriggeredAt, cursorPosition) + messageInput.preeditText); + } + onSelectionEndChanged: room.input.updateState(selectionStart, selectionEnd, cursorPosition, text) + onSelectionStartChanged: room.input.updateState(selectionStart, selectionEnd, cursorPosition, text) + onTextChanged: { + if (room) + room.input.updateState(selectionStart, selectionEnd, cursorPosition, text); + forceActiveFocus(); + if (cursorPosition > 0) + lastChar = text.charAt(cursorPosition - 1); + else + lastChar = ''; + if (lastChar == '@') { + messageInput.openCompleter(selectionStart - 1, "user"); + } else if (lastChar == ':') { + messageInput.openCompleter(selectionStart - 1, "emoji"); + } else if (lastChar == '#') { + messageInput.openCompleter(selectionStart - 1, "roomAliases"); + } else if (lastChar == "/" && cursorPosition == 1) { + messageInput.openCompleter(selectionStart - 1, "command"); + } + } Connections { function onRoomChanged() { messageInput.clear(); if (room) messageInput.append(room.input.text); - completer.completerName = ""; messageInput.forceActiveFocus(); } target: timelineView } - Connections { function onCompletionClicked(completion) { messageInput.insertCompletion(completion); @@ -334,43 +315,39 @@ Rectangle { target: completer } - Popup { id: popup - x: messageInput.positionToRectangle(messageInput.completerTriggeredAt).x - y: messageInput.positionToRectangle(messageInput.completerTriggeredAt).y - height - background: null padding: 0 - - Completer { - anchors.fill: parent - id: completer - rowMargin: 2 - rowSpacing: 0 - } + x: messageInput.positionToRectangle(messageInput.completerTriggeredAt).x + y: messageInput.positionToRectangle(messageInput.completerTriggeredAt).y - height enter: Transition { NumberAnimation { - property: "opacity" + duration: 100 from: 0 + property: "opacity" to: 1 - duration: 100 } - } - exit: Transition { NumberAnimation { - property: "opacity" + duration: 100 from: 1 + property: "opacity" to: 0 - duration: 100 } } - } + Completer { + id: completer + + anchors.fill: parent + rowMargin: 2 + rowSpacing: 0 + } + } Connections { function onTextChanged(newText) { messageInput.text = newText; @@ -380,16 +357,13 @@ Rectangle { ignoreUnknownSignals: true target: room ? room.input : null } - Connections { - function onReplyChanged() { + function onEditChanged() { messageInput.forceActiveFocus(); } - - function onEditChanged() { + function onReplyChanged() { messageInput.forceActiveFocus(); } - function onThreadChanged() { messageInput.forceActiveFocus(); } @@ -397,7 +371,6 @@ Rectangle { ignoreUnknownSignals: true target: room } - Connections { function onFocusInput() { messageInput.forceActiveFocus(); @@ -405,59 +378,56 @@ Rectangle { target: TimelineManager } - MouseArea { + acceptedButtons: Qt.MiddleButton // workaround for wrong cursor shape on some platforms anchors.fill: parent - acceptedButtons: Qt.MiddleButton cursorShape: Qt.IBeamCursor - onPressed: (mouse) => mouse.accepted = room.input.tryPasteAttachment(true) - } + onPressed: mouse => mouse.accepted = room.input.tryPasteAttachment(true) + } } - } - ImageButton { id: stickerButton - visible: showAllButtons Layout.alignment: Qt.AlignRight | Qt.AlignBottom Layout.margins: 8 - hoverEnabled: true - width: 22 + ToolTip.text: qsTr("Stickers") + ToolTip.visible: hovered height: 22 + hoverEnabled: true image: ":/icons/icons/ui/sticky-note-solid.svg" - ToolTip.visible: hovered - ToolTip.text: qsTr("Stickers") - onClicked: stickerPopup.visible ? stickerPopup.close() : stickerPopup.show(stickerButton, room.roomId, function(row) { - room.input.sticker(row); - TimelineManager.focusMessageInput(); - }) + visible: showAllButtons + width: 22 + + onClicked: stickerPopup.visible ? stickerPopup.close() : stickerPopup.show(stickerButton, room.roomId, function (row) { + room.input.sticker(row); + TimelineManager.focusMessageInput(); + }) StickerPicker { id: stickerPopup emoji: false } - } - ImageButton { id: emojiButton Layout.alignment: Qt.AlignRight | Qt.AlignBottom Layout.margins: 8 - hoverEnabled: true - width: 22 + ToolTip.text: qsTr("Emoji") + ToolTip.visible: hovered height: 22 + hoverEnabled: true image: ":/icons/icons/ui/smile.svg" - ToolTip.visible: hovered - ToolTip.text: qsTr("Emoji") - onClicked: emojiPopup.visible ? emojiPopup.close() : emojiPopup.show(emojiButton, room.roomId, function(plaintext, markdown) { - messageInput.insert(messageInput.cursorPosition, markdown); - TimelineManager.focusMessageInput(); - }) + width: 22 + + onClicked: emojiPopup.visible ? emojiPopup.close() : emojiPopup.show(emojiButton, room.roomId, function (plaintext, markdown) { + messageInput.insert(messageInput.cursorPosition, markdown); + TimelineManager.focusMessageInput(); + }) StickerPicker { id: emojiPopup @@ -465,28 +435,25 @@ Rectangle { emoji: true } } - ImageButton { Layout.alignment: Qt.AlignRight | Qt.AlignBottom Layout.margins: 8 - hoverEnabled: true - width: 22 - height: 22 - image: ":/icons/icons/ui/send.svg" Layout.rightMargin: 8 - ToolTip.visible: hovered ToolTip.text: qsTr("Send") + ToolTip.visible: hovered + height: 22 + hoverEnabled: true + image: ":/icons/icons/ui/send.svg" + width: 22 + onClicked: { room.input.send(); } } - } - Text { anchors.centerIn: parent - visible: room ? (!room.permissions.canSend(MtxEvent.TextMessage)) : false text: qsTr("You don't have permission to send messages in this room") + visible: room ? (!room.permissions.canSend(MtxEvent.TextMessage)) : false } - } diff --git a/resources/qml/MessageInputWarning.qml b/resources/qml/MessageInputWarning.qml index be73df2a..4d5578b3 100644 --- a/resources/qml/MessageInputWarning.qml +++ b/resources/qml/MessageInputWarning.qml @@ -10,37 +10,35 @@ import im.nheko 1.0 Rectangle { id: warningRoot - required property string text property color bubbleColor: Nheko.theme.error + required property string text - implicitHeight: visible ? warningDisplay.implicitHeight + 4 * Nheko.paddingSmall : 0 - height: implicitHeight Layout.fillWidth: true color: palette.window // required to hide the timeline behind this warning + height: implicitHeight + implicitHeight: visible ? warningDisplay.implicitHeight + 4 * Nheko.paddingSmall : 0 Rectangle { id: warningRect - visible: warningRoot.visible + anchors.fill: parent + anchors.margins: visible ? Nheko.paddingSmall : 0 + border.color: bubbleColor + border.width: 1 // TODO: Qt.alpha() would make more sense but it wasn't working... color: Qt.rgba(bubbleColor.r, bubbleColor.g, bubbleColor.b, 0.3) - border.width: 1 - border.color: bubbleColor radius: 3 - anchors.fill: parent - anchors.margins: visible ? Nheko.paddingSmall : 0 + visible: warningRoot.visible z: 3 Label { id: warningDisplay anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter anchors.margins: Nheko.paddingSmall + anchors.verticalCenter: parent.verticalCenter text: warningRoot.text textFormat: Text.PlainText } - } - } diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index 158bc236..57bfe216 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -14,89 +14,269 @@ import QtQuick.Layouts 1.2 import QtQuick.Window 2.13 import im.nheko 1.0 - Item { id: chatRoot - property int padding: Nheko.paddingMedium property int availableWidth: width - + property int padding: Nheko.paddingMedium property string searchString: "" // HACK: https://bugreports.qt.io/browse/QTBUG-83972, qtwayland cannot auto hide menu Connections { function onHideMenu() { - messageContextMenu.close() - replyContextMenu.close() + messageContextMenu.close(); + replyContextMenu.close(); } + target: MainWindow } - ScrollBar { id: scrollbar - parent: chat.parent - anchors.top: parent.top - anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.top: parent.top + parent: chat.parent } ListView { id: chat - anchors.fill: parent - - property int delegateMaxWidth: ((Settings.timelineMaxWidth > 100 && Settings.timelineMaxWidth < chatRoot.availableWidth) ? Settings.timelineMaxWidth : chatRoot.availableWidth) - chatRoot.padding * 2 - (scrollbar.interactive? scrollbar.width : 0) - + property int delegateMaxWidth: ((Settings.timelineMaxWidth > 100 && Settings.timelineMaxWidth < chatRoot.availableWidth) ? Settings.timelineMaxWidth : chatRoot.availableWidth) - chatRoot.padding * 2 - (scrollbar.interactive ? scrollbar.width : 0) readonly property alias filteringInProgress: filteredTimeline.filteringInProgress - displayMarginBeginning: height / 2 - displayMarginEnd: height / 2 - - TimelineFilter { - id: filteredTimeline - source: room - filterByThread: room ? room.thread : "" - filterByContent: chatRoot.searchString - } - - model: (filteredTimeline.filterByThread || filteredTimeline.filterByContent) ? filteredTimeline : room + ScrollBar.vertical: scrollbar + anchors.fill: parent + anchors.rightMargin: scrollbar.interactive ? scrollbar.width : 0 // reuseItems still has a few bugs, see https://bugreports.qt.io/browse/QTBUG-95105 https://bugreports.qt.io/browse/QTBUG-95107 //onModelChanged: if (room) room.sendReset() //reuseItems: true boundsBehavior: Flickable.StopAtBounds + displayMarginBeginning: height / 2 + displayMarginEnd: height / 2 + model: (filteredTimeline.filterByThread || filteredTimeline.filterByContent) ? filteredTimeline : room //pixelAligned: true spacing: 2 verticalLayoutDirection: ListView.BottomToTop + + delegate: Item { + id: wrapper + + required property string blurhash + required property string body + required property string callType + required property var day + required property string duration + required property int encryptionError + required property string eventId + required property string filename + required property string filesize + required property string formattedBody + required property int index + required property bool isEditable + required property bool isEdited + required property bool isEncrypted + required property bool isOnlyEmoji + required property bool isSender + required property bool isStateEvent + required property int notificationlevel + required property int originalWidth + property var previousMessageDay: (index + 1) >= chat.count ? 0 : chat.model.dataByIndex(index + 1, Room.Day) + property bool previousMessageIsStateEvent: (index + 1) >= chat.count ? true : chat.model.dataByIndex(index + 1, Room.IsStateEvent) + property string previousMessageUserId: (index + 1) >= chat.count ? "" : chat.model.dataByIndex(index + 1, Room.UserId) + required property double proportionalHeight + required property var reactions + required property int relatedEventCacheBuster + required property string replyTo + required property string roomName + required property string roomTopic + property bool scrolledToThis: eventId === room.scrollTarget && (y + height > chat.y + chat.contentY && y < chat.y + chat.height + chat.contentY) + required property int status + required property string threadId + required property string thumbnailUrl + required property var timestamp + required property int trustlevel + required property int type + required property string typeString + required property string url + required property string userId + required property string userName + + ListView.delayRemove: true + anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined + height: section.active ? section.height + timelinerow.height : timelinerow.height + width: chat.delegateMaxWidth + + Loader { + id: section + + property var day: wrapper.day + property bool isSender: wrapper.isSender + property bool isStateEvent: wrapper.isStateEvent + property int parentWidth: parent.width + property var previousMessageDay: wrapper.previousMessageDay + property bool previousMessageIsStateEvent: wrapper.previousMessageIsStateEvent + property string previousMessageUserId: wrapper.previousMessageUserId + property date timestamp: wrapper.timestamp + property string userId: wrapper.userId + property string userName: wrapper.userName + + active: previousMessageUserId !== userId || previousMessageDay !== day || previousMessageIsStateEvent !== isStateEvent + //asynchronous: true + sourceComponent: sectionHeader + visible: status == Loader.Ready + z: 4 + } + TimelineRow { + id: timelinerow + + blurhash: wrapper.blurhash + body: wrapper.body + callType: wrapper.callType + duration: wrapper.duration + encryptionError: wrapper.encryptionError + eventId: chat.model, wrapper.eventId + filename: wrapper.filename + filesize: wrapper.filesize + formattedBody: wrapper.formattedBody + index: wrapper.index + isEditable: wrapper.isEditable + isEdited: wrapper.isEdited + isEncrypted: wrapper.isEncrypted + isOnlyEmoji: wrapper.isOnlyEmoji + isSender: wrapper.isSender + isStateEvent: wrapper.isStateEvent + notificationlevel: wrapper.notificationlevel + originalWidth: wrapper.originalWidth + proportionalHeight: wrapper.proportionalHeight + reactions: wrapper.reactions + relatedEventCacheBuster: wrapper.relatedEventCacheBuster + replyTo: wrapper.replyTo + roomName: wrapper.roomName + roomTopic: wrapper.roomTopic + status: wrapper.status + threadId: wrapper.threadId + thumbnailUrl: wrapper.thumbnailUrl + timestamp: wrapper.timestamp + trustlevel: wrapper.trustlevel + type: chat.model, wrapper.type + typeString: wrapper.typeString + url: wrapper.url + userId: wrapper.userId + userName: wrapper.userName + y: section.visible && section.active ? section.y + section.height : 0 + + background: Rectangle { + id: scrollHighlight + + color: palette.highlight + enabled: false + opacity: 0 + visible: true + z: 1 + + states: State { + name: "revealed" + when: wrapper.scrolledToThis + } + transitions: Transition { + from: "" + to: "revealed" + + SequentialAnimation { + PropertyAnimation { + duration: 500 + easing.type: Easing.InOutQuad + from: 0 + properties: "opacity" + target: scrollHighlight + to: 1 + } + PropertyAnimation { + duration: 500 + easing.type: Easing.InOutQuad + from: 1 + properties: "opacity" + target: scrollHighlight + to: 0 + } + ScriptAction { + script: room.eventShown() + } + } + } + } + + onHoveredChanged: { + if (!Settings.mobileMode && hovered) { + if (!messageActions.hovered) { + messageActions.attached = timelinerow; + messageActions.model = timelinerow; + } + } + } + } + Connections { + function onMovementEnded() { + if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height) + chat.model.currentIndex = index; + } + + target: chat + } + } + footer: Item { + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: Nheko.paddingLarge + // hacky, but works + height: loadingSpinner.height + 2 * Nheko.paddingLarge + visible: (room && room.paginationInProgress) || chat.filteringInProgress + + Spinner { + id: loadingSpinner + + anchors.centerIn: parent + anchors.margins: Nheko.paddingLarge + foreground: palette.mid + running: (room && room.paginationInProgress) || chat.filteringInProgress + z: 3 + } + } + + Window.onActiveChanged: readTimer.running = Window.active onCountChanged: { // Mark timeline as read - if (atYEnd && room) model.currentIndex = 0; + if (atYEnd && room) + model.currentIndex = 0; } - ScrollBar.vertical: scrollbar - - anchors.rightMargin: scrollbar.interactive? scrollbar.width : 0 + TimelineFilter { + id: filteredTimeline + filterByContent: chatRoot.searchString + filterByThread: room ? room.thread : "" + source: room + } Control { id: messageActions property Item attached: null - property alias model: row.model // use comma to update on scroll property var attachedPos: chat.contentY, attached ? chat.mapFromItem(attached, attached ? attached.width - width : 0, -height) : null - padding: Nheko.paddingSmall + property alias model: row.model hoverEnabled: true + padding: Nheko.paddingSmall visible: Settings.buttonsInTimeline && !!attached && (attached.hovered || hovered) x: attached ? attachedPos.x : 0 y: attached ? attachedPos.y + Nheko.paddingSmall : 0 z: 10 background: Rectangle { - color: palette.window border.color: palette.buttonText border.width: 1 + color: palette.window radius: padding } - contentItem: RowLayout { id: row @@ -111,174 +291,166 @@ Item { delegate: AbstractButton { id: button - required property string modelData - - property color highlightColor: palette.highlight property color buttonTextColor: palette.buttonText + property color highlightColor: palette.highlight + required property string modelData property bool showImage: modelData.startsWith("mxc://") //Layout.preferredHeight: fontMetrics.height Layout.alignment: Qt.AlignBottom - focusPolicy: Qt.NoFocus - width: showImage ? 16 : buttonText.implicitWidth height: showImage ? 16 : buttonText.implicitHeight - implicitWidth: showImage ? 16 : buttonText.implicitWidth implicitHeight: showImage ? 16 : buttonText.implicitHeight + implicitWidth: showImage ? 16 : buttonText.implicitWidth + width: showImage ? 16 : buttonText.implicitWidth + + onClicked: { + room.input.reaction(row.model.eventId, modelData); + TimelineManager.focusMessageInput(); + } Label { id: buttonText - visible: !button.showImage - anchors.centerIn: parent - padding: 0 - text: button.modelData color: button.hovered ? button.highlightColor : button.buttonTextColor font.family: Settings.emojiFont - verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter + padding: 0 + text: button.modelData + verticalAlignment: Text.AlignVCenter + visible: !button.showImage } - Image { id: buttonImg // Workaround, can't get icon.source working for now... anchors.fill: parent + fillMode: Image.PreserveAspectFit source: button.showImage ? (button.modelData.replace("mxc://", "image://MxcImage/") + "?scale") : "" sourceSize.height: button.height sourceSize.width: button.width - fillMode: Image.PreserveAspectFit } - CursorShape { anchors.fill: parent cursorShape: Qt.PointingHandCursor } - Ripple { color: Qt.rgba(buttonTextColor.r, buttonTextColor.g, buttonTextColor.b, 0.5) } - - onClicked: { - room.input.reaction(row.model.eventId, modelData); - TimelineManager.focusMessageInput(); - } } - } - ImageButton { - visible: !!row.model && row.model.isEditable + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: qsTr("Edit") + ToolTip.visible: hovered buttonTextColor: palette.buttonText - width: 16 hoverEnabled: true image: ":/icons/icons/ui/edit.svg" - ToolTip.visible: hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: qsTr("Edit") + visible: !!row.model && row.model.isEditable + width: 16 + onClicked: { - if (row.model.isEditable) room.edit = row.model.eventId; + if (row.model.isEditable) + room.edit = row.model.eventId; } } - ImageButton { id: reactButton - visible: room ? room.permissions.canSend(MtxEvent.Reaction) : false - width: 16 - hoverEnabled: true - image: ":/icons/icons/ui/smile-add.svg" - ToolTip.visible: hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: qsTr("React") - onClicked: emojiPopup.visible ? emojiPopup.close() : emojiPopup.show(reactButton, room.roomId, function(plaintext, markdown) { - var event_id = row.model ? row.model.eventId : ""; - room.input.reaction(event_id, plaintext); - TimelineManager.focusMessageInput(); - }) - } + ToolTip.visible: hovered + hoverEnabled: true + image: ":/icons/icons/ui/smile-add.svg" + visible: room ? room.permissions.canSend(MtxEvent.Reaction) : false + width: 16 + onClicked: emojiPopup.visible ? emojiPopup.close() : emojiPopup.show(reactButton, room.roomId, function (plaintext, markdown) { + var event_id = row.model ? row.model.eventId : ""; + room.input.reaction(event_id, plaintext); + TimelineManager.focusMessageInput(); + }) + } ImageButton { - visible: room ? room.permissions.canSend(MtxEvent.TextMessage) : false - width: 16 - hoverEnabled: true - image: (row.model && row.model.threadId) ? ":/icons/icons/ui/thread.svg" : ":/icons/icons/ui/new-thread.svg" - ToolTip.visible: hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: (row.model && row.model.threadId) ? qsTr("Reply in thread") : qsTr("New thread") + ToolTip.visible: hovered + hoverEnabled: true + image: (row.model && row.model.threadId) ? ":/icons/icons/ui/thread.svg" : ":/icons/icons/ui/new-thread.svg" + visible: room ? room.permissions.canSend(MtxEvent.TextMessage) : false + width: 16 + onClicked: room.thread = (row.model.threadId || row.model.eventId) } - ImageButton { - visible: room ? room.permissions.canSend(MtxEvent.TextMessage) : false - width: 16 - hoverEnabled: true - image: ":/icons/icons/ui/reply.svg" - ToolTip.visible: hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: qsTr("Reply") + ToolTip.visible: hovered + hoverEnabled: true + image: ":/icons/icons/ui/reply.svg" + visible: room ? room.permissions.canSend(MtxEvent.TextMessage) : false + width: 16 + onClicked: room.reply = row.model.eventId } - ImageButton { - visible: !!row.model && filteredTimeline.filterByContent + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: qsTr("Go to message") + ToolTip.visible: hovered buttonTextColor: palette.buttonText - width: 16 hoverEnabled: true image: ":/icons/icons/ui/go-to.svg" - ToolTip.visible: hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: qsTr("Go to message") + visible: !!row.model && filteredTimeline.filterByContent + width: 16 + onClicked: { topBar.searchString = ""; room.showEvent(row.model.eventId); } } - ImageButton { id: optionsButton - width: 16 - hoverEnabled: true - image: ":/icons/icons/ui/options.svg" - ToolTip.visible: hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: qsTr("Options") + ToolTip.visible: hovered + hoverEnabled: true + image: ":/icons/icons/ui/options.svg" + width: 16 + onClicked: messageContextMenu.show(row.model.eventId, row.model.threadId, row.model.type, row.model.isSender, row.model.isEncrypted, row.model.isEditable, "", row.model.body, optionsButton) } - } - } - Shortcut { sequence: StandardKey.MoveToPreviousPage + onActivated: { chat.contentY = chat.contentY - chat.height * 0.9; chat.returnToBounds(); } } - Shortcut { sequence: StandardKey.MoveToNextPage + onActivated: { chat.contentY = chat.contentY + chat.height * 0.9; chat.returnToBounds(); } } - Shortcut { sequence: StandardKey.Cancel + onActivated: { - if(room.input.uploads.length > 0) + if (room.input.uploads.length > 0) room.input.declineUploads(); - else if(room.reply) + else if (room.reply) room.reply = undefined; else if (room.edit) room.edit = undefined; else - room.thread = undefined + room.thread = undefined; TimelineManager.focusMessageInput(); } } @@ -287,19 +459,20 @@ Item { // Better solution welcome. Shortcut { sequence: "Alt+Up" + onActivated: room.reply = room.indexToId(room.reply ? room.idToIndex(room.reply) + 1 : 0) } - Shortcut { sequence: "Alt+Down" + onActivated: { var idx = room.reply ? room.idToIndex(room.reply) - 1 : -1; room.reply = idx >= 0 ? room.indexToId(idx) : null; } } - Shortcut { sequence: "Alt+F" + onActivated: { if (room.reply) { var forwardMess = forwardCompleterComponent.createObject(timelineRoot); @@ -310,355 +483,157 @@ Item { } } } - Shortcut { sequence: "Ctrl+E" + onActivated: { room.edit = room.reply; } } - - Window.onActiveChanged: readTimer.running = Window.active - Timer { id: readTimer + interval: 1000 + // force current read index to update onTriggered: { if (room) - room.setCurrentIndex(room.currentIndex); - + room.setCurrentIndex(room.currentIndex); } - interval: 1000 } - Component { id: sectionHeader Column { - topPadding: userName_.visible? 4: 0 - bottomPadding: Settings.bubbles? (isSender && previousMessageDay == day? 0 : 2) : 3 + bottomPadding: Settings.bubbles ? (isSender && previousMessageDay == day ? 0 : 2) : 3 + height: ((previousMessageDay !== day) ? dateBubble.height : 0) + (isStateEvent ? 0 : userName.height + 8) spacing: 8 + topPadding: userName_.visible ? 4 : 0 visible: (previousMessageUserId !== userId || previousMessageDay !== day || isStateEvent !== previousMessageIsStateEvent) width: parentWidth - height: ((previousMessageDay !== day) ? dateBubble.height : 0) + (isStateEvent? 0 : userName.height +8 ) Label { id: dateBubble anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined - visible: room && previousMessageDay !== day - text: room ? room.formatDateSeparator(timestamp) : "" color: palette.text height: Math.round(fontMetrics.height * 1.4) - width: contentWidth * 1.2 horizontalAlignment: Text.AlignHCenter + text: room ? room.formatDateSeparator(timestamp) : "" verticalAlignment: Text.AlignVCenter + visible: room && previousMessageDay !== day + width: contentWidth * 1.2 background: Rectangle { - radius: parent.height / 2 color: palette.window + radius: parent.height / 2 } - } - Row { - height: userName_.height - spacing: 8 - visible: !isStateEvent && (!isSender || !Settings.bubbles) id: userInfo - Avatar { - id: messageUserAvatar - - width: Nheko.avatarSize * (Settings.smallAvatars? 0.5 : 1) - height: Nheko.avatarSize * (Settings.smallAvatars? 0.5 : 1) - url: !room ? "" : room.avatarUrl(userId).replace("mxc://", "image://MxcImage/") - displayName: userName - userid: userId - onClicked: room.openUserProfile(userId) - ToolTip.visible: messageUserAvatar.hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: userid - } - - Connections { - function onRoomAvatarUrlChanged() { - messageUserAvatar.url = room.avatarUrl(userId).replace("mxc://", "image://MxcImage/"); - } - - function onScrollToIndex(index) { - chat.positionViewAtIndex(index, ListView.Center); - } - - target: room - } property int remainingWidth: chat.delegateMaxWidth - spacing - messageUserAvatar.width - AbstractButton { - id: userNameButton - contentItem: ElidedLabel { - id: userName_ - fullText: userName - color: TimelineManager.userColor(userId, palette.base) - textFormat: Text.RichText - elideWidth: Math.min(userInfo.remainingWidth-Math.min(statusMsg.implicitWidth,userInfo.remainingWidth/3), userName_.fullTextWidth) - } - ToolTip.visible: hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: userId - onClicked: room.openUserProfile(userId) - leftInset: 0 - rightInset: 0 - leftPadding: 0 - rightPadding: 0 - - CursorShape { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - } - - } - - Label { - id: statusMsg - anchors.baseline: userNameButton.baseline - color: palette.buttonText - text: userStatus.replace(/\n/g, " ") - textFormat: Text.PlainText - elide: Text.ElideRight - width: Math.min(implicitWidth, userInfo.remainingWidth - userName_.width - parent.spacing) - font.italic: true - font.pointSize: Math.floor(fontMetrics.font.pointSize * 0.8) - ToolTip.text: qsTr("%1's status message").arg(userName) - ToolTip.visible: statusMsgHoverHandler.hovered - ToolTip.delay: Nheko.tooltipDelay - - HoverHandler { - id: statusMsgHoverHandler - } - - property string userStatus: Presence.userStatus(userId) - Connections { - target: Presence - function onPresenceChanged(id) { - if (id == userId) statusMsg.userStatus = Presence.userStatus(userId); - } - } - } - - } - - } - - } - - delegate: Item { - id: wrapper - - required property double proportionalHeight - required property int type - required property string typeString - required property int originalWidth - required property string blurhash - required property string body - required property string formattedBody - required property string eventId - required property string filename - required property string filesize - required property string url - required property string thumbnailUrl - required property string duration - required property bool isOnlyEmoji - required property bool isSender - required property bool isEncrypted - required property bool isEditable - required property bool isEdited - required property bool isStateEvent - property bool previousMessageIsStateEvent: (index + 1) >= chat.count ? true : chat.model.dataByIndex(index+1, Room.IsStateEvent) - required property string replyTo - required property string threadId - required property string userId - required property string roomTopic - required property string roomName - required property string callType - required property var reactions - required property int trustlevel - required property int notificationlevel - required property int encryptionError - required property var timestamp - required property int status - required property int index - required property int relatedEventCacheBuster - required property var day - property string previousMessageUserId: (index + 1) >= chat.count ? "" : chat.model.dataByIndex(index+1, Room.UserId) - property var previousMessageDay: (index + 1) >= chat.count ? 0 : chat.model.dataByIndex(index+1, Room.Day) - required property string userName - property bool scrolledToThis: eventId === room.scrollTarget && (y + height > chat.y + chat.contentY && y < chat.y + chat.height + chat.contentY) - - anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined - width: chat.delegateMaxWidth - height: section.active ? section.height + timelinerow.height : timelinerow.height - ListView.delayRemove: true - - Loader { - id: section - - property int parentWidth: parent.width - property string userId: wrapper.userId - property string previousMessageUserId: wrapper.previousMessageUserId - property var day: wrapper.day - property var previousMessageDay: wrapper.previousMessageDay - property bool previousMessageIsStateEvent: wrapper.previousMessageIsStateEvent - property bool isStateEvent: wrapper.isStateEvent - property bool isSender: wrapper.isSender - property string userName: wrapper.userName - property date timestamp: wrapper.timestamp - - z: 4 - active: previousMessageUserId !== userId || previousMessageDay !== day || previousMessageIsStateEvent !== isStateEvent - //asynchronous: true - sourceComponent: sectionHeader - visible: status == Loader.Ready - } - - TimelineRow { - id: timelinerow - - proportionalHeight: wrapper.proportionalHeight - type: chat.model, wrapper.type - typeString: wrapper.typeString - originalWidth: wrapper.originalWidth - blurhash: wrapper.blurhash - body: wrapper.body - formattedBody: wrapper.formattedBody - eventId: chat.model, wrapper.eventId - filename: wrapper.filename - filesize: wrapper.filesize - url: wrapper.url - thumbnailUrl: wrapper.thumbnailUrl - duration: wrapper.duration - isOnlyEmoji: wrapper.isOnlyEmoji - isSender: wrapper.isSender - isEncrypted: wrapper.isEncrypted - isEditable: wrapper.isEditable - isEdited: wrapper.isEdited - isStateEvent: wrapper.isStateEvent - replyTo: wrapper.replyTo - threadId: wrapper.threadId - userId: wrapper.userId - userName: wrapper.userName - roomTopic: wrapper.roomTopic - roomName: wrapper.roomName - callType: wrapper.callType - reactions: wrapper.reactions - trustlevel: wrapper.trustlevel - notificationlevel: wrapper.notificationlevel - encryptionError: wrapper.encryptionError - timestamp: wrapper.timestamp - status: wrapper.status - index: wrapper.index - relatedEventCacheBuster: wrapper.relatedEventCacheBuster - y: section.visible && section.active ? section.y + section.height : 0 - - onHoveredChanged: { - if (!Settings.mobileMode && hovered) { - if (!messageActions.hovered) { - messageActions.attached = timelinerow; - messageActions.model = timelinerow; - } - } - } - background: Rectangle { - id: scrollHighlight - - opacity: 0 - visible: true - z: 1 - enabled: false - color: palette.highlight - - states: State { - name: "revealed" - when: wrapper.scrolledToThis - } - - transitions: Transition { - from: "" - to: "revealed" - - SequentialAnimation { - PropertyAnimation { - target: scrollHighlight - properties: "opacity" - easing.type: Easing.InOutQuad - from: 0 - to: 1 - duration: 500 - } - PropertyAnimation { - target: scrollHighlight - properties: "opacity" - easing.type: Easing.InOutQuad - from: 1 - to: 0 - duration: 500 - } + height: userName_.height + spacing: 8 + visible: !isStateEvent && (!isSender || !Settings.bubbles) - ScriptAction { - script: room.eventShown() - } + Avatar { + id: messageUserAvatar + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: userid + ToolTip.visible: messageUserAvatar.hovered + displayName: userName + height: Nheko.avatarSize * (Settings.smallAvatars ? 0.5 : 1) + url: !room ? "" : room.avatarUrl(userId).replace("mxc://", "image://MxcImage/") + userid: userId + width: Nheko.avatarSize * (Settings.smallAvatars ? 0.5 : 1) + + onClicked: room.openUserProfile(userId) + } + Connections { + function onRoomAvatarUrlChanged() { + messageUserAvatar.url = room.avatarUrl(userId).replace("mxc://", "image://MxcImage/"); + } + function onScrollToIndex(index) { + chat.positionViewAtIndex(index, ListView.Center); } + target: room } + AbstractButton { + id: userNameButton - } - } + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: userId + ToolTip.visible: hovered + leftInset: 0 + leftPadding: 0 + rightInset: 0 + rightPadding: 0 - Connections { - function onMovementEnded() { - if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height) - chat.model.currentIndex = index; + contentItem: ElidedLabel { + id: userName_ - } + color: TimelineManager.userColor(userId, palette.base) + elideWidth: Math.min(userInfo.remainingWidth - Math.min(statusMsg.implicitWidth, userInfo.remainingWidth / 3), userName_.fullTextWidth) + fullText: userName + textFormat: Text.RichText + } - target: chat - } + onClicked: room.openUserProfile(userId) - } + CursorShape { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + } + } + Label { + id: statusMsg - footer: Item { - anchors.horizontalCenter: parent.horizontalCenter - anchors.margins: Nheko.paddingLarge - visible: (room && room.paginationInProgress) || chat.filteringInProgress - // hacky, but works - height: loadingSpinner.height + 2 * Nheko.paddingLarge + property string userStatus: Presence.userStatus(userId) - Spinner { - id: loadingSpinner + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: qsTr("%1's status message").arg(userName) + ToolTip.visible: statusMsgHoverHandler.hovered + anchors.baseline: userNameButton.baseline + color: palette.buttonText + elide: Text.ElideRight + font.italic: true + font.pointSize: Math.floor(fontMetrics.font.pointSize * 0.8) + text: userStatus.replace(/\n/g, " ") + textFormat: Text.PlainText + width: Math.min(implicitWidth, userInfo.remainingWidth - userName_.width - parent.spacing) - anchors.centerIn: parent - anchors.margins: Nheko.paddingLarge - running: (room && room.paginationInProgress) || chat.filteringInProgress - foreground: palette.mid - z: 3 - } + HoverHandler { + id: statusMsgHoverHandler + + } + Connections { + function onPresenceChanged(id) { + if (id == userId) + statusMsg.userStatus = Presence.userStatus(userId); + } + target: Presence + } + } + } + } } } - Platform.Menu { id: messageContextMenu property string eventId - property string threadId - property string link - property string text property int eventType - property bool isEncrypted property bool isEditable + property bool isEncrypted property bool isSender + property string link + property string text + property string threadId function show(eventId_, threadId_, eventType_, isSender_, isEncrypted_, isEditable_, link_, text_, showAt_) { eventId = eventId_; @@ -668,104 +643,106 @@ Item { isEditable = isEditable_; isSender = isSender_; if (text_) - text = text_; + text = text_; else - text = ""; + text = ""; if (link_) - link = link_; + link = link_; else - link = ""; + link = ""; if (showAt_) - open(showAt_); + open(showAt_); else - open(); + open(); } Component { id: removeReason + InputDialog { id: removeReasonDialog property string eventId - title: qsTr("Reason for removal") prompt: qsTr("Enter reason for removal or hit enter for no reason:") - onAccepted: function(text) { + title: qsTr("Reason for removal") + + onAccepted: function (text) { room.redactEvent(eventId, text); } } } - Platform.MenuItem { - visible: filteredTimeline.filterByContent - enabled: visible - text: qsTr("Go to &message") - onTriggered: function() { + enabled: visible + text: qsTr("Go to &message") + visible: filteredTimeline.filterByContent + + onTriggered: function () { topBar.searchString = ""; room.showEvent(messageContextMenu.eventId); } - } - + } Platform.MenuItem { - visible: messageContextMenu.text enabled: visible text: qsTr("&Copy") + visible: messageContextMenu.text + onTriggered: Clipboard.text = messageContextMenu.text } - Platform.MenuItem { - visible: messageContextMenu.link enabled: visible text: qsTr("Copy &link location") + visible: messageContextMenu.link + onTriggered: Clipboard.text = messageContextMenu.link } - Platform.MenuItem { id: reactionOption - visible: room ? room.permissions.canSend(MtxEvent.Reaction) : false text: qsTr("Re&act") - onTriggered: emojiPopup.visible ? emojiPopup.close() : emojiPopup.show(null, room.roomId, function(plaintext, markdown) { - room.input.reaction(messageContextMenu.eventId, plaintext); - TimelineManager.focusMessageInput(); - }) - } + visible: room ? room.permissions.canSend(MtxEvent.Reaction) : false + onTriggered: emojiPopup.visible ? emojiPopup.close() : emojiPopup.show(null, room.roomId, function (plaintext, markdown) { + room.input.reaction(messageContextMenu.eventId, plaintext); + TimelineManager.focusMessageInput(); + }) + } Platform.MenuItem { - visible: room ? room.permissions.canSend(MtxEvent.TextMessage) : false text: qsTr("Repl&y") + visible: room ? room.permissions.canSend(MtxEvent.TextMessage) : false + onTriggered: room.reply = (messageContextMenu.eventId) } - Platform.MenuItem { - visible: messageContextMenu.isEditable && (room ? room.permissions.canSend(MtxEvent.TextMessage) : false) enabled: visible text: qsTr("&Edit") + visible: messageContextMenu.isEditable && (room ? room.permissions.canSend(MtxEvent.TextMessage) : false) + onTriggered: room.edit = (messageContextMenu.eventId) } - Platform.MenuItem { - visible: (room ? room.permissions.canSend(MtxEvent.TextMessage) : false) enabled: visible text: qsTr("&Thread") + visible: (room ? room.permissions.canSend(MtxEvent.TextMessage) : false) + onTriggered: room.thread = (messageContextMenu.threadId || messageContextMenu.eventId) } - Platform.MenuItem { - visible: (room ? room.permissions.canChange(MtxEvent.PinnedEvents) : false) enabled: visible text: visible && room.pinnedMessages.includes(messageContextMenu.eventId) ? qsTr("Un&pin") : qsTr("&Pin") + visible: (room ? room.permissions.canChange(MtxEvent.PinnedEvents) : false) + onTriggered: visible && room.pinnedMessages.includes(messageContextMenu.eventId) ? room.unpin(messageContextMenu.eventId) : room.pin(messageContextMenu.eventId) } - Platform.MenuItem { text: qsTr("&Read receipts") + onTriggered: room.showReadReceipts(messageContextMenu.eventId) } - Platform.MenuItem { - visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker || messageContextMenu.eventType == MtxEvent.TextMessage || messageContextMenu.eventType == MtxEvent.LocationMessage || messageContextMenu.eventType == MtxEvent.EmoteMessage || messageContextMenu.eventType == MtxEvent.NoticeMessage text: qsTr("&Forward") + visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker || messageContextMenu.eventType == MtxEvent.TextMessage || messageContextMenu.eventType == MtxEvent.LocationMessage || messageContextMenu.eventType == MtxEvent.EmoteMessage || messageContextMenu.eventType == MtxEvent.NoticeMessage + onTriggered: { var forwardMess = forwardCompleterComponent.createObject(timelineRoot); forwardMess.setMessageEventId(messageContextMenu.eventId); @@ -773,28 +750,27 @@ Item { timelineRoot.destroyOnClose(forwardMess); } } - Platform.MenuItem { text: qsTr("&Mark as read") } - Platform.MenuItem { text: qsTr("View raw message") + onTriggered: room.viewRawMessage(messageContextMenu.eventId) } - Platform.MenuItem { - // TODO(Nico): Fix this still being iterated over, when using keyboard to select options - visible: messageContextMenu.isEncrypted enabled: visible text: qsTr("View decrypted raw message") + // TODO(Nico): Fix this still being iterated over, when using keyboard to select options + visible: messageContextMenu.isEncrypted + onTriggered: room.viewDecryptedRawMessage(messageContextMenu.eventId) } - Platform.MenuItem { - visible: (room ? room.permissions.canRedact() : false) || messageContextMenu.isSender text: qsTr("Remo&ve message") - onTriggered: function() { + visible: (room ? room.permissions.canRedact() : false) || messageContextMenu.isSender + + onTriggered: function () { var dialog = removeReason.createObject(timelineRoot); dialog.eventId = messageContextMenu.eventId; dialog.show(); @@ -802,44 +778,40 @@ Item { timelineRoot.destroyOnClose(dialog); } } - Platform.MenuItem { - visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker enabled: visible text: qsTr("&Save as") + visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker + onTriggered: room.saveMedia(messageContextMenu.eventId) } - Platform.MenuItem { - visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker enabled: visible text: qsTr("&Open in external program") + visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker + onTriggered: room.openMedia(messageContextMenu.eventId) } - Platform.MenuItem { - visible: messageContextMenu.eventId enabled: visible text: qsTr("Copy link to eve&nt") + visible: messageContextMenu.eventId + onTriggered: room.copyLinkToEvent(messageContextMenu.eventId) } - } - Component { id: forwardCompleterComponent ForwardCompleter { } - } - Platform.Menu { id: replyContextMenu - property string text - property string link property string eventId + property string link + property string text function show(text_, link_, eventId_) { text = text_; @@ -849,85 +821,100 @@ Item { } Platform.MenuItem { - visible: replyContextMenu.text enabled: visible text: qsTr("&Copy") + visible: replyContextMenu.text + onTriggered: Clipboard.text = replyContextMenu.text } - Platform.MenuItem { - visible: replyContextMenu.link enabled: visible text: qsTr("Copy &link location") + visible: replyContextMenu.link + onTriggered: Clipboard.text = replyContextMenu.link } - Platform.MenuItem { - visible: true enabled: visible text: qsTr("&Go to quoted message") + visible: true + onTriggered: room.showEvent(replyContextMenu.eventId) } - } RoundButton { id: toEndButton - anchors { - bottom: parent.bottom - right: scrollbar.left - bottomMargin: Nheko.paddingMedium+(fullWidth-width)/2 - rightMargin: Nheko.paddingMedium+(fullWidth-width)/2 - } + property int fullWidth: 40 - width: 0 - height: width - radius: width/2 - onClicked: function() { chat.positionViewAtBeginning(); TimelineManager.focusMessageInput(); } + flat: true + height: width hoverEnabled: true + radius: width / 2 + width: 0 background: Rectangle { - color: toEndButton.down ? palette.highlight : palette.button - opacity: enabled ? 1 : 0.3 border.color: toEndButton.hovered ? palette.highlight : palette.buttonText border.width: 1 + color: toEndButton.down ? palette.highlight : palette.button + opacity: enabled ? 1 : 0.3 radius: toEndButton.radius } - states: [ State { name: "" - PropertyChanges { target: toEndButton; width: 0 } + + PropertyChanges { + target: toEndButton + width: 0 + } }, State { name: "shown" when: !chat.atYEnd - PropertyChanges { target: toEndButton; width: toEndButton.fullWidth } + + PropertyChanges { + target: toEndButton + width: toEndButton.fullWidth + } } ] - - Image { - id: buttonImg - anchors.fill: parent - anchors.margins: Nheko.paddingMedium - source: "image://colorimage/:/icons/icons/ui/download.svg?" + (toEndButton.down ? palette.highlightedText : palette.buttonText) - fillMode: Image.PreserveAspectFit - } - transitions: Transition { from: "" - to: "shown" reversible: true + to: "shown" SequentialAnimation { - PauseAnimation { duration: 500 } + PauseAnimation { + duration: 500 + } PropertyAnimation { - target: toEndButton - properties: "width" - easing.type: Easing.InOutQuad duration: 200 + easing.type: Easing.InOutQuad + properties: "width" + target: toEndButton } } } + + onClicked: function () { + chat.positionViewAtBeginning(); + TimelineManager.focusMessageInput(); + } + + anchors { + bottom: parent.bottom + bottomMargin: Nheko.paddingMedium + (fullWidth - width) / 2 + right: scrollbar.left + rightMargin: Nheko.paddingMedium + (fullWidth - width) / 2 + } + Image { + id: buttonImg + + anchors.fill: parent + anchors.margins: Nheko.paddingMedium + fillMode: Image.PreserveAspectFit + source: "image://colorimage/:/icons/icons/ui/download.svg?" + (toEndButton.down ? palette.highlightedText : palette.buttonText) + } } } diff --git a/resources/qml/PrivacyScreen.qml b/resources/qml/PrivacyScreen.qml index da196667..a3539df7 100644 --- a/resources/qml/PrivacyScreen.qml +++ b/resources/qml/PrivacyScreen.qml @@ -11,9 +11,8 @@ Item { id: privacyScreen readonly property bool active: Settings.privacyScreen && screenSaver.state === "Visible" - property var timelineRoot property int screenTimeout - + property var timelineRoot required property var windowTarget Connections { @@ -24,29 +23,28 @@ Item { } else { if (timelineRoot.visible) screenSaverTimer.start(); - } } target: windowTarget } - Timer { id: screenSaverTimer interval: screenTimeout * 1000 running: !windowTarget.active + onTriggered: { screenSaver.state = "Visible"; } } - Item { id: screenSaver - state: "Invisible" anchors.fill: parent + state: "Invisible" visible: false + states: [ State { name: "Visible" @@ -55,20 +53,18 @@ Item { target: screenSaver visible: true } - PropertyChanges { - target: screenSaver opacity: 1 + target: screenSaver } }, State { name: "Invisible" PropertyChanges { - target: screenSaver opacity: 0 + target: screenSaver } - PropertyChanges { target: screenSaver visible: false @@ -78,39 +74,33 @@ Item { transitions: [ Transition { from: "Invisible" - to: "Visible" reversible: true + to: "Visible" SequentialAnimation { NumberAnimation { - target: screenSaver - property: "visible" duration: 0 + property: "visible" + target: screenSaver } - NumberAnimation { - target: screenSaver - property: "opacity" duration: 300 easing.type: Easing.Linear + property: "opacity" + target: screenSaver } - } - } ] MultiEffect { id: blur - blurEnabled: true - anchors.fill: parent - source: timelineRoot blur: 1.0 + blurEnabled: true blurMax: 32 + source: timelineRoot } - } - } diff --git a/resources/qml/QuickSwitcher.qml b/resources/qml/QuickSwitcher.qml index 5878b391..9ccefdec 100644 --- a/resources/qml/QuickSwitcher.qml +++ b/resources/qml/QuickSwitcher.qml @@ -11,33 +11,36 @@ Popup { id: quickSwitcher property int textHeight: Math.round(Qt.application.font.pixelSize * 2.4) + property int textMargin: Nheko.paddingSmall background: null - width: Math.min(Math.max(Math.round(parent.width / 2),450),parent.width) // limiting width to parent.width/2 can be a bit narrow - x: Math.round(parent.width / 2 - contentWidth / 2) - y: Math.round(parent.height / 4) - modal: true closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + modal: true parent: Overlay.overlay + width: Math.min(Math.max(Math.round(parent.width / 2), 450), parent.width) // limiting width to parent.width/2 can be a bit narrow + x: Math.round(parent.width / 2 - contentWidth / 2) + y: Math.round(parent.height / 4) + + Overlay.modal: Rectangle { + color: "#aa1E1E1E" + } + + onClosed: TimelineManager.focusMessageInput() onOpened: { roomTextInput.forceActiveFocus(); } - onClosed: TimelineManager.focusMessageInput() - property int textMargin: Nheko.paddingSmall - Column{ + Column { anchors.fill: parent spacing: 1 MatrixTextField { id: roomTextInput - width: parent.width - font.pixelSize: Math.ceil(quickSwitcher.textHeight * 0.6) color: palette.text - onTextEdited: { - completerPopup.completer.searchString = text; - } + font.pixelSize: Math.ceil(quickSwitcher.textHeight * 0.6) + width: parent.width + Keys.onPressed: { if (event.key == Qt.Key_Up || event.key == Qt.Key_Backtab) { event.accepted = true; @@ -45,49 +48,43 @@ Popup { } else if (event.key == Qt.Key_Down || event.key == Qt.Key_Tab) { event.accepted = true; if (event.key == Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier)) - completerPopup.up(); + completerPopup.up(); else - completerPopup.down(); + completerPopup.down(); } else if (event.matches(StandardKey.InsertParagraphSeparator)) { completerPopup.finishCompletion(); event.accepted = true; } } + onTextEdited: { + completerPopup.completer.searchString = text; + } } - Completer { id: completerPopup - visible: roomTextInput.text.length > 0 - width: parent.width - completerName: "room" - bottomToTop: false - fullWidth: true avatarHeight: quickSwitcher.textHeight avatarWidth: quickSwitcher.textHeight + bottomToTop: false centerRowContent: false + completerName: "room" + fullWidth: true rowMargin: Math.round(quickSwitcher.textMargin / 2) rowSpacing: quickSwitcher.textMargin + visible: roomTextInput.text.length > 0 + width: parent.width } } - Connections { function onCompletionSelected(id) { Rooms.setCurrentRoom(id); quickSwitcher.close(); } - function onCountChanged() { if (completerPopup.count > 0 && (completerPopup.currentIndex < 0 || completerPopup.currentIndex >= completerPopup.count)) - completerPopup.currentIndex = 0; - + completerPopup.currentIndex = 0; } target: completerPopup } - - Overlay.modal: Rectangle { - color: "#aa1E1E1E" - } - } diff --git a/resources/qml/Reactions.qml b/resources/qml/Reactions.qml index caee708e..5ab58beb 100644 --- a/resources/qml/Reactions.qml +++ b/resources/qml/Reactions.qml @@ -11,10 +11,11 @@ import im.nheko 1.0 Flow { id: reactionFlow + property string eventId + // lower-contrast colors to avoid distracting from text & to enhance hover effect property color gentleHighlight: Qt.hsla(palette.highlight.hslHue, palette.highlight.hslSaturation, palette.highlight.hslLightness, 0.8) property color gentleText: Qt.hsla(palette.text.hslHue, palette.text.hslSaturation, palette.text.hslLightness, 0.6) - property string eventId property alias reactions: repeater.model spacing: 4 @@ -25,40 +26,39 @@ Flow { delegate: AbstractButton { id: reaction - hoverEnabled: true - ToolTip.visible: hovered ToolTip.delay: Nheko.tooltipDelay - onClicked: { - console.debug("Picked " + modelData.key + "in response to " + reactionFlow.eventId + ". selfReactedEvent: " + modelData.selfReactedEvent); - room.input.reaction(reactionFlow.eventId, modelData.key); - } - Component.onCompleted: { - ToolTip.text = Qt.binding(function() { - if (textMetrics.elidedText === textMetrics.text) { - return modelData.users; - } - return modelData.displayKey + "\n" + modelData.users; - }) - } - leftPadding: textMetrics.height / 2 - rightPadding: textMetrics.height / 2 + ToolTip.visible: hovered + hoverEnabled: true + leftPadding: textMetrics.height / 2 + rightPadding: textMetrics.height / 2 + background: Rectangle { + anchors.centerIn: parent + border.color: reaction.hovered ? palette.text : gentleText + border.width: 1 + color: reaction.hovered ? palette.highlight : (modelData.selfReactedEvent !== '' ? gentleHighlight : palette.window) + implicitHeight: reaction.implicitHeight + implicitWidth: reaction.implicitWidth + radius: reaction.height / 2 + } contentItem: Row { spacing: textMetrics.height / 4 TextMetrics { id: textMetrics - font.family: Settings.emojiFont elide: Text.ElideRight elideWidth: 150 + font.family: Settings.emojiFont text: modelData.displayKey } - Text { id: reactionText anchors.baseline: reactionCounter.baseline + color: (reaction.hovered || modelData.selfReactedEvent !== '') ? palette.highlightedText : palette.text + font.family: Settings.emojiFont + maximumLineCount: 1 text: { // When an emoji font is selected that doesn't have …, it is dropped from elidedText. So we add it back. if (textMetrics.elidedText !== modelData.displayKey) { @@ -68,51 +68,45 @@ Flow { } return textMetrics.elidedText; } - font.family: Settings.emojiFont - color: (reaction.hovered || modelData.selfReactedEvent !== '') ? palette.highlightedText: palette.text - maximumLineCount: 1 visible: !modelData.key.startsWith("mxc://") } Image { anchors.verticalCenter: divider.verticalCenter + fillMode: Image.PreserveAspectFit height: textMetrics.height - width: textMetrics.height source: modelData.key.startsWith("mxc://") ? (modelData.key.replace("mxc://", "image://MxcImage/") + "?scale") : "" visible: modelData.key.startsWith("mxc://") - fillMode: Image.PreserveAspectFit + width: textMetrics.height } - Rectangle { id: divider + color: reaction.hovered ? palette.text : gentleText height: Math.floor(reactionCounter.implicitHeight * 1.4) width: 1 - color: reaction.hovered ? palette.text: gentleText } - Text { id: reactionCounter anchors.verticalCenter: divider.verticalCenter - text: modelData.count + color: (reaction.hovered || modelData.selfReactedEvent !== '') ? palette.highlightedText : palette.windowText font: reaction.font - color: (reaction.hovered || modelData.selfReactedEvent !== '') ? palette.highlightedText: palette.windowText + text: modelData.count } - } - background: Rectangle { - anchors.centerIn: parent - implicitWidth: reaction.implicitWidth - implicitHeight: reaction.implicitHeight - border.color: reaction.hovered ? palette.text: gentleText - color: reaction.hovered ? palette.highlight : (modelData.selfReactedEvent !== '' ? gentleHighlight : palette.window) - border.width: 1 - radius: reaction.height / 2 + Component.onCompleted: { + ToolTip.text = Qt.binding(function () { + if (textMetrics.elidedText === textMetrics.text) { + return modelData.users; + } + return modelData.displayKey + "\n" + modelData.users; + }); + } + onClicked: { + console.debug("Picked " + modelData.key + "in response to " + reactionFlow.eventId + ". selfReactedEvent: " + modelData.selfReactedEvent); + room.input.reaction(reactionFlow.eventId, modelData.key); } - } - } - } diff --git a/resources/qml/ReplyPopup.qml b/resources/qml/ReplyPopup.qml index 6fceb4e5..ce24297c 100644 --- a/resources/qml/ReplyPopup.qml +++ b/resources/qml/ReplyPopup.qml @@ -12,91 +12,89 @@ Rectangle { id: replyPopup Layout.fillWidth: true - visible: room && (room.reply || room.edit || room.thread) + color: palette.window // Height of child, plus margins, plus border implicitHeight: (room && room.reply ? replyPreview.height : Math.max(closeEditButton.height, closeThreadButton.height)) + Nheko.paddingSmall - color: palette.window + visible: room && (room.reply || room.edit || room.thread) z: 3 Reply { id: replyPreview - property var modelData: room ? room.getDump(room.reply, room.id) : { - } + property var modelData: room ? room.getDump(room.reply, room.id) : {} - visible: room && room.reply anchors.left: parent.left - anchors.leftMargin: replyPopup.width < 450? Nheko.paddingSmall : (CallManager.callsSupported? 2*(22+16) : 1*(22+16)) + anchors.leftMargin: replyPopup.width < 450 ? Nheko.paddingSmall : (CallManager.callsSupported ? 2 * (22 + 16) : 1 * (22 + 16)) anchors.right: parent.right - anchors.rightMargin: replyPopup.width < 450? 2*(22+16) : 3*(22+16) + anchors.rightMargin: replyPopup.width < 450 ? 2 * (22 + 16) : 3 * (22 + 16) anchors.top: parent.top anchors.topMargin: Nheko.paddingSmall - userColor: TimelineManager.userColor(modelData.userId, palette.window) blurhash: modelData.blurhash ?? "" body: modelData.body ?? "" - formattedBody: modelData.formattedBody ?? "" + encryptionError: modelData.encryptionError ?? 0 eventId: modelData.eventId ?? "" filename: modelData.filename ?? "" filesize: modelData.filesize ?? "" + formattedBody: modelData.formattedBody ?? "" + isOnlyEmoji: modelData.isOnlyEmoji ?? false + originalWidth: modelData.originalWidth ?? 0 proportionalHeight: modelData.proportionalHeight ?? 1 type: modelData.type ?? MtxEvent.UnknownMessage typeString: modelData.typeString ?? "" url: modelData.url ?? "" - originalWidth: modelData.originalWidth ?? 0 - isOnlyEmoji: modelData.isOnlyEmoji ?? false + userColor: TimelineManager.userColor(modelData.userId, palette.window) userId: modelData.userId ?? "" userName: modelData.userName ?? "" - encryptionError: modelData.encryptionError ?? 0 + visible: room && room.reply width: parent.width } - ImageButton { id: closeReplyButton - visible: room && room.reply + ToolTip.text: qsTr("Close") + ToolTip.visible: closeReplyButton.hovered + anchors.margins: Nheko.paddingSmall anchors.right: replyPreview.right anchors.top: replyPreview.top - anchors.margins: Nheko.paddingSmall - hoverEnabled: true - width: 16 height: 16 + hoverEnabled: true image: ":/icons/icons/ui/dismiss.svg" - ToolTip.visible: closeReplyButton.hovered - ToolTip.text: qsTr("Close") + visible: room && room.reply + width: 16 + onClicked: room.reply = undefined } - ImageButton { id: closeEditButton - visible: room && room.edit - anchors.right: closeThreadButton.left + ToolTip.text: qsTr("Cancel Edit") + ToolTip.visible: closeEditButton.hovered anchors.margins: 8 + anchors.right: closeThreadButton.left anchors.top: parent.top + height: 22 hoverEnabled: true image: ":/icons/icons/ui/dismiss_edit.svg" + visible: room && room.edit width: 22 - height: 22 - ToolTip.visible: closeEditButton.hovered - ToolTip.text: qsTr("Cancel Edit") + onClicked: room.edit = undefined } - ImageButton { id: closeThreadButton - visible: room && room.thread - anchors.right: parent.right + ToolTip.text: qsTr("Cancel Thread") + ToolTip.visible: closeThreadButton.hovered anchors.margins: 8 + anchors.right: parent.right anchors.top: parent.top - hoverEnabled: true buttonTextColor: room ? TimelineManager.userColor(room.thread, palette.base) : palette.buttonText + height: 22 + hoverEnabled: true image: ":/icons/icons/ui/dismiss_thread.svg" + visible: room && room.thread width: 22 - height: 22 - ToolTip.visible: closeThreadButton.hovered - ToolTip.text: qsTr("Cancel Thread") + onClicked: room.thread = undefined } - } diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index 851608b6..b41696e0 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -18,37 +18,386 @@ Page { property int avatarSize: Math.ceil(fontMetrics.lineSpacing * 2.3) property bool collapsed: false + background: Rectangle { + color: Nheko.theme.sidebarBackground + } + footer: ColumnLayout { + spacing: 0 + + Rectangle { + Layout.fillWidth: true + color: Nheko.theme.separator + height: 1 + } + Pane { + Layout.alignment: Qt.AlignBottom + Layout.fillWidth: true + Layout.minimumHeight: 40 + horizontalPadding: Nheko.paddingMedium + verticalPadding: 0 + + background: Rectangle { + color: palette.window + } + contentItem: RowLayout { + id: buttonRow + + ImageButton { + Layout.fillWidth: true + Layout.margins: Nheko.paddingMedium + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: qsTr("Start a new chat") + ToolTip.visible: hovered + height: 22 + hoverEnabled: true + image: ":/icons/icons/ui/add-square-button.svg" + width: 22 + + onClicked: roomJoinCreateMenu.open(parent) + + Platform.Menu { + id: roomJoinCreateMenu + + Platform.MenuItem { + text: qsTr("Join a room") + + onTriggered: Nheko.openJoinRoomDialog() + } + Platform.MenuItem { + text: qsTr("Create a new room") + + onTriggered: { + var createRoom = createRoomComponent.createObject(timelineRoot); + createRoom.show(); + timelineRoot.destroyOnClose(createRoom); + } + } + Platform.MenuItem { + text: qsTr("Start a direct chat") + + onTriggered: { + var createDirect = createDirectComponent.createObject(timelineRoot); + createDirect.show(); + timelineRoot.destroyOnClose(createDirect); + } + } + Platform.MenuItem { + text: qsTr("Create a new community") + + onTriggered: { + var createRoom = createRoomComponent.createObject(timelineRoot, { + "space": true + }); + createRoom.show(); + timelineRoot.destroyOnClose(createRoom); + } + } + } + } + ImageButton { + Layout.fillWidth: true + Layout.margins: Nheko.paddingMedium + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: qsTr("Room directory") + ToolTip.visible: hovered + height: 22 + hoverEnabled: true + image: ":/icons/icons/ui/room-directory.svg" + visible: !collapsed + width: 22 + + onClicked: { + var win = roomDirectoryComponent.createObject(timelineRoot); + win.show(); + timelineRoot.destroyOnClose(win); + } + } + ImageButton { + Layout.fillWidth: true + Layout.margins: Nheko.paddingMedium + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: qsTr("Search rooms (Ctrl+K)") + ToolTip.visible: hovered + height: 22 + hoverEnabled: true + image: ":/icons/icons/ui/search.svg" + ripple: false + visible: !collapsed + width: 22 + + onClicked: { + var component = Qt.createComponent("qrc:/qml/QuickSwitcher.qml"); + if (component.status == Component.Ready) { + var quickSwitch = component.createObject(timelineRoot); + quickSwitch.open(); + destroyOnClosed(quickSwitch); + } else { + console.error("Failed to create component: " + component.errorString()); + } + } + } + ImageButton { + Layout.fillWidth: true + Layout.margins: Nheko.paddingMedium + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: qsTr("User settings") + ToolTip.visible: hovered + height: 22 + hoverEnabled: true + image: ":/icons/icons/ui/settings.svg" + ripple: false + visible: !collapsed + width: 22 + + onClicked: mainWindow.push(userSettingsPage) + } + } + } + } + header: ColumnLayout { + spacing: 0 + + Pane { + id: userInfoPanel + + function openUserProfile() { + Nheko.updateUserProfile(); + var component = Qt.createComponent("qrc:/qml/dialogs/UserProfile.qml"); + if (component.status == Component.Ready) { + var userProfile = component.createObject(timelineRoot, { + "profile": Nheko.currentUser + }); + userProfile.show(); + timelineRoot.destroyOnClose(userProfile); + } else { + console.error("Failed to create component: " + component.errorString()); + } + } + + Layout.alignment: Qt.AlignBottom + Layout.fillWidth: true + Layout.minimumHeight: 40 + //Layout.preferredHeight: userInfoGrid.implicitHeight + 2 * Nheko.paddingMedium + padding: Nheko.paddingMedium + + background: Rectangle { + color: palette.window + } + contentItem: RowLayout { + id: userInfoGrid + + property var profile: Nheko.currentUser + + spacing: Nheko.paddingMedium + + Avatar { + id: avatar + + Layout.alignment: Qt.AlignVCenter + Layout.preferredHeight: fontMetrics.lineSpacing * 2 + Layout.preferredWidth: fontMetrics.lineSpacing * 2 + displayName: userInfoGrid.profile ? userInfoGrid.profile.displayName : "" + enabled: false + url: (userInfoGrid.profile ? userInfoGrid.profile.avatarUrl : "").replace("mxc://", "image://MxcImage/") + userid: userInfoGrid.profile ? userInfoGrid.profile.userid : "" + } + ColumnLayout { + id: col + + Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + Layout.preferredWidth: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2 + spacing: 0 + visible: !collapsed + width: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2 + + ElidedLabel { + Layout.alignment: Qt.AlignBottom + elideWidth: col.width + font.pointSize: fontMetrics.font.pointSize * 1.1 + font.weight: Font.DemiBold + fullText: userInfoGrid.profile ? userInfoGrid.profile.displayName : "" + } + ElidedLabel { + Layout.alignment: Qt.AlignTop + color: palette.buttonText + elideWidth: col.width + font.pointSize: fontMetrics.font.pointSize * 0.9 + fullText: userInfoGrid.profile ? userInfoGrid.profile.userid : "" + } + } + Item { + } + ImageButton { + id: logoutButton + + Layout.alignment: Qt.AlignVCenter + Layout.preferredHeight: fontMetrics.lineSpacing * 2 + Layout.preferredWidth: fontMetrics.lineSpacing * 2 + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: qsTr("Logout") + ToolTip.visible: hovered + image: ":/icons/icons/ui/power-off.svg" + visible: !collapsed + + onClicked: Nheko.openLogoutDialog() + } + } + + InputDialog { + id: statusDialog + + prompt: qsTr("Enter your status message:") + title: qsTr("Status Message") + + onAccepted: function (text) { + Nheko.setStatusMessage(text); + } + } + Platform.Menu { + id: userInfoMenu + + Platform.MenuItem { + text: qsTr("Profile settings") + + onTriggered: userInfoPanel.openUserProfile() + } + Platform.MenuItem { + text: qsTr("Set status message") + + onTriggered: statusDialog.show() + } + } + TapHandler { + acceptedButtons: Qt.LeftButton + gesturePolicy: TapHandler.ReleaseWithinBounds + margin: -Nheko.paddingSmall + + onLongPressed: userInfoMenu.open() + onSingleTapped: userInfoPanel.openUserProfile() + } + TapHandler { + acceptedButtons: Qt.RightButton + gesturePolicy: TapHandler.ReleaseWithinBounds + margin: -Nheko.paddingSmall + + onSingleTapped: userInfoMenu.open() + } + } + Rectangle { + Layout.fillWidth: true + color: Nheko.theme.separator + height: 2 + } + Rectangle { + id: unverifiedStuffBubble + + Layout.fillWidth: true + color: Qt.lighter(Nheko.theme.orange, verifyButtonHovered.hovered ? 1.2 : 1) + implicitHeight: explanation.height + Nheko.paddingMedium * 2 + visible: SelfVerificationStatus.status != SelfVerificationStatus.AllVerified + + RowLayout { + id: unverifiedStuffBubbleContainer + + height: explanation.height + Nheko.paddingMedium * 2 + spacing: 0 + width: parent.width + + Label { + id: explanation + + Layout.fillWidth: true + Layout.margins: Nheko.paddingMedium + Layout.rightMargin: Nheko.paddingSmall + color: palette.buttonText + text: { + switch (SelfVerificationStatus.status) { + case SelfVerificationStatus.NoMasterKey: + //: Cross-signing setup has not run yet. + return qsTr("Encryption not set up"); + case SelfVerificationStatus.UnverifiedMasterKey: + //: The user just signed in with this device and hasn't verified their master key. + return qsTr("Unverified login"); + case SelfVerificationStatus.UnverifiedDevices: + //: There are unverified devices signed in to this account. + return qsTr("Please verify your other devices"); + default: + return ""; + } + } + textFormat: Text.PlainText + wrapMode: Text.Wrap + } + ImageButton { + id: closeUnverifiedBubble + + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.rightMargin: Nheko.paddingMedium + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: qsTr("Close") + ToolTip.visible: closeUnverifiedBubble.hovered + height: fontMetrics.font.pixelSize + hoverEnabled: true + image: ":/icons/icons/ui/dismiss.svg" + width: fontMetrics.font.pixelSize + + onClicked: unverifiedStuffBubble.visible = false + } + } + HoverHandler { + id: verifyButtonHovered + + acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad + enabled: !closeUnverifiedBubble.hovered + } + TapHandler { + acceptedButtons: Qt.LeftButton + enabled: !closeUnverifiedBubble.hovered + + onSingleTapped: { + if (SelfVerificationStatus.status == SelfVerificationStatus.UnverifiedDevices) + SelfVerificationStatus.verifyUnverifiedDevices(); + else + SelfVerificationStatus.statusChanged(); + } + } + } + Rectangle { + Layout.fillWidth: true + color: Nheko.theme.separator + height: 1 + visible: unverifiedStuffBubble.visible + } + } + // HACK: https://bugreports.qt.io/browse/QTBUG-83972, qtwayland cannot auto hide menu Connections { function onHideMenu() { - userInfoMenu.close() - roomContextMenu.close() + userInfoMenu.close(); + roomContextMenu.close(); } + target: MainWindow } - Component { id: roomDirectoryComponent RoomDirectory { } - } - Component { id: createRoomComponent CreateRoom { } } - Component { id: createDirectComponent CreateDirect { } } - ListView { id: roomlist @@ -56,226 +405,44 @@ Page { anchors.right: parent.right height: parent.height model: Rooms - //reuseItems: true + //reuseItems: true ScrollBar.vertical: ScrollBar { id: scrollbar - parent: !collapsed && Settings.scrollbarsInRoomlist ? roomlist : null - } - - Connections { - function onCurrentRoomChanged() { - if (Rooms.currentRoom) - roomlist.positionViewAtIndex(Rooms.roomidToIndex(Rooms.currentRoom.roomId), ListView.Contain); - - } - - target: Rooms - } - - Component { - id: roomWindowComponent - - ApplicationWindow { - id: roomWindowW - - property var room: null - property var roomPreview: null - - Component.onCompleted: { - MainWindow.addPerRoomWindow(room.roomId || roomPreview.roomid, roomWindowW); - Nheko.setTransientParent(roomWindowW, null); - } - Component.onDestruction: MainWindow.removePerRoomWindow(room.roomId || roomPreview.roomid, roomWindowW) - - height: 650 - width: 420 - minimumWidth: 150 - minimumHeight: 150 - color: palette.window - title: room.plainRoomName - //flags: Qt.Window | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - - Shortcut { - sequence: StandardKey.Cancel - onActivated: roomWindowW.close() - } - - TimelineView { - id: timeline - - privacyScreen: privacyScreen - anchors.fill: parent - room: roomWindowW.room - roomPreview: roomWindowW.roomPreview.roomid ? roomWindowW.roomPreview : null - } - - PrivacyScreen { - id: privacyScreen - - anchors.fill: parent - visible: Settings.privacyScreen - screenTimeout: Settings.privacyScreenTimeout - timelineRoot: timeline - windowTarget: roomWindowW - } - - onActiveChanged: { room.lastReadIdOnWindowFocus(); } - } - - } - - - Component { - id: nestedSpaceMenuLevel - - SpaceMenuLevel { - roomid: roomContextMenu.roomid - childMenu: rootSpaceMenu.childMenu - } - } - - - Platform.Menu { - id: roomContextMenu - - property string roomid - property var tags - - function show(roomid_, tags_) { - roomid = roomid_; - tags = tags_; - open(); - } - - InputDialog { - id: newTag - - title: qsTr("New tag") - prompt: qsTr("Enter the tag you want to use:") - onAccepted: function(text) { - Rooms.toggleTag(roomContextMenu.roomid, "u." + text, true); - } - } - - Platform.MenuItem { - text: qsTr("Open separately") - onTriggered: { - var roomWindow = roomWindowComponent.createObject(null, { - "room": Rooms.getRoomById(roomContextMenu.roomid), - "roomPreview": Rooms.getRoomPreviewById(roomContextMenu.roomid) - }); - roomWindow.showNormal(); - destroyOnClose(roomWindow); - } - } - - Platform.MenuItem { - text: qsTr("Room settings") - onTriggered: TimelineManager.openRoomSettings(roomContextMenu.roomid) - } - - Platform.MenuItem { - text: qsTr("Leave room") - onTriggered: TimelineManager.openLeaveRoomDialog(roomContextMenu.roomid) - } - - Platform.MenuItem { - text: qsTr("Copy room link") - onTriggered: Rooms.copyLink(roomContextMenu.roomid) - } - - Platform.Menu { - id: tagsMenu - title: qsTr("Tag room as:") - Instantiator { - model: Communities.tagsWithDefault - onObjectAdded: (index, object) => tagsMenu.insertItem(index, object) - onObjectRemoved: (index, object) => tagsMenu.removeItem(object) - - delegate: Platform.MenuItem { - property string t: modelData - - text: { - switch (t) { - case "m.favourite": - return qsTr("Favourite"); - case "m.lowpriority": - return qsTr("Low priority"); - case "m.server_notice": - return qsTr("Server notice"); - default: - return t.substring(2); - } - } - checkable: true - checked: roomContextMenu.tags !== undefined && roomContextMenu.tags.includes(t) - onTriggered: Rooms.toggleTag(roomContextMenu.roomid, t, checked) - } - - } - - Platform.MenuItem { - text: qsTr("Create new tag...") - onTriggered: newTag.show() - } - } - - SpaceMenuLevel { - id: rootSpaceMenu - - roomid: roomContextMenu.roomid - position: -1 - title: qsTr("Add or remove from community...") - childMenu: nestedSpaceMenuLevel - } + parent: !collapsed && Settings.scrollbarsInRoomlist ? roomlist : null } - delegate: ItemDelegate { id: roomItem + required property string avatarUrl property color backgroundColor: palette.window - property color importantText: palette.text - property color unimportantText: palette.buttonText property color bubbleBackground: palette.highlight property color bubbleText: palette.highlightedText - required property string roomName - required property string roomId - required property string avatarUrl - required property string time - required property string lastMessage - required property var tags - required property bool isInvite - required property bool isSpace - required property int notificationCount + required property string directChatOtherUserId required property bool hasLoudNotification required property bool hasUnreadMessages + property color importantText: palette.text required property bool isDirect - required property string directChatOtherUserId - - Ripple { - color: Qt.rgba(palette.dark.r, palette.dark.g, palette.dark.b, 0.5) - } + required property bool isInvite + required property bool isSpace + required property string lastMessage + required property int notificationCount + required property string roomId + required property string roomName + required property var tags + required property string time + property color unimportantText: palette.buttonText - height: avatarSize + 2 * Nheko.paddingMedium - width: ListView.view.width - ((scrollbar.interactive && scrollbar.visible && scrollbar.parent) ? scrollbar.width : 0) - state: "normal" - ToolTip.visible: hovered && collapsed ToolTip.delay: Nheko.tooltipDelay ToolTip.text: roomName - onClicked: { - console.log("tapped " + roomId); - - if (!Rooms.currentRoom || Rooms.currentRoom.roomId !== roomId) - Rooms.setCurrentRoom(roomId); - else - Rooms.resetCurrentRoom(); - } - onPressAndHold: { - if (!isInvite) - roomContextMenu.show(roomId, tags); + ToolTip.visible: hovered && collapsed + height: avatarSize + 2 * Nheko.paddingMedium + state: "normal" + width: ListView.view.width - ((scrollbar.interactive && scrollbar.visible && scrollbar.parent) ? scrollbar.width : 0) + background: Rectangle { + color: backgroundColor } states: [ State { @@ -283,31 +450,45 @@ Page { when: roomItem.hovered && !((Rooms.currentRoom && roomId == Rooms.currentRoom.roomId) || Rooms.currentRoomPreview.roomid == roomId) PropertyChanges { - target: roomItem backgroundColor: palette.dark - importantText: palette.brightText - unimportantText: palette.brightText bubbleBackground: palette.highlight bubbleText: palette.highlightedText + importantText: palette.brightText + target: roomItem + unimportantText: palette.brightText } - }, State { name: "selected" when: (Rooms.currentRoom && roomId == Rooms.currentRoom.roomId) || Rooms.currentRoomPreview.roomid == roomId PropertyChanges { - target: roomItem backgroundColor: palette.highlight - importantText: palette.highlightedText - unimportantText: palette.highlightedText bubbleBackground: palette.highlightedText bubbleText: palette.highlight + importantText: palette.highlightedText + target: roomItem + unimportantText: palette.highlightedText } - } ] + onClicked: { + console.log("tapped " + roomId); + if (!Rooms.currentRoom || Rooms.currentRoom.roomId !== roomId) + Rooms.setCurrentRoom(roomId); + else + Rooms.resetCurrentRoom(); + } + onPressAndHold: { + if (!isInvite) + roomContextMenu.show(roomId, tags); + } + + Ripple { + color: Qt.rgba(palette.dark.r, palette.dark.g, palette.dark.b, 0.5) + } + // NOTE(Nico): We want to prevent the touch areas from overlapping. For some reason we need to add 1px of padding for that... Item { anchors.fill: parent @@ -315,76 +496,71 @@ Page { TapHandler { acceptedButtons: Qt.RightButton + acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad + gesturePolicy: TapHandler.ReleaseWithinBounds + onSingleTapped: { if (!TimelineManager.isInvite) roomContextMenu.show(roomId, tags); - } - gesturePolicy: TapHandler.ReleaseWithinBounds - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad } - } - RowLayout { - spacing: Nheko.paddingMedium anchors.fill: parent anchors.margins: Nheko.paddingMedium + spacing: Nheko.paddingMedium Avatar { id: avatar - enabled: false Layout.alignment: Qt.AlignVCenter + displayName: roomName + enabled: false height: avatarSize - width: avatarSize + roomid: roomId url: avatarUrl.replace("mxc://", "image://MxcImage/") - displayName: roomName userid: isDirect ? directChatOtherUserId : "" - roomid: roomId + width: avatarSize NotificationBubble { id: collapsedNotificationBubble - notificationCount: roomItem.notificationCount - hasLoudNotification: roomItem.hasLoudNotification - bubbleBackgroundColor: roomItem.bubbleBackground - bubbleTextColor: roomItem.bubbleText - anchors.right: parent.right anchors.bottom: parent.bottom anchors.margins: -Nheko.paddingSmall + anchors.right: parent.right + bubbleBackgroundColor: roomItem.bubbleBackground + bubbleTextColor: roomItem.bubbleText + hasLoudNotification: roomItem.hasLoudNotification mayBeVisible: collapsed && (isSpace ? Settings.spaceNotifications : true) + notificationCount: roomItem.notificationCount } - } - ColumnLayout { id: textContent - visible: !collapsed Layout.alignment: Qt.AlignLeft Layout.fillWidth: true Layout.minimumWidth: 100 - width: parent.width - avatar.width Layout.preferredWidth: parent.width - avatar.width height: avatar.height spacing: Nheko.paddingSmall + visible: !collapsed + width: parent.width - avatar.width NotificationBubble { id: notificationBubble - parent: isSpace ? titleRow : subtextRow - notificationCount: roomItem.notificationCount - hasLoudNotification: roomItem.hasLoudNotification - bubbleBackgroundColor: roomItem.bubbleBackground - bubbleTextColor: roomItem.bubbleText Layout.alignment: Qt.AlignRight Layout.leftMargin: Nheko.paddingSmall - Layout.preferredWidth: implicitWidth Layout.preferredHeight: implicitHeight + Layout.preferredWidth: implicitWidth + bubbleBackgroundColor: roomItem.bubbleBackground + bubbleTextColor: roomItem.bubbleText + hasLoudNotification: roomItem.hasLoudNotification mayBeVisible: !collapsed && (isSpace ? Settings.spaceNotifications : true) + notificationCount: roomItem.notificationCount + parent: isSpace ? titleRow : subtextRow } - RowLayout { id: titleRow @@ -394,433 +570,216 @@ Page { ElidedLabel { id: rN + Layout.alignment: Qt.AlignBaseline + Layout.fillWidth: true color: roomItem.importantText elideWidth: width fullText: TimelineManager.htmlEscape(roomName) textFormat: Text.RichText - Layout.fillWidth: true } - Label { id: timestamp - visible: !isInvite && !isSpace - width: visible ? 0 : undefined Layout.alignment: Qt.AlignRight | Qt.AlignBaseline - font.pixelSize: fontMetrics.font.pixelSize * 0.9 color: roomItem.unimportantText + font.pixelSize: fontMetrics.font.pixelSize * 0.9 text: time + visible: !isInvite && !isSpace + width: visible ? 0 : undefined } - } - RowLayout { id: subtextRow + Layout.alignment: Qt.AlignBottom Layout.fillWidth: true + height: visible ? 0 : undefined spacing: 0 visible: !isSpace - height: visible ? 0 : undefined - Layout.alignment: Qt.AlignBottom ElidedLabel { + Layout.fillWidth: true color: roomItem.unimportantText - font.pixelSize: fontMetrics.font.pixelSize * 0.9 elideWidth: width + font.pixelSize: fontMetrics.font.pixelSize * 0.9 fullText: TimelineManager.htmlEscape(lastMessage) textFormat: Text.RichText - Layout.fillWidth: true } - } - } - } - Rectangle { anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter - height: parent.height - Nheko.paddingSmall * 2 - width: 3 color: palette.highlight + height: parent.height - Nheko.paddingSmall * 2 visible: hasUnreadMessages + width: 3 } - - background: Rectangle { - color: backgroundColor - } - - } - - } - - background: Rectangle { - color: Nheko.theme.sidebarBackground - } - - header: ColumnLayout { - spacing: 0 - - Pane { - id: userInfoPanel - - function openUserProfile() { - Nheko.updateUserProfile(); - var component = Qt.createComponent("qrc:/qml/dialogs/UserProfile.qml") - if (component.status == Component.Ready) { - var userProfile = component.createObject(timelineRoot, {"profile": Nheko.currentUser}); - userProfile.show(); - timelineRoot.destroyOnClose(userProfile); - } else { - console.error("Failed to create component: " + component.errorString()); - } - } - - - Layout.fillWidth: true - Layout.alignment: Qt.AlignBottom - //Layout.preferredHeight: userInfoGrid.implicitHeight + 2 * Nheko.paddingMedium - padding: Nheko.paddingMedium - Layout.minimumHeight: 40 - - background: Rectangle {color: palette.window} - - InputDialog { - id: statusDialog - - title: qsTr("Status Message") - prompt: qsTr("Enter your status message:") - onAccepted: function(text) { - Nheko.setStatusMessage(text); - } - } - - Platform.Menu { - id: userInfoMenu - - Platform.MenuItem { - text: qsTr("Profile settings") - onTriggered: userInfoPanel.openUserProfile() - } - - Platform.MenuItem { - text: qsTr("Set status message") - onTriggered: statusDialog.show() - } - - } - - TapHandler { - margin: -Nheko.paddingSmall - acceptedButtons: Qt.LeftButton - onSingleTapped: userInfoPanel.openUserProfile() - onLongPressed: userInfoMenu.open() - gesturePolicy: TapHandler.ReleaseWithinBounds - } - - TapHandler { - margin: -Nheko.paddingSmall - acceptedButtons: Qt.RightButton - onSingleTapped: userInfoMenu.open() - gesturePolicy: TapHandler.ReleaseWithinBounds - } - - contentItem: RowLayout { - id: userInfoGrid - - property var profile: Nheko.currentUser - - spacing: Nheko.paddingMedium - - Avatar { - id: avatar - - Layout.alignment: Qt.AlignVCenter - Layout.preferredWidth: fontMetrics.lineSpacing * 2 - Layout.preferredHeight: fontMetrics.lineSpacing * 2 - url: (userInfoGrid.profile ? userInfoGrid.profile.avatarUrl : "").replace("mxc://", "image://MxcImage/") - displayName: userInfoGrid.profile ? userInfoGrid.profile.displayName : "" - userid: userInfoGrid.profile ? userInfoGrid.profile.userid : "" - enabled: false - } - - ColumnLayout { - id: col - - visible: !collapsed - Layout.alignment: Qt.AlignLeft - Layout.fillWidth: true - width: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2 - Layout.preferredWidth: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2 - spacing: 0 - - ElidedLabel { - Layout.alignment: Qt.AlignBottom - font.pointSize: fontMetrics.font.pointSize * 1.1 - font.weight: Font.DemiBold - fullText: userInfoGrid.profile ? userInfoGrid.profile.displayName : "" - elideWidth: col.width - } - - ElidedLabel { - Layout.alignment: Qt.AlignTop - color: palette.buttonText - font.pointSize: fontMetrics.font.pointSize * 0.9 - elideWidth: col.width - fullText: userInfoGrid.profile ? userInfoGrid.profile.userid : "" - } - - } - - Item { - } - - ImageButton { - id: logoutButton - - visible: !collapsed - Layout.alignment: Qt.AlignVCenter - Layout.preferredWidth: fontMetrics.lineSpacing * 2 - Layout.preferredHeight: fontMetrics.lineSpacing * 2 - image: ":/icons/icons/ui/power-off.svg" - ToolTip.visible: hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: qsTr("Logout") - onClicked: Nheko.openLogoutDialog() - } - - } - - } - - Rectangle { - color: Nheko.theme.separator - height: 2 - Layout.fillWidth: true } - Rectangle { - id: unverifiedStuffBubble - - color: Qt.lighter(Nheko.theme.orange, verifyButtonHovered.hovered ? 1.2 : 1) - Layout.fillWidth: true - implicitHeight: explanation.height + Nheko.paddingMedium * 2 - visible: SelfVerificationStatus.status != SelfVerificationStatus.AllVerified - - RowLayout { - id: unverifiedStuffBubbleContainer - - width: parent.width - height: explanation.height + Nheko.paddingMedium * 2 - spacing: 0 - - Label { - id: explanation - - Layout.margins: Nheko.paddingMedium - Layout.rightMargin: Nheko.paddingSmall - color: palette.buttonText - Layout.fillWidth: true - text: { - switch (SelfVerificationStatus.status) { - case SelfVerificationStatus.NoMasterKey: - //: Cross-signing setup has not run yet. - return qsTr("Encryption not set up"); - case SelfVerificationStatus.UnverifiedMasterKey: - //: The user just signed in with this device and hasn't verified their master key. - return qsTr("Unverified login"); - case SelfVerificationStatus.UnverifiedDevices: - //: There are unverified devices signed in to this account. - return qsTr("Please verify your other devices"); - default: - return ""; - } - } - textFormat: Text.PlainText - wrapMode: Text.Wrap - } + Connections { + function onCurrentRoomChanged() { + if (Rooms.currentRoom) + roomlist.positionViewAtIndex(Rooms.roomidToIndex(Rooms.currentRoom.roomId), ListView.Contain); + } - ImageButton { - id: closeUnverifiedBubble + target: Rooms + } + Component { + id: roomWindowComponent - Layout.rightMargin: Nheko.paddingMedium - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - hoverEnabled: true - width: fontMetrics.font.pixelSize - height: fontMetrics.font.pixelSize - image: ":/icons/icons/ui/dismiss.svg" - ToolTip.visible: closeUnverifiedBubble.hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: qsTr("Close") - onClicked: unverifiedStuffBubble.visible = false + ApplicationWindow { + id: roomWindowW + + property var room: null + property var roomPreview: null + + color: palette.window + height: 650 + minimumHeight: 150 + minimumWidth: 150 + title: room.plainRoomName + width: 420 + + Component.onCompleted: { + MainWindow.addPerRoomWindow(room.roomId || roomPreview.roomid, roomWindowW); + Nheko.setTransientParent(roomWindowW, null); + } + Component.onDestruction: MainWindow.removePerRoomWindow(room.roomId || roomPreview.roomid, roomWindowW) + onActiveChanged: { + room.lastReadIdOnWindowFocus(); } - } + //flags: Qt.Window | Qt.WindowCloseButtonHint | Qt.WindowTitleHint + Shortcut { + sequence: StandardKey.Cancel - HoverHandler { - id: verifyButtonHovered + onActivated: roomWindowW.close() + } + TimelineView { + id: timeline - enabled: !closeUnverifiedBubble.hovered - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad - } + anchors.fill: parent + privacyScreen: privacyScreen + room: roomWindowW.room + roomPreview: roomWindowW.roomPreview.roomid ? roomWindowW.roomPreview : null + } + PrivacyScreen { + id: privacyScreen - TapHandler { - enabled: !closeUnverifiedBubble.hovered - acceptedButtons: Qt.LeftButton - onSingleTapped: { - if (SelfVerificationStatus.status == SelfVerificationStatus.UnverifiedDevices) - SelfVerificationStatus.verifyUnverifiedDevices(); - else - SelfVerificationStatus.statusChanged(); + anchors.fill: parent + screenTimeout: Settings.privacyScreenTimeout + timelineRoot: timeline + visible: Settings.privacyScreen + windowTarget: roomWindowW } } - } + Component { + id: nestedSpaceMenuLevel - Rectangle { - color: Nheko.theme.separator - height: 1 - Layout.fillWidth: true - visible: unverifiedStuffBubble.visible + SpaceMenuLevel { + childMenu: rootSpaceMenu.childMenu + roomid: roomContextMenu.roomid + } } + Platform.Menu { + id: roomContextMenu - } + property string roomid + property var tags - footer: ColumnLayout { - spacing: 0 + function show(roomid_, tags_) { + roomid = roomid_; + tags = tags_; + open(); + } - Rectangle { - color: Nheko.theme.separator - height: 1 - Layout.fillWidth: true - } + InputDialog { + id: newTag - Pane { - Layout.fillWidth: true - Layout.alignment: Qt.AlignBottom - Layout.minimumHeight: 40 + prompt: qsTr("Enter the tag you want to use:") + title: qsTr("New tag") - horizontalPadding: Nheko.paddingMedium - verticalPadding: 0 + onAccepted: function (text) { + Rooms.toggleTag(roomContextMenu.roomid, "u." + text, true); + } + } + Platform.MenuItem { + text: qsTr("Open separately") - background: Rectangle {color: palette.window} - contentItem: RowLayout { - id: buttonRow + onTriggered: { + var roomWindow = roomWindowComponent.createObject(null, { + "room": Rooms.getRoomById(roomContextMenu.roomid), + "roomPreview": Rooms.getRoomPreviewById(roomContextMenu.roomid) + }); + roomWindow.showNormal(); + destroyOnClose(roomWindow); + } + } + Platform.MenuItem { + text: qsTr("Room settings") - ImageButton { - Layout.fillWidth: true - hoverEnabled: true - width: 22 - height: 22 - image: ":/icons/icons/ui/add-square-button.svg" - ToolTip.visible: hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: qsTr("Start a new chat") - Layout.margins: Nheko.paddingMedium - onClicked: roomJoinCreateMenu.open(parent) + onTriggered: TimelineManager.openRoomSettings(roomContextMenu.roomid) + } + Platform.MenuItem { + text: qsTr("Leave room") - Platform.Menu { - id: roomJoinCreateMenu + onTriggered: TimelineManager.openLeaveRoomDialog(roomContextMenu.roomid) + } + Platform.MenuItem { + text: qsTr("Copy room link") - Platform.MenuItem { - text: qsTr("Join a room") - onTriggered: Nheko.openJoinRoomDialog() - } + onTriggered: Rooms.copyLink(roomContextMenu.roomid) + } + Platform.Menu { + id: tagsMenu - Platform.MenuItem { - text: qsTr("Create a new room") - onTriggered: { - var createRoom = createRoomComponent.createObject(timelineRoot); - createRoom.show(); - timelineRoot.destroyOnClose(createRoom); - } - } + title: qsTr("Tag room as:") - Platform.MenuItem { - text: qsTr("Start a direct chat") - onTriggered: { - var createDirect = createDirectComponent.createObject(timelineRoot); - createDirect.show(); - timelineRoot.destroyOnClose(createDirect); - } - } + Instantiator { + model: Communities.tagsWithDefault - Platform.MenuItem { - text: qsTr("Create a new community") - onTriggered: { - var createRoom = createRoomComponent.createObject(timelineRoot, { "space": true }); - createRoom.show(); - timelineRoot.destroyOnClose(createRoom); + delegate: Platform.MenuItem { + property string t: modelData + + checkable: true + checked: roomContextMenu.tags !== undefined && roomContextMenu.tags.includes(t) + text: { + switch (t) { + case "m.favourite": + return qsTr("Favourite"); + case "m.lowpriority": + return qsTr("Low priority"); + case "m.server_notice": + return qsTr("Server notice"); + default: + return t.substring(2); } } + onTriggered: Rooms.toggleTag(roomContextMenu.roomid, t, checked) } + onObjectAdded: (index, object) => tagsMenu.insertItem(index, object) + onObjectRemoved: (index, object) => tagsMenu.removeItem(object) } + Platform.MenuItem { + text: qsTr("Create new tag...") - ImageButton { - visible: !collapsed - Layout.fillWidth: true - hoverEnabled: true - width: 22 - height: 22 - image: ":/icons/icons/ui/room-directory.svg" - ToolTip.visible: hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: qsTr("Room directory") - Layout.margins: Nheko.paddingMedium - onClicked: { - var win = roomDirectoryComponent.createObject(timelineRoot); - win.show(); - timelineRoot.destroyOnClose(win); - } - } - - ImageButton { - visible: !collapsed - Layout.fillWidth: true - hoverEnabled: true - ripple: false - width: 22 - height: 22 - image: ":/icons/icons/ui/search.svg" - ToolTip.visible: hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: qsTr("Search rooms (Ctrl+K)") - Layout.margins: Nheko.paddingMedium - onClicked: { - var component = Qt.createComponent("qrc:/qml/QuickSwitcher.qml") - if (component.status == Component.Ready) { - var quickSwitch = component.createObject(timelineRoot); - quickSwitch.open(); - destroyOnClosed(quickSwitch); - } else { - console.error("Failed to create component: " + component.errorString()); - } - } - } - - ImageButton { - visible: !collapsed - Layout.fillWidth: true - hoverEnabled: true - ripple: false - width: 22 - height: 22 - image: ":/icons/icons/ui/settings.svg" - ToolTip.visible: hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: qsTr("User settings") - Layout.margins: Nheko.paddingMedium - onClicked: mainWindow.push(userSettingsPage); + onTriggered: newTag.show() } - } + SpaceMenuLevel { + id: rootSpaceMenu + childMenu: nestedSpaceMenuLevel + position: -1 + roomid: roomContextMenu.roomid + title: qsTr("Add or remove from community...") + } } - } - } diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml index 01fde18e..cb000040 100644 --- a/resources/qml/Root.qml +++ b/resources/qml/Root.qml @@ -20,19 +20,14 @@ import im.nheko.EmojiModel 1.0 Pane { id: timelineRoot - background: null - padding: 0 - - FontMetrics { - id: fontMetrics - } - - RoomDirectoryModel { - id: publicRooms + function destroyOnClose(obj) { + if (obj.closing != undefined) + obj.closing.connect(() => obj.destroy(1000)); + else if (obj.aboutToHide != undefined) + obj.aboutToHide.connect(() => obj.destroy(1000)); } - - UserDirectoryModel { - id: userDirectory + function destroyOnClosed(obj) { + obj.aboutToHide.connect(() => obj.destroy(1000)); } //Timer { @@ -41,54 +36,49 @@ Pane { // running: true // repeat: true //} - function showAliasEditor(settings) { - var component = Qt.createComponent("qrc:/qml/dialogs/AliasEditor.qml") + var component = Qt.createComponent("qrc:/qml/dialogs/AliasEditor.qml"); if (component.status == Component.Ready) { var dialog = component.createObject(timelineRoot, { - "roomSettings": settings - }); + "roomSettings": settings + }); dialog.show(); destroyOnClose(dialog); } else { console.error("Failed to create component: " + component.errorString()); } - } - - function showPLEditor(settings) { - var component = Qt.createComponent("qrc:/qml/dialogs/PowerLevelEditor.qml") + function showAllowedRoomsEditor(settings) { + var component = Qt.createComponent("qrc:/qml/dialogs/AllowedRoomsSettingsDialog.qml"); if (component.status == Component.Ready) { var dialog = component.createObject(timelineRoot, { - "roomSettings": settings - }); + "roomSettings": settings + }); dialog.show(); destroyOnClose(dialog); } else { console.error("Failed to create component: " + component.errorString()); } } - - function showSpacePLApplyPrompt(settings, editingModel) { - var component = Qt.createComponent("qrc:/qml/dialogs/PowerLevelSpacesApplyDialog.qml") + function showPLEditor(settings) { + var component = Qt.createComponent("qrc:/qml/dialogs/PowerLevelEditor.qml"); if (component.status == Component.Ready) { var dialog = component.createObject(timelineRoot, { - "roomSettings": settings, - "editingModel": editingModel - }); + "roomSettings": settings + }); dialog.show(); destroyOnClose(dialog); } else { console.error("Failed to create component: " + component.errorString()); } } - - function showAllowedRoomsEditor(settings) { - var component = Qt.createComponent("qrc:/qml/dialogs/AllowedRoomsSettingsDialog.qml") + function showSpacePLApplyPrompt(settings, editingModel) { + var component = Qt.createComponent("qrc:/qml/dialogs/PowerLevelSpacesApplyDialog.qml"); if (component.status == Component.Ready) { var dialog = component.createObject(timelineRoot, { - "roomSettings": settings - }); + "roomSettings": settings, + "editingModel": editingModel + }); dialog.show(); destroyOnClose(dialog); } else { @@ -96,23 +86,37 @@ Pane { } } + background: null + padding: 0 + + FontMetrics { + id: fontMetrics + + } + RoomDirectoryModel { + id: publicRooms + + } + UserDirectoryModel { + id: userDirectory + + } Component { id: readReceiptsDialog ReadReceipts { } - } - Shortcut { sequence: StandardKey.Quit + onActivated: Qt.quit() } - Shortcut { sequence: "Ctrl+K" + onActivated: { - var component = Qt.createComponent("qrc:/qml/QuickSwitcher.qml") + var component = Qt.createComponent("qrc:/qml/QuickSwitcher.qml"); if (component.status == Component.Ready) { var quickSwitch = component.createObject(timelineRoot); quickSwitch.open(); @@ -122,50 +126,49 @@ Pane { } } } - Shortcut { // Add alternative shortcut, because sometimes Alt+A is stolen by the TextEdit sequences: ["Alt+A", "Ctrl+Shift+A"] + onActivated: Rooms.nextRoomWithActivity() } - Shortcut { sequence: "Ctrl+Down" + onActivated: Rooms.nextRoom() } - Shortcut { sequence: "Ctrl+Up" + onActivated: Rooms.previousRoom() } - Connections { - function onOpenLogoutDialog() { - var component = Qt.createComponent("qrc:/qml/dialogs/LogoutDialog.qml") + function onOpenJoinRoomDialog() { + var component = Qt.createComponent("qrc:/qml/dialogs/JoinRoomDialog.qml"); if (component.status == Component.Ready) { var dialog = component.createObject(timelineRoot); - dialog.open(); + dialog.show(); destroyOnClose(dialog); } else { console.error("Failed to create component: " + component.errorString()); } } - - function onOpenJoinRoomDialog() { - var component = Qt.createComponent("qrc:/qml/dialogs/JoinRoomDialog.qml") + function onOpenLogoutDialog() { + var component = Qt.createComponent("qrc:/qml/dialogs/LogoutDialog.qml"); if (component.status == Component.Ready) { var dialog = component.createObject(timelineRoot); - dialog.show(); + dialog.open(); destroyOnClose(dialog); } else { console.error("Failed to create component: " + component.errorString()); } } - function onShowRoomJoinPrompt(summary) { - var component = Qt.createComponent("qrc:/qml/dialogs/ConfirmJoinRoomDialog.qml") + var component = Qt.createComponent("qrc:/qml/dialogs/ConfirmJoinRoomDialog.qml"); if (component.status == Component.Ready) { - var dialog = component.createObject(timelineRoot, {"summary": summary}); + var dialog = component.createObject(timelineRoot, { + "summary": summary + }); dialog.show(); destroyOnClose(dialog); } else { @@ -175,12 +178,13 @@ Pane { target: Nheko } - Connections { function onNewDeviceVerificationRequest(flow) { - var component = Qt.createComponent("qrc:/qml/device-verification/DeviceVerification.qml") + var component = Qt.createComponent("qrc:/qml/device-verification/DeviceVerification.qml"); if (component.status == Component.Ready) { - var dialog = component.createObject(timelineRoot, {"flow": flow}); + var dialog = component.createObject(timelineRoot, { + "flow": flow + }); dialog.show(); destroyOnClose(dialog); } else { @@ -190,101 +194,71 @@ Pane { target: VerificationManager } - - function destroyOnClose(obj) { - if (obj.closing != undefined) obj.closing.connect(() => obj.destroy(1000)); - else if (obj.aboutToHide != undefined) obj.aboutToHide.connect(() => obj.destroy(1000)); - } - - function destroyOnClosed(obj) { - obj.aboutToHide.connect(() => obj.destroy(1000)); - } - Connections { - function onOpenProfile(profile) { - var component = Qt.createComponent("qrc:/qml/dialogs/UserProfile.qml") + function onOpenInviteUsersDialog(invitees) { + var component = Qt.createComponent("qrc:/qml/dialogs/InviteDialog.qml"); if (component.status == Component.Ready) { - var userProfile = component.createObject(timelineRoot, {"profile": profile}); - userProfile.show(); - destroyOnClose(userProfile); + var dialog = component.createObject(timelineRoot, { + "invitees": invitees + }); + dialog.show(); + destroyOnClose(dialog); } else { console.error("Failed to create component: " + component.errorString()); } } - - function onShowImagePackSettings(room, packlist) { - var component = Qt.createComponent("qrc:/qml/dialogs/ImagePackSettingsDialog.qml") - + function onOpenLeaveRoomDialog(roomid, reason) { + var component = Qt.createComponent("qrc:/qml/dialogs/LeaveRoomDialog.qml"); if (component.status == Component.Ready) { - var packSet = component.createObject(timelineRoot, { - "room": room, - "packlist": packlist - }); - packSet.show(); - destroyOnClose(packSet); + var dialog = component.createObject(timelineRoot, { + "roomId": roomid, + "reason": reason + }); + dialog.open(); + destroyOnClose(dialog); + } else { + console.error("Failed to create component: " + component.errorString()); + } + } + function onOpenProfile(profile) { + var component = Qt.createComponent("qrc:/qml/dialogs/UserProfile.qml"); + if (component.status == Component.Ready) { + var userProfile = component.createObject(timelineRoot, { + "profile": profile + }); + userProfile.show(); + destroyOnClose(userProfile); } else { console.error("Failed to create component: " + component.errorString()); } } - function onOpenRoomMembersDialog(members, room) { - var component = Qt.createComponent("qrc:/qml/dialogs/RoomMembers.qml") + var component = Qt.createComponent("qrc:/qml/dialogs/RoomMembers.qml"); if (component.status == Component.Ready) { var membersDialog = component.createObject(timelineRoot, { - "members": members, - "room": room - }); + "members": members, + "room": room + }); membersDialog.show(); destroyOnClose(membersDialog); } else { console.error("Failed to create component: " + component.errorString()); } - } - function onOpenRoomSettingsDialog(settings) { - var component = Qt.createComponent("qrc:/qml/dialogs/RoomSettings.qml") + var component = Qt.createComponent("qrc:/qml/dialogs/RoomSettings.qml"); if (component.status == Component.Ready) { var roomSettings = component.createObject(timelineRoot, { - "roomSettings": settings - }); + "roomSettings": settings + }); roomSettings.show(); destroyOnClose(roomSettings); } else { console.error("Failed to create component: " + component.errorString()); } - - } - - function onOpenInviteUsersDialog(invitees) { - var component = Qt.createComponent("qrc:/qml/dialogs/InviteDialog.qml") - if (component.status == Component.Ready) { - var dialog = component.createObject(timelineRoot, { - "invitees": invitees - }); - dialog.show(); - destroyOnClose(dialog); - } else { - console.error("Failed to create component: " + component.errorString()); - } } - - function onOpenLeaveRoomDialog(roomid, reason) { - var component = Qt.createComponent("qrc:/qml/dialogs/LeaveRoomDialog.qml") - if (component.status == Component.Ready) { - var dialog = component.createObject(timelineRoot, { - "roomId": roomid, - "reason": reason - }); - dialog.open(); - destroyOnClose(dialog); - } else { - console.error("Failed to create component: " + component.errorString()); - } - } - function onShowImageOverlay(room, eventId, url, originalWidth, proportionalHeight) { - var component = Qt.createComponent("qrc:/qml/dialogs/ImageOverlay.qml") + var component = Qt.createComponent("qrc:/qml/dialogs/ImageOverlay.qml"); if (component.status == Component.Ready) { var dialog = component.createObject(timelineRoot, { "room": room, @@ -292,22 +266,33 @@ Pane { "url": url, "originalWidth": originalWidth ?? 0, "proportionalHeight": proportionalHeight ?? 0 - } - ); + }); dialog.showFullScreen(); destroyOnClose(dialog); } else { console.error("Failed to create component: " + component.errorString()); } } + function onShowImagePackSettings(room, packlist) { + var component = Qt.createComponent("qrc:/qml/dialogs/ImagePackSettingsDialog.qml"); + if (component.status == Component.Ready) { + var packSet = component.createObject(timelineRoot, { + "room": room, + "packlist": packlist + }); + packSet.show(); + destroyOnClose(packSet); + } else { + console.error("Failed to create component: " + component.errorString()); + } + } target: TimelineManager } - Connections { function onNewInviteState() { if (CallManager.haveCallInvite && Settings.mobileMode) { - var component = Qt.createComponent("qrc:/qml/voip/CallInvite.qml") + var component = Qt.createComponent("qrc:/qml/voip/CallInvite.qml"); if (component.status == Component.Ready) { var dialog = component.createObject(timelineRoot); dialog.open(); @@ -320,131 +305,110 @@ Pane { target: CallManager } - SelfVerificationCheck { } - InputDialog { id: uiaPassPrompt echoMode: TextInput.Password - title: UIA.title prompt: qsTr("Please enter your login password to continue:") - onAccepted: (t) => { + title: UIA.title + + onAccepted: t => { return UIA.continuePassword(t); } } - InputDialog { id: uiaEmailPrompt - title: UIA.title prompt: qsTr("Please enter a valid email address to continue:") - onAccepted: (t) => { + title: UIA.title + + onAccepted: t => { return UIA.continueEmail(t); } } - PhoneNumberInputDialog { id: uiaPhoneNumberPrompt - title: UIA.title prompt: qsTr("Please enter a valid phone number to continue:") + title: UIA.title + onAccepted: (p, t) => { return UIA.continuePhoneNumber(p, t); } } - InputDialog { id: uiaTokenPrompt - title: UIA.title prompt: qsTr("Please enter the token which has been sent to you:") - onAccepted: (t) => { + title: UIA.title + + onAccepted: t => { return UIA.submit3pidToken(t); } } - Platform.MessageDialog { id: uiaErrorDialog buttons: Platform.MessageDialog.Ok } - Platform.MessageDialog { id: uiaConfirmationLinkDialog buttons: Platform.MessageDialog.Ok text: qsTr("Wait for the confirmation link to arrive, then continue.") + onAccepted: UIA.continue3pidReceived() } - Connections { - function onPassword() { - console.log("UIA: password needed"); - uiaPassPrompt.show(); + function onConfirm3pidToken() { + uiaConfirmationLinkDialog.open(); } - function onEmail() { uiaEmailPrompt.show(); } - + function onError(msg) { + uiaErrorDialog.text = msg; + uiaErrorDialog.open(); + } + function onPassword() { + console.log("UIA: password needed"); + uiaPassPrompt.show(); + } function onPhoneNumber() { uiaPhoneNumberPrompt.show(); } - function onPrompt3pidToken() { uiaTokenPrompt.show(); } - function onConfirm3pidToken() { - uiaConfirmationLinkDialog.open(); - } - - function onError(msg) { - uiaErrorDialog.text = msg; - uiaErrorDialog.open(); - } - target: UIA } - StackView { id: mainWindow - anchors.fill: parent - initialItem: welcomePage - - Transition { - id: reducedMotionTransitionExit - PropertyAnimation { - property: "opacity" - from: 1 - to:0 - duration: 200 - } - } - Transition { - id: reducedMotionTransitionEnter - SequentialAnimation { - PropertyAction { property: "opacity"; value: 0 } - PauseAnimation { duration: 200 } - PropertyAnimation { - property: "opacity" - from: 0 - to:1 - duration: 200 - } - } - } + property Transition popEnterOrg + property Transition popExitOrg // for some reason direct bindings to a hidden StackView don't work, so manually store and restore here. property Transition pushEnterOrg property Transition pushExitOrg - property Transition popEnterOrg - property Transition popExitOrg property Transition replaceEnterOrg property Transition replaceExitOrg + + function updateTrans() { + pushEnter = Settings.reducedMotion ? reducedMotionTransitionEnter : pushEnterOrg; + pushExit = Settings.reducedMotion ? reducedMotionTransitionExit : pushExitOrg; + popEnter = Settings.reducedMotion ? reducedMotionTransitionEnter : popEnterOrg; + popExit = Settings.reducedMotion ? reducedMotionTransitionExit : popExitOrg; + replaceEnter = Settings.reducedMotion ? reducedMotionTransitionEnter : replaceEnterOrg; + replaceExit = Settings.reducedMotion ? reducedMotionTransitionExit : replaceExitOrg; + } + + anchors.fill: parent + initialItem: welcomePage + Component.onCompleted: { pushEnterOrg = pushEnter; popEnterOrg = popEnter; @@ -452,78 +416,94 @@ Pane { pushExitOrg = pushExit; popExitOrg = popExit; replaceExitOrg = replaceExit; - - updateTrans() + updateTrans(); } - function updateTrans() { - pushEnter = Settings.reducedMotion ? reducedMotionTransitionEnter : pushEnterOrg; - pushExit = Settings.reducedMotion ? reducedMotionTransitionExit : pushExitOrg; - popEnter = Settings.reducedMotion ? reducedMotionTransitionEnter : popEnterOrg; - popExit = Settings.reducedMotion ? reducedMotionTransitionExit : popExitOrg; - replaceEnter = Settings.reducedMotion ? reducedMotionTransitionEnter : replaceEnterOrg; - replaceExit = Settings.reducedMotion ? reducedMotionTransitionExit : replaceExitOrg; + Transition { + id: reducedMotionTransitionExit + + PropertyAnimation { + duration: 200 + from: 1 + property: "opacity" + to: 0 + } } + Transition { + id: reducedMotionTransitionEnter + SequentialAnimation { + PropertyAction { + property: "opacity" + value: 0 + } + PauseAnimation { + duration: 200 + } + PropertyAnimation { + duration: 200 + from: 0 + property: "opacity" + to: 1 + } + } + } Connections { - target: Settings function onReducedMotionChanged() { mainWindow.updateTrans(); } + + target: Settings } } - Component { id: welcomePage WelcomePage { } } - Component { id: chatPage ChatPage { } } - Component { id: loginPage LoginPage { } } - Component { id: registerPage RegisterPage { } } - Component { id: userSettingsPage UserSettingsPage { } - } + Snackbar { + id: snackbar - - Snackbar { id: snackbar } - + } Connections { + function onShowNotification(msg) { + snackbar.showNotification(msg); + console.log("New snack: " + msg); + } function onSwitchToChatPage() { mainWindow.replace(null, chatPage); } function onSwitchToLoginPage(error) { - mainWindow.replace(welcomePage, {}, loginPage, {"error": error}, StackView.PopTransition); - } - function onShowNotification(msg) { - snackbar.showNotification(msg); - console.log("New snack: " + msg); + mainWindow.replace(welcomePage, {}, loginPage, { + "error": error + }, StackView.PopTransition); } + target: MainWindow } - } diff --git a/resources/qml/SelfVerificationCheck.qml b/resources/qml/SelfVerificationCheck.qml index bb7ea5f0..80897ff9 100644 --- a/resources/qml/SelfVerificationCheck.qml +++ b/resources/qml/SelfVerificationCheck.qml @@ -10,22 +10,29 @@ import QtQuick.Layouts 1.3 import im.nheko 1.0 Item { - visible: false enabled: false + visible: false Dialog { id: showRecoverKeyDialog property string recoveryKey: "" - parent: Overlay.overlay anchors.centerIn: parent + closePolicy: Popup.NoAutoClose height: content.height + implicitFooterHeight + implicitHeaderHeight - width: content.width - padding: 0 modal: true + padding: 0 + parent: Overlay.overlay standardButtons: Dialog.Ok - closePolicy: Popup.NoAutoClose + width: content.width + + background: Rectangle { + border.color: Nheko.theme.separator + border.width: 1 + color: palette.window + radius: Nheko.paddingSmall + } ColumnLayout { id: content @@ -33,45 +40,33 @@ Item { spacing: 0 Label { + Layout.fillWidth: true Layout.margins: Nheko.paddingMedium Layout.maximumWidth: (Overlay.overlay ? Overlay.overlay.width : 400) - Nheko.paddingMedium * 4 - Layout.fillWidth: true - text: qsTr("This is your recovery key. You will need it to restore access to your encrypted messages and verification keys. Keep this safe. Don't share it with anyone and don't lose it! Do not pass go! Do not collect $200!") color: palette.text + text: qsTr("This is your recovery key. You will need it to restore access to your encrypted messages and verification keys. Keep this safe. Don't share it with anyone and don't lose it! Do not pass go! Do not collect $200!") wrapMode: Text.Wrap } - TextEdit { - Layout.maximumWidth: (Overlay.overlay ? Overlay.overlay.width : 400) - Nheko.paddingMedium * 4 Layout.alignment: Qt.AlignHCenter + Layout.maximumWidth: (Overlay.overlay ? Overlay.overlay.width : 400) - Nheko.paddingMedium * 4 + color: palette.text + font.bold: true horizontalAlignment: TextEdit.AlignHCenter - verticalAlignment: TextEdit.AlignVCenter readOnly: true selectByMouse: true text: showRecoverKeyDialog.recoveryKey - color: palette.text - font.bold: true + verticalAlignment: TextEdit.AlignVCenter wrapMode: TextEdit.Wrap } - } - - background: Rectangle { - color: palette.window - border.color: Nheko.theme.separator - border.width: 1 - radius: Nheko.paddingSmall - } - } - P.MessageDialog { id: successDialog buttons: P.MessageDialog.Ok text: qsTr("Encryption setup successfully") } - P.MessageDialog { id: failureDialog @@ -80,85 +75,86 @@ Item { buttons: P.MessageDialog.Ok text: qsTr("Failed to setup encryption: %1").arg(errorMessage) } - MainWindowDialog { id: bootstrapCrosssigning + background: Rectangle { + border.color: Nheko.theme.separator + border.width: 1 + color: palette.window + radius: Nheko.paddingSmall + } + onAccepted: SelfVerificationStatus.setupCrosssigning(storeSecretsOnline.checked, usePassword.checked ? passwordField.text : "", useOnlineKeyBackup.checked) GridLayout { id: grid - width: bootstrapCrosssigning.useableWidth + columnSpacing: 0 columns: 2 rowSpacing: 0 - columnSpacing: 0 + width: bootstrapCrosssigning.useableWidth z: 1 Label { - Layout.margins: Nheko.paddingMedium Layout.alignment: Qt.AlignHCenter Layout.columnSpan: 2 + Layout.margins: Nheko.paddingMedium + color: palette.text font.pointSize: fontMetrics.font.pointSize * 2 text: qsTr("Setup Encryption") - color: palette.text wrapMode: Text.Wrap } - Label { - Layout.margins: Nheko.paddingMedium Layout.alignment: Qt.AlignLeft Layout.columnSpan: 2 + Layout.margins: Nheko.paddingMedium Layout.maximumWidth: grid.width - Nheko.paddingMedium * 2 - text: qsTr("Hello and welcome to Matrix!\nIt seems like you are new. Before you can securely encrypt your messages, we need to setup a few small things. You can either press accept immediately or adjust a few basic options. We also try to explain a few of the basics. You can skip those parts, but they might prove to be helpful!") color: palette.text + text: qsTr("Hello and welcome to Matrix!\nIt seems like you are new. Before you can securely encrypt your messages, we need to setup a few small things. You can either press accept immediately or adjust a few basic options. We also try to explain a few of the basics. You can skip those parts, but they might prove to be helpful!") wrapMode: Text.Wrap } - Label { - Layout.margins: Nheko.paddingMedium Layout.alignment: Qt.AlignLeft Layout.columnSpan: 1 + Layout.margins: Nheko.paddingMedium Layout.maximumWidth: Math.floor(grid.width / 2) - Nheko.paddingMedium * 2 - text: "Store secrets online.\nYou have a few secrets to make all the encryption magic work. While you can keep them stored only locally, we recommend storing them encrypted on the server. Otherwise it will be painful to recover them. Only disable this if you are paranoid and like losing your data!" color: palette.text + text: "Store secrets online.\nYou have a few secrets to make all the encryption magic work. While you can keep them stored only locally, we recommend storing them encrypted on the server. Otherwise it will be painful to recover them. Only disable this if you are paranoid and like losing your data!" wrapMode: Text.Wrap } - Item { - Layout.margins: Nheko.paddingMedium - Layout.preferredHeight: storeSecretsOnline.height Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter Layout.fillWidth: true + Layout.margins: Nheko.paddingMedium + Layout.preferredHeight: storeSecretsOnline.height ToggleButton { id: storeSecretsOnline checked: true + onClicked: console.log("Store secrets toggled: " + checked) } - } - Label { - Layout.margins: Nheko.paddingMedium Layout.alignment: Qt.AlignLeft Layout.columnSpan: 1 - Layout.rowSpan: 2 + Layout.margins: Nheko.paddingMedium Layout.maximumWidth: Math.floor(grid.width / 2) - Nheko.paddingMedium * 2 - visible: storeSecretsOnline.checked - text: "Set an online backup password.\nWe recommend you DON'T set a password and instead only rely on the recovery key. You will get a recovery key in any case when storing the cross-signing secrets online, but passwords are usually not very random, so they are easier to attack than a completely random recovery key. If you choose to use a password, DON'T make it the same as your login password, otherwise your server can read all your encrypted messages. (You don't want that.)" + Layout.rowSpan: 2 color: palette.text + text: "Set an online backup password.\nWe recommend you DON'T set a password and instead only rely on the recovery key. You will get a recovery key in any case when storing the cross-signing secrets online, but passwords are usually not very random, so they are easier to attack than a completely random recovery key. If you choose to use a password, DON'T make it the same as your login password, otherwise your server can read all your encrypted messages. (You don't want that.)" + visible: storeSecretsOnline.checked wrapMode: Text.Wrap } - Item { + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true Layout.margins: Nheko.paddingMedium - Layout.topMargin: Nheko.paddingLarge Layout.preferredHeight: storeSecretsOnline.height - Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.rowSpan: usePassword.checked ? 1 : 2 - Layout.fillWidth: true + Layout.topMargin: Nheko.paddingLarge visible: storeSecretsOnline.checked ToggleButton { @@ -166,57 +162,43 @@ Item { checked: false } - } - MatrixTextField { id: passwordField - Layout.margins: Nheko.paddingMedium - Layout.maximumWidth: Math.floor(grid.width / 2) - Nheko.paddingMedium * 2 Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.columnSpan: 1 Layout.fillWidth: true - visible: storeSecretsOnline.checked && usePassword.checked + Layout.margins: Nheko.paddingMedium + Layout.maximumWidth: Math.floor(grid.width / 2) - Nheko.paddingMedium * 2 echoMode: TextInput.Password + visible: storeSecretsOnline.checked && usePassword.checked } - Label { - Layout.margins: Nheko.paddingMedium Layout.alignment: Qt.AlignLeft Layout.columnSpan: 1 + Layout.margins: Nheko.paddingMedium Layout.maximumWidth: Math.floor(grid.width / 2) - Nheko.paddingMedium * 2 - text: "Use online key backup.\nStore the keys for your messages securely encrypted online. In general you do want this, because it protects your messages from becoming unreadable, if you log out by accident. It does however carry a small security risk, if you ever share your recovery key by accident. Currently this also has some other weaknesses, that might allow the server to insert new keys into your backup. The server will however never be able to read your messages." color: palette.text + text: "Use online key backup.\nStore the keys for your messages securely encrypted online. In general you do want this, because it protects your messages from becoming unreadable, if you log out by accident. It does however carry a small security risk, if you ever share your recovery key by accident. Currently this also has some other weaknesses, that might allow the server to insert new keys into your backup. The server will however never be able to read your messages." wrapMode: Text.Wrap } - Item { - Layout.margins: Nheko.paddingMedium - Layout.preferredHeight: storeSecretsOnline.height Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter Layout.fillWidth: true + Layout.margins: Nheko.paddingMedium + Layout.preferredHeight: storeSecretsOnline.height ToggleButton { id: useOnlineKeyBackup checked: true + onClicked: console.log("Online key backup toggled: " + checked) } - } - } - - background: Rectangle { - color: palette.window - border.color: Nheko.theme.separator - border.width: 1 - radius: Nheko.paddingSmall - } - } - MainWindowDialog { id: verifyMasterKey @@ -225,54 +207,61 @@ Item { GridLayout { id: masterGrid - width: verifyMasterKey.useableWidth columns: 1 + width: verifyMasterKey.useableWidth z: 1 Label { - Layout.margins: Nheko.paddingMedium Layout.alignment: Qt.AlignHCenter + Layout.margins: Nheko.paddingMedium + color: palette.text //Layout.columnSpan: 2 font.pointSize: fontMetrics.font.pointSize * 2 text: qsTr("Activate Encryption") - color: palette.text wrapMode: Text.Wrap } - Label { - Layout.margins: Nheko.paddingMedium Layout.alignment: Qt.AlignLeft + Layout.margins: Nheko.paddingMedium //Layout.columnSpan: 2 Layout.maximumWidth: grid.width - Nheko.paddingMedium * 2 - text: qsTr("It seems like you have encryption already configured for this account. To be able to access your encrypted messages and make this device appear as trusted, you can either verify an existing device or (if you have one) enter your recovery passphrase. Please select one of the options below.\nIf you choose verify, you need to have the other device available. If you choose \"enter passphrase\", you will need your recovery key or passphrase. If you click cancel, you can choose to verify yourself at a later point.") color: palette.text + text: qsTr("It seems like you have encryption already configured for this account. To be able to access your encrypted messages and make this device appear as trusted, you can either verify an existing device or (if you have one) enter your recovery passphrase. Please select one of the options below.\nIf you choose verify, you need to have the other device available. If you choose \"enter passphrase\", you will need your recovery key or passphrase. If you click cancel, you can choose to verify yourself at a later point.") wrapMode: Text.Wrap } - FlatButton { Layout.alignment: Qt.AlignHCenter text: qsTr("verify") + onClicked: { SelfVerificationStatus.verifyMasterKey(); verifyMasterKey.close(); } } - FlatButton { - visible: SelfVerificationStatus.hasSSSS Layout.alignment: Qt.AlignHCenter text: qsTr("enter passphrase") + visible: SelfVerificationStatus.hasSSSS + onClicked: { SelfVerificationStatus.verifyMasterKeyWithPassphrase(); verifyMasterKey.close(); } } - } - } - Connections { + function onSetupCompleted() { + successDialog.open(); + } + function onSetupFailed(m) { + failureDialog.errorMessage = m; + failureDialog.open(); + } + function onShowRecoveryKey(key) { + showRecoverKeyDialog.recoveryKey = key; + showRecoverKeyDialog.open(); + } function onStatusChanged() { console.log("STATUS CHANGED: " + SelfVerificationStatus.status); if (SelfVerificationStatus.status == SelfVerificationStatus.NoMasterKey) { @@ -285,21 +274,6 @@ Item { } } - function onShowRecoveryKey(key) { - showRecoverKeyDialog.recoveryKey = key; - showRecoverKeyDialog.open(); - } - - function onSetupCompleted() { - successDialog.open(); - } - - function onSetupFailed(m) { - failureDialog.errorMessage = m; - failureDialog.open(); - } - target: SelfVerificationStatus } - } diff --git a/resources/qml/StatusIndicator.qml b/resources/qml/StatusIndicator.qml index 862f9d7a..4a305ac5 100644 --- a/resources/qml/StatusIndicator.qml +++ b/resources/qml/StatusIndicator.qml @@ -9,15 +9,9 @@ import im.nheko 1.0 ImageButton { id: indicator - required property int status required property string eventId + required property int status - width: 16 - height: 16 - hoverEnabled: true - changeColorOnHover: (status == MtxEvent.Read) - cursor: (status == MtxEvent.Read) ? Qt.PointingHandCursor : Qt.ArrowCursor - ToolTip.visible: hovered && status != MtxEvent.Empty ToolTip.text: { switch (status) { case MtxEvent.Failed: @@ -32,11 +26,11 @@ ImageButton { return ""; } } - onClicked: { - if (status == MtxEvent.Read) - room.showReadReceipts(eventId); - - } + ToolTip.visible: hovered && status != MtxEvent.Empty + changeColorOnHover: (status == MtxEvent.Read) + cursor: (status == MtxEvent.Read) ? Qt.PointingHandCursor : Qt.ArrowCursor + height: 16 + hoverEnabled: true image: { switch (status) { case MtxEvent.Failed: @@ -51,4 +45,10 @@ ImageButton { return ""; } } + width: 16 + + onClicked: { + if (status == MtxEvent.Read) + room.showReadReceipts(eventId); + } } diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml index 07cb5ce2..a064bd15 100644 --- a/resources/qml/TimelineRow.qml +++ b/resources/qml/TimelineRow.qml @@ -13,72 +13,45 @@ import im.nheko 1.0 AbstractButton { id: r - required property double proportionalHeight - required property int type - required property string typeString - required property int originalWidth required property string blurhash required property string body - required property string formattedBody + required property string callType + required property int duration + required property int encryptionError required property string eventId required property string filename required property string filesize - required property string url - required property string thumbnailUrl - required property bool isOnlyEmoji - required property bool isSender - required property bool isEncrypted + required property string formattedBody + required property int index required property bool isEditable required property bool isEdited + required property bool isEncrypted + required property bool isOnlyEmoji + required property bool isSender required property bool isStateEvent + required property int notificationlevel + required property int originalWidth + required property double proportionalHeight + required property var reactions + required property int relatedEventCacheBuster required property string replyTo + required property string roomName + required property string roomTopic + required property int status required property string threadId + required property string thumbnailUrl + required property var timestamp + required property int trustlevel + required property int type + required property string typeString + required property string url required property string userId required property string userName - required property string roomTopic - required property string roomName - required property string callType - required property var reactions - required property int trustlevel - required property int notificationlevel - required property int encryptionError - required property int duration - required property var timestamp - required property int status - required property int index - required property int relatedEventCacheBuster + height: row.height + (reactionRow.height > 0 ? reactionRow.height - 2 : 0) + unreadRow.height hoverEnabled: true - width: parent.width - height: row.height+(reactionRow.height > 0 ? reactionRow.height-2 : 0 )+unreadRow.height - - Rectangle { - color: (Settings.messageHoverHighlight && hovered) ? palette.alternateBase : "transparent" - anchors.fill: parent - // this looks better without margins - TapHandler { - acceptedButtons: Qt.RightButton - onSingleTapped: messageContextMenu.show(eventId, threadId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText) - gesturePolicy: TapHandler.ReleaseWithinBounds - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad - } - } - - onPressAndHold: messageContextMenu.show(eventId, threadId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText) - onDoubleClicked: room.reply = eventId - - DragHandler { - id: draghandler - yAxis.enabled: false - xAxis.maximum: 100 - xAxis.minimum: -100 - onActiveChanged: { - if(!active && (x < -70 || x > 70)) - room.reply = eventId - } - } states: State { name: "dragging" when: draghandler.active @@ -86,265 +59,292 @@ AbstractButton { transitions: Transition { from: "dragging" to: "" + PropertyAnimation { - target: r - properties: "x" + duration: 100 easing.type: Easing.InOutQuad + properties: "x" + target: r to: 0 - duration: 100 } } onClicked: { - let link = contentItem.child.linkAt != undefined && contentItem.child.linkAt(pressX-row.x-msg.x, pressY-row.y-msg.y-contentItem.y); + let link = contentItem.child.linkAt != undefined && contentItem.child.linkAt(pressX - row.x - msg.x, pressY - row.y - msg.y - contentItem.y); if (link) { - Nheko.openLink(link) + Nheko.openLink(link); } } + onDoubleClicked: room.reply = eventId + onPressAndHold: messageContextMenu.show(eventId, threadId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText) + + Rectangle { + anchors.fill: parent + color: (Settings.messageHoverHighlight && hovered) ? palette.alternateBase : "transparent" + + // this looks better without margins + TapHandler { + acceptedButtons: Qt.RightButton + acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad + gesturePolicy: TapHandler.ReleaseWithinBounds + + onSingleTapped: messageContextMenu.show(eventId, threadId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText) + } + } + DragHandler { + id: draghandler + + xAxis.maximum: 100 + xAxis.minimum: -100 + yAxis.enabled: false + onActiveChanged: { + if (!active && (x < -70 || x > 70)) + room.reply = eventId; + } + } AbstractButton { - anchors.leftMargin: Settings.smallAvatars? 0 : (Nheko.avatarSize + 8) // align bubble with section header + ToolTip.delay: Nheko.tooltipDelay + ToolTip.text: qsTr("Part of a thread") + ToolTip.visible: hovered anchors.left: parent.left + anchors.leftMargin: Settings.smallAvatars ? 0 : (Nheko.avatarSize + 8) // align bubble with section header + height: parent.height visible: threadId width: 4 - height: parent.height + + onClicked: room.thread = threadId Rectangle { id: threadLine - color: TimelineManager.userColor(threadId, palette.base) anchors.fill: parent + color: TimelineManager.userColor(threadId, palette.base) } - - ToolTip.visible: hovered - ToolTip.delay: Nheko.tooltipDelay - ToolTip.text: qsTr("Part of a thread") - onClicked: room.thread = threadId } - Rectangle { id: row - property bool bubbleOnRight : isSender && Settings.bubbles - anchors.leftMargin: (isStateEvent || Settings.smallAvatars? 0 : (Nheko.avatarSize + 8)) + (threadId ? 6 : 0) // align bubble with section header - anchors.left: (isStateEvent || bubbleOnRight) ? undefined : parent.left - anchors.right: (isStateEvent || !bubbleOnRight) ? undefined : parent.right - anchors.horizontalCenter: isStateEvent? parent.horizontalCenter : undefined - property int maxWidth: (parent.width-(Settings.smallAvatars || isStateEvent? 0 : Nheko.avatarSize+8))*(Settings.bubbles && !isStateEvent? 0.9 : 1) - width: Settings.bubbles? Math.min(maxWidth,Math.max(reply.implicitWidth+8,contentItem.implicitWidth+metadata.width+20)) : maxWidth - height: msg.height+msg.anchors.margins*2 - property color userColor: TimelineManager.userColor(userId, palette.base) property color bgColor: palette.base + property bool bubbleOnRight: isSender && Settings.bubbles + property int maxWidth: (parent.width - (Settings.smallAvatars || isStateEvent ? 0 : Nheko.avatarSize + 8)) * (Settings.bubbles && !isStateEvent ? 0.9 : 1) + property color userColor: TimelineManager.userColor(userId, palette.base) + + anchors.horizontalCenter: isStateEvent ? parent.horizontalCenter : undefined + anchors.left: (isStateEvent || bubbleOnRight) ? undefined : parent.left + anchors.leftMargin: (isStateEvent || Settings.smallAvatars ? 0 : (Nheko.avatarSize + 8)) + (threadId ? 6 : 0) // align bubble with section header + anchors.right: (isStateEvent || !bubbleOnRight) ? undefined : parent.right + border.color: Nheko.theme.red + border.width: r.notificationlevel == MtxEvent.Highlight ? 1 : 0 color: (Settings.bubbles && !isStateEvent) ? Qt.tint(bgColor, Qt.hsla(userColor.hslHue, 0.5, userColor.hslLightness, 0.2)) : "#00000000" + height: msg.height + msg.anchors.margins * 2 radius: 4 - border.width: r.notificationlevel == MtxEvent.Highlight ? 1 : 0 - border.color: Nheko.theme.red + width: Settings.bubbles ? Math.min(maxWidth, Math.max(reply.implicitWidth + 8, contentItem.implicitWidth + metadata.width + 20)) : maxWidth GridLayout { + id: msg + + columnSpacing: 2 + columns: Settings.bubbles ? 1 : 2 + rowSpacing: 0 + rows: Settings.bubbles ? 3 : 2 + anchors { left: parent.left - top: parent.top - right: parent.right - margins: (Settings.bubbles && ! isStateEvent)? 4 : 2 leftMargin: 4 + margins: (Settings.bubbles && !isStateEvent) ? 4 : 2 + right: parent.right rightMargin: 4 + top: parent.top } - id: msg - rowSpacing: 0 - columnSpacing: 2 - columns: Settings.bubbles? 1 : 2 - rows: Settings.bubbles? 3 : 2 // fancy reply, if this is a reply Reply { - Layout.row: 0 - Layout.column: 0 - Layout.fillWidth: true - Layout.maximumWidth: Settings.bubbles? Number.MAX_VALUE : implicitWidth - Layout.bottomMargin: visible? 2 : 0 - Layout.preferredHeight: height id: reply function fromModel(role) { return replyTo != "" ? room.dataById(replyTo, role, r.eventId) : null; } - visible: replyTo - userColor: r.relatedEventCacheBuster, TimelineManager.userColor(userId, palette.base) + + Layout.bottomMargin: visible ? 2 : 0 + Layout.column: 0 + Layout.fillWidth: true + Layout.maximumWidth: Settings.bubbles ? Number.MAX_VALUE : implicitWidth + Layout.preferredHeight: height + Layout.row: 0 blurhash: r.relatedEventCacheBuster, fromModel(Room.Blurhash) ?? "" body: r.relatedEventCacheBuster, fromModel(Room.Body) ?? "" - formattedBody: r.relatedEventCacheBuster, fromModel(Room.FormattedBody) ?? "" + callType: r.relatedEventCacheBuster, fromModel(Room.CallType) ?? "" + duration: r.relatedEventCacheBuster, fromModel(Room.Duration) ?? 0 + encryptionError: r.relatedEventCacheBuster, fromModel(Room.EncryptionError) ?? 0 eventId: fromModel(Room.EventId) ?? "" filename: r.relatedEventCacheBuster, fromModel(Room.Filename) ?? "" filesize: r.relatedEventCacheBuster, fromModel(Room.Filesize) ?? "" + formattedBody: r.relatedEventCacheBuster, fromModel(Room.FormattedBody) ?? "" + isOnlyEmoji: r.relatedEventCacheBuster, fromModel(Room.IsOnlyEmoji) ?? false + isStateEvent: r.relatedEventCacheBuster, fromModel(Room.IsStateEvent) ?? false + originalWidth: r.relatedEventCacheBuster, fromModel(Room.OriginalWidth) ?? 0 proportionalHeight: r.relatedEventCacheBuster, fromModel(Room.ProportionalHeight) ?? 1 + relatedEventCacheBuster: r.relatedEventCacheBuster, fromModel(Room.RelatedEventCacheBuster) ?? 0 + roomName: r.relatedEventCacheBuster, fromModel(Room.RoomName) ?? "" + roomTopic: r.relatedEventCacheBuster, fromModel(Room.RoomTopic) ?? "" + thumbnailUrl: r.relatedEventCacheBuster, fromModel(Room.ThumbnailUrl) ?? "" type: r.relatedEventCacheBuster, fromModel(Room.Type) ?? MtxEvent.UnknownMessage typeString: r.relatedEventCacheBuster, fromModel(Room.TypeString) ?? "" url: r.relatedEventCacheBuster, fromModel(Room.Url) ?? "" - originalWidth: r.relatedEventCacheBuster, fromModel(Room.OriginalWidth) ?? 0 - isOnlyEmoji: r.relatedEventCacheBuster, fromModel(Room.IsOnlyEmoji) ?? false - isStateEvent: r.relatedEventCacheBuster, fromModel(Room.IsStateEvent) ?? false + userColor: r.relatedEventCacheBuster, TimelineManager.userColor(userId, palette.base) userId: r.relatedEventCacheBuster, fromModel(Room.UserId) ?? "" userName: r.relatedEventCacheBuster, fromModel(Room.UserName) ?? "" - thumbnailUrl: r.relatedEventCacheBuster, fromModel(Room.ThumbnailUrl) ?? "" - duration: r.relatedEventCacheBuster, fromModel(Room.Duration) ?? 0 - roomTopic: r.relatedEventCacheBuster, fromModel(Room.RoomTopic) ?? "" - roomName: r.relatedEventCacheBuster, fromModel(Room.RoomName) ?? "" - callType: r.relatedEventCacheBuster, fromModel(Room.CallType) ?? "" - encryptionError: r.relatedEventCacheBuster, fromModel(Room.EncryptionError) ?? 0 - relatedEventCacheBuster: r.relatedEventCacheBuster, fromModel(Room.RelatedEventCacheBuster) ?? 0 + visible: replyTo } // actual message content MessageDelegate { - Layout.row: 1 + id: contentItem + Layout.column: 0 Layout.fillWidth: true Layout.preferredHeight: height - id: contentItem - + Layout.row: 1 blurhash: r.blurhash body: r.body - formattedBody: r.formattedBody + callType: r.callType + duration: r.duration + encryptionError: r.encryptionError eventId: r.eventId filename: r.filename filesize: r.filesize + formattedBody: r.formattedBody + isOnlyEmoji: r.isOnlyEmoji + isReply: false + isStateEvent: r.isStateEvent + metadataWidth: metadata.width + originalWidth: r.originalWidth proportionalHeight: r.proportionalHeight + relatedEventCacheBuster: r.relatedEventCacheBuster + roomName: r.roomName + roomTopic: r.roomTopic + thumbnailUrl: r.thumbnailUrl type: r.type typeString: r.typeString ?? "" url: r.url - thumbnailUrl: r.thumbnailUrl - duration: r.duration - originalWidth: r.originalWidth - isOnlyEmoji: r.isOnlyEmoji - isStateEvent: r.isStateEvent userId: r.userId userName: r.userName - roomTopic: r.roomTopic - roomName: r.roomName - callType: r.callType - encryptionError: r.encryptionError - relatedEventCacheBuster: r.relatedEventCacheBuster - isReply: false - metadataWidth: metadata.width } - Row { id: metadata - Layout.column: Settings.bubbles? 0 : 1 - Layout.row: Settings.bubbles? 2 : 0 - Layout.rowSpan: Settings.bubbles? 1 : 2 - Layout.bottomMargin: -2 - Layout.topMargin: (contentItem.fitsMetadata && Settings.bubbles)? -height-Layout.bottomMargin : 0 + + property int iconSize: Math.floor(fontMetrics.ascent * scaling) + property double scaling: Settings.bubbles ? 0.75 : 1 + Layout.alignment: Qt.AlignTop | Qt.AlignRight + Layout.bottomMargin: -2 + Layout.column: Settings.bubbles ? 0 : 1 Layout.preferredWidth: implicitWidth - visible: !isStateEvent + Layout.row: Settings.bubbles ? 2 : 0 + Layout.rowSpan: Settings.bubbles ? 1 : 2 + Layout.topMargin: (contentItem.fitsMetadata && Settings.bubbles) ? -height - Layout.bottomMargin : 0 spacing: 2 - - property double scaling: Settings.bubbles? 0.75 : 1 - - property int iconSize: Math.floor(fontMetrics.ascent*scaling) + visible: !isStateEvent StatusIndicator { Layout.alignment: Qt.AlignRight | Qt.AlignTop + anchors.verticalCenter: ts.verticalCenter + eventId: r.eventId height: parent.iconSize - width: parent.iconSize status: r.status - eventId: r.eventId - anchors.verticalCenter: ts.verticalCenter + width: parent.iconSize } - Image { - visible: isEdited || eventId == room.edit Layout.alignment: Qt.AlignRight | Qt.AlignTop - height: parent.iconSize - width: parent.iconSize - sourceSize.width: parent.iconSize * Screen.devicePixelRatio - sourceSize.height: parent.iconSize * Screen.devicePixelRatio - source: "image://colorimage/:/icons/icons/ui/edit.svg?" + ((eventId == room.edit) ? palette.highlight : palette.buttonText) - ToolTip.visible: editHovered.hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: qsTr("Edited") + ToolTip.visible: editHovered.hovered anchors.verticalCenter: ts.verticalCenter + height: parent.iconSize + source: "image://colorimage/:/icons/icons/ui/edit.svg?" + ((eventId == room.edit) ? palette.highlight : palette.buttonText) + sourceSize.height: parent.iconSize * Screen.devicePixelRatio + sourceSize.width: parent.iconSize * Screen.devicePixelRatio + visible: isEdited || eventId == room.edit + width: parent.iconSize HoverHandler { id: editHovered - } + } } - ImageButton { - visible: threadId Layout.alignment: Qt.AlignRight | Qt.AlignTop - height: parent.iconSize - width: parent.iconSize - image: ":/icons/icons/ui/thread.svg" - buttonTextColor: TimelineManager.userColor(threadId, palette.base) - ToolTip.visible: hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: qsTr("Part of a thread") + ToolTip.visible: hovered anchors.verticalCenter: ts.verticalCenter + buttonTextColor: TimelineManager.userColor(threadId, palette.base) + height: parent.iconSize + image: ":/icons/icons/ui/thread.svg" + visible: threadId + width: parent.iconSize + onClicked: room.thread = threadId } - EncryptionIndicator { - visible: room.isEncrypted - encrypted: isEncrypted - trust: trustlevel Layout.alignment: Qt.AlignRight | Qt.AlignTop + anchors.verticalCenter: ts.verticalCenter + encrypted: isEncrypted height: parent.iconSize - width: parent.iconSize - sourceSize.width: parent.iconSize * Screen.devicePixelRatio sourceSize.height: parent.iconSize * Screen.devicePixelRatio - anchors.verticalCenter: ts.verticalCenter + sourceSize.width: parent.iconSize * Screen.devicePixelRatio + trust: trustlevel + visible: room.isEncrypted + width: parent.iconSize } - Label { id: ts + Layout.alignment: Qt.AlignRight | Qt.AlignTop Layout.preferredWidth: implicitWidth - text: timestamp.toLocaleTimeString(Locale.ShortFormat) - color: palette.inactive.text - ToolTip.visible: ma.hovered ToolTip.delay: Nheko.tooltipDelay ToolTip.text: Qt.formatDateTime(timestamp, Qt.DefaultLocaleLongDate) - font.pointSize: fontMetrics.font.pointSize*parent.scaling + ToolTip.visible: ma.hovered + color: palette.inactive.text + font.pointSize: fontMetrics.font.pointSize * parent.scaling + text: timestamp.toLocaleTimeString(Locale.ShortFormat) + HoverHandler { id: ma - } + } } } } } - Reactions { + id: reactionRow + + eventId: r.eventId + layoutDirection: row.bubbleOnRight ? Qt.RightToLeft : Qt.LeftToRight + reactions: r.reactions + width: row.maxWidth + anchors { + left: row.bubbleOnRight ? undefined : row.left + right: row.bubbleOnRight ? row.right : undefined top: row.bottom topMargin: -4 - left: row.bubbleOnRight? undefined : row.left - right: row.bubbleOnRight? row.right : undefined } - width: row.maxWidth - layoutDirection: row.bubbleOnRight? Qt.RightToLeft : Qt.LeftToRight - - id: reactionRow - - reactions: r.reactions - eventId: r.eventId } - Rectangle { id: unreadRow + + color: palette.highlight + height: visible ? 3 : 0 + visible: (r.index > 0 && (room.fullyReadEventId == r.eventId)) + anchors { - top: reactionRow.bottom - topMargin: 5 left: parent.left right: parent.right + top: reactionRow.bottom + topMargin: 5 } - color: palette.highlight - - visible: (r.index > 0 && (room.fullyReadEventId == r.eventId)) - height: visible ? 3 : 0 - } } diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 8fc567f2..24489d0b 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -20,86 +20,85 @@ import im.nheko.EmojiModel 1.0 Item { id: timelineView + required property PrivacyScreen privacyScreen property var room: null property var roomPreview: null - property bool showBackButton: false property bool shouldEffectsRun: false - required property PrivacyScreen privacyScreen - clip: true - - onRoomChanged: if (room != null) room.triggerSpecialEffects() - - StickerPicker { - id: emojiPopup + property bool showBackButton: false - emoji: true - } + clip: true // focus message input on key press, but not on Ctrl-C and such. - Keys.onPressed: (event) => { + Keys.onPressed: event => { if (event.text && event.key !== Qt.Key_Enter && event.key !== Qt.Key_Return && !topBar.searchHasFocus) { TimelineManager.focusMessageInput(); room.input.setText(room.input.text + event.text); } } + onRoomChanged: if (room != null) + room.triggerSpecialEffects() + + StickerPicker { + id: emojiPopup + emoji: true + } Shortcut { sequence: StandardKey.Close + onActivated: Rooms.resetCurrentRoom() } - Label { - visible: !room && !TimelineManager.isInitialSync && (!roomPreview || !roomPreview.roomid) anchors.centerIn: parent - text: qsTr("No room open") font.pointSize: 24 + text: qsTr("No room open") + visible: !room && !TimelineManager.isInitialSync && (!roomPreview || !roomPreview.roomid) } - Spinner { - visible: TimelineManager.isInitialSync anchors.centerIn: parent foreground: palette.mid - running: TimelineManager.isInitialSync // height is somewhat arbitrary here... don't set width because width scales w/ height height: parent.height / 16 - z: 3 opacity: hh.hovered ? 0.3 : 1 + running: TimelineManager.isInitialSync + visible: TimelineManager.isInitialSync + z: 3 - Behavior on opacity { - NumberAnimation { duration: 100; } + Behavior on opacity { + NumberAnimation { + duration: 100 + } } HoverHandler { id: hh + } } - ColumnLayout { id: timelineLayout - visible: room != null && !room.isSpace - enabled: visible anchors.fill: parent + enabled: visible spacing: 0 + visible: room != null && !room.isSpace TopBar { id: topBar showBackButton: timelineView.showBackButton } - Rectangle { Layout.fillWidth: true + color: Nheko.theme.separator height: 1 z: 3 - color: Nheko.theme.separator } - Rectangle { id: msgView - Layout.fillWidth: true Layout.fillHeight: true + Layout.fillWidth: true color: palette.base ColumnLayout { @@ -118,143 +117,121 @@ Item { target: timelineView } - MessageView { + Layout.fillWidth: true implicitHeight: msgView.height - typingIndicator.height searchString: topBar.searchString - Layout.fillWidth: true } - Loader { source: CallManager.isOnCall && CallManager.callType != CallType.VOICE ? "voip/VideoCall.qml" : "" + onLoaded: TimelineManager.setVideoCallItem() } - } - TypingIndicator { id: typingIndicator - } + } } - } - CallInviteBar { id: callInviteBar Layout.fillWidth: true z: 3 } - ActiveCallBar { Layout.fillWidth: true z: 3 } - Rectangle { Layout.fillWidth: true - z: 3 - height: 1 color: Nheko.theme.separator + height: 1 + z: 3 } - - UploadBox { } - MessageInputWarning { text: qsTr("You are about to notify the whole room") visible: (room && room.permissions.canPingRoom() && room.input.containsAtRoom) } - MessageInputWarning { text: qsTr("The command /%1 is not recognized and will be sent as part of your message").arg(room ? room.input.currentCommand : "") visible: room ? room.input.containsInvalidCommand && !room.input.containsIncompleteCommand : false } - MessageInputWarning { + bubbleColor: Nheko.theme.orange text: qsTr("/%1 looks like an incomplete command. To send it anyway, add a space to the end of your message.").arg(room ? room.input.currentCommand : "") visible: room ? room.input.containsIncompleteCommand : false - bubbleColor: Nheko.theme.orange } - ReplyPopup { } - MessageInput { } - } - ColumnLayout { id: preview + property string avatarUrl: room ? room.roomAvatarUrl : (roomPreview ? roomPreview.roomAvatarUrl : "") + property string reason: roomPreview ? roomPreview.reason : "" property string roomId: room ? room.roomId : (roomPreview ? roomPreview.roomid : "") property string roomName: room ? room.roomName : (roomPreview ? roomPreview.roomName : "") property string roomTopic: room ? room.roomTopic : (roomPreview ? roomPreview.roomTopic : "") - property string avatarUrl: room ? room.roomAvatarUrl : (roomPreview ? roomPreview.roomAvatarUrl : "") - property string reason: roomPreview ? roomPreview.reason : "" - visible: room != null && room.isSpace || roomPreview != null - enabled: visible anchors.fill: parent anchors.margins: Nheko.paddingLarge + enabled: visible spacing: Nheko.paddingLarge + visible: room != null && room.isSpace || roomPreview != null Item { Layout.fillHeight: true } - Avatar { - url: parent.avatarUrl.replace("mxc://", "image://MxcImage/") - roomid: parent.roomId + Layout.alignment: Qt.AlignHCenter displayName: parent.roomName + enabled: false height: 130 + roomid: parent.roomId + url: parent.avatarUrl.replace("mxc://", "image://MxcImage/") width: 130 - Layout.alignment: Qt.AlignHCenter - enabled: false } - RowLayout { - spacing: Nheko.paddingMedium Layout.alignment: Qt.AlignHCenter + spacing: Nheko.paddingMedium MatrixText { - text: !(roomPreview?.isFetched ?? false) ? qsTr("No preview available") : preview.roomName font.pixelSize: 24 + text: !(roomPreview?.isFetched ?? false) ? qsTr("No preview available") : preview.roomName } - ImageButton { + ToolTip.text: qsTr("Settings") + ToolTip.visible: hovered + hoverEnabled: true image: ":/icons/icons/ui/settings.svg" visible: !!room - hoverEnabled: true - ToolTip.visible: hovered - ToolTip.text: qsTr("Settings") + onClicked: TimelineManager.openRoomSettings(room.roomId) } - } - RowLayout { - visible: !!room - spacing: Nheko.paddingMedium Layout.alignment: Qt.AlignHCenter + spacing: Nheko.paddingMedium + visible: !!room MatrixText { text: qsTr("%n member(s)", "", room ? room.roomMemberCount : 0) } - ImageButton { - image: ":/icons/icons/ui/people.svg" - hoverEnabled: true - ToolTip.visible: hovered ToolTip.text: qsTr("View members of %1").arg(room ? room.roomName : "") + ToolTip.visible: hovered + hoverEnabled: true + image: ":/icons/icons/ui/people.svg" + onClicked: TimelineManager.openRoomMembers(room) } - } - ScrollView { Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true @@ -262,54 +239,53 @@ Item { Layout.rightMargin: Nheko.paddingLarge TextArea { - text: (roomPreview?.isFetched ?? false) ? TimelineManager.escapeEmoji(preview.roomTopic) : qsTr("This room is possibly inaccessible. If this room is private, you should remove it from this community.") - wrapMode: TextEdit.WordWrap - textFormat: TextEdit.RichText - readOnly: true background: null - selectByMouse: true horizontalAlignment: TextEdit.AlignHCenter + readOnly: true + selectByMouse: true + text: (roomPreview?.isFetched ?? false) ? TimelineManager.escapeEmoji(preview.roomTopic) : qsTr("This room is possibly inaccessible. If this room is private, you should remove it from this community.") + textFormat: TextEdit.RichText + wrapMode: TextEdit.WordWrap + onLinkActivated: Nheko.openLink(link) CursorShape { anchors.fill: parent cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor } - } - } - FlatButton { - visible: roomPreview && !roomPreview.isInvite Layout.alignment: Qt.AlignHCenter text: qsTr("join the conversation") + visible: roomPreview && !roomPreview.isInvite + onClicked: Rooms.joinPreview(roomPreview.roomid) } - FlatButton { - visible: roomPreview && roomPreview.isInvite Layout.alignment: Qt.AlignHCenter text: qsTr("accept invite") + visible: roomPreview && roomPreview.isInvite + onClicked: Rooms.acceptInvite(roomPreview.roomid) } - FlatButton { - visible: roomPreview && roomPreview.isInvite Layout.alignment: Qt.AlignHCenter text: qsTr("decline invite") + visible: roomPreview && roomPreview.isInvite + onClicked: Rooms.declineInvite(roomPreview.roomid) } - FlatButton { - visible: !!room Layout.alignment: Qt.AlignHCenter text: qsTr("leave") + visible: !!room + onClicked: TimelineManager.openLeaveRoomDialog(room.roomId) } - ScrollView { id: reasonField + property bool showReason: false Layout.alignment: Qt.AlignHCenter @@ -319,17 +295,15 @@ Item { visible: preview.reason !== "" && showReason TextArea { - text: TimelineManager.escapeEmoji(preview.reason) - wrapMode: TextEdit.WordWrap - textFormat: TextEdit.RichText - readOnly: true background: null - selectByMouse: true horizontalAlignment: TextEdit.AlignHCenter + readOnly: true + selectByMouse: true + text: TimelineManager.escapeEmoji(preview.reason) + textFormat: TextEdit.RichText + wrapMode: TextEdit.WordWrap } - } - Button { id: showReasonButton @@ -337,76 +311,94 @@ Item { //Layout.fillWidth: true Layout.leftMargin: Nheko.paddingLarge Layout.rightMargin: Nheko.paddingLarge - - visible: preview.reason !== "" text: reasonField.showReason ? qsTr("Hide invite reason") : qsTr("Show invite reason") + visible: preview.reason !== "" + onClicked: { reasonField.showReason = !reasonField.showReason; } } - Item { - visible: room != null Layout.preferredHeight: Math.ceil(fontMetrics.lineSpacing * 2) + visible: room != null } - Item { Layout.fillHeight: true } - } - ImageButton { id: backToRoomsButton - anchors.top: parent.top + ToolTip.text: qsTr("Back to room list") + ToolTip.visible: hovered anchors.left: parent.left anchors.margins: Nheko.paddingMedium - width: Nheko.avatarSize - height: Nheko.avatarSize - visible: (room == null || room.isSpace) && showBackButton + anchors.top: parent.top enabled: visible + height: Nheko.avatarSize image: ":/icons/icons/ui/angle-arrow-left.svg" - ToolTip.visible: hovered - ToolTip.text: qsTr("Back to room list") + visible: (room == null || room.isSpace) && showBackButton + width: Nheko.avatarSize + onClicked: Rooms.resetCurrentRoom() } - TimelineEffects { id: timelineEffects anchors.fill: parent } - NhekoDropArea { anchors.fill: parent roomid: room ? room.roomId : "" } - Timer { id: effectsTimer - onTriggered: shouldEffectsRun = false; + interval: timelineEffects.maxLifespan repeat: false running: false - } + onTriggered: shouldEffectsRun = false + } Connections { + function onConfetti() { + if (!Settings.fancyEffects) + return; + shouldEffectsRun = true; + timelineEffects.pulseConfetti(); + room.markSpecialEffectsDone(); + } + function onConfettiDone() { + if (!Settings.fancyEffects) + return; + effectsTimer.restart(); + } function onOpenReadReceiptsDialog(rr) { var dialog = readReceiptsDialog.createObject(timelineRoot, { - "readReceipts": rr, - "room": room - }); + "readReceipts": rr, + "room": room + }); dialog.show(); timelineRoot.destroyOnClose(dialog); } - + function onRainfall() { + if (!Settings.fancyEffects) + return; + shouldEffectsRun = true; + timelineEffects.pulseRainfall(); + room.markSpecialEffectsDone(); + } + function onRainfallDone() { + if (!Settings.fancyEffects) + return; + effectsTimer.restart(); + } function onShowRawMessageDialog(rawMessage) { - var component = Qt.createComponent("qrc:/qml/dialogs/RawMessageDialog.qml") + var component = Qt.createComponent("qrc:/qml/dialogs/RawMessageDialog.qml"); if (component.status == Component.Ready) { var dialog = component.createObject(timelineRoot, { - "rawMessage": rawMessage - }); + "rawMessage": rawMessage + }); dialog.show(); timelineRoot.destroyOnClose(dialog); } else { @@ -414,43 +406,6 @@ Item { } } - function onConfetti() - { - if (!Settings.fancyEffects) - return - - shouldEffectsRun = true; - timelineEffects.pulseConfetti() - room.markSpecialEffectsDone() - } - - function onConfettiDone() - { - if (!Settings.fancyEffects) - return - - effectsTimer.restart(); - } - - function onRainfall() - { - if (!Settings.fancyEffects) - return - - shouldEffectsRun = true; - timelineEffects.pulseRainfall() - room.markSpecialEffectsDone() - } - - function onRainfallDone() - { - if (!Settings.fancyEffects) - return - - effectsTimer.restart(); - } - target: room } - } diff --git a/resources/qml/ToggleButton.qml b/resources/qml/ToggleButton.qml index 66902bfd..f3bd5cce 100644 --- a/resources/qml/ToggleButton.qml +++ b/resources/qml/ToggleButton.qml @@ -11,17 +11,44 @@ Switch { id: toggleButton implicitWidth: indicatorItem.width - state: checked ? "on" : "off" + + indicator: Item { + id: indicatorItem + + implicitHeight: 24 + implicitWidth: 48 + y: parent.height / 2 - height / 2 + + Rectangle { + id: track + + color: Qt.rgba(border.color.r, border.color.g, border.color.b, 0.6) + height: parent.height * 0.6 + radius: height / 2 + width: parent.width - height + x: radius + y: parent.height / 2 - height / 2 + } + Rectangle { + id: handle + + border.color: "#767676" + color: palette.button + height: width + radius: width / 2 + width: parent.height * 0.9 + y: parent.height / 2 - height / 2 + } + } states: [ State { name: "off" PropertyChanges { - target: track border.color: "#767676" + target: track } - PropertyChanges { target: handle x: 0 @@ -31,10 +58,9 @@ Switch { name: "on" PropertyChanges { - target: track border.color: palette.highlight + target: track } - PropertyChanges { target: handle x: indicatorItem.width - handle.width @@ -43,55 +69,22 @@ Switch { ] transitions: [ Transition { - to: "off" reversible: true + to: "off" ParallelAnimation { NumberAnimation { - target: handle - property: "x" duration: 200 easing.type: Easing.InOutQuad + property: "x" + target: handle } - ColorAnimation { - target: track - properties: "color,border.color" duration: 200 + properties: "color,border.color" + target: track } } } ] - - indicator: Item { - id: indicatorItem - - implicitWidth: 48 - implicitHeight: 24 - y: parent.height / 2 - height / 2 - - Rectangle { - id: track - - height: parent.height * 0.6 - radius: height / 2 - width: parent.width - height - x: radius - y: parent.height / 2 - height / 2 - color: Qt.rgba(border.color.r, border.color.g, border.color.b, 0.6) - } - - Rectangle { - id: handle - - y: parent.height / 2 - height / 2 - width: parent.height * 0.9 - height: width - radius: width / 2 - color: palette.button - border.color: "#767676" - } - - } - } diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index a54c5ed7..3f2d8d2a 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -8,212 +8,142 @@ import QtQuick.Controls 2.15 import QtQuick.Layouts 1.2 import QtQuick.Window 2.15 import im.nheko 1.0 - import "./delegates" Pane { id: topBar - property bool showBackButton: false - property string roomName: room ? room.roomName : qsTr("No room selected") - property string roomId: room ? room.roomId : "" property string avatarUrl: room ? room.roomAvatarUrl : "" - property string roomTopic: room ? room.roomTopic : "" - property bool isEncrypted: room ? room.isEncrypted : false - property int trustlevel: room ? room.trustlevel : Crypto.Unverified - property bool isDirect: room ? room.isDirect : false property string directChatOtherUserId: room ? room.directChatOtherUserId : "" - + property bool isDirect: room ? room.isDirect : false + property bool isEncrypted: room ? room.isEncrypted : false + property string roomId: room ? room.roomId : "" + property string roomName: room ? room.roomName : qsTr("No room selected") + property string roomTopic: room ? room.roomTopic : "" property bool searchHasFocus: searchField.focus && searchField.enabled - property string searchString: "" - - // HACK: https://bugreports.qt.io/browse/QTBUG-83972, qtwayland cannot auto hide menu - Connections { - function onHideMenu() { - roomOptionsMenu.close() - } - target: MainWindow - } - - onRoomIdChanged: { - searchString = ""; - searchButton.searchActive = false; - searchField.text = "" - } - - Shortcut { - sequence: StandardKey.Find - onActivated: searchButton.searchActive = !searchButton.searchActive - } + property bool showBackButton: false + property int trustlevel: room ? room.trustlevel : Crypto.Unverified Layout.fillWidth: true implicitHeight: topLayout.height + Nheko.paddingMedium * 2 + padding: 0 z: 3 - padding: 0 background: Rectangle { color: palette.window } - - TapHandler { - onSingleTapped: { - if (eventPoint.position.y > topBar.height - (pinnedMessages.visible ? pinnedMessages.height : 0) - (widgets.visible ? widgets.height : 0)) { - eventPoint.accepted = true - return; - } - if (showBackButton && eventPoint.position.x < Nheko.paddingMedium + backToRoomsButton.width) { - eventPoint.accepted = true - return; - } - if (eventPoint.position.x > topBar.width - Nheko.paddingMedium - roomOptionsButton.width) { - eventPoint.accepted = true - return; - } - - if (communityLabel.visible && eventPoint.position.y < communityAvatar.height + Nheko.paddingMedium + Nheko.paddingSmall/2) { - if (!Communities.trySwitchToSpace(room.parentSpace.roomid)) - room.parentSpace.promptJoin(); - eventPoint.accepted = true - return; - } - - if (room) { - let p = topBar.mapToItem(roomTopicC, eventPoint.position.x, eventPoint.position.y); - let link = roomTopicC.linkAt(p.x, p.y); - - if (link) { - Nheko.openLink(link); - } else { - TimelineManager.openRoomSettings(room.roomId); - } - } - - eventPoint.accepted = true; - } - gesturePolicy: TapHandler.ReleaseWithinBounds - } - - HoverHandler { - grabPermissions: PointerHandler.TakeOverForbidden | PointerHandler.CanTakeOverFromAnything - } - contentItem: Item { GridLayout { id: topLayout anchors.left: parent.left - anchors.right: parent.right anchors.margins: Nheko.paddingMedium + anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter columnSpacing: Nheko.paddingSmall rowSpacing: Nheko.paddingSmall - Avatar { id: communityAvatar - visible: roomid && room.parentSpace.isLoaded && ("space:"+room.parentSpace.roomid != Communities.currentTagId) - property string avatarUrl: (Settings.groupView && room && room.parentSpace && room.parentSpace.roomAvatarUrl) || "" property string communityId: (Settings.groupView && room && room.parentSpace && room.parentSpace.roomid) || "" property string communityName: (Settings.groupView && room && room.parentSpace && room.parentSpace.roomName) || "" + Layout.alignment: Qt.AlignRight Layout.column: 1 Layout.row: 0 - Layout.alignment: Qt.AlignRight - width: fontMetrics.lineSpacing - height: fontMetrics.lineSpacing - url: avatarUrl.replace("mxc://", "image://MxcImage/") - roomid: communityId displayName: communityName enabled: false + height: fontMetrics.lineSpacing + roomid: communityId + url: avatarUrl.replace("mxc://", "image://MxcImage/") + visible: roomid && room.parentSpace.isLoaded && ("space:" + room.parentSpace.roomid != Communities.currentTagId) + width: fontMetrics.lineSpacing } - Label { id: communityLabel - visible: communityAvatar.visible Layout.column: 2 - Layout.row: 0 Layout.fillWidth: true + Layout.row: 0 color: palette.text - text: qsTr("In %1").arg(communityAvatar.displayName) - maximumLineCount: 1 elide: Text.ElideRight + maximumLineCount: 1 + text: qsTr("In %1").arg(communityAvatar.displayName) textFormat: Text.RichText + visible: communityAvatar.visible } - ImageButton { id: backToRoomsButton - Layout.column: 0 - Layout.row: 1 - Layout.rowSpan: 2 Layout.alignment: Qt.AlignVCenter + Layout.column: 0 Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium - visible: showBackButton - image: ":/icons/icons/ui/angle-arrow-left.svg" - ToolTip.visible: hovered + Layout.row: 1 + Layout.rowSpan: 2 ToolTip.text: qsTr("Back to room list") + ToolTip.visible: hovered + image: ":/icons/icons/ui/angle-arrow-left.svg" + visible: showBackButton + onClicked: Rooms.resetCurrentRoom() } - Avatar { + Layout.alignment: Qt.AlignVCenter Layout.column: 1 Layout.row: 1 Layout.rowSpan: 2 - Layout.alignment: Qt.AlignVCenter - width: Nheko.avatarSize + displayName: roomName + enabled: false height: Nheko.avatarSize - url: avatarUrl.replace("mxc://", "image://MxcImage/") roomid: roomId + url: avatarUrl.replace("mxc://", "image://MxcImage/") userid: isDirect ? directChatOtherUserId : "" - displayName: roomName - enabled: false + width: Nheko.avatarSize } - Label { - Layout.fillWidth: true Layout.column: 2 + Layout.fillWidth: true Layout.row: 1 color: palette.text - font.pointSize: fontMetrics.font.pointSize * 1.1 + elide: Text.ElideRight font.bold: true - text: roomName + font.pointSize: fontMetrics.font.pointSize * 1.1 maximumLineCount: 1 - elide: Text.ElideRight + text: roomName textFormat: Text.RichText } - MatrixText { id: roomTopicC - Layout.fillWidth: true + Layout.column: 2 - Layout.row: 2 + Layout.fillWidth: true Layout.maximumHeight: fontMetrics.lineSpacing * 2 // show 2 lines - selectByMouse: false - enabled: false + Layout.row: 2 clip: true + enabled: false + selectByMouse: false text: roomTopic } - ImageButton { id: pinButton property bool pinsShown: !Settings.hiddenPins.includes(roomId) - visible: !!room && room.pinnedMessages.length > 0 - Layout.column: 3 - Layout.row: 1 - Layout.rowSpan: 2 Layout.alignment: Qt.AlignVCenter + Layout.column: 3 Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium - image: pinsShown ? ":/icons/icons/ui/pin.svg" : ":/icons/icons/ui/pin-off.svg" - ToolTip.visible: hovered + Layout.row: 1 + Layout.rowSpan: 2 ToolTip.text: qsTr("Show or hide pinned messages") + ToolTip.visible: hovered + image: pinsShown ? ":/icons/icons/ui/pin.svg" : ":/icons/icons/ui/pin-off.svg" + visible: !!room && room.pinnedMessages.length > 0 + onClicked: { var ps = Settings.hiddenPins; if (pinsShown) { @@ -226,242 +156,280 @@ Pane { } Settings.hiddenPins = ps; } - } - AbstractButton { Layout.column: 4 - Layout.row: 1 - Layout.rowSpan: 2 Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium + Layout.row: 1 + Layout.rowSpan: 2 + background: null contentItem: EncryptionIndicator { - encrypted: isEncrypted - trust: trustlevel - enabled: false - unencryptedIcon: ":/icons/icons/ui/people.svg" - unencryptedColor: palette.buttonText - unencryptedHoverColor: palette.highlight - hovered: parent.hovered - ToolTip.delay: Nheko.tooltipDelay ToolTip.text: { if (!isEncrypted) - return qsTr("Show room members."); - + return qsTr("Show room members."); switch (trustlevel) { - case Crypto.Verified: + case Crypto.Verified: return qsTr("This room contains only verified devices."); - case Crypto.TOFU: + case Crypto.TOFU: return qsTr("This room contains verified devices and devices which have never changed their master key."); - default: + default: return qsTr("This room contains unverified devices!"); } } + enabled: false + encrypted: isEncrypted + hovered: parent.hovered + trust: trustlevel + unencryptedColor: palette.buttonText + unencryptedHoverColor: palette.highlight + unencryptedIcon: ":/icons/icons/ui/people.svg" } - background: null onClicked: TimelineManager.openRoomMembers(room) } - ImageButton { id: searchButton property bool searchActive: false - visible: !!room - Layout.column: 5 - Layout.row: 1 - Layout.rowSpan: 2 Layout.alignment: Qt.AlignVCenter + Layout.column: 5 Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium - image: ":/icons/icons/ui/search.svg" - ToolTip.visible: hovered + Layout.row: 1 + Layout.rowSpan: 2 ToolTip.text: qsTr("Search this room") - onClicked: searchActive = !searchActive + ToolTip.visible: hovered + image: ":/icons/icons/ui/search.svg" + visible: !!room + onClicked: searchActive = !searchActive onSearchActiveChanged: { if (searchActive) { searchField.forceActiveFocus(); - } - else { + } else { searchField.clear(); topBar.searchString = ""; } } } - ImageButton { id: roomOptionsButton - visible: !!room - Layout.column: 6 - Layout.row: 1 - Layout.rowSpan: 2 Layout.alignment: Qt.AlignVCenter + Layout.column: 6 Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium - image: ":/icons/icons/ui/options.svg" - ToolTip.visible: hovered + Layout.row: 1 + Layout.rowSpan: 2 ToolTip.text: qsTr("Room options") + ToolTip.visible: hovered + image: ":/icons/icons/ui/options.svg" + visible: !!room + onClicked: roomOptionsMenu.open(roomOptionsButton) Platform.Menu { id: roomOptionsMenu Platform.MenuItem { - visible: room ? room.permissions.canInvite() : false text: qsTr("Invite users") + visible: room ? room.permissions.canInvite() : false + onTriggered: TimelineManager.openInviteUsers(roomId) } - Platform.MenuItem { text: qsTr("Members") + onTriggered: TimelineManager.openRoomMembers(room) } - Platform.MenuItem { text: qsTr("Leave room") + onTriggered: TimelineManager.openLeaveRoomDialog(roomId) } - Platform.MenuItem { text: qsTr("Settings") + onTriggered: TimelineManager.openRoomSettings(roomId) } - } - } - ScrollView { id: pinnedMessages - Layout.row: 3 Layout.column: 2 Layout.columnSpan: 4 - Layout.fillWidth: true Layout.preferredHeight: Math.min(contentHeight, Nheko.avatarSize * 4) - - visible: !!room && room.pinnedMessages.length > 0 && !Settings.hiddenPins.includes(roomId) - clip: true - + Layout.row: 3 ScrollBar.horizontal.visible: false + clip: true + visible: !!room && room.pinnedMessages.length > 0 && !Settings.hiddenPins.includes(roomId) ListView { - - spacing: Nheko.paddingSmall model: room ? room.pinnedMessages : undefined + spacing: Nheko.paddingSmall + delegate: RowLayout { required property string modelData - width: ListView.view.width height: implicitHeight + width: ListView.view.width Reply { id: reply + property var e: room ? room.getDump(modelData, "pins") : {} - Connections { - function onPinnedMessagesChanged() { reply.e = room.getDump(modelData, "pins") } - target: room - } + Layout.fillWidth: true Layout.preferredHeight: height - - userColor: TimelineManager.userColor(e.userId, palette.window) blurhash: e.blurhash ?? "" body: e.body ?? "" - formattedBody: e.formattedBody ?? "" + encryptionError: e.encryptionError ?? 0 eventId: e.eventId ?? "" filename: e.filename ?? "" filesize: e.filesize ?? "" + formattedBody: e.formattedBody ?? "" + isOnlyEmoji: e.isOnlyEmoji ?? false + keepFullText: true + originalWidth: e.originalWidth ?? 0 proportionalHeight: e.proportionalHeight ?? 1 type: e.type ?? MtxEvent.UnknownMessage typeString: e.typeString ?? "" url: e.url ?? "" - originalWidth: e.originalWidth ?? 0 - isOnlyEmoji: e.isOnlyEmoji ?? false + userColor: TimelineManager.userColor(e.userId, palette.window) userId: e.userId ?? "" userName: e.userName ?? "" - encryptionError: e.encryptionError ?? 0 - keepFullText: true - } + Connections { + function onPinnedMessagesChanged() { + reply.e = room.getDump(modelData, "pins"); + } + + target: room + } + } ImageButton { id: deletePinButton + Layout.alignment: Qt.AlignTop | Qt.AlignLeft Layout.preferredHeight: 16 Layout.preferredWidth: 16 - Layout.alignment: Qt.AlignTop | Qt.AlignLeft - visible: room.permissions.canChange(MtxEvent.PinnedEvents) - + ToolTip.text: qsTr("Unpin") + ToolTip.visible: hovered hoverEnabled: true image: ":/icons/icons/ui/dismiss.svg" - ToolTip.visible: hovered - ToolTip.text: qsTr("Unpin") + visible: room.permissions.canChange(MtxEvent.PinnedEvents) onClicked: room.unpin(modelData) } } - - } } - ScrollView { id: widgets - Layout.row: 4 Layout.column: 2 Layout.columnSpan: 4 - Layout.fillWidth: true Layout.preferredHeight: Math.min(contentHeight, Nheko.avatarSize * 1.5) - - visible: !!room && room.widgetLinks.length > 0 && !Settings.hiddenWidgets.includes(roomId) - clip: true - + Layout.row: 4 ScrollBar.horizontal.visible: false + clip: true + visible: !!room && room.widgetLinks.length > 0 && !Settings.hiddenWidgets.includes(roomId) ListView { - - spacing: Nheko.paddingSmall model: room ? room.widgetLinks : undefined + spacing: Nheko.paddingSmall + delegate: MatrixText { required property var modelData color: palette.text text: modelData } - - } } - MatrixTextField { id: searchField - visible: searchButton.searchActive - enabled: visible - hasClear: true - Layout.row: 5 Layout.column: 2 Layout.columnSpan: 4 - Layout.fillWidth: true - + Layout.row: 5 + enabled: visible + hasClear: true placeholderText: qsTr("Enter search query") + visible: searchButton.searchActive + onAccepted: topBar.searchString = text } } - CursorShape { - anchors.fill: parent anchors.bottomMargin: (pinnedMessages.visible ? pinnedMessages.height : 0) + (widgets.visible ? widgets.height : 0) + anchors.fill: parent cursorShape: Qt.PointingHandCursor } } + + onRoomIdChanged: { + searchString = ""; + searchButton.searchActive = false; + searchField.text = ""; + } + + // HACK: https://bugreports.qt.io/browse/QTBUG-83972, qtwayland cannot auto hide menu + Connections { + function onHideMenu() { + roomOptionsMenu.close(); + } + + target: MainWindow + } + Shortcut { + sequence: StandardKey.Find + + onActivated: searchButton.searchActive = !searchButton.searchActive + } + TapHandler { + gesturePolicy: TapHandler.ReleaseWithinBounds + + onSingleTapped: { + if (eventPoint.position.y > topBar.height - (pinnedMessages.visible ? pinnedMessages.height : 0) - (widgets.visible ? widgets.height : 0)) { + eventPoint.accepted = true; + return; + } + if (showBackButton && eventPoint.position.x < Nheko.paddingMedium + backToRoomsButton.width) { + eventPoint.accepted = true; + return; + } + if (eventPoint.position.x > topBar.width - Nheko.paddingMedium - roomOptionsButton.width) { + eventPoint.accepted = true; + return; + } + if (communityLabel.visible && eventPoint.position.y < communityAvatar.height + Nheko.paddingMedium + Nheko.paddingSmall / 2) { + if (!Communities.trySwitchToSpace(room.parentSpace.roomid)) + room.parentSpace.promptJoin(); + eventPoint.accepted = true; + return; + } + if (room) { + let p = topBar.mapToItem(roomTopicC, eventPoint.position.x, eventPoint.position.y); + let link = roomTopicC.linkAt(p.x, p.y); + if (link) { + Nheko.openLink(link); + } else { + TimelineManager.openRoomSettings(room.roomId); + } + } + eventPoint.accepted = true; + } + } + HoverHandler { + grabPermissions: PointerHandler.TakeOverForbidden | PointerHandler.CanTakeOverFromAnything + } } diff --git a/resources/qml/TypingIndicator.qml b/resources/qml/TypingIndicator.qml index 704fe8ef..b6c502d8 100644 --- a/resources/qml/TypingIndicator.qml +++ b/resources/qml/TypingIndicator.qml @@ -8,30 +8,28 @@ import QtQuick.Layouts 1.2 import im.nheko 1.0 Item { - implicitHeight: Math.max(fontMetrics.height * 1.2, typingDisplay.height) Layout.fillWidth: true + implicitHeight: Math.max(fontMetrics.height * 1.2, typingDisplay.height) Rectangle { id: typingRect - visible: (room && room.typingUsers.length > 0) - color: palette.base anchors.fill: parent + color: palette.base + visible: (room && room.typingUsers.length > 0) z: 3 Label { id: typingDisplay + anchors.bottom: parent.bottom anchors.left: parent.left anchors.leftMargin: 10 anchors.right: parent.right anchors.rightMargin: 10 - anchors.bottom: parent.bottom color: palette.text text: room ? room.formatTypingUsers(room.typingUsers, palette.base) : "" textFormat: Text.RichText } - } - } diff --git a/resources/qml/UploadBox.qml b/resources/qml/UploadBox.qml index ccec6131..54007163 100644 --- a/resources/qml/UploadBox.qml +++ b/resources/qml/UploadBox.qml @@ -4,7 +4,6 @@ import "./components" import "./ui" - import QtQuick 2.9 import QtQuick.Controls 2.5 import QtQuick.Layouts 1.3 @@ -12,31 +11,33 @@ import im.nheko 1.0 Page { id: uploadPopup - visible: room && room.input.uploads.length > 0 - Layout.preferredHeight: 200 - clip: true Layout.fillWidth: true - + Layout.preferredHeight: 200 + clip: true padding: Nheko.paddingMedium + visible: room && room.input.uploads.length > 0 + background: Rectangle { + color: palette.base + } contentItem: ListView { id: uploadsList + anchors.horizontalCenter: parent.horizontalCenter boundsBehavior: Flickable.StopAtBounds + model: room ? room.input.uploads : undefined + orientation: ListView.Horizontal + spacing: Nheko.paddingMedium + width: Math.min(contentWidth, parent.availableWidth) ScrollBar.horizontal: ScrollBar { id: scr - } - - orientation: ListView.Horizontal - width: Math.min(contentWidth, parent.availableWidth) - model: room ? room.input.uploads : undefined - spacing: Nheko.paddingMedium + } delegate: Pane { + height: uploadPopup.availableHeight - buttons.height - (scr.visible ? scr.height : 0) padding: Nheko.paddingSmall - height: uploadPopup.availableHeight - buttons.height - (scr.visible? scr.height : 0) width: uploadPopup.availableHeight - buttons.height background: Rectangle { @@ -45,46 +46,48 @@ Page { } contentItem: ColumnLayout { Image { + property string typeStr: switch (modelData.mediaType) { + case MediaUpload.Video: + return "video-file"; + case MediaUpload.Audio: + return "music"; + case MediaUpload.Image: + return "image"; + default: + return "zip"; + } + Layout.fillHeight: true Layout.fillWidth: true - - sourceSize.height: parent.availableHeight - namefield.height - sourceSize.width: parent.availableWidth fillMode: Image.PreserveAspectFit - smooth: true mipmap: true - - property string typeStr: switch(modelData.mediaType) { - case MediaUpload.Video: return "video-file"; - case MediaUpload.Audio: return "music"; - case MediaUpload.Image: return "image"; - default: return "zip"; - } - source: (modelData.thumbnail != "") ? modelData.thumbnail : ("image://colorimage/:/icons/icons/ui/"+typeStr+".svg?" + palette.buttonText) + smooth: true + source: (modelData.thumbnail != "") ? modelData.thumbnail : ("image://colorimage/:/icons/icons/ui/" + typeStr + ".svg?" + palette.buttonText) + sourceSize.height: parent.availableHeight - namefield.height + sourceSize.width: parent.availableWidth } MatrixTextField { id: namefield + Layout.fillWidth: true text: modelData.filename + onTextEdited: modelData.filename = text } } } } - footer: DialogButtonBox { id: buttons standardButtons: DialogButtonBox.Cancel - Button { - text: qsTr("Upload %n file(s)", "", (room ? room.input.uploads.length : 0)) - DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole - } + onAccepted: room.input.acceptUploads() onRejected: room.input.declineUploads() - } - background: Rectangle { - color: palette.base + Button { + DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole + text: qsTr("Upload %n file(s)", "", (room ? room.input.uploads.length : 0)) + } } } From 9ce1e205e641ea50e61213def5547a500832ac70 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 02:23:47 +0200 Subject: [PATCH 048/128] Improve timestamp layouting in room list --- resources/qml/RoomList.qml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index b41696e0..36c366a9 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -539,13 +539,12 @@ Page { id: textContent Layout.alignment: Qt.AlignLeft - Layout.fillWidth: true Layout.minimumWidth: 100 Layout.preferredWidth: parent.width - avatar.width height: avatar.height spacing: Nheko.paddingSmall visible: !collapsed - width: parent.width - avatar.width + width: roomItem.width - avatar.width NotificationBubble { id: notificationBubble @@ -565,28 +564,29 @@ Page { id: titleRow Layout.alignment: Qt.AlignTop - Layout.fillWidth: true + Layout.preferredWidth: roomItem.width - avatar.width spacing: Nheko.paddingSmall - ElidedLabel { - id: rN - - Layout.alignment: Qt.AlignBaseline + Item { Layout.fillWidth: true - color: roomItem.importantText - elideWidth: width - fullText: TimelineManager.htmlEscape(roomName) - textFormat: Text.RichText + Layout.alignment: Qt.AlignBottom + + ElidedLabel { + anchors.bottom: parent.bottom + color: roomItem.importantText + elideWidth: parent.width + fullText: TimelineManager.htmlEscape(roomName) + textFormat: Text.RichText + } } Label { id: timestamp - Layout.alignment: Qt.AlignRight | Qt.AlignBaseline + Layout.alignment: Qt.AlignRight | Qt.AlignBottom color: roomItem.unimportantText font.pixelSize: fontMetrics.font.pixelSize * 0.9 text: time visible: !isInvite && !isSpace - width: visible ? 0 : undefined } } RowLayout { From 8e61596d157880b4b7b96518c33faf947370d8aa Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 02:50:54 +0200 Subject: [PATCH 049/128] Fix message height --- resources/qml/MessageView.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index 57bfe216..a38a2f49 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -103,7 +103,7 @@ Item { ListView.delayRemove: true anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined - height: section.active ? section.height + timelinerow.height : timelinerow.height + height: (section.item?.height ?? 0) + timelinerow.height width: chat.delegateMaxWidth Loader { @@ -506,7 +506,6 @@ Item { Column { bottomPadding: Settings.bubbles ? (isSender && previousMessageDay == day ? 0 : 2) : 3 - height: ((previousMessageDay !== day) ? dateBubble.height : 0) + (isStateEvent ? 0 : userName.height + 8) spacing: 8 topPadding: userName_.visible ? 4 : 0 visible: (previousMessageUserId !== userId || previousMessageDay !== day || isStateEvent !== previousMessageIsStateEvent) From e09188c4d08e46bd51aac21701f97ddcd6e0629a Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 02:51:37 +0200 Subject: [PATCH 050/128] Remove style sheets --- resources/res.qrc | 5 --- resources/styles/nheko-dark.qss | 77 --------------------------------- resources/styles/nheko.qss | 68 ----------------------------- resources/styles/system.qss | 39 ----------------- src/UserSettingsPage.cpp | 17 +------- 5 files changed, 2 insertions(+), 204 deletions(-) delete mode 100644 resources/styles/nheko-dark.qss delete mode 100644 resources/styles/nheko.qss delete mode 100644 resources/styles/system.qss diff --git a/resources/res.qrc b/resources/res.qrc index 841f956e..ed32b2bf 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -90,11 +90,6 @@ nheko-32.png nheko-16.png - - styles/system.qss - styles/nheko.qss - styles/nheko-dark.qss - qtquickcontrols2.conf qml/Root.qml diff --git a/resources/styles/nheko-dark.qss b/resources/styles/nheko-dark.qss deleted file mode 100644 index 597397cd..00000000 --- a/resources/styles/nheko-dark.qss +++ /dev/null @@ -1,77 +0,0 @@ -TextLabel, -QLabel { - color: #caccd1; -} - -TextLabel::a { - color: #38a3d8; -} - -QuickSwitcher, -ReplyPopup, -SuggestionsPopup, -UserSettingsPage, -#scroll_widget, -#UserSettingScrollWidget { - background-color: #202228; -} - -QLineEdit, -EditModal, -dialogs--ReCaptcha, -dialogs--JoinRoom { - background-color: #202228; - color: #caccd1; -} - -PopupItem { - background-color: #202228; - qproperty-hoverColor: rgba(45, 49, 57, 120); -} - -FlatButton { - qproperty-foregroundColor: #727274; - qproperty-backgroundColor: #333; - qproperty-disabledForegroundColor: #222; -} - -RaisedButton { - qproperty-foregroundColor: #caccd1; - qproperty-backgroundColor: #333; -} - -FloatingButton { - qproperty-backgroundColor: #2d3139; - qproperty-foregroundColor: white; -} - -TextField { - qproperty-backgroundColor: #202228; - qproperty-inkColor: #caccd1; - qproperty-labelColor: #caccd1; -} - -TextInputWidget { - border: none; -} - -TextInputWidget, -TextInputWidget > QTextEdit, -TextInputWidget > QLineEdit { - background-color: #2d3139; - color: #caccd1; -} - -Toggle { - qproperty-activeColor: #38a3d8; - qproperty-disabledColor: gray; - qproperty-inactiveColor: gray; - qproperty-trackColor: rgb(240, 240, 240); -} - -QListWidget { - color: #caccd1; - background-color: #202228; -} - -QSplitter::handle { image: none; } diff --git a/resources/styles/nheko.qss b/resources/styles/nheko.qss deleted file mode 100644 index b4b7d427..00000000 --- a/resources/styles/nheko.qss +++ /dev/null @@ -1,68 +0,0 @@ -TextLabel, -QLabel { - color: #333; -} - -TextLabel::a { - color: #0077b5; -} - - -PopupItem { - background-color: white; - qproperty-hoverColor: rgba(192, 193, 195, 120); -} - -FlatButton { - qproperty-foregroundColor: #495057; -} - -RaisedButton { - qproperty-foregroundColor: white; -} - -dialogs--ReCaptcha, -dialogs--JoinRoom, -EditModal, -QListWidget { - background-color: white; - color: #495057; -} - -QComboBox, -QPushButton { - background-color: white; - color: #333; -} - -FloatingButton { - qproperty-backgroundColor: #efefef; - qproperty-foregroundColor: black; -} - -TextField { - qproperty-backgroundColor: white; - qproperty-inkColor: #333; - qproperty-labelColor: #333; -} - -QListWidget, -TextInputWidget, -QTextEdit, -QLineEdit { - background-color: white; - color: #333; -} - -TextInputWidget { - border: none; -} - -Toggle { - qproperty-activeColor: #38a3d8; - qproperty-disabledColor: gray; - qproperty-inactiveColor: gray; - qproperty-trackColor: rgb(240, 240, 240); -} - -QSplitter::handle { image: none; } diff --git a/resources/styles/system.qss b/resources/styles/system.qss deleted file mode 100644 index d2305974..00000000 --- a/resources/styles/system.qss +++ /dev/null @@ -1,39 +0,0 @@ -TextInputWidget { - border: none; -} - -PopupItem { - qproperty-hoverColor: palette(base); -} - -FlatButton { - qproperty-foregroundColor: palette(text); -} - -RaisedButton { - qproperty-foregroundColor: palette(button-text); -} - -TextField { - qproperty-backgroundColor: palette(window); -} - -QTextEdit, -QLineEdit, -QListWidget { - background-color: palette(window); -} - -FloatingButton { - qproperty-backgroundColor: palette(base); - qproperty-foregroundColor: palette(text); -} - -Toggle { - qproperty-activeColor: palette(highlight); - qproperty-disabledColor: palette(dark); - qproperty-inactiveColor: palette(mid); - qproperty-trackColor: palette(base); -} - -QSplitter::handle { image: none; } diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index 7e7cead3..84453962 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -852,21 +852,8 @@ UserSettings::setOpenVideoExternal(bool state) void UserSettings::applyTheme() { - QFile stylefile; - - if (this->theme() == QLatin1String("light")) { - stylefile.setFileName(QStringLiteral(":/styles/styles/nheko.qss")); - } else if (this->theme() == QLatin1String("dark")) { - stylefile.setFileName(QStringLiteral(":/styles/styles/nheko-dark.qss")); - } else { - stylefile.setFileName(QStringLiteral(":/styles/styles/system.qss")); - } - QApplication::setPalette(Theme::paletteFromTheme(this->theme())); - - stylefile.open(QFile::ReadOnly); - QString stylesheet = QString(stylefile.readAll()); - - qobject_cast(QApplication::instance())->setStyleSheet(stylesheet); + QGuiApplication::setPalette(Theme::paletteFromTheme(this->theme())); + QApplication::setPalette(Theme::paletteFromTheme(this->theme())); } void From 24f370d6c0a779373d1484206bb8ff617b1e24f2 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 02:58:36 +0200 Subject: [PATCH 051/128] Use multidata in timeline model --- src/UserSettingsPage.cpp | 4 ++-- src/timeline/TimelineModel.cpp | 23 ++++++++++++++++++++++- src/timeline/TimelineModel.h | 1 + 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index 84453962..ea7f22c4 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -852,8 +852,8 @@ UserSettings::setOpenVideoExternal(bool state) void UserSettings::applyTheme() { - QGuiApplication::setPalette(Theme::paletteFromTheme(this->theme())); - QApplication::setPalette(Theme::paletteFromTheme(this->theme())); + QGuiApplication::setPalette(Theme::paletteFromTheme(this->theme())); + QApplication::setPalette(Theme::paletteFromTheme(this->theme())); } void diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 0e99e7e1..f3b3ce81 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -875,7 +875,6 @@ QVariant TimelineModel::data(const QModelIndex &index, int role) const { using namespace mtx::accessors; - namespace acc = mtx::accessors; if (index.row() < 0 && index.row() >= rowCount()) return {}; @@ -891,6 +890,28 @@ TimelineModel::data(const QModelIndex &index, int role) const return data(*event, role); } +void +TimelineModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const +{ + if (index.row() < 0 && index.row() >= rowCount()) + return; + + // HACK(Nico): fetchMore likes to break with dynamically sized delegates and reuseItems + if (index.row() + 1 == rowCount() && !m_paginationInProgress) + const_cast(this)->fetchMore(index); + + auto event = events.get(rowCount() - index.row() - 1); + + if (!event) + return; + + for (QModelRoleData &roleData : roleDataSpan) { + int role = roleData.role(); + + roleData.setData(data(*event, role)); + } +} + QVariant TimelineModel::dataById(const QString &id, int role, const QString &relatedTo) { diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 02a5ee80..d1f04e21 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -277,6 +277,7 @@ public: QHash roleNames() const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + void multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const override; QVariant data(const mtx::events::collections::TimelineEvents &event, int role) const; Q_INVOKABLE QVariant dataById(const QString &id, int role, const QString &relatedTo); Q_INVOKABLE QVariant dataByIndex(int i, int role = Qt::DisplayRole) const From 19787d664c6112b8af8d885a5d1cdf705cba8152 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 22:43:56 +0200 Subject: [PATCH 052/128] Fix QChar range --- src/Cache.cpp | 3 +-- src/dock/Dock.cpp | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Cache.cpp b/src/Cache.cpp index 1c29d530..b3981c64 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -4424,8 +4424,7 @@ Cache::displayName(const QString &room_id, const QString &user_id) static bool isDisplaynameSafe(const std::string &s) { - for (std::uint32_t cc : QString::fromStdString(s).toStdU32String()) { - auto c = QChar(cc); + for (QChar c : QString::fromStdString(s)) { if (c.isPrint() && !c.isSpace()) return false; } diff --git a/src/dock/Dock.cpp b/src/dock/Dock.cpp index 08e7adba..0b573c20 100644 --- a/src/dock/Dock.cpp +++ b/src/dock/Dock.cpp @@ -60,6 +60,8 @@ void Dock::setUnreadCount(const int count) { unitySetNotificationCount(count); + + // qGuiApp->setBadgeNumber(count); } void Dock::unitySetNotificationCount(const int count) From 05ba0c8835b5b1875bea24d68cfd78db1c05ab85 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 22:44:47 +0200 Subject: [PATCH 053/128] Bump mtxclient dep --- CMakeLists.txt | 2 +- io.github.NhekoReborn.Nheko.yaml | 2 +- resources/qml/QuickSwitcher.qml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 87eb8474..9c7c17e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -603,7 +603,7 @@ if(USE_BUNDLED_MTXCLIENT) FetchContent_Declare( MatrixClient GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git - GIT_TAG e136bc27b28d3bb5683735eb5a65d6ef2534ca3a + GIT_TAG f4425af712afc6ad704a39b93c912432bd3c1914 ) set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "") set(BUILD_LIB_TESTS OFF CACHE INTERNAL "") diff --git a/io.github.NhekoReborn.Nheko.yaml b/io.github.NhekoReborn.Nheko.yaml index d45dba3d..0be3632f 100644 --- a/io.github.NhekoReborn.Nheko.yaml +++ b/io.github.NhekoReborn.Nheko.yaml @@ -213,7 +213,7 @@ modules: buildsystem: cmake-ninja name: mtxclient sources: - - commit: e136bc27b28d3bb5683735eb5a65d6ef2534ca3a + - commit: f4425af712afc6ad704a39b93c912432bd3c1914 #tag: v0.9.2 type: git url: https://github.com/Nheko-Reborn/mtxclient.git diff --git a/resources/qml/QuickSwitcher.qml b/resources/qml/QuickSwitcher.qml index 9ccefdec..bd2628bb 100644 --- a/resources/qml/QuickSwitcher.qml +++ b/resources/qml/QuickSwitcher.qml @@ -41,7 +41,7 @@ Popup { font.pixelSize: Math.ceil(quickSwitcher.textHeight * 0.6) width: parent.width - Keys.onPressed: { + Keys.onPressed: (event) => { if (event.key == Qt.Key_Up || event.key == Qt.Key_Backtab) { event.accepted = true; completerPopup.up(); From d2c616ee67f5bf33f83c4652dfd3d142439ef65e Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 2 Jun 2023 23:03:56 +0200 Subject: [PATCH 054/128] Fix request for empty image --- resources/qml/Avatar.qml | 4 +++- resources/qml/CommunitiesList.qml | 4 +++- resources/qml/QuickSwitcher.qml | 2 +- resources/qml/RoomList.qml | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/resources/qml/Avatar.qml b/resources/qml/Avatar.qml index 53124f28..5a28b5de 100644 --- a/resources/qml/Avatar.qml +++ b/resources/qml/Avatar.qml @@ -57,7 +57,9 @@ AbstractButton { fillMode: avatar.crop ? Image.PreserveAspectCrop : Image.PreserveAspectFit mipmap: true smooth: true - source: if (avatar.url.startsWith('image://')) { + source: if (avatar.url.startsWith('image://colorimage')) { + return avatar.url + "&radius=" + (Settings.avatarCircles ? 100 : 25) + ((avatar.crop) ? "" : "&scale"); + } else if (avatar.url.startsWith('image://')) { return avatar.url + "?radius=" + (Settings.avatarCircles ? 100 : 25) + ((avatar.crop) ? "" : "&scale"); } else if (avatar.url.startsWith(':/')) { return "image://colorimage/" + avatar.url + "?" + textColor; diff --git a/resources/qml/CommunitiesList.qml b/resources/qml/CommunitiesList.qml index 62a29a2d..d93f5900 100644 --- a/resources/qml/CommunitiesList.qml +++ b/resources/qml/CommunitiesList.qml @@ -146,8 +146,10 @@ Page { url: { if (model.avatarUrl.startsWith("mxc://")) return model.avatarUrl.replace("mxc://", "image://MxcImage/"); - else + else if (model.avatarUrl.length > 0) return "image://colorimage/" + model.avatarUrl + "?" + communityItem.unimportantText; + else + return ""; } width: avatarSize diff --git a/resources/qml/QuickSwitcher.qml b/resources/qml/QuickSwitcher.qml index bd2628bb..90e6560c 100644 --- a/resources/qml/QuickSwitcher.qml +++ b/resources/qml/QuickSwitcher.qml @@ -41,7 +41,7 @@ Popup { font.pixelSize: Math.ceil(quickSwitcher.textHeight * 0.6) width: parent.width - Keys.onPressed: (event) => { + Keys.onPressed: event => { if (event.key == Qt.Key_Up || event.key == Qt.Key_Backtab) { event.accepted = true; completerPopup.up(); diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index 36c366a9..ac4f8c3a 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -568,8 +568,8 @@ Page { spacing: Nheko.paddingSmall Item { - Layout.fillWidth: true Layout.alignment: Qt.AlignBottom + Layout.fillWidth: true ElidedLabel { anchors.bottom: parent.bottom From b1c2b384c6649b3d6604760f2b20f45f84d6e19f Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 00:30:44 +0200 Subject: [PATCH 055/128] Fix username label eliding loop --- resources/qml/MessageView.qml | 12 +++++++++--- resources/qml/dialogs/ReadReceipts.qml | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index a38a2f49..e80770bb 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -572,17 +572,23 @@ Item { rightInset: 0 rightPadding: 0 - contentItem: ElidedLabel { + contentItem: Label { id: userName_ color: TimelineManager.userColor(userId, palette.base) - elideWidth: Math.min(userInfo.remainingWidth - Math.min(statusMsg.implicitWidth, userInfo.remainingWidth / 3), userName_.fullTextWidth) - fullText: userName + text: TimelineManager.escapeEmoji(userNameTextMetrics.elidedText) textFormat: Text.RichText } onClicked: room.openUserProfile(userId) + TextMetrics { + id: userNameTextMetrics + + elide: Text.ElideRight + elideWidth: userInfo.remainingWidth - Math.min(statusMsg.implicitWidth, userInfo.remainingWidth / 3) + text: userName + } CursorShape { anchors.fill: parent cursorShape: Qt.PointingHandCursor diff --git a/resources/qml/dialogs/ReadReceipts.qml b/resources/qml/dialogs/ReadReceipts.qml index 83b8b8af..523b47cb 100644 --- a/resources/qml/dialogs/ReadReceipts.qml +++ b/resources/qml/dialogs/ReadReceipts.qml @@ -91,7 +91,7 @@ ApplicationWindow { Layout.fillWidth: true ElidedLabel { - text: model.displayName + fullText: model.displayName color: TimelineManager.userColor(model ? model.mxid : "", palette.window) font.pointSize: fontMetrics.font.pointSize elideWidth: del.width - Nheko.paddingMedium - avatar.width @@ -99,7 +99,7 @@ ApplicationWindow { } ElidedLabel { - text: model.timestamp + fullText: model.timestamp color: palette.buttonText font.pointSize: fontMetrics.font.pointSize * 0.9 elideWidth: del.width - Nheko.paddingMedium - avatar.width From 93a9fca4758ab3387b81384310f0afbf082a6494 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 00:50:55 +0200 Subject: [PATCH 056/128] Try to fix flatpak build and change appid --- .gitlab-ci.yml | 4 +- CMakeLists.txt | 2 +- README.md | 2 +- ...koReborn.Nheko.yaml => im.nheko.Nheko.yaml | 83 ++++++++++--------- nheko-nightly.flatpakref | 2 +- src/main.cpp | 2 +- 6 files changed, 48 insertions(+), 47 deletions(-) rename io.github.NhekoReborn.Nheko.yaml => im.nheko.Nheko.yaml (78%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3dfc7f59..97e1eaf2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -213,9 +213,9 @@ build-flatpak: - mkdir -p build-flatpak - cd build-flatpak - echo -e "\e[0Ksection_start:`date +%s`:build_flatpak[collapsed=true]\r\e[0K\e[1m\e[95mBuilding flatpak" - - flatpak-builder --install-deps-from=flathub --user --disable-rofiles-fuse --ccache --repo=repo --default-branch=${CI_COMMIT_REF_NAME//\//_} --subject="Build of Nheko ${VERSION} `date` for ${ARCH}" app ../io.github.NhekoReborn.Nheko.yaml + - flatpak-builder --install-deps-from=flathub --user --disable-rofiles-fuse --ccache --repo=repo --default-branch=${CI_COMMIT_REF_NAME//\//_} --subject="Build of Nheko ${VERSION} `date` for ${ARCH}" app ../im.nheko.Nheko.yaml - echo -e "\e[0Ksection_end:`date +%s`:build_flatpak\r\e[0K" - - flatpak build-bundle repo nheko-${ARCH}.flatpak io.github.NhekoReborn.Nheko ${CI_COMMIT_REF_NAME//\//_} + - flatpak build-bundle repo nheko-${ARCH}.flatpak im.nheko.Nheko ${CI_COMMIT_REF_NAME//\//_} after_script: - echo -e "\e[0Ksection_start:`date +%s`:upload_flatpak[collapsed=true]\r\e[0K\e[1m\e[95mUploading flatpak" - bash ./.ci/upload-nightly-gitlab.sh build-flatpak/nheko-${ARCH}.flatpak diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c7c17e2..ae91ae95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -799,7 +799,7 @@ endif() if(UNIX AND NOT APPLE) if(FLATPAK) - set(APPID "io.github.NhekoReborn.Nheko") + set(APPID "im.nheko.Nheko") set_target_properties(nheko PROPERTIES OUTPUT_NAME "${APPID}") else() set(APPID "nheko") diff --git a/README.md b/README.md index fc20e0c9..46e6b9a2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ nheko [![Build status](https://ci.appveyor.com/api/projects/status/07qrqbfylsg4hw2h/branch/master?svg=true)](https://ci.appveyor.com/project/redsky17/nheko/branch/master) [![Stable Version](https://img.shields.io/badge/download-stable-green.svg)](https://github.com/Nheko-Reborn/nheko/releases/latest) [![Nightly](https://img.shields.io/badge/download-nightly-green.svg)](https://matrix-static.neko.dev/room/!TshDrgpBNBDmfDeEGN:neko.dev/) -Download Nightly Flatpak +Download Nightly Flatpak [![#nheko-reborn:matrix.org](https://img.shields.io/matrix/nheko-reborn:matrix.org.svg?label=%23nheko-reborn:matrix.org)](https://matrix.to/#/#nheko-reborn:matrix.org) [![Arch package](https://repology.org/badge/version-for-repo/arch/nheko.svg)](https://archlinux.org/packages/community/x86_64/nheko/) Download on Flathub diff --git a/io.github.NhekoReborn.Nheko.yaml b/im.nheko.Nheko.yaml similarity index 78% rename from io.github.NhekoReborn.Nheko.yaml rename to im.nheko.Nheko.yaml index 0be3632f..f0357d3c 100644 --- a/io.github.NhekoReborn.Nheko.yaml +++ b/im.nheko.Nheko.yaml @@ -1,7 +1,7 @@ -id: io.github.NhekoReborn.Nheko -command: io.github.NhekoReborn.Nheko +id: im.nheko.Nheko +command: im.nheko.Nheko runtime: org.kde.Platform -runtime-version: '5.15-22.08' +runtime-version: '6.5' sdk: org.kde.Sdk finish-args: - --device=dri @@ -44,9 +44,9 @@ cleanup: modules: - name: lmdb sources: - - sha256: f3927859882eb608868c8c31586bb7eb84562a40a6bf5cc3e13b6b564641ea28 + - sha256: 8c5a93ac3cc97427c54571ad5a6140b7469389d01e6d2f43df39f96d3a4ccef7 type: archive - url: https://github.com/LMDB/lmdb/archive/LMDB_0.9.22.tar.gz + url: https://git.openldap.org/openldap/openldap/-/archive/LMDB_0.9.30/openldap-LMDB_0.9.30.tar.gz make-install-args: - prefix=/app no-autogen: true @@ -109,45 +109,46 @@ modules: tag: 0.20.4 type: git url: https://gitlab.gnome.org/GNOME/libsecret.git - - config-opts: - - -DCMAKE_BUILD_TYPE=Release - - -DAVIF_CODEC_AOM=ON - #- -DBUILD_SHARED_LIBS=OFF - buildsystem: cmake-ninja - name: libavif - sources: - - sha256: 66e82854ceb84a3e542bc140a343bc90e56c68f3ecb4fff63e636c136ed9a05e - type: archive - url: https://github.com/AOMediaCodec/libavif/archive/refs/tags/v0.10.1.tar.gz - - config-opts: - - -DCMAKE_BUILD_TYPE=Release - - -DWITH_EXAMPLES=OFF - #- -DBUILD_SHARED_LIBS=OFF - buildsystem: cmake-ninja - name: libheif - sources: - - sha256: e1ac2abb354fdc8ccdca71363ebad7503ad731c84022cf460837f0839e171718 - type: archive - url: https://github.com/strukturag/libheif/releases/download/v1.12.0/libheif-1.12.0.tar.gz - - config-opts: - - -DCMAKE_BUILD_TYPE=Release - - -DKIMAGEFORMATS_HEIF=ON - buildsystem: cmake-ninja - name: KImageFormats - sources: - - commit: ae6b724824fc2fdf71d50dc7ae0052ad1551b25a - tag: v5.93.0 - type: git - url: https://invent.kde.org/frameworks/kimageformats.git + #- config-opts: + # - -DCMAKE_BUILD_TYPE=Release + # - -DAVIF_CODEC_AOM=ON + # #- -DBUILD_SHARED_LIBS=OFF + # buildsystem: cmake-ninja + # name: libavif + # sources: + # - sha256: 66e82854ceb84a3e542bc140a343bc90e56c68f3ecb4fff63e636c136ed9a05e + # type: archive + # url: https://github.com/AOMediaCodec/libavif/archive/refs/tags/v0.10.1.tar.gz + #- config-opts: + # - -DCMAKE_BUILD_TYPE=Release + # - -DWITH_EXAMPLES=OFF + # #- -DBUILD_SHARED_LIBS=OFF + # buildsystem: cmake-ninja + # name: libheif + # sources: + # - sha256: e1ac2abb354fdc8ccdca71363ebad7503ad731c84022cf460837f0839e171718 + # type: archive + # url: https://github.com/strukturag/libheif/releases/download/v1.12.0/libheif-1.12.0.tar.gz + #- config-opts: + # - -DCMAKE_BUILD_TYPE=Release + # - -DKIMAGEFORMATS_HEIF=ON + # buildsystem: cmake-ninja + # name: KImageFormats + # sources: + # - commit: ae6b724824fc2fdf71d50dc7ae0052ad1551b25a + # tag: v5.93.0 + # type: git + # url: https://invent.kde.org/frameworks/kimageformats.git - config-opts: - -DCMAKE_BUILD_TYPE=Release - -DBUILD_TEST_APPLICATION=OFF - -DQTKEYCHAIN_STATIC=ON + - -DBUILD_WITH_QT6=ON buildsystem: cmake-ninja name: QtKeychain sources: - - commit: f59ac26be709fd2d8d7a062fab1cf1e67a93806c - tag: v0.13.1 + - commit: 69f993c47efed7e557d79a30a367014d9a27d809 + tag: v0.14.1 type: git url: https://github.com/frankosterfeld/qtkeychain.git - config-opts: @@ -170,15 +171,15 @@ modules: - buildsystem: meson name: gstreamer sources: - - commit: f7806a854aad960eae3288db4a67a574f92428fe - tag: 1.20.5 + - commit: ecd471f5ea4645102b206a43d863f0f0fe7d04ec + tag: 1.22.3 type: git url: https://gitlab.freedesktop.org/gstreamer/gstreamer.git config-opts: - --auto-features=disabled - -Dgood=enabled - - -Dgst-plugins-good:qt5=enabled - - -Dqt5=enabled + - -Dgst-plugins-good:qt6=enabled + - -Dqt6=enabled - -Dbase=enabled - -Dgst-plugins-base:gl=enabled - -Dgst-plugins-base:gl_platform=glx,egl diff --git a/nheko-nightly.flatpakref b/nheko-nightly.flatpakref index 74e47ecd..484b5de0 100644 --- a/nheko-nightly.flatpakref +++ b/nheko-nightly.flatpakref @@ -1,6 +1,6 @@ [Flatpak Ref] Title=Nheko Nightly -Name=io.github.NhekoReborn.Nheko +Name=im.nheko.Nheko Branch=master Url=https://flatpak.neko.dev/repo/nightly SuggestRemoteName=nheko-nightlies diff --git a/src/main.cpp b/src/main.cpp index 1a7843db..951d53f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -254,7 +254,7 @@ main(int argc, char *argv[]) app.setWindowIcon(QIcon::fromTheme(QStringLiteral("nheko"), QIcon{":/logos/nheko.png"})); #endif #ifdef NHEKO_FLATPAK - app.setDesktopFileName(QStringLiteral("io.github.NhekoReborn.Nheko")); + app.setDesktopFileName(QStringLiteral("im.nheko.Nheko")); #else app.setDesktopFileName(QStringLiteral("nheko")); #endif From e15237f423594b1587905a16a808b7d6df9ad087 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 00:55:36 +0200 Subject: [PATCH 057/128] QtKeychain used a different tag pattern for 0.14.1... --- im.nheko.Nheko.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im.nheko.Nheko.yaml b/im.nheko.Nheko.yaml index f0357d3c..2c39448a 100644 --- a/im.nheko.Nheko.yaml +++ b/im.nheko.Nheko.yaml @@ -148,7 +148,7 @@ modules: name: QtKeychain sources: - commit: 69f993c47efed7e557d79a30a367014d9a27d809 - tag: v0.14.1 + tag: 0.14.1 type: git url: https://github.com/frankosterfeld/qtkeychain.git - config-opts: From 47d3fd1e3a07f10edbc960ec76dc7a0d1fd1e6ce Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 01:06:33 +0200 Subject: [PATCH 058/128] Try to fix gstreamer build --- im.nheko.Nheko.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/im.nheko.Nheko.yaml b/im.nheko.Nheko.yaml index 2c39448a..5a744996 100644 --- a/im.nheko.Nheko.yaml +++ b/im.nheko.Nheko.yaml @@ -179,7 +179,7 @@ modules: - --auto-features=disabled - -Dgood=enabled - -Dgst-plugins-good:qt6=enabled - - -Dqt6=enabled + #- -Dqt6=enabled <- not available on 1.22 - -Dbase=enabled - -Dgst-plugins-base:gl=enabled - -Dgst-plugins-base:gl_platform=glx,egl From 46f02bb0c38862449f2d7d787d0f4bdbf37b7365 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 01:15:05 +0200 Subject: [PATCH 059/128] Fix qtkeychain include --- src/Cache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cache.cpp b/src/Cache.cpp index b3981c64..2d87304c 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -21,7 +21,7 @@ #if __has_include() #include #else -#include +#include #endif #include From 6a53944805cfd74d0035c303b98a40a80bdf76de Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 01:31:11 +0200 Subject: [PATCH 060/128] Update alpine dependencies --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 97e1eaf2..51fe3d12 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,14 +18,14 @@ build-clazy: TRAVIS_OS_NAME: linux before_script: - echo -e "\e[0Ksection_start:`date +%s`:install_deps[collapsed=true]\r\e[0K\e[1m\e[95mInstalling apk dependencies" - - apk add asciidoctor cmake cmark-dev gst-plugins-bad-dev gst-plugins-base-dev gstreamer-dev lmdb-dev lmdbxx nlohmann-json olm-dev openssl-dev qt5-qtbase-dev qt5-qtdeclarative-dev qt5-qtmultimedia-dev qt5-qtquickcontrols2-dev qt5-qtsvg-dev qt5-qttools-dev qtkeychain-dev samurai spdlog-dev xcb-util-wm-dev zlib-dev ccache curl-dev libevent-dev meson clazy clang16 gcc musl-dev git re2-dev + - apk add asciidoctor cmake cmark-dev gst-plugins-bad-dev gst-plugins-base-dev gstreamer-dev lmdb-dev lmdbxx nlohmann-json olm-dev openssl-dev qt6-qtbase-dev qt6-qtdeclarative-dev qt6-qtmultimedia-dev qt6-qtsvg-dev qt6-qttools-dev samurai spdlog-dev xcb-util-wm-dev zlib-dev ccache curl-dev libevent-dev meson clazy clang16 gcc musl-dev git re2-dev libsecret-dev - echo -e "\e[0Ksection_end:`date +%s`:install_deps\r\e[0K" script: - export PATH="/usr/lib/ccache:${PATH}" - export CMAKE_BUILD_PARALLEL_LEVEL=$(cat /proc/cpuinfo | awk '/^processor/{print $3}' | wc -l) - cmake -GNinja -H. -Bbuild -DCMAKE_INSTALL_PREFIX=.deps/usr - -DHUNTER_ENABLED=OFF -DBUILD_SHARED_LIBS=OFF -DUSE_BUNDLED_OPENSSL=ON -DUSE_BUNDLED_MTXCLIENT=ON -DUSE_BUNDLED_COEURL=ON -DUSE_BUNDLED_OLM=ON + -DHUNTER_ENABLED=OFF -DBUILD_SHARED_LIBS=OFF -DUSE_BUNDLED_OPENSSL=ON -DUSE_BUNDLED_MTXCLIENT=ON -DUSE_BUNDLED_COEURL=ON -DUSE_BUNDLED_OLM=ON -DUSE_BUNDLED_QTKEYCHAIN=ON -DVOIP=OFF -DCMAKE_BUILD_TYPE=Release -DCI_BUILD=ON -DFETCHCONTENT_QUIET=OFF -DCMAKE_CXX_COMPILER=clazy @@ -50,7 +50,7 @@ build-gcc11: libssl-dev libqt5multimedia5-plugins libqt5multimediagsttools5 libqt5multimediaquick5 libqt5svg5-dev qtmultimedia5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools qtdeclarative5-dev qml-module-qtmultimedia qml-module-qtquick-controls2 qml-module-qtquick-layouts qml-module-qt-labs-platform - qt5keychain-dev ccache clazy libcurl4-openssl-dev libevent-dev libspdlog-dev git nlohmann-json3-dev libcmark-dev asciidoc time # libolm-dev + qt5keychain-dev ccache libcurl4-openssl-dev libevent-dev libspdlog-dev git nlohmann-json3-dev libcmark-dev asciidoc time # libolm-dev # need recommended deps for wget - apt-get -y install wget - /usr/sbin/update-ccache-symlinks @@ -249,7 +249,7 @@ appimage-amd64: libssl-dev libqt5multimedia5-plugins libqt5multimediagsttools5 libqt5multimediaquick5 libqt5svg5-dev qtmultimedia5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools qtdeclarative5-dev qml-module-qtmultimedia qml-module-qtquick-controls2 qml-module-qtquick-layouts qml-module-qt-labs-platform - qt5keychain-dev ccache clazy libcurl4-openssl-dev libevent-dev libspdlog-dev nlohmann-json3-dev libcmark-dev asciidoc libre2-dev libgtest-dev libgl1-mesa-dev qml-module-qtquick-particles2 + qt5keychain-dev ccache libcurl4-openssl-dev libevent-dev libspdlog-dev nlohmann-json3-dev libcmark-dev asciidoc libre2-dev libgtest-dev libgl1-mesa-dev qml-module-qtquick-particles2 # Installing the packages needed to build AppImage - apt-get -yq install breeze-icon-theme desktop-file-utils elfutils fakeroot file gnupg2 gtk-update-icon-cache libgdk-pixbuf2.0-dev libgdk-pixbuf2.0-0 libglib2.0-bin librsvg2-dev libyaml-dev strace zsync squashfs-tools From 23d9decbce1b0c757c2e3c246d3ad0cc661ad3f8 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 01:43:48 +0200 Subject: [PATCH 061/128] Fix a few clazy warnings --- src/MainWindow.cpp | 13 +------------ src/MainWindow.h | 3 +-- src/Utils.cpp | 16 +++++++++------- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index ecb5ffd0..63f20752 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -318,18 +318,6 @@ MainWindow::setWindowTitle(int notificationCount) QQuickView::setTitle(name); } -bool -MainWindow::event(QEvent *event) -{ - auto type = event->type(); - - if (type == QEvent::Close) { - closeEvent(static_cast(event)); - } - - return QQuickView::event(event); -} - // HACK: https://bugreports.qt.io/browse/QTBUG-83972, qtwayland cannot auto hide menu void MainWindow::mousePressEvent(QMouseEvent *event) @@ -403,6 +391,7 @@ MainWindow::closeEvent(QCloseEvent *event) if (!qApp->isSavingSession() && isVisible() && pageSupportsTray() && userSettings_->tray()) { event->ignore(); hide(); + return; } } diff --git a/src/MainWindow.h b/src/MainWindow.h index 08ffcbba..543b0f69 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -64,8 +64,7 @@ public: QString focusedRoom() const; protected: - void closeEvent(QCloseEvent *event); - bool event(QEvent *event) override; + void closeEvent(QCloseEvent *event) override; // HACK: https://bugreports.qt.io/browse/QTBUG-83972, qtwayland cannot auto hide menu void mousePressEvent(QMouseEvent *) override; diff --git a/src/Utils.cpp b/src/Utils.cpp index 2249379d..8ff8cec6 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -66,9 +66,9 @@ utils::stripReplyFromBody(const std::string &bodyi) if (body.startsWith(QLatin1String("> <"))) { auto segments = body.split('\n'); while (!segments.isEmpty() && segments.begin()->startsWith('>')) - segments.erase(segments.begin()); + segments.erase(segments.cbegin()); if (!segments.empty() && segments.first().isEmpty()) - segments.erase(segments.begin()); + segments.erase(segments.cbegin()); body = segments.join('\n'); } @@ -80,8 +80,9 @@ std::string utils::stripReplyFromFormattedBody(const std::string &formatted_bodyi) { QString formatted_body = QString::fromStdString(formatted_bodyi); - formatted_body.remove(QRegularExpression(QStringLiteral(".*"), - QRegularExpression::DotMatchesEverythingOption)); + static QRegularExpression replyRegex(QStringLiteral(".*"), + QRegularExpression::DotMatchesEverythingOption); + formatted_body.remove(replyRegex); formatted_body.replace(QLatin1String("@room"), QString::fromUtf8("@\u2060room")); return formatted_body.toStdString(); } @@ -409,9 +410,10 @@ utils::linkifyMessage(const QString &body) // Convert to valid XML. auto doc = body; doc.replace(conf::strings::url_regex, conf::strings::url_html); - doc.replace( - QRegularExpression(QStringLiteral("\\b(?(matrix:[\\S]{5,}))(?![\"'])\\b")), - conf::strings::url_html); + + static QRegularExpression matrixURIRegex( + QStringLiteral("\\b(?(matrix:[\\S]{5,}))(?![\"'])\\b")); + doc.replace(matrixURIRegex, conf::strings::url_html); return doc; } From 681e9da6682154a674c0e7ef416ce1900e465745 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 01:44:07 +0200 Subject: [PATCH 062/128] Update tumbleweed deps --- .gitlab-ci.yml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 51fe3d12..a0a7c951 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -107,16 +107,15 @@ build-tw: "zlib-devel" "libQt5PlatformHeaders-devel" "cmake(re2)" - "cmake(Qt5Concurrent)" - "cmake(Qt5Core)" - "cmake(Qt5DBus)" - "cmake(Qt5Keychain)" - "cmake(Qt5LinguistTools)" - "cmake(Qt5Multimedia)" - "cmake(Qt5Network)" - "cmake(Qt5QuickControls2)" - "cmake(Qt5Svg)" - "cmake(Qt5Widgets)" + "cmake(Qt6Core)" + "cmake(Qt6DBus)" + "cmake(Qt6Keychain)" + "cmake(Qt6LinguistTools)" + "cmake(Qt6Multimedia)" + "cmake(Qt6QuickControls2)" + "cmake(Qt6Svg)" + "cmake(Qt6Widgets)" + "cmake(Qt6Gui)" "pkgconfig(libcurl)" "pkgconfig(libevent)" "pkgconfig(gstreamer-webrtc-1.0)" From 5fed4d21b1f1f7d6530ef63a79ee3420a691d7d3 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 01:51:36 +0200 Subject: [PATCH 063/128] Fix a few more clazy warnings --- src/Cache.cpp | 4 +++- src/encryption/Olm.cpp | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Cache.cpp b/src/Cache.cpp index 2d87304c..7671af02 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -4424,7 +4424,9 @@ Cache::displayName(const QString &room_id, const QString &user_id) static bool isDisplaynameSafe(const std::string &s) { - for (QChar c : QString::fromStdString(s)) { + const auto str = QString::fromStdString(s); + + for (QChar c : str) { if (c.isPrint() && !c.isSpace()) return false; } diff --git a/src/encryption/Olm.cpp b/src/encryption/Olm.cpp index 733ce94f..b4310f26 100644 --- a/src/encryption/Olm.cpp +++ b/src/encryption/Olm.cpp @@ -1363,12 +1363,12 @@ send_encrypted_to_device_messages(const std::mapwarn("Not creating new session with {}:{} " "because of rate limit", From 10e15c0f96eca0d1c74d62a7e9ec249ee9e40bb8 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 01:57:47 +0200 Subject: [PATCH 064/128] Disable ubuntu builds until a recent enough Qt version is available --- .ci/macos/Brewfile | 2 +- .gitlab-ci.yml | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.ci/macos/Brewfile b/.ci/macos/Brewfile index 0674eb61..717447fc 100644 --- a/.ci/macos/Brewfile +++ b/.ci/macos/Brewfile @@ -6,7 +6,7 @@ brew "clang-format" brew "cmake" brew "ninja" brew "openssl" -brew "qt5" +brew "qt6" brew "nlohmann_json" brew "gstreamer" brew "qtkeychain" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a0a7c951..27e0807b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,7 +37,8 @@ build-clazy: paths: - .ccache -build-gcc11: +# disabled until I find a qt6.5 ppa +.build-gcc11: stage: build image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/ubuntu:22.04 tags: [docker] @@ -232,7 +233,8 @@ build-flatpak: paths: ['build-flatpak/nheko-${ARCH}.flatpak'] name: flatpak-${CI_COMMIT_REF_NAME}-${VERSION}-${ARCH} -appimage-amd64: +# disabled until I find a qt6.5 ppa for Ubuntu +.appimage-amd64: stage: build image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/ubuntu:22.04 tags: [docker] @@ -324,7 +326,7 @@ github-release: rules: - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/' dependencies: - - appimage-amd64 + #- appimage-amd64 <- disabled because of missing packages - build-flatpak - codesign-macos before_script: From c7976514ff72ed123de3acee4abdf0b3eee7e112 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 02:02:58 +0200 Subject: [PATCH 065/128] Update Qt in Windows CI --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 4a0b1eec..49bb1e51 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,7 +22,7 @@ build: verbosity: minimal install: - - set QT_DIR=C:\Qt\5.15\msvc2019_64 + - set QT_DIR=C:\Qt\6.5\msvc2019_64 - set PATH=C:\Strawberry\perl\bin;C:\Python39-x64;%QT_DIR%\bin;%PATH% build_script: From 9e983b1584fb7d13c7417725c2f191fdbf82c9d0 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 02:05:56 +0200 Subject: [PATCH 066/128] Remove a few more QPairs --- src/encryption/Olm.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/encryption/Olm.cpp b/src/encryption/Olm.cpp index b4310f26..8993f715 100644 --- a/src/encryption/Olm.cpp +++ b/src/encryption/Olm.cpp @@ -1306,7 +1306,7 @@ send_encrypted_to_device_messages(const std::map, qint64> rateLimit; + static QMap, qint64> rateLimit; nlohmann::json ev_json = std::visit([](const auto &e) { return nlohmann::json(e); }, event); @@ -1569,13 +1569,13 @@ send_encrypted_to_device_messages(const std::mapwarn("Not creating new session with {}:{} " "because of rate limit", From 308efd48b6867603e6e16ee9927ed656835a1036 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 02:12:21 +0200 Subject: [PATCH 067/128] Fix one more clazy issue --- src/timeline/InputBar.cpp | 4 +++- src/timeline/TimelineModel.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 6980c364..2f3b6eae 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -776,7 +776,9 @@ InputBar::getCommandAndArgs(const QString ¤tText) const if (!currentText.startsWith('/')) return {{}, currentText}; - int command_end = currentText.indexOf(QRegularExpression(QStringLiteral("\\s"))); + static QRegularExpression spaceRegex(QStringLiteral("\\s")); + + int command_end = currentText.indexOf(spaceRegex); if (command_end == -1) command_end = currentText.size(); auto name = currentText.mid(1, command_end - 1); diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index f3b3ce81..6cec615b 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -1340,7 +1340,7 @@ TimelineModel::formatDateSeparator(QDate date) const QString fmt = QLocale::system().dateFormat(QLocale::LongFormat); if (now.date().year() == date.year()) { - QRegularExpression rx(QStringLiteral("[^a-zA-Z]*y+[^a-zA-Z]*")); + static QRegularExpression rx(QStringLiteral("[^a-zA-Z]*y+[^a-zA-Z]*")); fmt = fmt.remove(rx); } From 3b4daca53e8a8f3141fa0f563814c3793066a63a Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 02:32:05 +0200 Subject: [PATCH 068/128] Remove WinMain --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae91ae95..eb75f1ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -694,7 +694,6 @@ if(APPLE) target_link_libraries (nheko PRIVATE Qt6::MacExtras) elseif(WIN32) target_compile_definitions(nheko PRIVATE WIN32_LEAN_AND_MEAN) - target_link_libraries (nheko PRIVATE ${NTDLIB} Qt6::WinMain) if(MSVC) target_compile_options(nheko PUBLIC "/Zc:__cplusplus") endif() From 7029547647d2d66596b8bb4307500376edad11a9 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 02:45:38 +0200 Subject: [PATCH 069/128] Link XCB always if X11 support is on --- CMakeLists.txt | 21 +++++++++++++-------- README.md | 2 +- src/ui/NhekoGlobalObject.cpp | 4 ++++ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eb75f1ac..f0aecc8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,7 +72,11 @@ if (APPLE OR WIN32) set(VOIP_DEFAULT OFF) endif() option(VOIP "Whether to enable voip support. Disable this, if you don't have gstreamer." ${VOIP_DEFAULT}) -cmake_dependent_option(SCREENSHARE_X11 "Whether to enable screenshare support on X11." ON "VOIP" OFF) +set(X11_DEFAULT) +if (WIN32 OR APPLE OR HAIKU) + set(X11_DEFAULT OFF) +endif() +option(X11 "Whether to enable X11 specific features (screenshare, window roles)." ${X11_DEFAULT}) cmake_dependent_option(SCREENSHARE_XDP "Whether to enable screenshare support using xdg-desktop-portal." ON "VOIP" OFF) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") @@ -615,9 +619,10 @@ endif() if (VOIP) include(FindPkgConfig) pkg_check_modules(GSTREAMER REQUIRED IMPORTED_TARGET gstreamer-sdp-1.0>=1.18 gstreamer-webrtc-1.0>=1.18) - if (SCREENSHARE_X11 AND NOT WIN32 AND NOT APPLE) - pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb xcb-ewmh) - endif() +endif() + +if (X11 AND NOT WIN32 AND NOT APPLE AND NOT HAIKU) + pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb xcb-ewmh) endif() # single instance functionality @@ -767,10 +772,10 @@ endif() if (TARGET PkgConfig::GSTREAMER) target_link_libraries(nheko PRIVATE PkgConfig::GSTREAMER) target_compile_definitions(nheko PRIVATE GSTREAMER_AVAILABLE) - if (TARGET PkgConfig::XCB) - target_link_libraries(nheko PRIVATE PkgConfig::XCB) - target_compile_definitions(nheko PRIVATE XCB_AVAILABLE) - endif() +endif() +if (TARGET PkgConfig::XCB) + target_link_libraries(nheko PRIVATE PkgConfig::XCB) + target_compile_definitions(nheko PRIVATE XCB_AVAILABLE) endif() if(MSVC) diff --git a/README.md b/README.md index 46e6b9a2..73f8587d 100644 --- a/README.md +++ b/README.md @@ -249,7 +249,7 @@ KDE has similar plugins, that can extend the supported image types even more. - Voice call support: dtls, opus, rtpmanager, srtp, webrtc - Video call support (optional): compositor, opengl, qmlgl, rtp, vpx - [libnice](https://gitlab.freedesktop.org/libnice/libnice) -- XCB, XCB-EWMH: For screensharing support on X11. VOIP needs to be enabled. Can be disabled with `-DSCREENSHARE_X11=OFF`. +- XCB, XCB-EWMH: For screensharing support on X11 and setting window roles. Can be disabled with `-DSCREENSHARE_X11=OFF`. - [qtkeychain](https://github.com/frankosterfeld/qtkeychain) (You need at least version 0.12 for proper Gnome Keychain support. The bundled version requires libsecret, unless you pass `-DLIBSECRET_SUPPORT=OFF`.) - A compiler that supports C++ 20: - Clang 16 (Only clazy 16 is tested in CI) diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp index 0bdb45f4..1bab73b5 100644 --- a/src/ui/NhekoGlobalObject.cpp +++ b/src/ui/NhekoGlobalObject.cpp @@ -18,7 +18,9 @@ #include "Utils.h" #include "voip/WebRTCSession.h" +#if XCB_AVAILABLE #include +#endif Nheko::Nheko() { @@ -184,6 +186,7 @@ Nheko::createRoom(bool space, void Nheko::setWindowRole([[maybe_unused]] QWindow *win, [[maybe_unused]] QString newRole) const { +#if XCB_AVAILABLE const QNativeInterface::QX11Application *x11Interface = qGuiApp->nativeInterface(); @@ -208,4 +211,5 @@ Nheko::setWindowRole([[maybe_unused]] QWindow *win, [[maybe_unused]] QString new 8, role.size(), role.data()); +#endif } From 770f79978ad953c1ce2f2e1b3079e5ad7c16f250 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 3 Jun 2023 04:06:13 +0200 Subject: [PATCH 070/128] Remove mac extras --- CMakeLists.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f0aecc8e..d64aa2c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -266,10 +266,6 @@ else() find_package(Qt6Keychain REQUIRED) endif() -if (APPLE) - find_package(Qt6MacExtras REQUIRED) -endif(APPLE) - if (Qt6Widgets_FOUND) if (Qt6Widgets_VERSION VERSION_LESS 6.5.0) message(STATUS "Qt version ${Qt6Widgets_VERSION}") @@ -695,9 +691,7 @@ set_target_properties(nheko CMAKE_SKIP_INSTALL_RPATH TRUE AUTOMOC ON) -if(APPLE) - target_link_libraries (nheko PRIVATE Qt6::MacExtras) -elseif(WIN32) +if(WIN32) target_compile_definitions(nheko PRIVATE WIN32_LEAN_AND_MEAN) if(MSVC) target_compile_options(nheko PUBLIC "/Zc:__cplusplus") From 2c53789d97d86bb4d28e4254e671c0e60efe9b38 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 4 Jun 2023 02:31:30 +0200 Subject: [PATCH 071/128] Fix member event binding loop --- resources/qml/delegates/MessageDelegate.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml index cd8109b4..3aea823f 100644 --- a/resources/qml/delegates/MessageDelegate.qml +++ b/resources/qml/delegates/MessageDelegate.qml @@ -602,7 +602,7 @@ Item { roleValue: MtxEvent.Member ColumnLayout { - width: parent.width + width: parent?.width ?? 100 NoticeMessage { body: formatted From 686cade0abb46c635d4751d7527cf53170121a7c Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 4 Jun 2023 02:44:41 +0200 Subject: [PATCH 072/128] Fix some undefined variables in the UploadBox --- resources/qml/UploadBox.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/qml/UploadBox.qml b/resources/qml/UploadBox.qml index 54007163..215003ec 100644 --- a/resources/qml/UploadBox.qml +++ b/resources/qml/UploadBox.qml @@ -36,6 +36,7 @@ Page { } delegate: Pane { + id: pane height: uploadPopup.availableHeight - buttons.height - (scr.visible ? scr.height : 0) padding: Nheko.paddingSmall width: uploadPopup.availableHeight - buttons.height @@ -63,8 +64,8 @@ Page { mipmap: true smooth: true source: (modelData.thumbnail != "") ? modelData.thumbnail : ("image://colorimage/:/icons/icons/ui/" + typeStr + ".svg?" + palette.buttonText) - sourceSize.height: parent.availableHeight - namefield.height - sourceSize.width: parent.availableWidth + sourceSize.height: pane.availableHeight - namefield.height + sourceSize.width: pane.availableWidth } MatrixTextField { id: namefield From 1b216870ebb7d424f80d7ff2ff17c3b43a7f4521 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 4 Jun 2023 03:22:57 +0200 Subject: [PATCH 073/128] Fix playable media playback --- .../qml/delegates/PlayableMediaMessage.qml | 37 +++++++++---------- resources/qml/ui/media/MediaControls.qml | 12 +++--- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml index 60a61372..fb7bf0cc 100644 --- a/resources/qml/delegates/PlayableMediaMessage.qml +++ b/resources/qml/delegates/PlayableMediaMessage.qml @@ -25,9 +25,9 @@ Item { property double divisor: isReply ? 4 : 2 property int tempWidth: originalWidth < 1? 400: originalWidth implicitWidth: type == MtxEvent.VideoMessage ? Math.round(tempWidth*Math.min((timelineView.height/divisor)/(tempWidth*proportionalHeight), 1)) : 500 - width: Math.min(parent.width, implicitWidth) + width: Math.min(parent?.width ?? implicitWidth, implicitWidth) height: (type == MtxEvent.VideoMessage ? width*proportionalHeight : 80) + fileInfoLabel.height - implicitHeight: height + //implicitHeight: height property int metadataWidth property bool fitsMetadata: (parent.width - fileInfoLabel.width) > metadataWidth+4 @@ -73,29 +73,28 @@ Item { } - } - - MediaControls { - id: mediaControls - - anchors.left: content.left - anchors.right: content.right - anchors.bottom: fileInfoLabel.top - playingVideo: type == MtxEvent.VideoMessage - positionValue: mxcmedia.position - duration: mediaLoaded ? mxcmedia.duration : content.duration - mediaLoaded: mxcmedia.loaded - mediaState: mxcmedia.state - onPositionChanged: mxcmedia.position = position - onPlayPauseActivated: mxcmedia.state == MediaPlayer.PlayingState ? mxcmedia.pause() : mxcmedia.play() - onLoadActivated: mxcmedia.eventId = eventId + MediaControls { + id: mediaControls + + anchors.left: videoContainer.left + anchors.right: videoContainer.right + anchors.bottom: videoContainer.bottom + playingVideo: type == MtxEvent.VideoMessage + positionValue: mxcmedia.position + duration: mediaLoaded ? mxcmedia.duration : content.duration + mediaLoaded: mxcmedia.loaded + mediaState: mxcmedia.playbackState + onPositionChanged: mxcmedia.position = position + onPlayPauseActivated: mxcmedia.playbackState == MediaPlayer.PlayingState ? mxcmedia.pause() : mxcmedia.play() + onLoadActivated: mxcmedia.eventId = eventId + } } // information about file name and file size Label { id: fileInfoLabel - anchors.bottom: content.bottom + anchors.top: videoContainer.bottom text: body + " [" + filesize + "]" textFormat: Text.RichText elide: Text.ElideRight diff --git a/resources/qml/ui/media/MediaControls.qml b/resources/qml/ui/media/MediaControls.qml index a48f15ea..bd5f6ddc 100644 --- a/resources/qml/ui/media/MediaControls.qml +++ b/resources/qml/ui/media/MediaControls.qml @@ -4,11 +4,11 @@ import "../" import "../../" -import QtMultimedia 5.15 -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.15 -import im.nheko 1.0 +import QtMultimedia +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import im.nheko Rectangle { id: control @@ -130,7 +130,7 @@ Rectangle { NhekoSlider { id: volumeSlider - property real desiredVolume: QtMultimedia.convertVolume(volumeSlider.value, QtMultimedia.LogarithmicVolumeScale, QtMultimedia.LinearVolumeScale) + property real desiredVolume: volumeSlider.value state: "" Layout.alignment: Qt.AlignLeft From 4c71f6f23fc5cd8333aacfebfe858aad71f2038b Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 4 Jun 2023 03:31:03 +0200 Subject: [PATCH 074/128] Remove QtMac header --- src/notifications/ManagerMac.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/src/notifications/ManagerMac.mm b/src/notifications/ManagerMac.mm index 73d4287f..69914ac6 100644 --- a/src/notifications/ManagerMac.mm +++ b/src/notifications/ManagerMac.mm @@ -14,7 +14,6 @@ #import #include -#include @interface UNNotificationAttachment (UNNotificationAttachmentAdditions) + (UNNotificationAttachment*)createFromImageData:(NSData*)imgData From 5f20f94e32a986d5a79a3dfd7038db378e92f5a7 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 4 Jun 2023 03:32:21 +0200 Subject: [PATCH 075/128] Use Badge function on non-dbus systems --- src/dock/Dock.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/dock/Dock.cpp b/src/dock/Dock.cpp index 0b573c20..a4745e54 100644 --- a/src/dock/Dock.cpp +++ b/src/dock/Dock.cpp @@ -60,8 +60,6 @@ void Dock::setUnreadCount(const int count) { unitySetNotificationCount(count); - - // qGuiApp->setBadgeNumber(count); } void Dock::unitySetNotificationCount(const int count) @@ -87,7 +85,8 @@ Dock::Dock(QObject *parent) { } void -Dock::setUnreadCount(const int) +Dock::setUnreadCount(const int count) { + qGuiApp->setBadgeNumber(count); } #endif From 838b091acd07b681fc52f6f705b2bee8ce8519d5 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 4 Jun 2023 03:51:58 +0200 Subject: [PATCH 076/128] Remove MacExtras include --- src/TrayIcon.cpp | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/src/TrayIcon.cpp b/src/TrayIcon.cpp index 5d500553..8eaf522e 100644 --- a/src/TrayIcon.cpp +++ b/src/TrayIcon.cpp @@ -12,10 +12,6 @@ #include "TrayIcon.h" -#if defined(Q_OS_MAC) -#include -#endif - MsgCountComposedIcon::MsgCountComposedIcon(const QString &filename) : QIconEngine() , icon_{QIcon{filename}} @@ -125,30 +121,5 @@ TrayIcon::TrayIcon(const QString &filename, QWindow *parent) void TrayIcon::setUnreadCount(int count) { -// Use the native badge counter in MacOS. -#if defined(Q_OS_MAC) -// currently, to avoid writing obj-c code, ignore deprecated warnings on the badge functions -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - auto labelText = count == 0 ? "" : QString::number(count); - - if (labelText == QtMac::badgeLabelText()) - return; - - QtMac::setBadgeLabelText(labelText); -#pragma clang diagnostic pop -#elif defined(Q_OS_WIN) -// FIXME: Find a way to use Windows apis for the badge counter (if any). -#else - if (count == icon_->msgCount) - return; - - // Custom drawing on Linux. - MsgCountComposedIcon *tmp = static_cast(icon_->clone()); - tmp->msgCount = count; - - setIcon(QIcon(tmp)); - - icon_ = tmp; -#endif + qGuiApp->setBadgeNumber(count); } From 8485e7ae81cd75b31af755e54dd7e61c1dc34574 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Mon, 5 Jun 2023 00:18:17 +0200 Subject: [PATCH 077/128] Workaround palette not set on new windows --- src/MainWindow.cpp | 14 ++++++++++++++ src/MainWindow.h | 13 +++++++++++++ src/main.cpp | 3 +++ 3 files changed, 30 insertions(+) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 63f20752..51b23e0f 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -376,6 +376,20 @@ MainWindow::showChatPage() emit switchToChatPage(); } +bool +NhekoFixupPaletteEventFilter::eventFilter(QObject *obj, QEvent *event) +{ + // Workaround for the QGuiApplication palette not being applied to toplevel windows for some + // reason?!? + if (event->type() == QEvent::ChildAdded && + obj->metaObject()->className() == QStringLiteral("QQuickRootItem")) { + for (const auto window : QGuiApplication::topLevelWindows()) { + QGuiApplication::postEvent(window, new QEvent(QEvent::ApplicationPaletteChange)); + } + } + return false; +} + void MainWindow::closeEvent(QCloseEvent *event) { diff --git a/src/MainWindow.h b/src/MainWindow.h index 543b0f69..0a5f9433 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -37,6 +37,19 @@ class MemberList; class ReCaptcha; } +class NhekoFixupPaletteEventFilter final : public QObject +{ + Q_OBJECT + +public: + NhekoFixupPaletteEventFilter(QObject *parent) + : QObject(parent) + { + } + + bool eventFilter(QObject *obj, QEvent *event) override; +}; + class MainWindow final : public QQuickView { Q_OBJECT diff --git a/src/main.cpp b/src/main.cpp index 951d53f0..da67ca43 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -309,6 +309,9 @@ main(int argc, char *argv[]) std::exit(1); } + auto filter = new NhekoFixupPaletteEventFilter(&app); + app.installEventFilter(filter); + if (parser.isSet(configName)) UserSettings::initialize(parser.value(configName)); else From 04c9eec8a457865557a0576c417d0ba5c412ca5e Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Mon, 5 Jun 2023 01:15:07 +0200 Subject: [PATCH 078/128] Fix palette in popups --- resources/qml/Completer.qml | 3 +++ resources/qml/ForwardCompleter.qml | 3 +++ resources/qml/QuickSwitcher.qml | 3 +++ resources/qml/Root.qml | 12 ++++++------ resources/qml/ui/Snackbar.qml | 3 +++ 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml index 00141d4d..eeefe5f0 100644 --- a/resources/qml/Completer.qml +++ b/resources/qml/Completer.qml @@ -24,6 +24,9 @@ Control { property int rowMargin: 0 property int rowSpacing: Nheko.paddingSmall + // Workaround palettes not inheriting for popups + palette: timelineRoot.palette + signal completionClicked(string completion) signal completionSelected(string id) diff --git a/resources/qml/ForwardCompleter.qml b/resources/qml/ForwardCompleter.qml index cc48c46f..7ad26491 100644 --- a/resources/qml/ForwardCompleter.qml +++ b/resources/qml/ForwardCompleter.qml @@ -24,6 +24,9 @@ Popup { x: Math.round(parent.width / 2 - width / 2) y: Math.round(parent.height / 4) + // Workaround palettes not inheriting for popups + palette: timelineRoot.palette + Overlay.modal: Rectangle { color: Qt.rgba(palette.window.r, palette.window.g, palette.window.b, 0.7) } diff --git a/resources/qml/QuickSwitcher.qml b/resources/qml/QuickSwitcher.qml index 90e6560c..7d3686ed 100644 --- a/resources/qml/QuickSwitcher.qml +++ b/resources/qml/QuickSwitcher.qml @@ -21,6 +21,9 @@ Popup { x: Math.round(parent.width / 2 - contentWidth / 2) y: Math.round(parent.height / 4) + // Workaround palettes not inheriting for popups + palette: timelineRoot.palette + Overlay.modal: Rectangle { color: "#aa1E1E1E" } diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml index cb000040..b869f95a 100644 --- a/resources/qml/Root.qml +++ b/resources/qml/Root.qml @@ -10,12 +10,12 @@ import "./pages" import "./voip" import "./ui" import Qt.labs.platform 1.1 as Platform -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuick.Layouts 1.3 -import QtQuick.Window 2.15 -import im.nheko 1.0 -import im.nheko.EmojiModel 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Window +import im.nheko +import im.nheko.EmojiModel Pane { id: timelineRoot diff --git a/resources/qml/ui/Snackbar.qml b/resources/qml/ui/Snackbar.qml index b3530522..0d334079 100644 --- a/resources/qml/ui/Snackbar.qml +++ b/resources/qml/ui/Snackbar.qml @@ -9,6 +9,9 @@ import im.nheko 1.0 Popup { id: snackbar + // Workaround palettes not inheriting for popups + palette: timelineRoot.palette + property var messages: [] property string currentMessage: "" From 04cbbd2837979b7208cc1a8d183b6dc4580d937b Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Tue, 6 Jun 2023 00:29:46 +0200 Subject: [PATCH 079/128] Replace some binding loops with others --- resources/qml/MessageView.qml | 1 + resources/qml/TimelineRow.qml | 1 - resources/qml/delegates/FileMessage.qml | 7 +++---- resources/qml/delegates/MessageDelegate.qml | 2 ++ resources/qml/delegates/TextMessage.qml | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index e80770bb..002f64b9 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -164,6 +164,7 @@ Item { userId: wrapper.userId userName: wrapper.userName y: section.visible && section.active ? section.y + section.height : 0 + width: wrapper.width background: Rectangle { id: scrollHighlight diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml index a064bd15..9c8ebdc6 100644 --- a/resources/qml/TimelineRow.qml +++ b/resources/qml/TimelineRow.qml @@ -50,7 +50,6 @@ AbstractButton { height: row.height + (reactionRow.height > 0 ? reactionRow.height - 2 : 0) + unreadRow.height hoverEnabled: true - width: parent.width states: State { name: "dragging" diff --git a/resources/qml/delegates/FileMessage.qml b/resources/qml/delegates/FileMessage.qml index e63ca8e3..48546592 100644 --- a/resources/qml/delegates/FileMessage.qml +++ b/resources/qml/delegates/FileMessage.qml @@ -11,14 +11,13 @@ Item { required property string filename required property string filesize - height: row.height + (Settings.bubbles? 16: 24) - width: parent.width - implicitWidth: row.implicitWidth+metadataWidth + height: rowa.height + (Settings.bubbles? 16: 24) + implicitWidth: rowa.implicitWidth + metadataWidth property int metadataWidth property bool fitsMetadata: true RowLayout { - id: row + id: rowa anchors.centerIn: parent width: parent.width - (Settings.bubbles? 16 : 24) diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml index 3aea823f..3683ee78 100644 --- a/resources/qml/delegates/MessageDelegate.qml +++ b/resources/qml/delegates/MessageDelegate.qml @@ -39,6 +39,8 @@ Item { property bool fitsMetadata: (chooser.child && chooser.child.fitsMetadata) ? chooser.child.fitsMetadata : false property int metadataWidth + implicitWidth: chooser.child?.implicitWidth + height: chooser.child ? chooser.child.height : Nheko.paddingLarge DelegateChooser { diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index 39e8b1a8..c6a8cace 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -14,7 +14,7 @@ MatrixText { required property string formatted property string copyText: selectedText ? getText(selectionStart, selectionEnd) : body property int metadataWidth - property bool fitsMetadata: positionAt(width,height-4) == positionAt(width-metadataWidth-10, height-4) + property bool fitsMetadata: false //positionAt(width,height-4) == positionAt(width-metadataWidth-10, height-4) // table border-collapse doesn't seem to work text: " From f145c2a41a312d51b995393f404d7100b4437c97 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 8 Jun 2023 00:32:02 +0200 Subject: [PATCH 080/128] Fix notification images --- src/dbus/NhekoDBusApi.cpp | 23 ++++++++++------------- src/notifications/Manager.h | 7 ------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/dbus/NhekoDBusApi.cpp b/src/dbus/NhekoDBusApi.cpp index a613b610..6b481941 100644 --- a/src/dbus/NhekoDBusApi.cpp +++ b/src/dbus/NhekoDBusApi.cpp @@ -190,20 +190,17 @@ operator<<(QDBusArgument &arg, const QImage &image) return arg; } - QImage i = image.height() > 100 || image.width() > 100 - ? image.scaledToHeight(100, Qt::SmoothTransformation) - : image; - i = std::move(i).convertToFormat(QImage::Format_RGBA8888); - + QImage i = image.height() > 100 || image.width() > 100 + ? image.scaledToHeight(100, Qt::SmoothTransformation) + : image; + bool hasAlpha = i.hasAlphaChannel(); + i = std::move(i).convertToFormat(hasAlpha ? QImage::Format_RGBA8888 : QImage::Format_RGB888); + + int channels = hasAlpha ? 4 : 3; + QByteArray arr(reinterpret_cast(i.bits()), static_cast(i.sizeInBytes())); arg.beginStructure(); - arg << i.width(); - arg << i.height(); - arg << i.bytesPerLine(); - arg << i.hasAlphaChannel(); - int channels = i.hasAlphaChannel() ? 4 : 3; - arg << i.depth() / channels; - arg << channels; - arg << QByteArray(reinterpret_cast(i.bits()), static_cast(i.sizeInBytes())); + arg << i.width() << i.height() << (int)i.bytesPerLine() << i.hasAlphaChannel() + << i.depth() / channels << channels << arr; arg.endStructure(); return arg; diff --git a/src/notifications/Manager.h b/src/notifications/Manager.h index bc37dbd8..7686d78e 100644 --- a/src/notifications/Manager.h +++ b/src/notifications/Manager.h @@ -111,10 +111,3 @@ private: // Only populated on Linux atm QMap notificationIds; }; - -#if defined(NHEKO_DBUS_SYS) -QDBusArgument & -operator<<(QDBusArgument &arg, const QImage &image); -const QDBusArgument & -operator>>(const QDBusArgument &arg, QImage &); -#endif From 07731f0a2b08e41dbffd3e4ba821e4ff3b1e1352 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 8 Jun 2023 01:51:27 +0200 Subject: [PATCH 081/128] Fix theme in cross-signing setup --- resources/qml/Completer.qml | 6 +++--- resources/qml/ForwardCompleter.qml | 6 +++--- resources/qml/MessageView.qml | 2 +- resources/qml/QuickSwitcher.qml | 6 +++--- resources/qml/SelfVerificationCheck.qml | 8 ++++++++ resources/qml/UploadBox.qml | 1 + 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml index eeefe5f0..7b18951c 100644 --- a/resources/qml/Completer.qml +++ b/resources/qml/Completer.qml @@ -24,9 +24,6 @@ Control { property int rowMargin: 0 property int rowSpacing: Nheko.paddingSmall - // Workaround palettes not inheriting for popups - palette: timelineRoot.palette - signal completionClicked(string completion) signal completionSelected(string id) @@ -76,6 +73,9 @@ Control { bottomPadding: 1 leftPadding: 1 + + // Workaround palettes not inheriting for popups + palette: timelineRoot.palette rightPadding: 1 topPadding: 1 diff --git a/resources/qml/ForwardCompleter.qml b/resources/qml/ForwardCompleter.qml index 7ad26491..0174e0f6 100644 --- a/resources/qml/ForwardCompleter.qml +++ b/resources/qml/ForwardCompleter.qml @@ -18,15 +18,15 @@ Popup { leftPadding: 10 modal: true + + // Workaround palettes not inheriting for popups + palette: timelineRoot.palette parent: Overlay.overlay rightPadding: 10 width: timelineRoot.width * 0.8 x: Math.round(parent.width / 2 - width / 2) y: Math.round(parent.height / 4) - // Workaround palettes not inheriting for popups - palette: timelineRoot.palette - Overlay.modal: Rectangle { color: Qt.rgba(palette.window.r, palette.window.g, palette.window.b, 0.7) } diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index 002f64b9..3eed4c48 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -163,8 +163,8 @@ Item { url: wrapper.url userId: wrapper.userId userName: wrapper.userName - y: section.visible && section.active ? section.y + section.height : 0 width: wrapper.width + y: section.visible && section.active ? section.y + section.height : 0 background: Rectangle { id: scrollHighlight diff --git a/resources/qml/QuickSwitcher.qml b/resources/qml/QuickSwitcher.qml index 7d3686ed..67718ecb 100644 --- a/resources/qml/QuickSwitcher.qml +++ b/resources/qml/QuickSwitcher.qml @@ -16,14 +16,14 @@ Popup { background: null closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside modal: true + + // Workaround palettes not inheriting for popups + palette: timelineRoot.palette parent: Overlay.overlay width: Math.min(Math.max(Math.round(parent.width / 2), 450), parent.width) // limiting width to parent.width/2 can be a bit narrow x: Math.round(parent.width / 2 - contentWidth / 2) y: Math.round(parent.height / 4) - // Workaround palettes not inheriting for popups - palette: timelineRoot.palette - Overlay.modal: Rectangle { color: "#aa1E1E1E" } diff --git a/resources/qml/SelfVerificationCheck.qml b/resources/qml/SelfVerificationCheck.qml index 80897ff9..1752df0e 100644 --- a/resources/qml/SelfVerificationCheck.qml +++ b/resources/qml/SelfVerificationCheck.qml @@ -23,6 +23,9 @@ Item { height: content.height + implicitFooterHeight + implicitHeaderHeight modal: true padding: 0 + + // Workaround palettes not inheriting for popups + palette: timelineRoot.palette parent: Overlay.overlay standardButtons: Dialog.Ok width: content.width @@ -78,6 +81,9 @@ Item { MainWindowDialog { id: bootstrapCrosssigning + // Workaround palettes not inheriting for popups + palette: timelineRoot.palette + background: Rectangle { border.color: Nheko.theme.separator border.width: 1 @@ -202,6 +208,8 @@ Item { MainWindowDialog { id: verifyMasterKey + // Workaround palettes not inheriting for popups + palette: timelineRoot.palette standardButtons: Dialog.Cancel GridLayout { diff --git a/resources/qml/UploadBox.qml b/resources/qml/UploadBox.qml index 215003ec..990fa422 100644 --- a/resources/qml/UploadBox.qml +++ b/resources/qml/UploadBox.qml @@ -37,6 +37,7 @@ Page { } delegate: Pane { id: pane + height: uploadPopup.availableHeight - buttons.height - (scr.visible ? scr.height : 0) padding: Nheko.paddingSmall width: uploadPopup.availableHeight - buttons.height From ca0340dd81f1a2bf11af5af626dc6d001abda827 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 8 Jun 2023 02:08:40 +0200 Subject: [PATCH 082/128] Fix communites sidebar color --- resources/qml/CommunitiesList.qml | 8 +++++--- resources/qml/emoji/StickerPicker.qml | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/resources/qml/CommunitiesList.qml b/resources/qml/CommunitiesList.qml index d93f5900..24444ae6 100644 --- a/resources/qml/CommunitiesList.qml +++ b/resources/qml/CommunitiesList.qml @@ -143,12 +143,14 @@ Page { enabled: false height: avatarSize roomid: model.id + textColor: model.avatarUrl.startsWith(":/") ? communityItem.unimportantText : communityItem.importantText url: { if (model.avatarUrl.startsWith("mxc://")) return model.avatarUrl.replace("mxc://", "image://MxcImage/"); - else if (model.avatarUrl.length > 0) - return "image://colorimage/" + model.avatarUrl + "?" + communityItem.unimportantText; - else + else if (model.avatarUrl.length > 0) { + console.log("image://colorimage/" + model.avatarUrl + "?" + communityItem.unimportantText); + return model.avatarUrl; + } else return ""; } width: avatarSize diff --git a/resources/qml/emoji/StickerPicker.qml b/resources/qml/emoji/StickerPicker.qml index 62d56a18..c10e57e7 100644 --- a/resources/qml/emoji/StickerPicker.qml +++ b/resources/qml/emoji/StickerPicker.qml @@ -231,6 +231,7 @@ Menu { height: sidebarAvatarSize width: sidebarAvatarSize url: modelData.url.replace("mxc://", "image://MxcImage/") + textColor: modelData.url.startsWith("mxc://") ? palette.text : palette.buttonText displayName: modelData.name roomid: modelData.name From 05f1f8f556ad1ffd1260c0e03d627c0ccc389541 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 8 Jun 2023 22:44:16 +0200 Subject: [PATCH 083/128] Fix translations (and simplify resource files) --- CMakeLists.txt | 17 +++++++++++++---- cmake/Translations.cmake | 28 ---------------------------- 2 files changed, 13 insertions(+), 32 deletions(-) delete mode 100644 cmake/Translations.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d64aa2c6..60cbe6ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -633,10 +633,13 @@ if (NOT APPLE AND NOT WIN32) endif() # -# Bundle translations. +# Bundle resources # -include(Translations) -set(TRANSLATION_DEPS ${LANG_QRC} ${QRC} ${QM_SRC}) +if(Qt6QuickCompiler_FOUND AND COMPILE_QML) + qtquick_compiler_add_resources(QRC resources/res.qrc) +else() + qt_add_resources(QRC resources/res.qrc) +endif() if (APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Foundation -framework Cocoa -framework UserNotifications") @@ -668,7 +671,7 @@ endif () set(NHEKO_DEPS ${SRC_FILES} - ${TRANSLATION_DEPS} + ${QRC} ${META_FILES_TO_INCLUDE}) if(ASAN) @@ -691,6 +694,12 @@ set_target_properties(nheko CMAKE_SKIP_INSTALL_RPATH TRUE AUTOMOC ON) +# +# Bundle translations +# +file(GLOB LANG_TS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/resources/langs/*.ts") +qt_add_translations(nheko RESOURCE_PREFIX "/translations" TS_FILES ${LANG_TS_SRC}) + if(WIN32) target_compile_definitions(nheko PRIVATE WIN32_LEAN_AND_MEAN) if(MSVC) diff --git a/cmake/Translations.cmake b/cmake/Translations.cmake deleted file mode 100644 index 9422570d..00000000 --- a/cmake/Translations.cmake +++ /dev/null @@ -1,28 +0,0 @@ -# -# Generate the translation resource file -# - -file(GLOB LANG_TS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/resources/langs/*.ts") - -qt_add_translation(QM_SRC ${LANG_TS_SRC}) -qt_create_translation(${QM_SRC}) -add_custom_target(LANG_QRC ALL DEPENDS ${QM_SRC}) - -# Generate a qrc file for the translations -set(_qrc ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc) - -if(NOT EXISTS ${_qrc}) - file(WRITE ${_qrc} "\n \n") - foreach(_lang ${QM_SRC}) - get_filename_component(_filename ${_lang} NAME) - file(APPEND ${_qrc} " ${_filename}\n") - endforeach(_lang) - file(APPEND ${_qrc} " \n\n") -endif() - -qt_add_resources(LANG_QRC ${_qrc}) -if(Qt5QuickCompiler_FOUND AND COMPILE_QML) - qtquick_compiler_add_resources(QRC resources/res.qrc) -else() - qt_add_resources(QRC resources/res.qrc) -endif() From 8259891a42336cbc839268d8beae4b456146d836 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 8 Jun 2023 23:24:32 +0200 Subject: [PATCH 084/128] Make settings combobox width dependent on content fixes #1164 --- resources/qml/CommunitiesList.qml | 5 ++--- resources/qml/pages/UserSettingsPage.qml | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/qml/CommunitiesList.qml b/resources/qml/CommunitiesList.qml index 24444ae6..81f0640e 100644 --- a/resources/qml/CommunitiesList.qml +++ b/resources/qml/CommunitiesList.qml @@ -147,10 +147,9 @@ Page { url: { if (model.avatarUrl.startsWith("mxc://")) return model.avatarUrl.replace("mxc://", "image://MxcImage/"); - else if (model.avatarUrl.length > 0) { - console.log("image://colorimage/" + model.avatarUrl + "?" + communityItem.unimportantText); + else if (model.avatarUrl.length > 0) return model.avatarUrl; - } else + else return ""; } width: avatarSize diff --git a/resources/qml/pages/UserSettingsPage.qml b/resources/qml/pages/UserSettingsPage.qml index 08581ac5..fa0f3898 100644 --- a/resources/qml/pages/UserSettingsPage.qml +++ b/resources/qml/pages/UserSettingsPage.qml @@ -99,6 +99,7 @@ Rectangle { model: r.model.values currentIndex: r.model.value onCurrentIndexChanged: r.model.value = currentIndex + implicitContentWidthPolicy: ComboBox.WidestTextWhenCompleted WheelHandler{} // suppress scrolling changing values } From 885168c08fc1b27805342b3485aabade1f30900a Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 9 Jun 2023 01:51:11 +0200 Subject: [PATCH 085/128] Use qt6 prefix to build macos packages --- .ci/macos/build.sh | 6 +++--- .ci/macos/notarize.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.ci/macos/build.sh b/.ci/macos/build.sh index 40ab2571..1d703a85 100755 --- a/.ci/macos/build.sh +++ b/.ci/macos/build.sh @@ -6,10 +6,10 @@ set -ue #TAG=$(git tag -l --points-at HEAD) # Add Qt binaries to path -PATH="$(brew --prefix qt5):${PATH}" +PATH="$(brew --prefix qt6):${PATH}" export PATH -CMAKE_PREFIX_PATH="$(brew --prefix qt5)" +CMAKE_PREFIX_PATH="$(brew --prefix qt6)" export CMAKE_PREFIX_PATH cmake -GNinja -S. -Bbuild \ @@ -28,5 +28,5 @@ cmake --build build make -j 4 cp libqtjdenticon.dylib ../nheko.app/Contents/MacOS ) - "$(brew --prefix qt5)/bin/macdeployqt" nheko.app -always-overwrite -qmldir=../resources/qml/ + "$(brew --prefix qt6)/bin/macdeployqt" nheko.app -always-overwrite -qmldir=../resources/qml/ ) diff --git a/.ci/macos/notarize.sh b/.ci/macos/notarize.sh index 345f4828..6dc057bc 100755 --- a/.ci/macos/notarize.sh +++ b/.ci/macos/notarize.sh @@ -6,7 +6,7 @@ set -u # https://forum.qt.io/topic/96652/how-to-notarize-qt-application-on-macos/18 # Add Qt binaries to path -PATH="/usr/local/opt/qt@5/bin/:${PATH}" +PATH="/usr/local/opt/qt@6/bin/:${PATH}" export PATH security unlock-keychain -p "${RUNNER_USER_PW}" login.keychain @@ -100,4 +100,4 @@ if [ -n "$VERSION" ]; then mv nheko.dmg "nheko-${VERSION}-${PLAT}.dmg" mkdir -p artifacts cp "nheko-${VERSION}-${PLAT}.dmg" artifacts/ -fi \ No newline at end of file +fi From 16960e2900b0bf495cdb3d32ed25e76efc1048ca Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 9 Jun 2023 02:40:50 +0200 Subject: [PATCH 086/128] Fix scrolling in image dialog --- resources/qml/dialogs/ImageOverlay.qml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/resources/qml/dialogs/ImageOverlay.qml b/resources/qml/dialogs/ImageOverlay.qml index fa874529..b914829e 100644 --- a/resources/qml/dialogs/ImageOverlay.qml +++ b/resources/qml/dialogs/ImageOverlay.qml @@ -25,12 +25,12 @@ Window { Component.onCompleted: Nheko.setWindowRole(imageOverlay, "imageoverlay") Shortcut { - sequence: StandardKey.Cancel + sequences: [StandardKey.Cancel] onActivated: imageOverlay.close() } Shortcut { - sequence: StandardKey.Copy + sequences: [StandardKey.Copy] onActivated: { if (room) { room.copyMedia(eventId); @@ -98,6 +98,10 @@ Window { WheelHandler { property: "scale" + // workaround for QTBUG-87646 / QTBUG-112394 / QTBUG-112432: + // Magic Mouse pretends to be a trackpad but doesn't work with PinchHandler + // and we don't yet distinguish mice and trackpads on Wayland either + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad target: imgContainer } From 2eccec6636b4d78ac3b5f4453a00a1e1d6db61d9 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 9 Jun 2023 03:13:41 +0200 Subject: [PATCH 087/128] Try to work around macdeployqt missing packages --- .ci/macos/build.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.ci/macos/build.sh b/.ci/macos/build.sh index 1d703a85..1c60015e 100755 --- a/.ci/macos/build.sh +++ b/.ci/macos/build.sh @@ -6,7 +6,7 @@ set -ue #TAG=$(git tag -l --points-at HEAD) # Add Qt binaries to path -PATH="$(brew --prefix qt6):${PATH}" +PATH="$(brew --prefix qt6)/bin/:${PATH}" export PATH CMAKE_PREFIX_PATH="$(brew --prefix qt6)" @@ -29,4 +29,6 @@ cmake --build build cp libqtjdenticon.dylib ../nheko.app/Contents/MacOS ) "$(brew --prefix qt6)/bin/macdeployqt" nheko.app -always-overwrite -qmldir=../resources/qml/ + # workaround for https://bugreports.qt.io/browse/QTBUG-100686 + cp "$(brew --prefix brotli)/lib/libbrotlicommon.1.dylib" nheko.app/Contents/Frameworks/libbrotlicommon.1.dylib ) From 805f0a30321a21d268ad1f678cb8d42670b2f03e Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 9 Jun 2023 19:38:58 +0200 Subject: [PATCH 088/128] Fix toggle placement in user settings --- resources/qml/pages/UserSettingsPage.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/qml/pages/UserSettingsPage.qml b/resources/qml/pages/UserSettingsPage.qml index fa0f3898..c23606ff 100644 --- a/resources/qml/pages/UserSettingsPage.qml +++ b/resources/qml/pages/UserSettingsPage.qml @@ -33,15 +33,17 @@ Rectangle { spacing: Nheko.paddingMedium + width: scroll.availableWidth anchors.fill: parent anchors.leftMargin: userSettingsDialog.collapsed ? 0 : (userSettingsDialog.width-userSettingsDialog.collapsePoint) * 0.4 + Nheko.paddingLarge anchors.rightMargin: anchors.leftMargin + Repeater { model: UserSettingsModel - Layout.fillWidth:true delegate: GridLayout { + width: scroll.availableWidth columns: collapsed? 1 : 2 rows: collapsed? 2: 1 required property var model @@ -78,7 +80,7 @@ Rectangle { Layout.columnSpan: (model.type == UserSettingsModel.SectionTitle && !userSettingsDialog.collapsed) ? 2 : 1 Layout.preferredHeight: child.height - Layout.preferredWidth: Math.min(child.implicitWidth, child.width || 1000) + Layout.preferredWidth: child.implicitWidth Layout.maximumWidth: model.type == UserSettingsModel.SectionTitle ? Number.POSITIVE_INFINITY : 400 Layout.fillWidth: model.type == UserSettingsModel.SectionTitle || model.type == UserSettingsModel.Options || model.type == UserSettingsModel.Number Layout.rightMargin: model.type == UserSettingsModel.SectionTitle ? 0 : Nheko.paddingMedium @@ -95,9 +97,9 @@ Rectangle { roleValue: UserSettingsModel.Options ComboBox { anchors.right: parent.right - width: Math.min(parent.width, implicitWidth) model: r.model.values currentIndex: r.model.value + width: Math.min(implicitWidth, scroll.availableWidth - Nheko.paddingMedium) onCurrentIndexChanged: r.model.value = currentIndex implicitContentWidthPolicy: ComboBox.WidestTextWhenCompleted @@ -109,7 +111,6 @@ Rectangle { SpinBox { anchors.right: parent.right - width: Math.min(parent.width, implicitWidth) from: model.valueLowerBound to: model.valueUpperBound stepSize: model.valueStep @@ -130,7 +131,6 @@ Rectangle { readonly property int decimals: 2 anchors.right: parent.right - width: Math.min(parent.width, implicitWidth) from: model.valueLowerBound * div to: model.valueUpperBound * div stepSize: model.valueStep * div From 2d7c007eb2cab03f0a5860eba40bd640b05cd94a Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 9 Jun 2023 20:14:41 +0200 Subject: [PATCH 089/128] Fix binding loop in roomlist --- resources/qml/RoomList.qml | 77 ++++++++++--------- .../qml/components/NotificationBubble.qml | 1 + 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index ac4f8c3a..615c67fa 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -546,66 +546,73 @@ Page { visible: !collapsed width: roomItem.width - avatar.width - NotificationBubble { - id: notificationBubble - - Layout.alignment: Qt.AlignRight - Layout.leftMargin: Nheko.paddingSmall - Layout.preferredHeight: implicitHeight - Layout.preferredWidth: implicitWidth - bubbleBackgroundColor: roomItem.bubbleBackground - bubbleTextColor: roomItem.bubbleText - hasLoudNotification: roomItem.hasLoudNotification - mayBeVisible: !collapsed && (isSpace ? Settings.spaceNotifications : true) - notificationCount: roomItem.notificationCount - parent: isSpace ? titleRow : subtextRow - } - RowLayout { + Item { id: titleRow Layout.alignment: Qt.AlignTop - Layout.preferredWidth: roomItem.width - avatar.width - spacing: Nheko.paddingSmall - - Item { - Layout.alignment: Qt.AlignBottom - Layout.fillWidth: true - - ElidedLabel { - anchors.bottom: parent.bottom - color: roomItem.importantText - elideWidth: parent.width - fullText: TimelineManager.htmlEscape(roomName) - textFormat: Text.RichText - } + Layout.fillWidth: true + Layout.preferredHeight: subtitleText.implicitHeight + + ElidedLabel { + id: titleText + + anchors.left: parent.left + color: roomItem.importantText + elideWidth: parent.width - (timestamp.visible ? timestamp.implicitWidth : 0) - (spaceNotificationBubble.visible ? spaceNotificationBubble.implicitWidth : 0) + fullText: TimelineManager.htmlEscape(roomName) + textFormat: Text.RichText } Label { id: timestamp - Layout.alignment: Qt.AlignRight | Qt.AlignBottom + anchors.baseline: titleText.baseline + anchors.right: parent.right color: roomItem.unimportantText font.pixelSize: fontMetrics.font.pixelSize * 0.9 text: time visible: !isInvite && !isSpace } + NotificationBubble { + id: spaceNotificationBubble + + anchors.right: parent.right + bubbleBackgroundColor: roomItem.bubbleBackground + bubbleTextColor: roomItem.bubbleText + hasLoudNotification: roomItem.hasLoudNotification + mayBeVisible: !collapsed && (isSpace ? Settings.spaceNotifications : false) + notificationCount: roomItem.notificationCount + parent: isSpace ? titleRow : subtextRow + } } - RowLayout { + Item { id: subtextRow Layout.alignment: Qt.AlignBottom Layout.fillWidth: true - height: visible ? 0 : undefined - spacing: 0 + Layout.preferredHeight: subtitleText.implicitHeight visible: !isSpace ElidedLabel { - Layout.fillWidth: true + id: subtitleText + + anchors.left: parent.left color: roomItem.unimportantText - elideWidth: width + elideWidth: subtextRow.width - (subtextNotificationBubble.visible ? subtextNotificationBubble.implicitWidth : 0) font.pixelSize: fontMetrics.font.pixelSize * 0.9 fullText: TimelineManager.htmlEscape(lastMessage) textFormat: Text.RichText } + NotificationBubble { + id: subtextNotificationBubble + + anchors.baseline: subtitleText.baseline + anchors.right: parent.right + bubbleBackgroundColor: roomItem.bubbleBackground + bubbleTextColor: roomItem.bubbleText + hasLoudNotification: roomItem.hasLoudNotification + mayBeVisible: !collapsed + notificationCount: roomItem.notificationCount + } } } } diff --git a/resources/qml/components/NotificationBubble.qml b/resources/qml/components/NotificationBubble.qml index f0a526d0..d4838e92 100644 --- a/resources/qml/components/NotificationBubble.qml +++ b/resources/qml/components/NotificationBubble.qml @@ -15,6 +15,7 @@ Rectangle { required property color bubbleTextColor property bool mayBeVisible: true property alias font: notificationBubbleText.font + baselineOffset: notificationBubbleText.baseline - bubbleRoot.top visible: mayBeVisible && notificationCount > 0 implicitHeight: notificationBubbleText.height + Nheko.paddingMedium From c7b78ca1825c597278df827269dd78437eb44ba2 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 9 Jun 2023 23:22:44 +0200 Subject: [PATCH 090/128] Properly set pack avatar fixes #1480 --- src/GridImagePackModel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/GridImagePackModel.cpp b/src/GridImagePackModel.cpp index 2d5960a4..cfd014f0 100644 --- a/src/GridImagePackModel.cpp +++ b/src/GridImagePackModel.cpp @@ -108,6 +108,8 @@ GridImagePackModel::GridImagePackModel(const std::string &roomId, bool stickers, PackDesc newPack{}; newPack.packname = pack.pack.pack ? QString::fromStdString(pack.pack.pack->display_name) : QString(); + newPack.packavatar = + pack.pack.pack ? QString::fromStdString(pack.pack.pack->avatar_url) : QString(); newPack.room_id = pack.source_room; newPack.state_key = pack.state_key; From 0dbc9444c3d43202db2db90e9bfae54811119a0c Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 10 Jun 2023 00:49:49 +0200 Subject: [PATCH 091/128] Add inviter to the invite reason fixes #622 --- resources/qml/TimelineView.qml | 25 +++++++++++++++++- src/Cache.cpp | 15 +++++++++-- src/CacheStructs.h | 1 + src/Cache_p.h | 13 +++++++++- src/timeline/RoomlistModel.cpp | 46 ++++++++++++++++++++++++++++++++++ src/timeline/RoomlistModel.h | 6 +++++ 6 files changed, 102 insertions(+), 4 deletions(-) diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 24489d0b..18085f28 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -283,6 +283,29 @@ Item { onClicked: TimelineManager.openLeaveRoomDialog(room.roomId) } + RowLayout { + Layout.alignment: Qt.AlignHCenter + spacing: Nheko.paddingMedium + visible: roomPreview && roomPreview.isInvite && reasonField.showReason + + MatrixText { + text: qsTr("Invited by %1 (%2)").arg(TimelineManager.escapeEmoji(inviterAvatar.displayName)).arg(TimelineManager.escapeEmoji(TimelineManager.htmlEscape(inviterAvatar.userid))) + } + Avatar { + id: inviterAvatar + + Layout.alignment: Qt.AlignHCenter + displayName: roomPreview?.inviterDisplayName ?? "" + enabled: true + height: 48 + roomid: preview.roomId + url: (roomPreview?.inviterAvatarUrl ?? "").replace("mxc://", "image://MxcImage/") + userid: roomPreview?.inviterUserId ?? "" + width: 48 + + onClicked: TimelineManager.openGlobalUserProfile(roomPreview.inviterUserId) + } + } ScrollView { id: reasonField @@ -312,7 +335,7 @@ Item { Layout.leftMargin: Nheko.paddingLarge Layout.rightMargin: Nheko.paddingLarge text: reasonField.showReason ? qsTr("Hide invite reason") : qsTr("Show invite reason") - visible: preview.reason !== "" + visible: roomPreview && roomPreview.isInvite onClicked: { reasonField.showReason = !reasonField.showReason; diff --git a/src/Cache.cpp b/src/Cache.cpp index 7671af02..f4aad6b3 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -2128,8 +2128,16 @@ Cache::saveInvite(lmdb::txn &txn, auto display_name = msg->content.display_name.empty() ? msg->state_key : msg->content.display_name; - MemberInfo tmp{ - display_name, msg->content.avatar_url, msg->content.reason, msg->content.is_direct}; + std::string inviter = ""; + if (msg->content.membership == mtx::events::state::Membership::Invite) { + inviter = msg->sender; + } + + MemberInfo tmp{display_name, + msg->content.avatar_url, + inviter, + msg->content.reason, + msg->content.is_direct}; membersdb.put(txn, msg->state_key, nlohmann::json(tmp).dump()); } else { @@ -5173,6 +5181,8 @@ to_json(nlohmann::json &j, const MemberInfo &info) { j["name"] = info.name; j["avatar_url"] = info.avatar_url; + if (!info.inviter.empty()) + j["inviter"] = info.inviter; if (info.is_direct) j["is_direct"] = info.is_direct; if (!info.reason.empty()) @@ -5186,6 +5196,7 @@ from_json(const nlohmann::json &j, MemberInfo &info) info.avatar_url = j.value("avatar_url", ""); info.is_direct = j.value("is_direct", false); info.reason = j.value("reason", ""); + info.inviter = j.value("inviter", ""); } void diff --git a/src/CacheStructs.h b/src/CacheStructs.h index 6dad4b19..13c24c99 100644 --- a/src/CacheStructs.h +++ b/src/CacheStructs.h @@ -117,6 +117,7 @@ struct MemberInfo { std::string name; std::string avatar_url; + std::string inviter = ""; std::string reason = ""; bool is_direct = false; }; diff --git a/src/Cache_p.h b/src/Cache_p.h index f8716e81..121e7e66 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -394,8 +394,19 @@ private: auto display_name = e->content.display_name.empty() ? e->state_key : e->content.display_name; + std::string inviter = ""; + if (e->content.membership == mtx::events::state::Membership::Invite) { + inviter = e->sender; + } + // Lightweight representation of a member. - MemberInfo tmp{display_name, e->content.avatar_url, e->content.reason}; + MemberInfo tmp{ + display_name, + e->content.avatar_url, + inviter, + e->content.reason, + e->content.is_direct, + }; membersdb.put(txn, e->state_key, nlohmann::json(tmp).dump()); break; diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp index 35507cbd..ec41cc12 100644 --- a/src/timeline/RoomlistModel.cpp +++ b/src/timeline/RoomlistModel.cpp @@ -1235,3 +1235,49 @@ FilteredRoomlistModel::previousRoom() } } } + +QString +RoomPreview::inviterAvatarUrl() const +{ + if (isInvite_) { + auto self = cache::client()->getInviteMember(roomid_.toStdString(), + http::client()->user_id().to_string()); + if (self && !self->inviter.empty()) { + auto other = cache::client()->getInviteMember(roomid_.toStdString(), self->inviter); + if (other && other->avatar_url.starts_with("mxc://")) { + return QString::fromStdString(other->avatar_url); + } + } + } + + return QString(); +} +QString +RoomPreview::inviterDisplayName() const +{ + if (isInvite_) { + auto self = cache::client()->getInviteMember(roomid_.toStdString(), + http::client()->user_id().to_string()); + if (self && !self->inviter.empty()) { + auto other = cache::client()->getInviteMember(roomid_.toStdString(), self->inviter); + if (other) { + return QString::fromStdString(other->name).toHtmlEscaped(); + } + } + } + + return QString(); +} +QString +RoomPreview::inviterUserId() const +{ + if (isInvite_) { + auto self = cache::client()->getInviteMember(roomid_.toStdString(), + http::client()->user_id().to_string()); + if (self && !self->inviter.empty()) { + return QString::fromStdString(self->inviter); + } + } + + return QString(); +} diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h index 9aaafc06..c06ab67d 100644 --- a/src/timeline/RoomlistModel.h +++ b/src/timeline/RoomlistModel.h @@ -31,6 +31,9 @@ class RoomPreview Q_PROPERTY(QString roomTopic READ roomTopic CONSTANT) Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl CONSTANT) Q_PROPERTY(QString reason READ reason CONSTANT) + Q_PROPERTY(QString inviterAvatarUrl READ inviterAvatarUrl CONSTANT) + Q_PROPERTY(QString inviterDisplayName READ inviterDisplayName CONSTANT) + Q_PROPERTY(QString inviterUserId READ inviterUserId CONSTANT) Q_PROPERTY(bool isInvite READ isInvite CONSTANT) Q_PROPERTY(bool isFetched READ isFetched CONSTANT) @@ -42,6 +45,9 @@ public: QString roomTopic() const { return roomTopic_; } QString roomAvatarUrl() const { return roomAvatarUrl_; } QString reason() const { return reason_; } + QString inviterAvatarUrl() const; + QString inviterDisplayName() const; + QString inviterUserId() const; bool isInvite() const { return isInvite_; } bool isFetched() const { return isFetched_; } From 4af8d7d397849d7240099f2096052b3683786d83 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 10 Jun 2023 01:09:20 +0200 Subject: [PATCH 092/128] Show some generic message for ACL changes fixes #1476 --- resources/qml/delegates/MessageDelegate.qml | 14 ++++++++++++++ src/timeline/TimelineModel.cpp | 5 +++++ src/timeline/TimelineModel.h | 2 ++ 3 files changed, 21 insertions(+) diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml index 3683ee78..68f65062 100644 --- a/resources/qml/delegates/MessageDelegate.qml +++ b/resources/qml/delegates/MessageDelegate.qml @@ -282,6 +282,20 @@ Item { } + DelegateChoice { + roleValue: MtxEvent.ServerAcl + + NoticeMessage { + body: formatted + isOnlyEmoji: false + isReply: d.isReply + keepFullText: d.keepFullText + isStateEvent: d.isStateEvent + formatted: qsTr("%1 changed which servers are allowed in this room.").arg(d.userName) + } + + } + DelegateChoice { roleValue: MtxEvent.Name diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 6cec615b..22fe63d4 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -216,6 +216,8 @@ qml_mtx_events::toRoomEventType(mtx::events::EventType e) return qml_mtx_events::EventType::Topic; case EventType::RoomTombstone: return qml_mtx_events::EventType::Tombstone; + case EventType::RoomServerAcl: + return qml_mtx_events::EventType::ServerAcl; case EventType::RoomRedaction: return qml_mtx_events::EventType::Redaction; case EventType::RoomPinnedEvents: @@ -334,6 +336,9 @@ qml_mtx_events::fromRoomEventType(qml_mtx_events::EventType t) /// m.room.tombstone case qml_mtx_events::Tombstone: return mtx::events::EventType::RoomTombstone; + /// m.room.server_acl + case qml_mtx_events::ServerAcl: + return mtx::events::EventType::RoomServerAcl; /// m.room.topic case qml_mtx_events::Topic: return mtx::events::EventType::RoomTopic; diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index d1f04e21..a232b4ee 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -85,6 +85,8 @@ enum EventType PowerLevels, /// m.room.tombstone Tombstone, + /// m.room.server_acl + ServerAcl, /// m.room.topic Topic, /// m.room.redaction From 396f49524286a3369634bcc8f0acbee3a471775d Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 10 Jun 2023 01:20:10 +0200 Subject: [PATCH 093/128] Fix linting --- src/CacheStructs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CacheStructs.h b/src/CacheStructs.h index 13c24c99..6e2f800a 100644 --- a/src/CacheStructs.h +++ b/src/CacheStructs.h @@ -118,8 +118,8 @@ struct MemberInfo std::string name; std::string avatar_url; std::string inviter = ""; - std::string reason = ""; - bool is_direct = false; + std::string reason = ""; + bool is_direct = false; }; void From 9796c40619542b2dbdf0c205e93f42b57b62f56c Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 10 Jun 2023 02:01:42 +0200 Subject: [PATCH 094/128] Use TextArea for message text Allows double click with the middle mouse button to reply and fixed the theming. fixes #1462 --- resources/qml/MatrixText.qml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/resources/qml/MatrixText.qml b/resources/qml/MatrixText.qml index 057a632f..6d611311 100644 --- a/resources/qml/MatrixText.qml +++ b/resources/qml/MatrixText.qml @@ -6,11 +6,21 @@ import QtQuick 2.5 import QtQuick.Controls 2.3 import im.nheko 1.0 -TextEdit { +TextArea { id: r property alias cursorShape: cs.cursorShape + leftInset: 0 + bottomInset: 0 + rightInset: 0 + topInset: 0 + leftPadding: 0 + bottomPadding: 0 + rightPadding: 0 + topPadding: 0 + background: null + ToolTip.text: hoveredLink ToolTip.visible: hoveredLink || false // this always has to be enabled, otherwise you can't click links anymore! @@ -29,6 +39,11 @@ TextEdit { } onLinkActivated: Nheko.openLink(link) + + // propagate events up + onPressAndHold: (event) => event.accepted = false + onPressed: (event) => event.accepted = (event.button == Qt.LeftButton) + CursorShape { id: cs From c0fe28137ef484b7abbb857da1bce362ff707e0c Mon Sep 17 00:00:00 2001 From: Weblate Date: Sat, 10 Jun 2023 18:38:54 +0000 Subject: [PATCH 095/128] Translated using Weblate (Indonesian) Currently translated at 100.0% (942 of 942 strings) Co-authored-by: Linerly Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/id/ Translation: Nheko/nheko --- resources/langs/nheko_id.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/langs/nheko_id.ts b/resources/langs/nheko_id.ts index 2906a3c9..7af25e13 100644 --- a/resources/langs/nheko_id.ts +++ b/resources/langs/nheko_id.ts @@ -1401,6 +1401,11 @@ Kamu dapat memberikan alasan untuk orang lain untuk menerima ketukanmu:Upload of '%1' failed Pengunggahan '%1' gagal + + + Select file(s) + Pilih berkas + InviteDialog From b12b76394a6001c92797d34bc45e966a23de7ac5 Mon Sep 17 00:00:00 2001 From: Weblate Date: Sat, 10 Jun 2023 18:38:54 +0000 Subject: [PATCH 096/128] Translated using Weblate (French) Currently translated at 72.8% (686 of 942 strings) Co-authored-by: Mayeul Cantan Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index cb11e3d3..69820a0a 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -774,7 +774,7 @@ Vous pouvez éventuellement fournir une raison afin que les membres acceptent vo Failed to update community: %1 - Echec de mise à jour de la communauté : %1 + Erreur lors de la mise à jour de cette communauté : %1 From 2d75f4a6fd2f38329c817b0d453c281cecfa284a Mon Sep 17 00:00:00 2001 From: Weblate Date: Sat, 10 Jun 2023 18:38:54 +0000 Subject: [PATCH 097/128] Translated using Weblate (Estonian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (942 of 942 strings) Co-authored-by: Priit Jõerüüt Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/et/ Translation: Nheko/nheko --- resources/langs/nheko_et.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/langs/nheko_et.ts b/resources/langs/nheko_et.ts index d8080eb7..380c3161 100644 --- a/resources/langs/nheko_et.ts +++ b/resources/langs/nheko_et.ts @@ -1403,6 +1403,11 @@ Kui soovid, siis võid lisada ka selgituse, miks peaks sinu koputusele reageerim Upload of '%1' failed „%1“ üleslaadimine ei õnnestunud + + + Select file(s) + Vali fail(id) + InviteDialog From 024486c989eca3a7ae679ddd6bd3dd00a7aad94d Mon Sep 17 00:00:00 2001 From: Joseph Donofry Date: Thu, 15 Jun 2023 19:08:22 -0400 Subject: [PATCH 098/128] Maybe fix macOS deployment (intel for now) --- .ci/macos/build.sh | 9 +++++---- CMakeLists.txt | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.ci/macos/build.sh b/.ci/macos/build.sh index 1c60015e..18d7912b 100755 --- a/.ci/macos/build.sh +++ b/.ci/macos/build.sh @@ -14,7 +14,7 @@ export CMAKE_PREFIX_PATH cmake -GNinja -S. -Bbuild \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_INSTALL_PREFIX=.deps/usr \ + -DCMAKE_INSTALL_PREFIX="$(pwd)" \ -DHUNTER_ROOT="../.hunter" \ -DHUNTER_ENABLED=ON -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHUNTER_CONFIGURATION_TYPES=RelWithDebInfo \ @@ -28,7 +28,8 @@ cmake --build build make -j 4 cp libqtjdenticon.dylib ../nheko.app/Contents/MacOS ) - "$(brew --prefix qt6)/bin/macdeployqt" nheko.app -always-overwrite -qmldir=../resources/qml/ - # workaround for https://bugreports.qt.io/browse/QTBUG-100686 - cp "$(brew --prefix brotli)/lib/libbrotlicommon.1.dylib" nheko.app/Contents/Frameworks/libbrotlicommon.1.dylib + # "$(brew --prefix qt6)/bin/macdeployqt" nheko.app -always-overwrite -qmldir=../resources/qml/ + # # workaround for https://bugreports.qt.io/browse/QTBUG-100686 + # cp "$(brew --prefix brotli)/lib/libbrotlicommon.1.dylib" nheko.app/Contents/Frameworks/libbrotlicommon.1.dylib + cmake --install build ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60cbe6ea..3feb49f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -804,6 +804,20 @@ if(MAN) add_subdirectory(man) endif() +# potential workaround for macdeployqt issues +if(APPLE) + install(TARGETS nheko + BUNDLE DESTINATION . + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + qt_generate_deploy_qml_app_script( + TARGET nheko + OUTPUT_SCRIPT deploy_script + NO_UNSUPPORTED_PLATFORM_ERROR + ) + install(SCRIPT ${deploy_script}) +endif() + if(UNIX AND NOT APPLE) if(FLATPAK) set(APPID "im.nheko.Nheko") From ed5c29bb396e6d04a116991d7f62996bcfaa0610 Mon Sep 17 00:00:00 2001 From: Joseph Donofry Date: Thu, 15 Jun 2023 19:49:47 -0400 Subject: [PATCH 099/128] Update install prefix --- .ci/macos/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci/macos/build.sh b/.ci/macos/build.sh index 18d7912b..18340258 100755 --- a/.ci/macos/build.sh +++ b/.ci/macos/build.sh @@ -14,7 +14,7 @@ export CMAKE_PREFIX_PATH cmake -GNinja -S. -Bbuild \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_INSTALL_PREFIX="$(pwd)" \ + -DCMAKE_INSTALL_PREFIX="nheko.app" \ -DHUNTER_ROOT="../.hunter" \ -DHUNTER_ENABLED=ON -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHUNTER_CONFIGURATION_TYPES=RelWithDebInfo \ @@ -31,5 +31,5 @@ cmake --build build # "$(brew --prefix qt6)/bin/macdeployqt" nheko.app -always-overwrite -qmldir=../resources/qml/ # # workaround for https://bugreports.qt.io/browse/QTBUG-100686 # cp "$(brew --prefix brotli)/lib/libbrotlicommon.1.dylib" nheko.app/Contents/Frameworks/libbrotlicommon.1.dylib - cmake --install build + cmake --install . ) From 2cb04fd741f0ffe29badb0d0e4772d127b91e9d9 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 11 Jun 2023 11:53:06 +0200 Subject: [PATCH 100/128] Remove explicit link styling --- resources/qml/delegates/TextMessage.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index c6a8cace..1237180b 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -19,7 +19,6 @@ MatrixText { // table border-collapse doesn't seem to work text: "