Compare commits
17 Commits
work/amazi
...
work/dphal
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43bde4c9d2 | ||
|
|
cab57cc656 | ||
|
|
63ddfb6cb8 | ||
|
|
ce84562829 | ||
|
|
7eda07d788 | ||
|
|
3105fb8aa8 | ||
|
|
e3fdcb8779 | ||
|
|
594018b188 | ||
|
|
774eb6a505 | ||
|
|
f9a6533ca9 | ||
|
|
c804b9ce14 | ||
|
|
d1acb97fe2 | ||
|
|
0a99e90591 | ||
|
|
c6313d2951 | ||
|
|
d2d48110cb | ||
|
|
a235f39c84 | ||
|
|
8e1303edbe |
@@ -7,7 +7,9 @@
|
||||
#include <QVariantList>
|
||||
|
||||
#include "accountmanager.h"
|
||||
#include "blockcache.h"
|
||||
#include "chatbarcache.h"
|
||||
#include "enums/messagecomponenttype.h"
|
||||
#include "models/actionsmodel.h"
|
||||
|
||||
#include "server.h"
|
||||
@@ -89,7 +91,7 @@ void ActionsTest::testActions()
|
||||
QFETCH(std::optional<Quotient::RoomMessageEvent::MsgType>, type);
|
||||
|
||||
auto cache = new ChatBarCache(this);
|
||||
cache->setText(command);
|
||||
cache->cache() += Block::CacheItem{.type = MessageComponentType::Text, .content = QTextDocumentFragment::fromMarkdown(command)};
|
||||
auto result = ActionsModel::handleAction(room, cache);
|
||||
QCOMPARE(resultText, std::get<std::optional<QString>>(result));
|
||||
QCOMPARE(type, std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result));
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "accountmanager.h"
|
||||
#include "blockcache.h"
|
||||
#include "chatbarcache.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
@@ -77,7 +78,7 @@ void ChatBarCacheTest::empty()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
|
||||
QCOMPARE(chatBarCache->text(), QString());
|
||||
QCOMPARE(chatBarCache->cache().toString(), QString());
|
||||
QCOMPARE(chatBarCache->isReplying(), false);
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
@@ -123,11 +124,11 @@ void ChatBarCacheTest::badParent()
|
||||
void ChatBarCacheTest::reply()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
chatBarCache->setText(u"some text"_s);
|
||||
chatBarCache->cache() += Block::CacheItem{.type = MessageComponentType::Text, .content = QTextDocumentFragment::fromMarkdown(u"some text"_s)};
|
||||
chatBarCache->setAttachmentPath(u"some/path"_s);
|
||||
chatBarCache->setReplyId(eventId);
|
||||
|
||||
QCOMPARE(chatBarCache->text(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->cache().toString(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->isReplying(), true);
|
||||
QCOMPARE(chatBarCache->replyId(), eventId);
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
@@ -141,11 +142,11 @@ void ChatBarCacheTest::reply()
|
||||
void ChatBarCacheTest::replyMissingUser()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
chatBarCache->setText(u"some text"_s);
|
||||
chatBarCache->cache() += Block::CacheItem{.type = MessageComponentType::Text, .content = QTextDocumentFragment::fromMarkdown(u"some text"_s)};
|
||||
chatBarCache->setAttachmentPath(u"some/path"_s);
|
||||
chatBarCache->setReplyId(eventId);
|
||||
|
||||
QCOMPARE(chatBarCache->text(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->cache().toString(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->isReplying(), true);
|
||||
QCOMPARE(chatBarCache->replyId(), eventId);
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
@@ -172,7 +173,7 @@ void ChatBarCacheTest::edit()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
|
||||
chatBarCache->setText(u"some text"_s);
|
||||
chatBarCache->cache() += Block::CacheItem{.type = MessageComponentType::Text, .content = QTextDocumentFragment::fromMarkdown(u"some text"_s)};
|
||||
chatBarCache->setAttachmentPath(u"some/path"_s);
|
||||
connect(chatBarCache.get(), &ChatBarCache::relationIdChanged, this, [this](const QString &oldEventId, const QString &newEventId) {
|
||||
QCOMPARE(oldEventId, QString());
|
||||
@@ -180,7 +181,7 @@ void ChatBarCacheTest::edit()
|
||||
});
|
||||
chatBarCache->setEditId(eventId);
|
||||
|
||||
QCOMPARE(chatBarCache->text(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->cache().toString(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->isReplying(), false);
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), true);
|
||||
@@ -193,11 +194,11 @@ void ChatBarCacheTest::edit()
|
||||
void ChatBarCacheTest::attachment()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
chatBarCache->setText(u"some text"_s);
|
||||
chatBarCache->cache() += Block::CacheItem{.type = MessageComponentType::Text, .content = QTextDocumentFragment::fromMarkdown(u"some text"_s)};
|
||||
chatBarCache->setEditId(eventId);
|
||||
chatBarCache->setAttachmentPath(u"some/path"_s);
|
||||
|
||||
QCOMPARE(chatBarCache->text(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->cache().toString(), u"some text"_s);
|
||||
QCOMPARE(chatBarCache->isReplying(), false);
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
|
||||
@@ -30,14 +30,14 @@ public:
|
||||
|
||||
ChatTextItemHelper *textItem() const
|
||||
{
|
||||
return m_keyHelper->textItem;
|
||||
return m_keyHelper->textItem();
|
||||
}
|
||||
void setTextItem(ChatTextItemHelper *textItem)
|
||||
{
|
||||
if (textItem == m_keyHelper->textItem) {
|
||||
if (textItem == m_keyHelper->textItem()) {
|
||||
return;
|
||||
}
|
||||
m_keyHelper->textItem = textItem;
|
||||
m_keyHelper->setTextItem(textItem);
|
||||
Q_EMIT textItemChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -400,7 +400,6 @@ void ModelTest::testCompletionModel()
|
||||
auto model = new CompletionModel(this);
|
||||
auto tester = new QAbstractItemModelTester(model, model);
|
||||
tester->setUseFetchMore(true);
|
||||
model->setRoom(room);
|
||||
model->setAutoCompletionType(CompletionModel::Room);
|
||||
auto roomListModel = new RoomListModel(this);
|
||||
roomListModel->setConnection(connection);
|
||||
|
||||
@@ -73,6 +73,16 @@ void WindowControllerTest::toggle()
|
||||
instance.toggleWindow();
|
||||
QCOMPARE(window.windowState(), Qt::WindowNoState);
|
||||
QCOMPARE(window.isVisible(), false);
|
||||
|
||||
// make sure we restore maximized state when toggling
|
||||
instance.toggleWindow();
|
||||
window.setVisibility(QWindow::Maximized);
|
||||
QCOMPARE(window.windowState(), Qt::WindowMaximized);
|
||||
instance.toggleWindow();
|
||||
QCOMPARE(window.isVisible(), false);
|
||||
instance.toggleWindow();
|
||||
QCOMPARE(window.windowState(), Qt::WindowMaximized);
|
||||
QCOMPARE(window.isVisible(), true);
|
||||
}
|
||||
|
||||
QTEST_MAIN(WindowControllerTest)
|
||||
|
||||
@@ -521,7 +521,9 @@
|
||||
<p xml:lang="ar">في الإصدار الأحدث، عند تشغيل التطبيق، ستظهر صفحة ترحيب تتيح اختيار الحساب المراد استخدامه وتسمح بالولوج إلى حسابات أخرى. كما تحذر شاشة الترحيب عندما يتعذر على نيوتشات تحميل حساب ما.</p>
|
||||
<p xml:lang="ca">En la versió més recent, en llançar l'aplicació, obtindreu una pàgina de benvinguda que us permetrà triar quin compte voleu utilitzar i permetrà iniciar sessió en altres comptes. La pantalla de benvinguda també us avisarà quan el NeoChat no pugui carregar un compte.</p>
|
||||
<p xml:lang="ca-valencia">En la versió més recent, en iniciar l'aplicació, obtindreu una pàgina de benvinguda que us permetrà triar quin compte voleu utilitzar i permetrà iniciar sessió en altres comptes. La pantalla de benvinguda també vos avisarà quan NeoChat no puga carregar un compte.</p>
|
||||
<p xml:lang="it">Nella versione più recente, all'avvio dell'applicazione, sarà visualizzata una pagina di benvenuto che consente di scegliere l'account da utilizzare e di accedere ad altri account. La schermata di benvenuto avvisa anche quando NeoChat non riesce a caricare un account.</p>
|
||||
<p xml:lang="ka">უახლეს ვერსიაში აპის გაშვებისას თქვენ მიღებთ მისალმების გვერდს, რომელიც საშუალებას გაძლევთ, აირჩიოთ ანგარიში, რომლის გამოყენებაც გსურთ და საშუალებას მოგცემთ, სხვა ანგარიშებში შეხვიდეთ. მისალმების ეკრანი ასევე გაგაფრთხილებთ, როცა NeoChat-ს ანგარიშის ჩატვირთვა არ შეეძლება.</p>
|
||||
<p xml:lang="nl">In de nieuwste versie krijgt u bij het opstarten van de toepassing een welkomstpagina te zien waar u kunt kiezen welk account u wilt gebruiken en waarmee u zich kunt aanmelden op andere accounts. Het welkomstscherm waarschuwt u ook als NeoChat een account niet kan laden.</p>
|
||||
<p xml:lang="pt-BR">Na versão mais recente, ao iniciar o aplicativo, você verá uma página de boas-vindas que permite escolher qual conta deseja usar e fazer login em outras contas. A tela de boas-vindas também avisará quando o NeoChat não conseguir carregar uma conta.</p>
|
||||
<p xml:lang="ru">В новой версии при запуске приложения открывается страница приветствия, на которой можно выбрать учётную запись для входа или добавить другие учётные записи. Также на странице приветствия отображается предупреждение, если NeoChat не удалось загрузить учётную запись.</p>
|
||||
<p xml:lang="sl">V najnovejši različici boste ob zagonu aplikacije prejeli pozdravno stran, kjer lahko izberete, kateri račun želite uporabiti, in se prijavite v druge račune. Pozdravna stran vas bo opozorila tudi, ko NeoChat ne bo mogel naložiti računa.</p>
|
||||
@@ -531,7 +533,9 @@
|
||||
<p xml:lang="ar">يتيح نيوتشات أيضاً تسجيل حساب جديد مباشرة من التطبيق نفسه. كما يمكن تعطيل حساب ماتركس من داخل نيوتشات.</p>
|
||||
<p xml:lang="ca">El NeoChat també us permetrà registrar un compte nou directament des de l'aplicació mateixa. També és possible desactivar el vostre compte de Matrix des del NeoChat.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat també us permetrà registrar un compte nou directament des de l'aplicació mateixa. També és possible desactivar el vostre compte de Matrix des de NeoChat.</p>
|
||||
<p xml:lang="it">NeoChat ti permetterà anche di registrare un nuovo account direttamente dall'applicazione. Puoi anche disattivare il tuo account Matrix direttamente da NeoChat.</p>
|
||||
<p xml:lang="ka">NeoChat ასევე საშუალებას მოგცემთ, დაარეგისტრიროთ ახალი ანგარიში პირდაპირ აპიდან. NeoChat-იდან ასევე შესაძლებელია თქვენი მატრიცის ანგარიშის დეაქტივაციაც.</p>
|
||||
<p xml:lang="nl">NeoChat biedt u ook de mogelijkheid om direct vanuit de toepassing een nieuw account aan te maken. U kunt uw Matrix-account ook deactiveren vanuit NeoChat.</p>
|
||||
<p xml:lang="pt-BR">O NeoChat também permite que você registre uma nova conta diretamente pelo aplicativo. Desativar sua conta Matrix também é possível a partir do NeoChat.</p>
|
||||
<p xml:lang="ru">В NeoChat также можно зарегистрировать новую учётную запись Matrix. Учётную запись Matrix также можно деактивировать непосредственно в NeoChat.</p>
|
||||
<p xml:lang="sl">NeoChat vam omogoča tudi registracijo novega računa neposredno iz same aplikacije. Deaktivacija računa Matrix je mogoča tudi znotraj NeoChata.</p>
|
||||
@@ -541,7 +545,9 @@
|
||||
<p xml:lang="ar">الفضاءات هي ميزة جديدة نسبياً في ماتركس تسمح بتجميع قنوات الدردشة معاً. يُستخدم هذا لتحسين قابلية اكتشاف الغرف، أو إدارة المجتمعات الكبيرة، أو مجرد ترتيب القنوات المشترك فيها. يمكن القيام بكل ذلك الآن دون مغادرة نيوتشات.</p>
|
||||
<p xml:lang="ca">Els espais són una característica relativament nova de Matrix que us permet agrupar canals de xat junts. Això s'utilitza per a millorar la descoberta de sales, gestionar comunitats grans, o simplement ordenar tots els canals en els quals esteu. Ara podeu fer tot això sense sortir del NeoChat.</p>
|
||||
<p xml:lang="ca-valencia">Els espais són una característica relativament nova de Matrix que us permet agrupar canals de xat junts. Açò s'utilitza per a millorar la descoberta de sales, gestionar comunitats grans, o senzillament ordenar tots els canals en els quals esteu. Ara podeu fer tot açò sense eixir de NeoChat.</p>
|
||||
<p xml:lang="it">Gli spazi sono una funzionalità relativamente nuova di Matrix che consente di raggruppare i canali di chat. Questa funzionalità viene utilizzata per migliorare la visibilità delle stanze, gestire grandi comunità o semplicemente riordinare tutti i canali in cui si è presenti. Ora è possibile fare tutto questo senza uscire da NeoChat.</p>
|
||||
<p xml:lang="ka">სივრცეები მატრიცის, შედარებით, ახალი ფუნქციაა, რომელიც ჩატის არხების დაჯგუფების საშუალებას გაძლევთ. ის გამოიყენება ოთახების აღმოჩენადობისთვის, დიდი საზოგადოებების სამართავად და ზოგადად არხების ერთად შესაკრებად. ამისი გაკეთება NeoChat-იდან გაუსვლელად შეგიძლიათ.</p>
|
||||
<p xml:lang="nl">Ruimtes zijn een relatief nieuwe functie van Matrix waarmee u chatkanalen kunt groeperen. Dit wordt gebruikt om de vindbaarheid van rooms te verbeteren, grote gemeenschappen te beheren of gewoon alle kanalen waarin u zit overzichtelijk te houden. U kunt dit nu allemaal doen zonder NeoChat te verlaten.</p>
|
||||
<p xml:lang="pt-BR">Os Espaços são um recurso relativamente novo do Matrix que permite agrupar canais de bate-papo. Isso é usado para melhorar a visibilidade das salas, gerenciar grandes comunidades ou simplesmente organizar todos os canais dos quais você participa. Agora você pode fazer tudo isso sem sair do NeoChat.</p>
|
||||
<p xml:lang="ru">Пространства — это относительно новая функция Matrix, позволяющая группировать каналы чатов. Они используются для упрощения поиска комнат, управления большими сообществами или просто для упорядочивания всех ваших каналов. Теперь это можно делать, не покидая NeoChat.</p>
|
||||
<p xml:lang="sl">Prostori so relativno nova funkcija Matrixa, ki omogoča združevanje klepetalnih kanalov. To se uporablja za izboljšanje vidnosti sob, upravljanje velikih skupnosti ali preprosto urejanje vseh kanalov, v katerih ste. Zdaj lahko vse to storite, ne da bi zapustili NeoChat.</p>
|
||||
@@ -551,7 +557,9 @@
|
||||
<p xml:lang="ar">لن يفوّت نيوتشات أي تنبيهات جديدة بعد الآن. أُضيفت صفحة جديدة تتضمن كافة التنبيهات الأخيرة، وعند إغلاق نيوتشات، ستظل القدرة على استقبال التنبيهات الدفعية قائمة. يُعلِمك الخط الزمني الرئيسي عند تحميل مزيد من الرسائل وعند الوصول إلى نهايته.</p>
|
||||
<p xml:lang="ca">El NeoChat ja no deixarà que us perdeu cap notificació nova. Hem afegit una pàgina nova que inclou totes les notificacions recents i quan el NeoChat estigui tancat, encara podreu rebre notificacions automàtiques. La línia de temps principal us avisarà quan s'estiguin carregant més missatges i quan arribeu al seu final.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat ja no deixarà que vos perdeu cap notificació nova. Hem afegit una pàgina nova que inclou totes les notificacions recents i quan NeoChat estiga tancat, encara podreu rebre notificacions automàtiques. La línia de temps principal vos avisarà quan s'estiguen carregant més missatges i quan arribeu fins al seu final.</p>
|
||||
<p xml:lang="it">NeoChat non ti farà più perdere nessuna nuova notifica. Abbiamo aggiunto una nuova pagina che include tutte le tue notifiche recenti e, anche quando NeoChat è chiuso, potrai comunque ricevere notifiche push. La cronologia principale ti informerà quando vengono caricati altri messaggi e quando ne hai raggiunto la fine.</p>
|
||||
<p xml:lang="ka">NeoChat აღარ მოგცემთ საშუალებას, ახალი შეტყობინებები გამოტოვოთ. ჩვენ დავამატეთ ახალი გვერდი, რომელიც თქვენს უახლეს გაფრთხილებებს შეიცავს და როცა NeoChat დახურულია, თქვენ მაინც შეძლებთ, პუშ-გაფრთხილებები მიიღოთ. მთავარი დროის ხაზი საშუალებას მოგცემთ, გაიგოთ, როდის მოხდება მეტი შეტყობინების ჩატვირთვა და როცა ბოლოში გახვალთ.</p>
|
||||
<p xml:lang="nl">NeoChat zorgt ervoor dat u geen nieuwe meldingen meer mist. We hebben een nieuwe pagina toegevoegd met al uw recente meldingen. Zelfs als NeoChat gesloten is, kunt u nog steeds push-meldingen ontvangen. De hoofdtijdlijn laat u weten wanneer er meer berichten worden geladen en wanneer u het einde van de tijdlijn hebt bereikt.</p>
|
||||
<p xml:lang="pt-BR">O NeoChat não deixará você perder mais nenhuma notificação. Adicionamos uma nova página que inclui todas as suas notificações recentes e, mesmo com o NeoChat fechado, você ainda poderá receber notificações push. A linha do tempo principal mostrará quando novas mensagens estiverem sendo carregadas e quando você chegar ao final.</p>
|
||||
<p xml:lang="ru">Вы более не пропустите ни одного нового уведомления NeoChat. Добавлена страница со всеми последними уведомлениями, а при закрытии приложения будут приходить push-уведомления. Основная лента сообщений теперь показывает процесс загрузки новых сообщений и её окончание.</p>
|
||||
<p xml:lang="sl">Z NeoChatom ne boste več zamudili nobenega novega obvestila. Dodali smo novo stran, ki vključuje vsa vaša nedavna obvestila, in ko je NeoChat zaprt, boste še vedno lahko prejemali potisna obvestila. Glavna časovnica vas bo obvestila, kdaj se nalagajo nova sporočila in kdaj pridete do konca.</p>
|
||||
@@ -562,6 +570,7 @@
|
||||
<p xml:lang="ca">Més millores del NeoChat</p>
|
||||
<p xml:lang="ca-valencia">Més millores de NeoChat</p>
|
||||
<p xml:lang="he">עוד פינוקים ב־NeoChat</p>
|
||||
<p xml:lang="it">Altre chicche di NeoChat</p>
|
||||
<p xml:lang="ka">NeoChat-ის მეტი სიკეთე</p>
|
||||
<p xml:lang="nl">Meer NeoChat-goodies</p>
|
||||
<p xml:lang="pt-BR">Mais novidades do NeoChat</p>
|
||||
@@ -577,6 +586,7 @@
|
||||
<li xml:lang="es">Códigos QR para compartir contactos</li>
|
||||
<li xml:lang="he">קודים מסוג QR לשיתוף אנשי קשר</li>
|
||||
<li xml:lang="ia">Codices QR per compartir contactos</li>
|
||||
<li xml:lang="it">Codice QR per condividere i contatti</li>
|
||||
<li xml:lang="ka">QR კოდები კონტაქტების გასაზიარებლად</li>
|
||||
<li xml:lang="nl">QR-codes om contactpersonen te delen</li>
|
||||
<li xml:lang="pt-BR">Códigos QR para compartilhar contatos</li>
|
||||
@@ -590,6 +600,7 @@
|
||||
<li xml:lang="ca-valencia">Actualitzacions millorades de les sales</li>
|
||||
<li xml:lang="he">שדרוגי חדרים משופרים</li>
|
||||
<li xml:lang="ia">Meliorate actualisationes de sala</li>
|
||||
<li xml:lang="it">Aggiornamenti delle stanze migliorati</li>
|
||||
<li xml:lang="ka">გაუმჯობესდა ოთახის განახლებები</li>
|
||||
<li xml:lang="nl">Opwaarderen van room verbeterd</li>
|
||||
<li xml:lang="pt-BR">Melhorias nas salas</li>
|
||||
@@ -603,6 +614,7 @@
|
||||
<li xml:lang="ca-valencia">S'ha afegit un botó per a rebutjar una invitació i ignorar l'usuari</li>
|
||||
<li xml:lang="he">נוסף כפתור לדחיית הזמנה והתעלמות ממשתמש</li>
|
||||
<li xml:lang="ia">Addite button per refusar invitation e ignorar usator</li>
|
||||
<li xml:lang="it">Aggiunto un pulsante per rifiutare l'invito e ignorare l'utente</li>
|
||||
<li xml:lang="ka">დაემატა ღილაკი მოსაწვევის უარყოფისთვის და მომხმარებლის დასაიგნორებლად</li>
|
||||
<li xml:lang="nl">Toegevoegde knop om uitnodiging af te wijzen en gebruiker te negeren</li>
|
||||
<li xml:lang="pt-BR">Adicionado botão para rejeitar convite e ignorar usuário</li>
|
||||
@@ -617,6 +629,7 @@
|
||||
<li xml:lang="es">Mostrar detalles de la seguridad del dispositivo</li>
|
||||
<li xml:lang="he">הצגת פרטי אבטחת מכשיר</li>
|
||||
<li xml:lang="ia">Monstra detalios de securitate de dispositivo</li>
|
||||
<li xml:lang="it">Visualizza i dettagli di sicurezza del dispositivo</li>
|
||||
<li xml:lang="ka">მოწყობილობის უსაფრთხოების დეტალების ჩვენება</li>
|
||||
<li xml:lang="nl">Details van apparaatbeveiliging tonen</li>
|
||||
<li xml:lang="pt-BR">Exibir detalhes de segurança do dispositivo</li>
|
||||
@@ -631,6 +644,7 @@
|
||||
<li xml:lang="es">Se han añadido ajustes de la seguridad de las salas</li>
|
||||
<li xml:lang="he">נוספו הגדרות אבטחת חדר</li>
|
||||
<li xml:lang="ia">Addite preferentias de securitate de sala</li>
|
||||
<li xml:lang="it">Aggiunte impostazioni di sicurezza delle stanze</li>
|
||||
<li xml:lang="ka">დაემატა ოთახის უსაფრთხოების პარამეტრები</li>
|
||||
<li xml:lang="nl">Beveiligingsinstelling voor room toegevoegd</li>
|
||||
<li xml:lang="pt-BR">Adicionadas configurações de segurança da sala</li>
|
||||
@@ -652,6 +666,7 @@
|
||||
<p xml:lang="ar">بعيداً عن التجديد البصري، يمكن لنيوتشات الآن عرض أحداث الموقع وكذلك خريطة بمواقع جميع المستخدمين الذين يبثون مواقعهم حالياً باستخدام تكامل ماتركس مع Itineray. يعد هذا رائعاً لتحديد أماكن الأصدقاء.</p>
|
||||
<p xml:lang="ca">A part d'una revisió visual, ara el NeoChat pot mostrar esdeveniments d'ubicació i també un mapa amb la ubicació de tots els usuaris que actualment emeten la seva ubicació utilitzant la integració de Matrix de l'Itineray. És genial per a localitzar on són els vostres amics.</p>
|
||||
<p xml:lang="ca-valencia">A part d'una revisió visual, ara NeoChat pot mostrar esdeveniments d'ubicació i també un mapa amb la ubicació de tots els usuaris que actualment emeten la seua ubicació utilitzant la integració de Matrix de l'Itineray. És genial per a localitzar on són els vostres amics.</p>
|
||||
<p xml:lang="it">Oltre a una revisione visuale, NeoChat ora può visualizzare eventi di localizzazione e anche una mappa con la posizione di tutti gli utenti che attualmente trasmettono la loro posizione utilizzando l'integrazione Matrix di Itineray. Ottimo per localizzare dove si trovano i tuoi amici.</p>
|
||||
<p xml:lang="ka">ვიზუალური მხრის განახლებასთან ერთად NeoChat-ს ახლა შეუძლია მდებარეობის მოვლენების ჩვენება და ასევე შეუძლია ყველა მომხმარებელი, რომელიც გადმოსცემს თავის მდებარეობას, Itinerary-ის მატრიცის ინტეგრაციით გაჩვენოთ. ეს კარგია იმისთვის, რომ გაიგოთ, სად არიან თქვენი მეგობრები.</p>
|
||||
<p xml:lang="nl">Naast een visuele herziening kan NeoChat nu locatiegebeurtenissen tonen en ook een kaart met de locatie van alle gebruikers die nu hun locatie uitzenden met de Matrix-integratie van Itineray. Geweldig voor lokaliseren waar uw vrienden zijn.</p>
|
||||
<p xml:lang="pt-BR">Além de uma reformulação visual, o NeoChat agora pode exibir eventos de localização e também um mapa com a localização de todos os usuários que estão transmitindo sua localização usando a integração Matrix do Itineray. Ótimo para localizar seus amigos.</p>
|
||||
@@ -671,7 +686,9 @@
|
||||
<p xml:lang="ar">يُحسّن نيوتشات تصميمه بتعديلات توفر مخططاً أكثر ضغطاً وقائمة أبسط تعمل بشكل أفضل مع قائمة الغرف المطوية.</p>
|
||||
<p xml:lang="ca">El NeoChat millora el seu disseny amb retocs que proporcionen una disposició més compacta i un menú més senzill que funciona millor per a la llista reduïda de sales.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat millora el seu disseny amb retocs que proporcionen una disposició més compacta i un menú més senzill que funciona millor per a la llista reduïda de sales.</p>
|
||||
<p xml:lang="it">NeoChat migliora il suo aspetto con modifiche che offrono una disposizione più compatta e un menu più semplice, più adatto all'elenco delle stanze ridotto.</p>
|
||||
<p xml:lang="ka">NeoChat-მა გააუმჯობესა თავისი დიზაინი ცვლილებებით, რომლებიც გაწვდით უფრო კომპაქტური განლაგებას და გამარტივებულ მენიუს, რომელიც უკეთ მუშაობს აკეცილი ოთახების სიისთვის.</p>
|
||||
<p xml:lang="nl">NeoChat verbetert zijn ontwerp met aanpassingen die zorgen voor een compactere indeling en een eenvoudiger menu dat beter werkt voor de ingeklapte roomslijst.</p>
|
||||
<p xml:lang="pt-BR">O NeoChat aprimorou seu design com ajustes que proporcionam um layout mais compacto e um menu mais simples, que funciona melhor para a lista de salas recolhida.</p>
|
||||
<p xml:lang="ru">В оформлении NeoChat реализованы изменения для более компактного расположения элементов и упрощённого меню, которое лучше работает со свёрнутым списком комнат.</p>
|
||||
<p xml:lang="sl">NeoChat izboljšuje svojo zasnovo s prilagoditvami, ki zagotavljajo bolj kompaktno postavitev in enostavnejši meni, ki bolje deluje za strnjen seznam sob.</p>
|
||||
@@ -681,7 +698,9 @@
|
||||
<p xml:lang="ar">حُسّنت أيضاً عناصر التحكم في الفيديو، وأُضيف أمر جديد /knock <room-id> لإرسال حدث طرق إلى غرفة، ويمكن الآن تحرير رسالة سابقة في السطر نفسه داخل لوحة الدردشة.</p>
|
||||
<p xml:lang="ca">També hem millorat els controls de vídeo, s'ha afegit una nova ordre /knock <id-sala> per a enviar un esdeveniment «knock» a una sala, i ara podeu editar un missatge anterior inclòs, dins de la subfinestra de xat.</p>
|
||||
<p xml:lang="ca-valencia">També hem millorat els controls de vídeo, s'ha afegit una nova ordre /knock <id-sala> per a enviar un esdeveniment «knock» a una sala, i ara podeu editar un missatge anterior inclòs, dins de la subfinestra de xat.</p>
|
||||
<p xml:lang="it">Abbiamo anche migliorato i controlli video, aggiunto un nuovo comando /knock <room-id> per inviare un evento knock a una stanza e ora puoi modificare un messaggio precedente in linea, all'interno del riquadro della chat.</p>
|
||||
<p xml:lang="ka">ჩვენ ასევე გავაუმჯობესეთ ვიდეოს მართვა, დავამატეთ ახალი ბრძანება /knock <ოთახის-id> ოთახში დაკაკუნების მოვლენის გასაგზავნად და ასევე შეგიძლიათ, წინა შეტყობინება ხაზშივე, ჩატის პანელში ჩაასწოროთ.</p>
|
||||
<p xml:lang="nl">We hebben ook de videobediening verbeterd, een nieuw commando /knock <room-id> toegevoegd om een klopgebeurtenis naar een room te sturen, en u kunt nu een eerder bericht rechtstreeks in het chatvenster bewerken.</p>
|
||||
<p xml:lang="pt-BR">Também melhoramos os controles de vídeo, adicionamos um novo comando /knock <room-id> para enviar um evento knock para uma sala, e agora você pode editar uma mensagem anterior em linha, no painel de bate-papo.</p>
|
||||
<p xml:lang="ru">Также улучшены элементы управления видео, добавлена новая команда /knock <room-id> для отправки события knock в комнату, а также реализовано редактирование предыдущих сообщений непосредственно в области чата.</p>
|
||||
<p xml:lang="sl">Izboljšali smo tudi video kontrole, dodali nov ukaz /knock <room-id> za pošiljanje dogodka knock v sobo, zdaj pa lahko urejate prejšnje sporočilo v vrstici, v podoknu za klepet.</p>
|
||||
@@ -691,7 +710,9 @@
|
||||
<p xml:lang="ar">تتضمن تحسينات سهولة الاستخدام الأخرى تجديد التنقل عبر لوحة المفاتيح واختصارات مثل Ctrl+PgUp/PgDn التي تسمح بالانتقال السريع بين الغرف.</p>
|
||||
<p xml:lang="ca">Altres millores d'usabilitat inclouen una revisió de la navegació amb el teclat i dreceres com Ctrl+Re Pàg/Av Pàg que us permeten saltar de sala en sala.</p>
|
||||
<p xml:lang="ca-valencia">Altres millores d'usabilitat inclouen una revisió de la navegació amb el teclat i dreceres com Ctrl+«Re Pàg»/«Av Pàg» que vos permeten saltar de sala en sala.</p>
|
||||
<p xml:lang="it">Altri miglioramenti dell'usabilità includono una revisione della navigazione tramite tastiera e scorciatoie come Ctrl+PagSu/PagGiù che consentono di passare da una stanza all'altra.</p>
|
||||
<p xml:lang="ka">სხვა გამოყენებადობის გაუმჯობესებები შეიცავს კლავიატურის ნავიგაციის გადაკეთებას და ისეთ მალსახმობებს, როგორიცაა Ctrl+PgUp/PgDn, რომელიც ოთახიდან ოთახზე გადასვლის საშუალებას გაძლევთ.</p>
|
||||
<p xml:lang="nl">Andere verbeteringen op het gebied van gebruiksgemak zijn onder meer een herziening van de toetsenbordnavigatie en sneltoetsen zoals Ctrl+PgUp/PgDn waarmee u van room naar room kunt springen.</p>
|
||||
<p xml:lang="pt-BR">Outras melhorias de usabilidade incluem uma reformulação da navegação pelo teclado e atalhos como Ctrl+PgUp/PgDn que permitem que você pule de sala em sala.</p>
|
||||
<p xml:lang="ru">К другим улучшениям в удобстве использования относится переработанная навигация с клавиатурой и комбинации клавиш, такие как Ctrl+PgUp/PgDn, для быстрого перехода между комнатами.</p>
|
||||
<p xml:lang="sl">Druge izboljšave uporabnosti vključujejo prenovo navigacije s tipkovnico in bližnjice, kot sta Ctrl+PgUp/PgDn, ki omogočajo preskakovanje med sobami.</p>
|
||||
@@ -716,7 +737,9 @@
|
||||
<p xml:lang="es">Nuevas funciones y corrección de fallos:</p>
|
||||
<p xml:lang="he">יכולות חדשות ותיקוני תקלות:</p>
|
||||
<p xml:lang="ia">Nove characteristicas e correctiones de faltas:</p>
|
||||
<p xml:lang="it">Nuove funzionalità e correzioni di bug:</p>
|
||||
<p xml:lang="ka">ახალი ფუნქციები და შეცდომების გასწორებები:</p>
|
||||
<p xml:lang="nl">Nieuwe functies en reparaties van bugs:</p>
|
||||
<p xml:lang="pt-BR">Novas funcionalidades e correções de bugs:</p>
|
||||
<p xml:lang="ru">Новые возможности и исправления ошибок:</p>
|
||||
<p xml:lang="sl">Nove zmožnosti in popravki napak:</p>
|
||||
@@ -730,7 +753,9 @@
|
||||
<li xml:lang="es">Se muestran notificaciones de todas las cuentas, no solo de la activa</li>
|
||||
<li xml:lang="he">התראות תופענה לכל החשבונות, לא רק לחשבון הפעיל</li>
|
||||
<li xml:lang="ia">Notificationes nunc essera monstrate per tote le contos,non solmente perlo que es active</li>
|
||||
<li xml:lang="it">Le notifiche saranno ora visualizzate per tutti gli account, non solo per quello attivo</li>
|
||||
<li xml:lang="ka">გაფრთხილებები ნაჩვენები იქნება ყველა ანგარიშისთვის და არა, მხოლოდ, აქტიურისთვის</li>
|
||||
<li xml:lang="nl">Meldingen worden nu voor alle accounts weergegeven, niet alleen voor het actieve account.</li>
|
||||
<li xml:lang="pt-BR">Agora, as notificações serão exibidas para todas as contas, não apenas para a conta ativa</li>
|
||||
<li xml:lang="ru">Уведомления будут выводиться для всех учётных записей, а не только для активной;</li>
|
||||
<li xml:lang="sl">Obvestila bodo zdaj prikazana za vse račune, ne le za aktivnega</li>
|
||||
@@ -743,7 +768,9 @@
|
||||
<li xml:lang="es">Nuevo modo «compacto» para la lista de salas</li>
|
||||
<li xml:lang="he">יש מצב „מצומצם” חדש לרשימת החדרים</li>
|
||||
<li xml:lang="ia">Il ha un nove modo 'compacte' per le lista de sala</li>
|
||||
<li xml:lang="it">C'è una nuova modalità «compatta» per l'elenco delle stanze</li>
|
||||
<li xml:lang="ka">ოთახების სიისთვის არსებობს ახალი "კომპაქტური" რეჟიმი</li>
|
||||
<li xml:lang="nl">Er is een nieuwe "compacte" modus voor de roomslijst.</li>
|
||||
<li xml:lang="pt-BR">Existe um novo modo "compacto" para a lista de salas</li>
|
||||
<li xml:lang="ru">Добавлен новый компактный режим списка комнат;</li>
|
||||
<li xml:lang="sl">Za seznam sob je na voljo nov "kompaktni" način.</li>
|
||||
@@ -756,7 +783,9 @@
|
||||
<li xml:lang="es">Ahora se puede buscar en el historial de salas</li>
|
||||
<li xml:lang="he">אפשר לחפש מעתה בהיסטוריית החדר</li>
|
||||
<li xml:lang="ia">Tu pote nunc cercar in lechronologia de sala</li>
|
||||
<li xml:lang="it">Ora è possibile cercare nella cronologia della stanza</li>
|
||||
<li xml:lang="ka">ახლა ოთახის ისტორიაში ძებნა შეგიძლიათ</li>
|
||||
<li xml:lang="nl">U kunt nu zoeken in de roomgeschiedenis.</li>
|
||||
<li xml:lang="pt-BR">Agora você pode pesquisar no histórico da sala</li>
|
||||
<li xml:lang="ru">Добавлен поиск по истории комнат;</li>
|
||||
<li xml:lang="sl">Zdaj lahko iščete po zgodovini sobe</li>
|
||||
@@ -768,7 +797,9 @@
|
||||
<li xml:lang="ca-valencia">Els emoji i les reaccions s'han millorat significativament</li>
|
||||
<li xml:lang="es">Los emojis y las reacciones se han mejorado significativamente</li>
|
||||
<li xml:lang="ia">Emojis e Reactiones ha essite meliorate significativemente</li>
|
||||
<li xml:lang="it">Emoji e reazioni sono state notevolmente migliorate</li>
|
||||
<li xml:lang="ka">ემოჯიები და რეაქციები საგრძნობლად გაუმჯობესდა</li>
|
||||
<li xml:lang="nl">Emoji's en reacties zijn aanzienlijk verbeterd.</li>
|
||||
<li xml:lang="pt-BR">Os emojis e as reações foram significativamente aprimorados</li>
|
||||
<li xml:lang="ru">Эмодзи и реакции были значительно улучшены;</li>
|
||||
<li xml:lang="sl">Čustvenčki in reakcije so bili znatno izboljšani</li>
|
||||
@@ -780,7 +811,9 @@
|
||||
<li xml:lang="ca-valencia">S'han corregit diverses fallades respecte les invitacions d'usuari</li>
|
||||
<li xml:lang="es">Se han corregido varios fallos relacionados con las invitaciones de los usuarios</li>
|
||||
<li xml:lang="ia">Corrigite multe fracassos circa invitationes de usator</li>
|
||||
<li xml:lang="it">Corretti diversi arresti anomali relativi agli inviti degli utenti</li>
|
||||
<li xml:lang="ka">გასწორდა რამდენიმე შეცდომა მომხმარებლის მოწვევის ფუნქციის გარშემო</li>
|
||||
<li xml:lang="nl">Diverse crashes rondom gebruikersuitnodigingen zijn verholpen.</li>
|
||||
<li xml:lang="pt-BR">Corrigidas várias falhas relacionadas a convites de usuários</li>
|
||||
<li xml:lang="ru">Исправлено несколько аварийных завершений, связанных с приглашениями пользователей;</li>
|
||||
<li xml:lang="sl">Odpravljenih je bilo več sesutij pri povabilih uporabnikov</li>
|
||||
@@ -792,7 +825,9 @@
|
||||
<li xml:lang="ca-valencia">Ara es pot configurar les opcions dels permisos de sala</li>
|
||||
<li xml:lang="es">Ahora se pueden configurar los ajustes de los permisos de las salas</li>
|
||||
<li xml:lang="ia">Preferentias depermission de sala nun pote esser configurate</li>
|
||||
<li xml:lang="it">Ora è possibile configurare le impostazioni dei permessi della stanza</li>
|
||||
<li xml:lang="ka">ახლა შეგიძლიათ ოთახზე წვდომების მორგება</li>
|
||||
<li xml:lang="nl">De toegangsinstellingen voor rooms kunnen nu worden geconfigureerd.</li>
|
||||
<li xml:lang="pt-BR">Agora é possível configurar as permissões da sala</li>
|
||||
<li xml:lang="ru">Добавлена возможность настраивать разрешения для комнат;</li>
|
||||
<li xml:lang="sl">Nastavitve dovoljenj za sobo je zdaj mogoče konfigurirati</li>
|
||||
@@ -816,6 +851,7 @@
|
||||
<p xml:lang="ca-valencia">Esta versió vos oferix diverses esmenes d'errors i millores xicotetes:</p>
|
||||
<p xml:lang="es">Esta versión proporciona diversas mejoras menores y correcciones de fallos:</p>
|
||||
<p xml:lang="ia">Iste version te porta varie parve correctiones de faltas e melioramentos:</p>
|
||||
<p xml:lang="it">Questa versione apporta diverse piccole correzioni di bug e miglioramenti:</p>
|
||||
<p xml:lang="ka">ეს ვერსია შეიცავს რამდენიმე პატარა შეცდომის გასწორებას და გაუმჯობესებას:</p>
|
||||
<p xml:lang="pt-BR">Esta versão traz diversas pequenas correções de bugs e melhorias:</p>
|
||||
<p xml:lang="ru">В этом выпуске исправлены различные ошибки и внесены улучшения:</p>
|
||||
@@ -827,6 +863,7 @@
|
||||
<li xml:lang="ar">يمكن تعطيل إرسال تنبيهات الكتابة الآن.</li>
|
||||
<li xml:lang="ca">Ara es pot desactivar l'enviament de notificacions d'escriptura.</li>
|
||||
<li xml:lang="ca-valencia">Ara es pot desactivar l'enviament de notificacions d'escriptura.</li>
|
||||
<li xml:lang="it">Ora è possibile disattivare l'invio di notifiche di digitazione.</li>
|
||||
<li xml:lang="ka">ახლა შეგიძლიათ, კრეფის შესახებ გაფრთხილება გამორთოთ.</li>
|
||||
<li xml:lang="pt-BR">Agora é possível desativar o envio de notificações de digitação.</li>
|
||||
<li xml:lang="ru">Отправку уведомлений о наборе текста теперь можно отключить;</li>
|
||||
@@ -837,6 +874,7 @@
|
||||
<li xml:lang="ar">في قائمة الغرف، يختفي شريط التمرير الآن بشكل صحيح عند عدم الحاجة إليه.</li>
|
||||
<li xml:lang="ca">A la llista de sales, la barra de desplaçament ara desapareixerà correctament quan no es necessiti.</li>
|
||||
<li xml:lang="ca-valencia">En la llista de sales, la barra de desplaçament ara desapareixerà correctament quan no es necessite.</li>
|
||||
<li xml:lang="it">NeoChat migliora il suo aspetto con modifiche che offrono una disposizione più compatta e un menu più semplice, più adatto all'elenco delle stanze ridotto.</li>
|
||||
<li xml:lang="ka">ოთახების სიაში ჩოჩია ახლა სწორად ქრება, როცა ის საჭირო არაა.</li>
|
||||
<li xml:lang="pt-BR">Na lista de salas, a barra de rolagem agora desaparecerá corretamente quando não for necessária.</li>
|
||||
<li xml:lang="ru">В списке комнат полоса прокрутки теперь скрывается, если не нужна;</li>
|
||||
@@ -847,6 +885,7 @@
|
||||
<li xml:lang="ar">في ويلاند، يبرز نيوتشات الآن بشكل صحيح عند النقر على التنبيه.</li>
|
||||
<li xml:lang="ca">Al Wayland, ara el NeoChat elevarà correctament en fer clic a una notificació.</li>
|
||||
<li xml:lang="ca-valencia">A Wayland, ara NeoChat elevarà correctament quan es clique damunt d'una notificació.</li>
|
||||
<li xml:lang="it">Su Wayland, NeoChat ora si aprirà correttamente quando fai clic su una notifica.</li>
|
||||
<li xml:lang="ka">Wayland-ზე NeoChat ახლა სწორად ამოიწევა, როცა გაფრთხილებაზე დააწკაპუნებთ.</li>
|
||||
<li xml:lang="pt-BR">No Wayland, o NeoChat agora será exibido corretamente ao clicar em uma notificação.</li>
|
||||
<li xml:lang="ru">В сеансах Wayland NeoChat теперь активируется при щелчке по уведомлению;</li>
|
||||
@@ -857,6 +896,7 @@
|
||||
<li xml:lang="ar">أُصلحت عدة علل كانت تتسبب أحياناً في إرسال الرسائل التي تحتوي على عناصر markdown أو HTML بشكل غير صحيح.</li>
|
||||
<li xml:lang="ca">S'han corregit diversos errors que de vegades feien que els missatges que contenien elements de Markdown i/o HTML s'enviessin incorrectament.</li>
|
||||
<li xml:lang="ca-valencia">S'han corregit diversos errors que de vegades feien que els missatges que contenien elements de Markdown i/o HTML s'enviaren incorrectament.</li>
|
||||
<li xml:lang="it">Sono stati corretti diversi bug che a volte causavano l'invio errato di messaggi contenenti elementi markdown e/o HTML.</li>
|
||||
<li xml:lang="ka">გასწორდა რამდენიმე შეცდომა, რომლებიც ხანდახან შეტყობინებებს, რომლებიც markdown-ს, ან/და HTML ელემენტებს შეიცავენ, არასწორად აგზავნიდნენ.</li>
|
||||
<li xml:lang="pt-BR">Diversos erros foram corrigidos, os quais, por vezes, causavam o envio incorreto de mensagens contendo elementos Markdown e/ou HTML.</li>
|
||||
<li xml:lang="ru">Исправлены ошибки, из-за которых сообщения, содержащие элементы разметки Markdown и/или HTML, иногда отправлялись некорректно;</li>
|
||||
@@ -867,6 +907,7 @@
|
||||
<li xml:lang="ar">يمكن التحكم في المبدل السريع باستخدام الفأرة الآن.</li>
|
||||
<li xml:lang="ca">El commutador ràpid ara es pot controlar amb el ratolí.</li>
|
||||
<li xml:lang="ca-valencia">El commutador ràpid ara es pot controlar amb el ratolí.</li>
|
||||
<li xml:lang="it">Ora è possibile controllare il cambio rapido tramite mouse.</li>
|
||||
<li xml:lang="ka">სწრაფი გადამრთველის მართვა ახლა თაგუნათი შეგიძლიათ.</li>
|
||||
<li xml:lang="pt-BR">O seletor rápido agora pode ser controlado usando o mouse.</li>
|
||||
<li xml:lang="ru">Для быстрого переключения теперь возможно использовать мышь;</li>
|
||||
@@ -877,6 +918,7 @@
|
||||
<li xml:lang="ar">يتوفر الآن خيار لتعطيل الفتح الآلي للشريط الجانبي للغرفة عند تغيير حجم النافذة.</li>
|
||||
<li xml:lang="ca">Ara hi ha una opció per a desactivar l'obertura automàtica de la barra lateral de la sala en canviar la mida de la finestra.</li>
|
||||
<li xml:lang="ca-valencia">Ara hi ha una opció per a desactivar l'obertura automàtica de la barra lateral de la sala en canviar la mida de la finestra.</li>
|
||||
<li xml:lang="it">Ora è disponibile un'opzione per disattivare l'apertura automatica della barra laterale della stanza quando si ridimensiona la finestra.</li>
|
||||
<li xml:lang="ka">ახლა გაქვთ არჩევანი, რომ გამორთოთ ავტომატური ოთახის გვერდითი პანელის გახსნა ფანჯრის ზომის შეცვლისას.</li>
|
||||
<li xml:lang="pt-BR">Agora existe uma opção para desativar a abertura automática da barra lateral da sala ao redimensionar a janela.</li>
|
||||
<li xml:lang="ru">Добавлена возможность отключить автоматическое открытие боковой панели комнат при изменении размера окна;</li>
|
||||
@@ -888,7 +930,9 @@
|
||||
<li xml:lang="ca">S'ha corregit la creació d'emojis personalitzats.</li>
|
||||
<li xml:lang="ca-valencia">S'ha corregit la creació d'emoji personalitzats.</li>
|
||||
<li xml:lang="es">Se ha corregido la creación de emojis personalizados.</li>
|
||||
<li xml:lang="he">יצירת אמוג׳ים בהתאמה אישית תוקנה.</li>
|
||||
<li xml:lang="ia">Creation de emojis personalisate ha essite corrigite.</li>
|
||||
<li xml:lang="it">È stata corretta la creazione di emoji personalizzate.</li>
|
||||
<li xml:lang="ka">გასწორდა მომხმარებლის ემოჯიების შექმნა.</li>
|
||||
<li xml:lang="pt-BR">A criação de emojis personalizados foi corrigida.</li>
|
||||
<li xml:lang="ru">Исправлено создание пользовательских эмодзи;</li>
|
||||
@@ -899,6 +943,8 @@
|
||||
<li xml:lang="ar">يعمل تحرير الرسالة الأخيرة أو الرد عليها باستخدام اختصارات لوحة المفاتيح بشكل صحيح الآن.</li>
|
||||
<li xml:lang="ca">L'edició o la resposta a l'últim missatge utilitzant les dreceres de teclat ara funciona correctament.</li>
|
||||
<li xml:lang="ca-valencia">L'edició o la resposta a l'últim missatge utilitzant les dreceres de teclat ara funciona correctament.</li>
|
||||
<li xml:lang="he">עריכה או תגובה להודעה האחרונה באמצעות מקשי קיצור במקלדת עובדת כראוי מעתה.</li>
|
||||
<li xml:lang="it">Ora la modifica o la risposta all'ultimo messaggio tramite le scorciatoie da tastiera funzionano correttamente.</li>
|
||||
<li xml:lang="ka">ბოლო შეტყობინების ჩასწორება და მასზე პასუხი კლავიატურის მალსახმობებით ახლა სწორად მუშაობს.</li>
|
||||
<li xml:lang="pt-BR">Agora, editar ou responder à última mensagem usando os atalhos de teclado funciona corretamente.</li>
|
||||
<li xml:lang="ru">Исправлена работа комбинаций клавиш для редактирования или ответа на последнее сообщение.</li>
|
||||
@@ -909,6 +955,8 @@
|
||||
<li xml:lang="ar">عند التبديل بين الغرف باستخدام لوحة المفاتيح، يكون اتجاه التبديل صحيحاً الآن.</li>
|
||||
<li xml:lang="ca">Quan es canvia entre sales utilitzant el teclat, la direcció de commutació ara és correcta.</li>
|
||||
<li xml:lang="ca-valencia">Quan es canvia entre sales utilitzant el teclat, la direcció de commutació ara és correcta.</li>
|
||||
<li xml:lang="he">בעת מעבר בין חדרים בעזרת המקלדת, כיוון ההחלפה הוא נכון מעתה.</li>
|
||||
<li xml:lang="it">Quando si passa da una stanza all'altra tramite la tastiera, la direzione del cambio è ora corretta.</li>
|
||||
<li xml:lang="ka">ოთახებს შორის კლავიატურით გადართვისას გადართვის მიმართულება ახლა სწორია.</li>
|
||||
<li xml:lang="pt-BR">Ao alternar entre salas usando o teclado, a direção da alternância agora está correta.</li>
|
||||
<li xml:lang="ru">При переключении между комнатами с клавиатуры направление переключения теперь корректное;</li>
|
||||
@@ -925,6 +973,7 @@
|
||||
<p xml:lang="ar">يتيح نيوتشات الآن ترشيح ودخول الغرفة مباشرة من KRunner (بحث بلازما). وبالإضافة إلى ذلك، تتوفر إصلاحات متنوعة للعلل المتعلقة بتنبيهات الكتابة.</p>
|
||||
<p xml:lang="ca">El NeoChat ara permet filtrar i entrar a una sala directament des del KRunner (Cerca del Plasma). A part d'això també hi ha diverses correccions d'errors pel que fa a les notificacions d'escriptura.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat ara permet filtrar i entrar a una sala directament des de KRunner (Busca de Plasma). A part d'açò també hi ha diverses esmenes d'errors pel que fa a les notificacions d'escriptura.</p>
|
||||
<p xml:lang="it">NeoChat ora consente di filtrare e accedere a una stanza direttamente da KRunner (Plasma Search). Oltre a ciò, sono state apportate diverse correzioni di bug riguardanti le notifiche di digitazione.</p>
|
||||
<p xml:lang="ka">NeoChat ახლა საშუალებას გაძლევთ, გაფილტროთ და შეხვიდეთ ოთახში პირდაპი KRunner-დან (Plasma-ის ძებნა). ამის გარდა ასევე გასწორდა სხვადასხვა შეცდომა კრეფის გაფრთხილების შესახებ.</p>
|
||||
<p xml:lang="pt-BR">O NeoChat agora permite filtrar e entrar em uma sala diretamente do KRunner (Busca do Plasma). Além disso, também foram feitas diversas correções de bugs relacionados às notificações de digitação.</p>
|
||||
<p xml:lang="ru">Добавлена возможность фильтрации и входа в комнату прямо из KRunner (поиск Plasma). Кроме того, исправлены различные ошибки, связанные с уведомлениями о наборе текста.</p>
|
||||
@@ -939,6 +988,8 @@
|
||||
<p xml:lang="ar">يركز نيوتشات 22.02 على الاستقرار ويضيف بعض تحسينات جودة الاستخدام</p>
|
||||
<p xml:lang="ca">El NeoChat 22.02 se centra en l'estabilitat i afegeix algunes millores de qualitat de vida</p>
|
||||
<p xml:lang="ca-valencia">NeoChat 22.02 se centra en l'estabilitat i afig algunes millores de qualitat de vida</p>
|
||||
<p xml:lang="he">NeoChat 22.02 מתמקד ביציבות ומוסיף מגוון שיפורים באיכות החיים</p>
|
||||
<p xml:lang="it">NeoChat 22.02 si concentra sulla stabilità e aggiunge alcuni miglioramenti alla qualità della vita</p>
|
||||
<p xml:lang="ka">NeoChat 22.02-ის ფოკუსია სტაბილურობა და ამატებს რამდენიმე ცხოვრების დონის გაუმჯობესებას</p>
|
||||
<p xml:lang="pt-BR">O NeoChat 22.02 foca na estabilidade e adiciona algumas melhorias de usabilidade</p>
|
||||
<p xml:lang="ru">В NeoChat 22.02 основное внимание уделено стабильности и добавлено несколько улучшений для удобства использования.</p>
|
||||
@@ -950,6 +1001,8 @@
|
||||
<li xml:lang="ar">إضافة دعم التصغير إلى صينية النظام عند بدء التشغيل</li>
|
||||
<li xml:lang="ca">Afegeix la implementació per a minimitzar a la safata del sistema en iniciar</li>
|
||||
<li xml:lang="ca-valencia">Afig la implementació per a minimitzar a la safata del sistema en iniciar</li>
|
||||
<li xml:lang="he">נוספה תמיכה למזעור לשורת המערכת עם ההפעלה</li>
|
||||
<li xml:lang="it">Aggiunge il supporto per la minimizzazione nella barra delle applicazioni all'avvio</li>
|
||||
<li xml:lang="ka">დაემატა გაშვებისას საათთან ჩაკეცვის მხარდაჭერა</li>
|
||||
<li xml:lang="pt-BR">Adicionado suporte para minimizar para a bandeja do sistema na inicialização</li>
|
||||
<li xml:lang="ru">Добавлена поддержка сворачивания в системный лоток при запуске;</li>
|
||||
@@ -961,6 +1014,8 @@
|
||||
<li xml:lang="ca">Millora de la verificació de la connectivitat a Internet</li>
|
||||
<li xml:lang="ca-valencia">Millora de la verificació de la connectivitat a Internet</li>
|
||||
<li xml:lang="es">Se ha mejorado la comprobación de la conectividad con internet.</li>
|
||||
<li xml:lang="he">בדיקת החיבור לאינטרנט השתפרה</li>
|
||||
<li xml:lang="it">Controllo della connettività Internet migliorato</li>
|
||||
<li xml:lang="ka">გაუმჯობესდა ინტერნეტკავშირის შემოწმება</li>
|
||||
<li xml:lang="pt-BR">Verificação de conectividade de internet aprimorada</li>
|
||||
<li xml:lang="ru">Улучшена проверка подключения к Интернету;</li>
|
||||
@@ -972,6 +1027,8 @@
|
||||
<li xml:lang="ca">Afegeix la implementació per a compartir imatges i fitxers amb altres aplicacions (Nextcloud, Imgur...)</li>
|
||||
<li xml:lang="ca-valencia">Afig la implementació per a compartir imatges i fitxers amb altres aplicacions (Nextcloud, Imgur…)</li>
|
||||
<li xml:lang="es">Se ha añadido compatibilidad para compartir imágenes y archivos con otras aplicaciones (Nextcloud, Imgur, etc.).</li>
|
||||
<li xml:lang="he">נוספה תמיכה בשיתוף תמונות וקבצים עם יישומים אחרים (Nextcloud, Imgur, …)</li>
|
||||
<li xml:lang="it">Aggiunge il supporto per la condivisione di immagini e file con altre applicazioni (Nextcloud, Imgur, ...)</li>
|
||||
<li xml:lang="ka">დაემატა გამოსახულებებისა და ფაილების სხვა აპებთან (Nextcloud, Imgur,...) გაზიარების მხარდაჭერა</li>
|
||||
<li xml:lang="pt-BR">Adicionado suporte para compartilhamento de imagens e arquivos com outros aplicativos (Nextcloud, Imgur, ...)</li>
|
||||
<li xml:lang="ru">Добавлена возможность обмена изображениями и файлами с другими приложениями (Nextcloud, Imgur, и прочими службами);</li>
|
||||
@@ -982,6 +1039,8 @@
|
||||
<li xml:lang="ar">تطبيق إضافة لصائق للحساب. يسمح هذا بتنظيم أسهل عند استخدام حسابات متعددة.</li>
|
||||
<li xml:lang="ca">Implementa l'addició d'etiquetes al compte. Això permet una organització més fàcil quan s'utilitzen diversos comptes.</li>
|
||||
<li xml:lang="ca-valencia">Implementa l'addició d'etiquetes al compte. Açò permet una organització més fàcil quan s'utilitzen diversos comptes.</li>
|
||||
<li xml:lang="he">מומשה הוספהת תוויות לחשבון. כך אפשר לסדר בקלות יותר כשמשתמשים במגוון חשבונות.</li>
|
||||
<li xml:lang="it">Implementa l'aggiunta di etichette per account. Ciò semplifica l'organizzazione quando si utilizzano più account.</li>
|
||||
<li xml:lang="ka">ახლა ანგარიშებს შეიძლიათ, ჭდეები დაამატოთ. ეს აადვილებს ორგანიზებას, როცა ერთზე მეტ ანგარიშს იყენებთ.</li>
|
||||
<li xml:lang="pt-BR">Implementada a adição de etiquetas para contas. Isso facilita a organização ao usar várias contas.</li>
|
||||
<li xml:lang="ru">Реализовано добавление меток для учётных записей; это упрощает организацию при использовании нескольких учётных записей.</li>
|
||||
@@ -992,6 +1051,8 @@
|
||||
<li xml:lang="ar">إعادة تصميم حوارات الضبط لاتباع نمط إعدادات نظام بلازما الجديد</li>
|
||||
<li xml:lang="ca">Redisseny dels diàlegs de configuració per a seguir l'estil nou de l'arranjament del sistema del Plasma</li>
|
||||
<li xml:lang="ca-valencia">Redisseny dels diàlegs de configuració per a seguir l'estil nou de Configuració del sistema de Plasma</li>
|
||||
<li xml:lang="he">חלוניות ההגדרות שלנו עוצבו מחדש כך שתיראנה יותר כמו סגנון הגדרות מערכת פלזמה החדש</li>
|
||||
<li xml:lang="it">Riprogettazione delle nostre finestre di configurazione per seguire il nuovo stile delle impostazioni di sistema di Plasma</li>
|
||||
<li xml:lang="ka">შეიცვალა დიზაინი კონფიგურაციის დიალოგებისთვის, რომ ისინი Plasma-ის სისტემური პარამეტრების სტილს მიჰყვებოდნენ</li>
|
||||
<li xml:lang="pt-BR">Redesenho das caixas de diálogo de configuração para seguir o novo estilo das Configurações do Sistema do Plasma.</li>
|
||||
<li xml:lang="ru">Реализован редизайн диалогов настройки в соответствии со стилем нового приложения «Параметры системы» Plasma;</li>
|
||||
@@ -1002,6 +1063,8 @@
|
||||
<li xml:lang="ar">إصلاح قضايا متنوعة أخرى وطلبات ميزات صغيرة، مما يقلل إجمالي القضايا المفتوحة بنسبة 20%.</li>
|
||||
<li xml:lang="ca">Corregeix diversos problemes i peticions de funcionalitats petites. Disminució de la quantitat total de problemes oberts en un 20%.</li>
|
||||
<li xml:lang="ca-valencia">Corregix diversos problemes i peticions de característiques xicotetes. Disminució de la quantitat total de problemes oberts en un 20%.</li>
|
||||
<li xml:lang="he">תוקנו מגוון תקלות שונות ובקשות מימוש קטנות. מה שמקטין את כמות הסוגיות הפתוחות ב־20%.</li>
|
||||
<li xml:lang="it">Corregge vari altri problemi e richieste di piccole funzionalità. Riduzione del 20% del numero totale di problemi aperti.</li>
|
||||
<li xml:lang="ka">გასწორდა სხვადასხვა შეცდომები და პატარა ფუნქციის მოთხოვნები. ღია პრობლემების ჯამური რაოდენობა შემცირდა 20%-ით.</li>
|
||||
<li xml:lang="pt-BR">Corrigido diversos outros problemas e implementação de pequenas solicitações de melhorias. Reduzido o número total de bugs em aberto em 20%.</li>
|
||||
<li xml:lang="ru">Исправлены прочие ошибки и реализованы небольшие запросы на новые возможности; общее количество открытых проблем сокращено на 20%.</li>
|
||||
@@ -1019,6 +1082,8 @@
|
||||
<p xml:lang="ca">El NeoChat 21.12 aporta moltes funcionalitats noves i correccions</p>
|
||||
<p xml:lang="ca-valencia">NeoChat 21.12 aporta moltes característiques noves i correccions</p>
|
||||
<p xml:lang="es">NeoChat 21.12 proporciona muchas funciones nuevas y correcciones.</p>
|
||||
<p xml:lang="he">ב־NeoChat 21.12 הוצגו מגוון יכולות ותיקונים חדשים</p>
|
||||
<p xml:lang="it">NeoChat 21.12 porta con sé tante nuove funzionalità e correzioni</p>
|
||||
<p xml:lang="ka">NeoChat 21.12 ბევრ ახალი ფუნქციას და შეცდომების გასწორებას შეიცავს</p>
|
||||
<p xml:lang="pt-BR">O NeoChat 21.12 traz muitas novidades e correções</p>
|
||||
<p xml:lang="ru">В NeoChat 21.12 добавлено множество новых возможностей и исправлений</p>
|
||||
@@ -1031,6 +1096,8 @@
|
||||
<li xml:lang="ca">S'han resolt diversos problemes relacionats amb l'inici de sessió, la sortida i el canvi de compte</li>
|
||||
<li xml:lang="ca-valencia">S'han resolt diversos problemes relacionats amb l'inici de sessió, l'eixida i el canvi de compte</li>
|
||||
<li xml:lang="es">Se han solucionado diversos problemas relacionados con el inicio y el cierre de sesión y con el cambio de cuenta.</li>
|
||||
<li xml:lang="he">נפתרו מספר בעיות שקשורות בכניסה ויציאה לחשבון והחלפת חשבונות</li>
|
||||
<li xml:lang="it">Risolti vari problemi relativi all'accesso, alla disconnessione e al cambio di account</li>
|
||||
<li xml:lang="ka">გადაიჭრა შესვლასთან, გასვლასთან და ანგარიშის გადართვასთან დაკავშირებული სხვადასხვა პრობლემა</li>
|
||||
<li xml:lang="pt-BR">Resolvidos diversos problemas relacionados a login, logout e troca de contas</li>
|
||||
<li xml:lang="ru">Устранены проблемы, связанные с входом, выходом и переключением учётных записей;</li>
|
||||
@@ -1042,6 +1109,8 @@
|
||||
<li xml:lang="ca">S'han corregit alguns problemes en la disposició de la línia de temps</li>
|
||||
<li xml:lang="ca-valencia">S'han corregit alguns problemes en la disposició de la línia de temps</li>
|
||||
<li xml:lang="es">Se han corregido varios problemas en la disposición de la línea de tiempo</li>
|
||||
<li xml:lang="he">תוקנו מספר בעיות בפריסת ציר הזמן</li>
|
||||
<li xml:lang="it">Corretti alcuni problemi nella disposizione della linea temporale</li>
|
||||
<li xml:lang="ka">გასწორდა დროის ხაზის განლაგების რამდენიმე პრობლემა</li>
|
||||
<li xml:lang="pt-BR">Corrigidos alguns problemas no layout da linha do tempo</li>
|
||||
<li xml:lang="ru">Исправлены некоторые проблемы в расположении ленты событий;</li>
|
||||
@@ -1053,6 +1122,8 @@
|
||||
<li xml:lang="ca">S'ha afegit la verificació ortogràfica mentre s'escriu un missatge</li>
|
||||
<li xml:lang="ca-valencia">S'ha afegit la verificació ortogràfica mentre s'escriu un missatge</li>
|
||||
<li xml:lang="es">Se ha añadido comprobación ortográfica durante la escritura de mensajes.</li>
|
||||
<li xml:lang="he">נוספה בדיקת איות בזמן כתיבת הודעות</li>
|
||||
<li xml:lang="it">Aggiunto il controllo ortografico durante la scrittura di un messaggio</li>
|
||||
<li xml:lang="ka">დაემატა მართლწერის შემოწმება შეტყობინების წერისას</li>
|
||||
<li xml:lang="pt-BR">Adicionada verificação ortográfica durante a escrita de mensagens</li>
|
||||
<li xml:lang="ru">Добавлена проверка орфографии при написании сообщения;</li>
|
||||
@@ -1064,6 +1135,8 @@
|
||||
<li xml:lang="ca">Pàgines de configuració millorades</li>
|
||||
<li xml:lang="ca-valencia">Pàgines de configuració millorades</li>
|
||||
<li xml:lang="es">Se han mejorado las páginas de preferencias.</li>
|
||||
<li xml:lang="he">עמודי ההגדרות השתפרו</li>
|
||||
<li xml:lang="it">Pagine delle impostazioni migliorate</li>
|
||||
<li xml:lang="ka">გაუმჯობესდა მორგების გვერდები</li>
|
||||
<li xml:lang="pt-BR">Páginas de configurações aprimoradas</li>
|
||||
<li xml:lang="ru">Улучшены страницы настроек;</li>
|
||||
@@ -1074,6 +1147,8 @@
|
||||
<li xml:lang="ar">تحسينات كثيرة لدعم أندرويد والأجهزة المحمولة بشكل عام</li>
|
||||
<li xml:lang="ca">Moltes millores a l'Android i suport general de mòbils</li>
|
||||
<li xml:lang="ca-valencia">Moltes millores a Android i suport general de mòbils</li>
|
||||
<li xml:lang="he">מגוון שיפורים לתמיכה ב־Android ובניידים בכלל</li>
|
||||
<li xml:lang="it">Molti miglioramenti al supporto Android e mobile in generale</li>
|
||||
<li xml:lang="ka">ბევრი გაუმჯობესება Android-ის და ზოგადი მობილური მხარდაჭერაში</li>
|
||||
<li xml:lang="pt-BR">Muitas melhorias no Android e no suporte geral para dispositivos móveis</li>
|
||||
<li xml:lang="ru">Многочисленные улучшения для Android и мобильных устройств в целом;</li>
|
||||
@@ -1084,6 +1159,7 @@
|
||||
<li xml:lang="ar">عرض blurhashes أثناء تحميل الصور</li>
|
||||
<li xml:lang="ca">Mostra «blurhashes» mentre es carreguen les imatges</li>
|
||||
<li xml:lang="ca-valencia">Mostra «blurhashes» mentre es carreguen les imatges</li>
|
||||
<li xml:lang="it">Mostra i trattini sfocati durante il caricamento delle immagini</li>
|
||||
<li xml:lang="ka">დაბინდული ადგილების ჩვენება, სანამ გამოსახულებები ჩაიტვირთება</li>
|
||||
<li xml:lang="pt-BR">Exibir os ícones de desfoque enquanto as imagens carregam</li>
|
||||
<li xml:lang="ru">Отображение размытых хешей во время загрузки изображений;</li>
|
||||
@@ -1095,6 +1171,8 @@
|
||||
<li xml:lang="ca">Permet mostrar emojis personalitzats</li>
|
||||
<li xml:lang="ca-valencia">Permet mostrar emoji personalitzats</li>
|
||||
<li xml:lang="es">Compatibilidad con emojis personalizados.</li>
|
||||
<li xml:lang="he">תמיכה בהצגת אמוג׳ים מותאמים אישית</li>
|
||||
<li xml:lang="it">Supporto per la visualizzazione di emoji personalizzati</li>
|
||||
<li xml:lang="ka">მორგებული ემოჯიების ჩვენების მხარდაჭერა</li>
|
||||
<li xml:lang="pt-BR">Suporte para exibição de emojis personalizados</li>
|
||||
<li xml:lang="ru">Отображение пользовательских эмодзи;</li>
|
||||
@@ -1106,6 +1184,8 @@
|
||||
<li xml:lang="ca">S'ha afegit un menú global</li>
|
||||
<li xml:lang="ca-valencia">S'ha afegit un menú global</li>
|
||||
<li xml:lang="es">Se ha añadido un menú global.</li>
|
||||
<li xml:lang="he">נוסף תפריט מקיף</li>
|
||||
<li xml:lang="it">Aggiunto un menu globale</li>
|
||||
<li xml:lang="ka">დაემატა გლობალური მენიუ</li>
|
||||
<li xml:lang="pt-BR">Adicionado um menu global</li>
|
||||
<li xml:lang="ru">Добавлено глобальное меню;</li>
|
||||
@@ -1116,6 +1196,8 @@
|
||||
<li xml:lang="ar">أُضيف دعم المحتوى المحروق</li>
|
||||
<li xml:lang="ca">S'ha afegit la implementació per als espòilers</li>
|
||||
<li xml:lang="ca-valencia">S'ha afegit la implementació per als espòilers</li>
|
||||
<li xml:lang="he">נוספה תמיכה בקלקלנים</li>
|
||||
<li xml:lang="it">Aggiunto supporto per gli spoiler</li>
|
||||
<li xml:lang="ka">დაემატა სპოილერების მხარდაჭერა</li>
|
||||
<li xml:lang="pt-BR">Adicionado suporte para spoilers</li>
|
||||
<li xml:lang="ru">Добавлена поддержка скрытого текста;</li>
|
||||
@@ -1127,6 +1209,8 @@
|
||||
<li xml:lang="ca">S'ha afegit un commutador ràpid per a canviar entre sales</li>
|
||||
<li xml:lang="ca-valencia">S'ha afegit un commutador ràpid per a canviar entre sales</li>
|
||||
<li xml:lang="es">Se ha añadido un selector rápido para cambiar de sala.</li>
|
||||
<li xml:lang="he">נוסף בורר מהיר למעבר בין חדרים</li>
|
||||
<li xml:lang="it">Aggiunto un commutatore rapido per passare da una stanza all'altra</li>
|
||||
<li xml:lang="ka">დაემატა სწრაფი გადამრთველი ოთახებს შორის</li>
|
||||
<li xml:lang="pt-BR">Adicionado um botão de troca rápida para alternar entre salas</li>
|
||||
<li xml:lang="ru">Добавлен быстрый переключатель для перехода между комнатами;</li>
|
||||
@@ -1137,6 +1221,8 @@
|
||||
<li xml:lang="ar">أُضيف دعم لتأثير خلفية ضبابية أنيقة اختياري</li>
|
||||
<li xml:lang="ca">S'ha afegit la implementació per a un efecte de difuminat de fons opcional</li>
|
||||
<li xml:lang="ca-valencia">S'ha afegit la implementació per a un efecte de difuminat de fons opcional</li>
|
||||
<li xml:lang="he">נוספה תמיכה באפקט רקע מטושטש מרהיב כרשות</li>
|
||||
<li xml:lang="it">Aggiunto supporto per un effetto di sfocatura dello sfondo opzionale</li>
|
||||
<li xml:lang="ka">დაემატა არასავალდებულო მდიდრული ბუნდოვანი ფონის ეფექტის მხარდაჭერა</li>
|
||||
<li xml:lang="pt-BR">Adicionada a opção de um efeito de desfoque de fundo sofisticado</li>
|
||||
<li xml:lang="ru">Добавлена поддержка необязательного эффекта размытого фона;</li>
|
||||
@@ -1147,6 +1233,8 @@
|
||||
<li xml:lang="ar">أدراج يمنى ويسرى قابلة لتغيير الحجم</li>
|
||||
<li xml:lang="ca">Calaixos esquerra i dreta redimensionables</li>
|
||||
<li xml:lang="ca-valencia">Calaixos esquerra i dreta redimensionables</li>
|
||||
<li xml:lang="he">מגירות גמישות משמאל ומימין</li>
|
||||
<li xml:lang="it">Cassetti sinistro e destro ridimensionabili</li>
|
||||
<li xml:lang="ka">ზომაცვლადი მარცხენა და მარჯვენა უჯრები</li>
|
||||
<li xml:lang="pt-BR">Gavetas redimensionáveis à esquerda e à direita</li>
|
||||
<li xml:lang="ru">Изменяемые размеры левой и правой панелей;</li>
|
||||
@@ -1157,6 +1245,8 @@
|
||||
<li xml:lang="ar">أُضيف تمييز الصيغة في رسائل json الخام</li>
|
||||
<li xml:lang="ca">S'ha afegit el ressaltat de sintaxi en els missatges JSON en brut</li>
|
||||
<li xml:lang="ca-valencia">S'ha afegit el ressaltat de sintaxi en els missatges JSON en brut</li>
|
||||
<li xml:lang="he">נוספה הדגשת תחביר בהודעות json גולמיות</li>
|
||||
<li xml:lang="it">Aggiunta l'evidenziazione della sintassi nei messaggi JSON non elaborati</li>
|
||||
<li xml:lang="ka">დაემატა სინტაქსის გამოკვეთა დაუმუშავებელ JSON შეტყობინებებში</li>
|
||||
<li xml:lang="pt-BR">Adicionada a coloração de sintaxe em mensagens JSON brutas</li>
|
||||
<li xml:lang="ru">Добавлена подсветка синтаксиса в необработанных JSON-сообщениях;</li>
|
||||
@@ -1168,6 +1258,8 @@
|
||||
<li xml:lang="ca">Millor suport del Wayland</li>
|
||||
<li xml:lang="ca-valencia">Millor suport de Wayland</li>
|
||||
<li xml:lang="es">Mejor compatibilidad con Wayland.</li>
|
||||
<li xml:lang="he">תמיכה משופרת ב־Wayland</li>
|
||||
<li xml:lang="it">Miglior supporto Wayland</li>
|
||||
<li xml:lang="ka">Wayland-ის უკეთესი მხარდაჭერა</li>
|
||||
<li xml:lang="pt-BR">Melhor suporte ao Wayland</li>
|
||||
<li xml:lang="ru">Улучшена поддержка Wayland;</li>
|
||||
@@ -1179,6 +1271,8 @@
|
||||
<li xml:lang="ca">Recepció i baixada de fitxers millorades</li>
|
||||
<li xml:lang="ca-valencia">Recepció i baixada de fitxers millorades</li>
|
||||
<li xml:lang="es">Se ha mejorado la recepción y la descarga de archivos.</li>
|
||||
<li xml:lang="he">קבלה והורדה משופרת של קבצים</li>
|
||||
<li xml:lang="it">Miglioramento della ricezione e dello scaricamento dei file</li>
|
||||
<li xml:lang="ka">გაუმჯობესდა ფაილების მიღება და გადმოწერა</li>
|
||||
<li xml:lang="pt-BR">Recepção e download de arquivos aprimorados</li>
|
||||
<li xml:lang="ru">Улучшены приём и загрузка файлов;</li>
|
||||
@@ -1195,6 +1289,7 @@
|
||||
<p xml:lang="ar">يوفر نيوتشات 1.2 إعادة تصميم كبرى لواجهة المستخدم. تستخدم صفحة الدردشة الآن فقاعات للرسائل، كما أُعيدت كتابة مكون الإدخال بالكامل بمظهر أجمل.</p>
|
||||
<p xml:lang="ca">El NeoChat 1.2 aporta un redisseny important de la interfície d'usuari. La pàgina de xat ara utilitza bombolles per als missatges i el component d'entrada s'ha reescrit completament amb un aspecte més agradable també.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat 1.2 aporta un redisseny important de la interfície d'usuari. La pàgina de xat ara utilitza bambolles per als missatges i el component d'entrada s'ha reescrit completament amb un aspecte més agradable també.</p>
|
||||
<p xml:lang="it">NeoChat 1.2 presenta un'importante riprogettazione dell'interfaccia utente. La pagina della chat ora utilizza le bolle per i messaggi e anche il componente di input è stato completamente riscritto con un aspetto più gradevole.</p>
|
||||
<p xml:lang="ka">NeoChat 1.2 მომხმარებლის ინტერფეისის დიზაინის თითქმის სრულ ცვლილებას შეიცავს. ჩატის გვერდი ახლა შეტყობინებებისთვის ბუშტებს იყენებს და შეყვანის კომპონენტი მთლიანად თავიდანაა დაწერილი, რომ უკეთ გამოიყურებოდეს.</p>
|
||||
<p xml:lang="pt-BR">O NeoChat 1.2 traz uma grande reformulação da interface do usuário. A página de bate-papo agora utiliza balões para as mensagens e o componente de entrada foi completamente reescrito com um visual mais agradável.</p>
|
||||
<p xml:lang="ru">В версии NeoChat 1.2 полностью изменён пользовательский интерфейс. На странице чата сообщения отображаются в виде пузырей, а компонент ввода был полностью переписан и получил более приятный внешний вид.</p>
|
||||
@@ -1205,6 +1300,8 @@
|
||||
<p xml:lang="ar">أصبح من الممكن الآن إرسال تفاعلات مخصصة عبر الرد على تعليق بالأمر /react <message>.</p>
|
||||
<p xml:lang="ca">Ara és possible enviar reaccions personalitzades responent a un comentari amb /react <missatge>.</p>
|
||||
<p xml:lang="ca-valencia">Ara és possible enviar reaccions personalitzades responent a un comentari amb /react <missatge>.</p>
|
||||
<p xml:lang="he">מעתה ניתן לשלוח סימני רגש מותאמים אישית על ידי תגובה להערה עם /react <message>.</p>
|
||||
<p xml:lang="it">Ora è possibile inviare reazioni personalizzate rispondendo a un commento con /react <messaggio>.</p>
|
||||
<p xml:lang="ka">ახლა შესაძლებელია მორგებული რეაქციების გაგზავნა კომენტარზე ბრძანებით /react <message> პასუხის საშუალებით.</p>
|
||||
<p xml:lang="pt-BR">Agora é possível enviar reações personalizadas respondendo a um comentário com /react <mensagem>.</p>
|
||||
<p xml:lang="ru">Теперь можно отправлять собственные реакции, ответив на сообщение командой /react <сообщение>.</p>
|
||||
@@ -1215,6 +1312,8 @@
|
||||
<p xml:lang="ar">يدعم نيوتشات الآن فتح معرفات Matrix URI من المتصفح.</p>
|
||||
<p xml:lang="ca">El NeoChat ara permet obrir els URI de Matrix des del navegador.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat ara permet obrir els URI de Matrix des del navegador.</p>
|
||||
<p xml:lang="he">NeoChat תומך מעתה בפתיחת כתובות פנימיות של Matrix מהדפדפן שלך.</p>
|
||||
<p xml:lang="it">NeoChat ora supporta l'apertura degli URI Matrix dal tuo browser.</p>
|
||||
<p xml:lang="ka">NeoChat-ს ახლა მატრიცის URI-ების გახსნა შეუძლია თქვენი ბრაუზერიდან.</p>
|
||||
<p xml:lang="pt-BR">O NeoChat agora suporta a abertura de URIs do Matrix a partir do seu navegador.</p>
|
||||
<p xml:lang="ru">В NeoChat добавлена поддержка открытия URI Matrix из браузера.</p>
|
||||
@@ -1231,6 +1330,7 @@
|
||||
<p xml:lang="ar">لعل أبرز ما في هذا الإصدار هو صفحة الولوج الجديدة كلياً. فهي تكتشف ضبط الخادم بناءً على معرف ماتركس الخاص بك. يتيح هذا الولوج إلى الخوادم التي تتطلب الولوج الموحد (SSO) (مثل خوادم موزيلا أو خادم ماتركس القادم لفيدورا).</p>
|
||||
<p xml:lang="ca">Probablement el més destacat d'aquest llançament és la pàgina d'inici de sessió completament nova. Detecta la configuració del servidor basant-se en l'identificador de Matrix. Això permet iniciar sessió en servidors que requereixen inici de sessió únic (SSO) (com el Mozilla o la instància d'entrada de Matrix de Fedora).</p>
|
||||
<p xml:lang="ca-valencia">Probablement el més destacat d'este llançament és la pàgina d'inici de sessió completament nova. Detecta la configuració del servidor basant-se en l'identificador de Matrix. Açò permet iniciar sessió en servidors que requerixen inici de sessió únic (SSO) (com Mozilla o la instància d'entrada de Matrix de Fedora).</p>
|
||||
<p xml:lang="it">Probabilmente il punto forte di questa versione è la pagina di accesso completamente rinnovata. Rileva la configurazione del server in base al tuo ID Matrix. Questo ti permette di accedere ai server che richiedono Single Sign-On (SSO) (come Mozilla o l'istanza Matrix in arrivo di Fedora).</p>
|
||||
<p xml:lang="ka">ალბათ ამ ვერსიის გამოკვეთილი ცვლილება სრულიად ახალი შესვლის გვერდია. ის სერვერის კონფიგურაციას თქვენი მატრიცის ID-ის მიხედვით ადგენს. ეს საშუალებას გაძლევთ, შეხვიდეთ სერვერებზე, რომლებიც SSO-ით (მაგ Mozilla, ან შემომავალი Fedora-ის მატრიცის გაშვებული ასლი) შესვლას ითხოვს.</p>
|
||||
<p xml:lang="pt-BR">Provavelmente, o grande destaque desta versão é a página de login completamente nova. Ela detecta a configuração do servidor com base no seu ID do Matrix. Isso permite que você faça login em servidores que exigem Single Sign-On (SSO) (como a instância do Mozilla Matrix ou a futura instância do Fedora Matrix).</p>
|
||||
<p xml:lang="ru">Главным нововведением этой версии стала полностью переработанная страница входа. Она определяет конфигурацию сервера по вашему идентификатору Matrix, что позволяет входить на серверы с единой системой аутентификации (например, Mozilla или готовящийся к запуску экземпляр Fedora Matrix).</p>
|
||||
@@ -1241,6 +1341,8 @@
|
||||
<p xml:lang="ar">تُكتشف الخوادم التي تتطلب الموافقة على شروط الخدمة قبل الاستخدام بشكل صحيح الآن وتُحوّل إلى صفحة شروط الخدمة الخاصة بها، مما يسمح للمستخدم بالموافقة عليها بدلاً من فشل تحميل الحساب بصمت.</p>
|
||||
<p xml:lang="ca">Els servidors que requereixen acceptar el TOS abans de l'ús ara es detecten correctament i redirigeixen a la seva pàgina web del TOS, que permet a l'usuari acceptar-lo en lloc de no carregar el compte en silenci.</p>
|
||||
<p xml:lang="ca-valencia">Els servidors que requerixen acceptar TOS abans de l'ús ara es detecten correctament i redirigixen a la seua pàgina web de TOS, que permet a l'usuari acceptar-lo en lloc de no carregar el compte en silenci.</p>
|
||||
<p xml:lang="he">שרתים שדורשים הסכמה לתנאי השירות לפי שאפשר להשתמש בהם מזוהים כעת ומופנים לעמוד תנאי השירות שלהם, כך מתאפשר למשתמש להסכים להם במקום להיכשל בשקט ולהיכשל בטעינת החשבון.</p>
|
||||
<p xml:lang="it">I server che richiedono l'accettazione dei termini di servizio prima dell'utilizzo ora vengono rilevati correttamente e reindirizzano alla pagina web dei termini di servizio, consentendo all'utente di accettarli invece di bloccare silenziosamente il caricamento dell'account.</p>
|
||||
<p xml:lang="ka">სერვერები, რომლებიც გამოყენების პირობებზე დათანხმებას ითხოვენ, ახლა სწორად არიან აღმოჩენილები და გადაგამისამართებთ მათი გამოყენების პირობების ვებგვერდზე, სადაც მომხმარებელს საშუალება აქვს, დაეთანხმოს მას იმის მაგიერ, ანგარიშის ჩატვირთვა შეცდომის გარეშე, ჩუმად ჩავარდეს.</p>
|
||||
<p xml:lang="pt-BR">Os servidores que exigem a aceitação dos Termos de Serviço antes do uso agora são detectados corretamente e redirecionam para a página dos Termos de Serviço, permitindo que o usuário os aceite em vez de simplesmente não conseguir carregar a conta.</p>
|
||||
<p xml:lang="ru">Теперь серверы, требующие согласия с условиями использования перед началом работы, определяются корректно и перенаправляют пользователя на соответствующую веб-страницу, позволяя принять условия вместо аварийного завершения загрузки учётной записи.</p>
|
||||
@@ -1251,6 +1353,8 @@
|
||||
<p xml:lang="ar">أصبح من الممكن الآن فتح غرفة في نافذة جديدة. يتيح هذا عرض غرف متعددة والتفاعل معها في الوقت ذاته.</p>
|
||||
<p xml:lang="ca">Ara és possible obrir una sala en una finestra nova. Això permet veure i interactuar amb diverses sales alhora.</p>
|
||||
<p xml:lang="ca-valencia">Ara és possible obrir una sala en una finestra nova. Açò permet veure i interactuar amb diverses sales alhora.</p>
|
||||
<p xml:lang="he">מעתה ניתן לפתוח חדר בחלון חדש. כך ניתן לצפות ולהתנהל מול מגוון חדרים באותו הזמן.</p>
|
||||
<p xml:lang="it">Ora è possibile aprire una stanza in una nuova finestra. Questo consente di visualizzare e interagire con più stanze contemporaneamente.</p>
|
||||
<p xml:lang="ka">ახლა შესაძლებელია, ოთახი ცალკე ფანჯარაში გახსნათ. ეს საშუალებას გაძლევთ, ერთდროულად მრავალ ოთახში ისაუბროთ.</p>
|
||||
<p xml:lang="pt-BR">Agora é possível abrir uma sala em uma nova janela. Isso permite visualizar e interagir com várias salas ao mesmo tempo.</p>
|
||||
<p xml:lang="ru">Добавлена возможность открытия комнаты в отдельном окне для одновременного просмотра и взаимодействия с несколькими комнатами.</p>
|
||||
@@ -1261,6 +1365,8 @@
|
||||
<p xml:lang="ar">أُضيفت بضعة أوامر لنيوتشات (/shrug, /lenny, /join, /ignore, ...).</p>
|
||||
<p xml:lang="ca">Hem afegit algunes ordres al NeoChat (/shrug, /lenny, /join, /ignore...).</p>
|
||||
<p xml:lang="ca-valencia">Hem afegit algunes ordres a NeoChat (/shrug, /lenny, /join, /ignore…).</p>
|
||||
<p xml:lang="he">הוספנו מספר פקודות ל־NeoChat (/shrug, /lenny, /join, /ignore, …).</p>
|
||||
<p xml:lang="it">Abbiamo aggiunto alcuni comandi a NeoChat (/shrug, /lenny, /join, /ignore, ...).</p>
|
||||
<p xml:lang="ka">NeoChat-ს რამდენიმე ბრძანება (/shrug, /lenny, /join, /ignore, ...) დავამატეთ.</p>
|
||||
<p xml:lang="pt-BR">Adicionamos alguns comandos ao NeoChat (/shrug, /lenny, /join, /ignore, ...).</p>
|
||||
<p xml:lang="ru">Добавлены команды для NeoChat (/shrug, /lenny, /join, /ignore, …).</p>
|
||||
@@ -1271,6 +1377,8 @@
|
||||
<p xml:lang="ar">حُسّن تكامل بلازما قليلاً. يُعرض الآن عدد الرسائل غير المقروءة في شريط مهام بلازما.</p>
|
||||
<p xml:lang="ca">Hem millorat una mica la integració amb el Plasma. Ara es mostra el nombre de missatges sense llegir a la barra de tasques del Plasma.</p>
|
||||
<p xml:lang="ca-valencia">Hem millorat una mica la integració amb Plasma. Ara es mostra el nombre de missatges sense llegir a la barra de tasques de Plasma.</p>
|
||||
<p xml:lang="he">שיפרנו מעט את השילוב מול פלזמה. כעת מספר ההודעות שלא נקראות מופיע בשורת המשימות של פלזמה.</p>
|
||||
<p xml:lang="it">Abbiamo migliorato leggermente l'integrazione con Plasma. Ora il numero di messaggi non letti viene visualizzato nella barra delle applicazioni di Plasma.</p>
|
||||
<p xml:lang="ka">ოდნავ გავაუმჯობესეთ Plasma-ის ინტეგრაცია. ახლა წაუკითხავი შეტყობინებების რაოდენობა Plasma-ის ამოცანათა პანელზე გამოჩნდება.</p>
|
||||
<p xml:lang="pt-BR">Aprimoramos um pouco a integração com o Plasma. Agora, o número de mensagens não lidas é exibido na barra de tarefas do Plasma.</p>
|
||||
<p xml:lang="ru">Улучшена интеграция с Plasma. Теперь число непрочитанных сообщений отображается в панели задач Plasma.</p>
|
||||
@@ -1287,6 +1395,8 @@
|
||||
<p xml:lang="ca">Aquesta versió corregeix diversos errors.</p>
|
||||
<p xml:lang="ca-valencia">Esta versió corregix diversos errors.</p>
|
||||
<p xml:lang="es">Esta versión corrige algunos fallos.</p>
|
||||
<p xml:lang="he">הגרסה הזאת מתקנת מגוון תקלות.</p>
|
||||
<p xml:lang="it">Questa versione corregge diversi bug.</p>
|
||||
<p xml:lang="ka">ეს ვერსია რამდენიმე შეცდომას ასწორებს.</p>
|
||||
<p xml:lang="pt-BR">Esta versão corrige vários bugs.</p>
|
||||
<p xml:lang="ru">В этой версии исправлены несколько ошибок.</p>
|
||||
@@ -1298,6 +1408,8 @@
|
||||
<li xml:lang="ar">لا يتطلب نيوتشات ضبط .well-know في الخادم ليعمل.</li>
|
||||
<li xml:lang="ca">El NeoChat no requereix una configuració «.well-know» al servidor per a funcionar.</li>
|
||||
<li xml:lang="ca-valencia">NeoChat no requerix una configuració «.well-know» al servidor per a funcionar.</li>
|
||||
<li xml:lang="he">NeoChat לא דורש הגדרות .well-know בשרת כדי לעבוד.</li>
|
||||
<li xml:lang="it">Per funzionare, NeoChat non richiede una configurazione .well-know sul server.</li>
|
||||
<li xml:lang="ka">NeoChat-ს სამუშაოდ სერვერზე .well-know კონფიგურაცია არ სჭირდება.</li>
|
||||
<li xml:lang="pt-BR">O NeoChat não requer uma configuração .well-know no servidor para funcionar.</li>
|
||||
<li xml:lang="ru">Для работы NeoChat не требуется конфигурация .well-known на сервере;</li>
|
||||
@@ -1308,6 +1420,8 @@
|
||||
<li xml:lang="ar">لن تظهر الرسائل المحررة مكررة بعد الآن.</li>
|
||||
<li xml:lang="ca">Els missatges editats ja no es mostraran duplicats.</li>
|
||||
<li xml:lang="ca-valencia">Els missatges editats ja no es mostraran duplicats.</li>
|
||||
<li xml:lang="he">הודעות שנערכו לא תופענה עוד ככפולות.</li>
|
||||
<li xml:lang="it">I messaggi modificati non saranno più visualizzati come duplicati.</li>
|
||||
<li xml:lang="ka">ჩასწორებული შეტყობინებები გამეორებულად აღარ გამოჩნდება.</li>
|
||||
<li xml:lang="pt-BR">As mensagens editadas não aparecerão mais duplicadas.</li>
|
||||
<li xml:lang="ru">Редактируемые сообщения больше не отображаются как дубликаты;</li>
|
||||
@@ -1318,6 +1432,8 @@
|
||||
<li xml:lang="ar">أُصلحت مشكلات رسومية متنوعة.</li>
|
||||
<li xml:lang="ca">S'han corregit diversos errors gràfics.</li>
|
||||
<li xml:lang="ca-valencia">S'han corregit diversos errors gràfics.</li>
|
||||
<li xml:lang="he">מגוון עיוותים גרפיים תוקנו.</li>
|
||||
<li xml:lang="it">Sono stati risolti vari problemi grafici.</li>
|
||||
<li xml:lang="ka">გასწორდა სხვადასხვა გრაფიკული შეცდომა.</li>
|
||||
<li xml:lang="pt-BR">Diversos problemas gráficos foram corrigidos.</li>
|
||||
<li xml:lang="ru">Исправлены различные графические дефекты;</li>
|
||||
@@ -1328,6 +1444,8 @@
|
||||
<li xml:lang="ar">يطلب نيوتشات الآن الموافقة على الشروط والأحكام إذا كانت مطلوبة بدلاً من عدم عرض شيء.</li>
|
||||
<li xml:lang="ca">El NeoChat ara demana consentiment als termes i condicions si es requereixen en lloc de no mostrar res.</li>
|
||||
<li xml:lang="ca-valencia">NeoChat ara demana consentiment als termes i condicions si es requerixen en lloc de no mostrar res.</li>
|
||||
<li xml:lang="he">NeoChat מבקש מעתה להסכים לתנאים ולהתניות במקרה הצורך במקום לא להציג כלום.</li>
|
||||
<li xml:lang="it">NeoChat ora chiede il consenso ai termini e alle condizioni, se necessario, anziché non visualizzare nulla.</li>
|
||||
<li xml:lang="ka">NeoChat ახლა გკითხავთ, ეთანხმებით თუ არა გამოყენების პირობებს, თუ ეს აუცილებელია, არაფრის ჩვენების მაგიერ.</li>
|
||||
<li xml:lang="pt-BR">O NeoChat agora solicita a aceitação dos termos e condições, se necessário, em vez de não exibir nada.</li>
|
||||
<li xml:lang="ru">В NeoChat реализован запрос согласия с условиями использования, если это требуется;</li>
|
||||
@@ -1338,6 +1456,8 @@
|
||||
<li xml:lang="ar">تُعرض صور المستخدمين الرمزية في قائمة الغرف بشكل صحيح الآن.</li>
|
||||
<li xml:lang="ca">Els avatars d'usuaris a la llista de sales ara es mostren correctament.</li>
|
||||
<li xml:lang="ca-valencia">Els avatars d'usuaris a la llista de sales ara es mostren correctament.</li>
|
||||
<li xml:lang="he">התמונות הייצוגיות של המשתמשים מופיעות נכון מעתה ברשימת החדרים.</li>
|
||||
<li xml:lang="it">Gli avatar degli utenti nell'elenco delle stanze ora vengono visualizzati correttamente.</li>
|
||||
<li xml:lang="ka">მომხმარებლის ავატარი ოთახების სიაში ახლა სწორადაა ნაჩვენები.</li>
|
||||
<li xml:lang="pt-BR">Os avatares dos usuários na lista de salas agora são exibidos corretamente.</li>
|
||||
<li xml:lang="ru">Аватары пользователей в списке комнат отображаются корректно;</li>
|
||||
@@ -1348,6 +1468,8 @@
|
||||
<li xml:lang="ar">إصلاح حفظ الصور</li>
|
||||
<li xml:lang="ca">Corregeix el desament de les imatges</li>
|
||||
<li xml:lang="ca-valencia">Corregix la guardada de les imatges</li>
|
||||
<li xml:lang="he">תוקנה שמירת תמונות</li>
|
||||
<li xml:lang="it">Corregge il salvataggio delle immagini</li>
|
||||
<li xml:lang="ka">გასწორდა სურათების შენახვა</li>
|
||||
<li xml:lang="pt-BR">Corrigido salvamento de imagem</li>
|
||||
<li xml:lang="ru">Исправлено сохранение изображений;</li>
|
||||
@@ -1364,6 +1486,8 @@
|
||||
<p xml:lang="ar">الإصدار الأولي لنيوتشات، عميل ماتركس لكيدي.</p>
|
||||
<p xml:lang="ca">Versió inicial de NeoChat, el client de Matrix de KDE.</p>
|
||||
<p xml:lang="ca-valencia">Versió inicial de NeoChat, el client de Matrix de KDE.</p>
|
||||
<p xml:lang="he">המהדורה הראשונית של NeoChat, לקוח המטריקס של KDE.</p>
|
||||
<p xml:lang="it">Versione iniziale di NeoChat, il client matrix di KDE.</p>
|
||||
<p xml:lang="ka">NeoChat-ის, KDE-ის მატრიცის კლიენტის პირველი ვერსია.</p>
|
||||
<p xml:lang="pt-BR">Lançamento inicial do NeoChat, o cliente Matrix do KDE.</p>
|
||||
<p xml:lang="ru">Первый выпуск NeoChat — клиента Matrix для KDE.</p>
|
||||
|
||||
@@ -7,7 +7,7 @@ msgstr ""
|
||||
"Project-Id-Version: neochat\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2026-02-23 00:44+0000\n"
|
||||
"PO-Revision-Date: 2026-02-21 17:34+0400\n"
|
||||
"PO-Revision-Date: 2026-02-24 22:31+0400\n"
|
||||
"Last-Translator: Zayed Al-Saidi <zayed.alsaidi@gmail.com>\n"
|
||||
"Language-Team: ar\n"
|
||||
"Language: ar\n"
|
||||
@@ -4808,48 +4808,36 @@ msgid "Space Settings"
|
||||
msgstr "إعدادات الفضاء"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:85 src/spaces/SpaceHomePage.qml:109
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt ""
|
||||
#| "@action:button 'Report' as in 'Report this user to the administrators'"
|
||||
#| msgid "Report…"
|
||||
#, kde-format
|
||||
msgctxt ""
|
||||
"@action:button 'Report' as in 'Report this space to the administrators'"
|
||||
msgid "Report…"
|
||||
msgstr "بلّغ…"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:90 src/spaces/SpaceHomePage.qml:114
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt "@title:dialog"
|
||||
#| msgid "Report User"
|
||||
#, kde-format
|
||||
msgctxt "@title:dialog"
|
||||
msgid "Report Space"
|
||||
msgstr "بلّغ عن المستخدم"
|
||||
msgstr "بلّغ عن فضاء"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:91 src/spaces/SpaceHomePage.qml:115
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt "@info:placeholder"
|
||||
#| msgid "Optionally give a reason for reporting this user"
|
||||
#, kde-format
|
||||
msgctxt "@info:placeholder"
|
||||
msgid "Optionally give a reason for reporting this space"
|
||||
msgstr "اختيارياً، أدخل سبب الإبلاغ عن هذا المستخدم"
|
||||
msgstr "اختيارياً، أدخل سبب الإبلاغ عن هذا الفضاء"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:93 src/spaces/SpaceHomePage.qml:117
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt ""
|
||||
#| "@action:button 'Report' as in 'Report this user to the administrators'"
|
||||
#| msgid "Report"
|
||||
#, kde-format
|
||||
msgctxt ""
|
||||
"@action:button 'Report' as in 'Report this space to the administrators'"
|
||||
msgid "Report"
|
||||
msgstr "بلّغ"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:97 src/spaces/SpaceHomePage.qml:121
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt "@title"
|
||||
#| msgid "Report User"
|
||||
#, kde-format
|
||||
msgctxt "@title"
|
||||
msgid "Report Space"
|
||||
msgstr "بلّغ عن المستخدم"
|
||||
msgstr "بلّغ عن فضاء"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:107
|
||||
#, kde-format
|
||||
|
||||
579
po/de/neochat.po
579
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgstr ""
|
||||
"Project-Id-Version: neochat\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2026-02-23 00:44+0000\n"
|
||||
"PO-Revision-Date: 2026-02-19 10:01+0200\n"
|
||||
"PO-Revision-Date: 2026-02-23 21:58+0200\n"
|
||||
"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>\n"
|
||||
"Language-Team: צוות התרגום של KDE ישראל\n"
|
||||
"Language: he\n"
|
||||
@@ -1179,15 +1179,13 @@ msgstr "יצירת קשר דרך דוא״ל (%1)"
|
||||
#, kde-format
|
||||
msgctxt "@title:window"
|
||||
msgid "Manage Key Storage"
|
||||
msgstr ""
|
||||
msgstr "ניהול אחסון מפתחות"
|
||||
|
||||
#: src/app/qml/UnlockSSSSDialog.qml:35
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt "@info:status"
|
||||
#| msgid "The security key or backup passphrase was not correct."
|
||||
#, kde-format
|
||||
msgctxt "@info:status"
|
||||
msgid "The recovery key was not correct."
|
||||
msgstr "מפתח האבטחה או ביטוי הצופן לגיבוי היו שגויים."
|
||||
msgstr "מפתח האבטחה היה שגוי."
|
||||
|
||||
#: src/app/qml/UnlockSSSSDialog.qml:41
|
||||
#, kde-format
|
||||
@@ -6174,7 +6172,7 @@ msgstr "כשהאפשרות הזאת פעילות, תמונות וסרטונים
|
||||
#, kde-format
|
||||
msgctxt "@info:label"
|
||||
msgid "Everyone"
|
||||
msgstr ""
|
||||
msgstr "כולם"
|
||||
|
||||
#: src/settings/NeoChatSecurityPage.qml:93
|
||||
#, fuzzy, kde-format
|
||||
@@ -6196,7 +6194,7 @@ msgstr "חסימת משתמשים"
|
||||
#, kde-format
|
||||
msgctxt "@info"
|
||||
msgid "Only users you share a room with can send you invites."
|
||||
msgstr ""
|
||||
msgstr "רק משתמשים שחולקים איתך חדר יכולים לשלוח לך הזמנות."
|
||||
|
||||
#: src/settings/NeoChatSecurityPage.qml:99
|
||||
#: src/settings/NeoChatSecurityPage.qml:112
|
||||
@@ -6209,13 +6207,13 @@ msgstr "השרת שלך לא תומך בהגדרה הזאת."
|
||||
#, kde-format
|
||||
msgctxt "@info:label"
|
||||
msgid "No one"
|
||||
msgstr ""
|
||||
msgstr "אף אחד"
|
||||
|
||||
#: src/settings/NeoChatSecurityPage.qml:112
|
||||
#, kde-format
|
||||
msgctxt "@info:description"
|
||||
msgid "No one can send you invites."
|
||||
msgstr ""
|
||||
msgstr "אף אחד לא יכול לשלוח לך הזמנות."
|
||||
|
||||
#: src/settings/NeoChatSecurityPage.qml:117
|
||||
#, kde-format
|
||||
@@ -6240,7 +6238,7 @@ msgstr "אם האפשרות פעילה, NeoChat ישתמש בהצפנה בעת
|
||||
#, kde-format
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Manage Key Storage"
|
||||
msgstr ""
|
||||
msgstr "ניהול אחסון מפתחות"
|
||||
|
||||
#: src/settings/NeoChatSecurityPage.qml:138
|
||||
#, kde-format
|
||||
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Project-Id-Version: neochat\n"
|
||||
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
|
||||
"POT-Creation-Date: 2026-02-23 00:44+0000\n"
|
||||
"PO-Revision-Date: 2026-02-21 12:21+0300\n"
|
||||
"PO-Revision-Date: 2026-02-23 08:01+0300\n"
|
||||
"Last-Translator: Emir SARI <emir_sari@icloud.com>\n"
|
||||
"Language-Team: Turkish <kde-l10n-tr@kde.org>\n"
|
||||
"Language: tr\n"
|
||||
@@ -4812,48 +4812,36 @@ msgid "Space Settings"
|
||||
msgstr "Alan Ayarları"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:85 src/spaces/SpaceHomePage.qml:109
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt ""
|
||||
#| "@action:button 'Report' as in 'Report this user to the administrators'"
|
||||
#| msgid "Report…"
|
||||
#, kde-format
|
||||
msgctxt ""
|
||||
"@action:button 'Report' as in 'Report this space to the administrators'"
|
||||
msgid "Report…"
|
||||
msgstr "Bildir…"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:90 src/spaces/SpaceHomePage.qml:114
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt "@title:dialog"
|
||||
#| msgid "Report User"
|
||||
#, kde-format
|
||||
msgctxt "@title:dialog"
|
||||
msgid "Report Space"
|
||||
msgstr "Kullanıcıyı Bildir"
|
||||
msgstr "Alanı Bildir"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:91 src/spaces/SpaceHomePage.qml:115
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt "@info:placeholder"
|
||||
#| msgid "Optionally give a reason for reporting this user"
|
||||
#, kde-format
|
||||
msgctxt "@info:placeholder"
|
||||
msgid "Optionally give a reason for reporting this space"
|
||||
msgstr "İsteğe bağlı olarak bu kullanıcıyı bildirme gerekçenizi verin"
|
||||
msgstr "İsteğe bağlı olarak bu alanı bildirme gerekçenizi verin"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:93 src/spaces/SpaceHomePage.qml:117
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt ""
|
||||
#| "@action:button 'Report' as in 'Report this user to the administrators'"
|
||||
#| msgid "Report"
|
||||
#, kde-format
|
||||
msgctxt ""
|
||||
"@action:button 'Report' as in 'Report this space to the administrators'"
|
||||
msgid "Report"
|
||||
msgstr "Bildir"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:97 src/spaces/SpaceHomePage.qml:121
|
||||
#, fuzzy, kde-format
|
||||
#| msgctxt "@title"
|
||||
#| msgid "Report User"
|
||||
#, kde-format
|
||||
msgctxt "@title"
|
||||
msgid "Report Space"
|
||||
msgstr "Kullanıcıyı Bildir"
|
||||
msgstr "Alanı Bildir"
|
||||
|
||||
#: src/rooms/SpaceListContextMenu.qml:107
|
||||
#, kde-format
|
||||
|
||||
@@ -32,6 +32,16 @@ void WindowController::setWindow(QWindow *window)
|
||||
{
|
||||
m_window = window;
|
||||
|
||||
if (window != nullptr) {
|
||||
// to restore maximized state after reopening from the system tray
|
||||
connect(m_window, &QWindow::windowStateChanged, this, [this]() {
|
||||
if (m_window->isVisible()) {
|
||||
m_wasMaximized = m_window->windowStates() & Qt::WindowMaximized;
|
||||
}
|
||||
});
|
||||
m_wasMaximized = m_window->windowStates() & Qt::WindowMaximized;
|
||||
}
|
||||
|
||||
Q_EMIT windowChanged();
|
||||
}
|
||||
|
||||
@@ -46,7 +56,11 @@ void WindowController::showAndRaiseWindow(const QString &startupId)
|
||||
return;
|
||||
}
|
||||
if (!m_window->isVisible()) {
|
||||
m_window->show();
|
||||
if (m_wasMaximized) {
|
||||
m_window->showMaximized();
|
||||
} else {
|
||||
m_window->show();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_WINDOWSYSTEM
|
||||
|
||||
@@ -67,5 +67,6 @@ Q_SIGNALS:
|
||||
private:
|
||||
WindowController() = default;
|
||||
|
||||
bool m_wasMaximized;
|
||||
QWindow *m_window = nullptr;
|
||||
};
|
||||
|
||||
@@ -78,41 +78,6 @@ Item {
|
||||
room: root.currentRoom
|
||||
maxAvailableWidth: chatBarSizeHelper.availableWidth
|
||||
}
|
||||
MouseArea {
|
||||
id: hoverArea
|
||||
anchors {
|
||||
top: chatModeButton.top
|
||||
left: root.left
|
||||
right: root.right
|
||||
bottom: core.top
|
||||
}
|
||||
propagateComposedEvents: true
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
QQC2.Button {
|
||||
id: chatModeButton
|
||||
anchors {
|
||||
bottom: core.top
|
||||
bottomMargin: Kirigami.Units.smallSpacing
|
||||
horizontalCenter: root.horizontalCenter
|
||||
}
|
||||
|
||||
visible: hoverArea.containsMouse || hovered || core.hovered
|
||||
width: Kirigami.Units.iconSizes.enormous
|
||||
height: Kirigami.Units.iconSizes.smallMedium
|
||||
|
||||
icon.name: NeoChatConfig.sendMessageWith === 0 ? "arrow-up" : "arrow-down"
|
||||
text: NeoChatConfig.sendMessageWith === 0 ? i18nc("@action:button", "Enter rich text mode") : i18nc("@action:button", "Exit rich text mode")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
|
||||
onClicked: NeoChatConfig.sendMessageWith = NeoChatConfig.sendMessageWith === 0 ? 1 : 0
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
QQC2.ToolTip.text: text
|
||||
}
|
||||
|
||||
LibNeoChat.DelegateSizeHelper {
|
||||
id: chatBarSizeHelper
|
||||
parentItem: root
|
||||
|
||||
@@ -27,11 +27,10 @@ QQC2.Control {
|
||||
type: root.chatBarType
|
||||
room: root.room
|
||||
sendMessageWithEnter: NeoChatConfig.sendMessageWith === 0
|
||||
sendTypingNotifications: NeoChatConfig.typingNotifications
|
||||
}
|
||||
|
||||
readonly property LibNeoChat.CompletionModel completionModel: LibNeoChat.CompletionModel {
|
||||
room: root.room
|
||||
type: root.chatBarType
|
||||
textItem: root.model.focusedTextItem
|
||||
roomListModel: RoomManager.roomListModel
|
||||
userListModel: RoomManager.userListModel
|
||||
@@ -72,6 +71,44 @@ QQC2.Control {
|
||||
visible: NeoChatConfig.sendMessageWith === 1
|
||||
}
|
||||
RowLayout {
|
||||
QQC2.ToolButton {
|
||||
id: emojiButton
|
||||
property EmojiDialog dialog
|
||||
|
||||
icon.name: "smiley"
|
||||
text: i18n("Emojis & Stickers")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
checked: dialog !== null
|
||||
|
||||
onClicked: {
|
||||
if(!checked){
|
||||
if(dialog) {
|
||||
dialog.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
dialog = Qt.createComponent('org.kde.neochat.chatbar', 'EmojiDialog').createObject(root, {
|
||||
modal: false,
|
||||
includeCustom: true,
|
||||
closeOnChosen: false,
|
||||
currentRoom: root.room,
|
||||
});
|
||||
dialog.y = -dialog.implicitHeight - Kirigami.Units.smallSpacing;
|
||||
dialog.onChosen.connect((emoji) => {
|
||||
root.chatButtonHelper.insertText(emoji);
|
||||
close();
|
||||
});
|
||||
dialog.onClosed.connect(() => {
|
||||
dialog = null;
|
||||
});
|
||||
dialog.open();
|
||||
}
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
QQC2.ToolTip.text: text
|
||||
}
|
||||
|
||||
QQC2.ScrollView {
|
||||
id: chatScrollView
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -230,21 +230,7 @@ RowLayout {
|
||||
}
|
||||
}
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
id: emojiButton
|
||||
visible: !Kirigami.Settings.isMobile
|
||||
icon.name: "smiley"
|
||||
text: i18n("Emojis & Stickers")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
|
||||
onClicked: {
|
||||
let dialog = (emojiDialog.createObject(root) as EmojiDialog).open();
|
||||
}
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
QQC2.ToolTip.text: text
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
id: linkButton
|
||||
enabled: root.chatButtonHelper.richFormatEnabled
|
||||
@@ -396,25 +382,4 @@ RowLayout {
|
||||
LinkDialog {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: emojiDialog
|
||||
EmojiDialog {
|
||||
x: root.width - width
|
||||
y: -implicitHeight
|
||||
|
||||
modal: false
|
||||
includeCustom: true
|
||||
closeOnChosen: false
|
||||
|
||||
currentRoom: root.room
|
||||
|
||||
onChosen: emoji => {
|
||||
root.chatButtonHelper.insertText(emoji);
|
||||
close();
|
||||
}
|
||||
onClosed: if (emojiButton.checked) {
|
||||
emojiButton.checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
import org.kde.neochat
|
||||
import org.kde.neochat.libneochat as LibNeoChat
|
||||
import org.kde.neochat.messagecontent as MessageContent
|
||||
|
||||
@@ -27,7 +28,7 @@ RowLayout {
|
||||
|
||||
required property real maxAvailableWidth
|
||||
|
||||
readonly property real overflowWidth: Kirigami.Units.gridUnit * 30
|
||||
readonly property real overflowWidth: Kirigami.Units.gridUnit * 50
|
||||
|
||||
function openLocationChooser(): void {
|
||||
Qt.createComponent('org.kde.neochat.chatbar', 'LocationChooser').createObject(QQC2.ApplicationWindow.overlay, {
|
||||
@@ -188,6 +189,20 @@ RowLayout {
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
QQC2.ToolTip.text: text
|
||||
}
|
||||
|
||||
QQC2.ToolButton {
|
||||
icon.name: "edit-select-text-symbolic"
|
||||
text: i18nc("@action:button", "Rich Text")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
checkable: true
|
||||
checked: NeoChatConfig.sendMessageWith === 1
|
||||
onClicked: NeoChatConfig.sendMessageWith = checked
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
QQC2.ToolTip.text: text
|
||||
}
|
||||
|
||||
QQC2.ToolButton {
|
||||
id: sendButton
|
||||
icon.name: "document-send"
|
||||
|
||||
@@ -9,6 +9,7 @@ target_sources(LibNeoChat PRIVATE
|
||||
neochatroommember.cpp
|
||||
accountmanager.cpp
|
||||
chatbarcache.cpp
|
||||
blockcache.cpp
|
||||
chatbarsyntaxhighlighter.cpp
|
||||
chatkeyhelper.cpp
|
||||
chatmarkdownhelper.cpp
|
||||
|
||||
92
src/libneochat/blockcache.cpp
Normal file
92
src/libneochat/blockcache.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// SPDX-FileCopyrightText: 2026 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "blockcache.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "chattextitemhelper.h"
|
||||
|
||||
using namespace Block;
|
||||
|
||||
inline QString formatQuote(const QString &input)
|
||||
{
|
||||
QString stringOut;
|
||||
auto splitString = input.split(u"\n\n"_s, Qt::SkipEmptyParts);
|
||||
for (auto &string : splitString) {
|
||||
if (string.startsWith(u'*')) {
|
||||
string.removeFirst();
|
||||
}
|
||||
if (string.startsWith(u'\"')) {
|
||||
string.removeFirst();
|
||||
}
|
||||
if (string.endsWith(u'*')) {
|
||||
string.removeLast();
|
||||
}
|
||||
if (string.endsWith(u'\"')) {
|
||||
string.removeLast();
|
||||
}
|
||||
if (!stringOut.isEmpty()) {
|
||||
stringOut += u"\n"_s;
|
||||
}
|
||||
stringOut += u"> "_s + string;
|
||||
}
|
||||
return stringOut;
|
||||
}
|
||||
|
||||
inline QString formatCode(const QString &input)
|
||||
{
|
||||
return u"```\n%1\n```"_s.arg(input).replace(u"\n\n"_s, u"\n"_s);
|
||||
}
|
||||
|
||||
inline QString trim(QString string)
|
||||
{
|
||||
while (string.startsWith(u"\n"_s)) {
|
||||
string.removeFirst();
|
||||
}
|
||||
while (string.endsWith(u"\n"_s)) {
|
||||
string.removeLast();
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
QString CacheItem::toString() const
|
||||
{
|
||||
auto newText = trim(content.toMarkdown(QTextDocument::MarkdownDialectGitHub));
|
||||
newText.replace(QRegularExpression(u"(?<!\n)\n(?!\n)"_s), u" "_s);
|
||||
if (type == MessageComponentType::Quote) {
|
||||
newText = formatQuote(newText);
|
||||
} else if (type == MessageComponentType::Code) {
|
||||
newText = formatCode(newText);
|
||||
}
|
||||
return newText;
|
||||
}
|
||||
|
||||
void Cache::fill(QList<MessageComponent> components)
|
||||
{
|
||||
std::ranges::for_each(components, [this](const MessageComponent &component) {
|
||||
if (!MessageComponentType::isTextType(component.type)) {
|
||||
return;
|
||||
}
|
||||
const auto textItem = component.attributes["chatTextItemHelper"_L1].value<ChatTextItemHelper *>();
|
||||
if (!textItem) {
|
||||
return;
|
||||
}
|
||||
append(CacheItem{
|
||||
.type = component.type,
|
||||
.content = textItem->toFragment(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
QString Cache::toString() const
|
||||
{
|
||||
QString text;
|
||||
std::ranges::for_each(constBegin(), constEnd(), [&text](const CacheItem &item) {
|
||||
if (!text.isEmpty()) {
|
||||
text += u"\n\n"_s;
|
||||
}
|
||||
text += item.toString();
|
||||
});
|
||||
return text;
|
||||
}
|
||||
63
src/libneochat/blockcache.h
Normal file
63
src/libneochat/blockcache.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// SPDX-FileCopyrightText: 2026 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QTextDocumentFragment>
|
||||
|
||||
#include "enums/messagecomponenttype.h"
|
||||
#include "messagecomponent.h"
|
||||
|
||||
namespace Block
|
||||
{
|
||||
/**
|
||||
* @struct CacheItem
|
||||
*
|
||||
* A structure to define an item stored in a Block::Cache.
|
||||
*
|
||||
* @sa Block::Cache
|
||||
*/
|
||||
struct CacheItem {
|
||||
MessageComponentType::Type type = MessageComponentType::Other;
|
||||
QTextDocumentFragment content;
|
||||
|
||||
/**
|
||||
* @brief Return the contents of the CacheItem as a single string.
|
||||
*/
|
||||
QString toString() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Cache
|
||||
*
|
||||
* A class to cache the contents of a ChatBarMessageContentModel.
|
||||
*
|
||||
* We can't store the actual content items as the QTextDocuments are attached to
|
||||
* text items that may be deleted by the QML engine. Instead we get the contents
|
||||
* as a QTextDocumentFragment in a Block::CacheItem which can be used to reconstruct the
|
||||
* model later.
|
||||
*
|
||||
* @sa ChatBarMessageContentModel, QTextDocumentFragment, QTextDocument, Block::CacheItem
|
||||
*/
|
||||
class Cache : private QList<CacheItem>
|
||||
{
|
||||
public:
|
||||
using QList<CacheItem>::constBegin, QList<CacheItem>::constEnd;
|
||||
using QList<CacheItem>::isEmpty;
|
||||
using QList<CacheItem>::clear;
|
||||
using QList<CacheItem>::append, QList<CacheItem>::operator+=, QList<CacheItem>::operator<<;
|
||||
|
||||
/**
|
||||
* @brief Fill the cache from a list of MessageComponents.
|
||||
*
|
||||
* @sa MessageComponent
|
||||
*/
|
||||
void fill(QList<MessageComponent> components);
|
||||
|
||||
/**
|
||||
* @brief Return the contents of the Cache as a single string.
|
||||
*/
|
||||
QString toString() const;
|
||||
};
|
||||
}
|
||||
@@ -33,49 +33,21 @@ ChatBarCache::ChatBarCache(QObject *parent)
|
||||
connect(this, &ChatBarCache::relationIdChanged, this, &ChatBarCache::relationAuthorIsPresentChanged);
|
||||
}
|
||||
|
||||
QString ChatBarCache::text() const
|
||||
Block::Cache &ChatBarCache::cache()
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
|
||||
void ChatBarCache::setText(const QString &text)
|
||||
{
|
||||
if (text == m_text) {
|
||||
return;
|
||||
}
|
||||
m_text = text;
|
||||
Q_EMIT textChanged();
|
||||
return m_cache;
|
||||
}
|
||||
|
||||
QString ChatBarCache::sendText() const
|
||||
{
|
||||
const auto cacheText = m_cache.toString();
|
||||
if (!attachmentPath().isEmpty()) {
|
||||
QUrl url(attachmentPath());
|
||||
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
||||
return text().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : text();
|
||||
return cacheText.isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : cacheText;
|
||||
}
|
||||
|
||||
return formatMentions();
|
||||
}
|
||||
|
||||
QString ChatBarCache::formatMentions() const
|
||||
{
|
||||
auto mentions = m_mentions;
|
||||
std::sort(mentions.begin(), mentions.end(), [](const auto &a, const auto &b) {
|
||||
return a.cursor.anchor() > b.cursor.anchor();
|
||||
});
|
||||
|
||||
auto formattedText = text();
|
||||
for (const auto &mention : mentions) {
|
||||
if (mention.text.isEmpty() || mention.id.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
formattedText = formattedText.replace(mention.cursor.anchor(),
|
||||
mention.cursor.position() - mention.cursor.anchor(),
|
||||
u"[%1](https://matrix.to/#/%2)"_s.arg(mention.text.toHtmlEscaped(), mention.id));
|
||||
}
|
||||
|
||||
return formattedText;
|
||||
return cacheText;
|
||||
}
|
||||
|
||||
bool ChatBarCache::isReplying() const
|
||||
@@ -232,11 +204,6 @@ void ChatBarCache::clearRelations()
|
||||
Q_EMIT attachmentPathChanged();
|
||||
}
|
||||
|
||||
QList<Mention> *ChatBarCache::mentions()
|
||||
{
|
||||
return &m_mentions;
|
||||
}
|
||||
|
||||
QString ChatBarCache::savedText() const
|
||||
{
|
||||
return m_savedText;
|
||||
@@ -287,14 +254,16 @@ void ChatBarCache::postMessage()
|
||||
|
||||
auto content = std::make_unique<Quotient::EventContent::TextContent>(sendText, u"text/html"_s);
|
||||
|
||||
room->post<Quotient::RoomMessageEvent>(text(), *std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result), std::move(content), relatesTo);
|
||||
room->post<Quotient::RoomMessageEvent>(m_cache.toString(),
|
||||
*std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result),
|
||||
std::move(content),
|
||||
relatesTo);
|
||||
clearCache();
|
||||
}
|
||||
|
||||
void ChatBarCache::clearCache()
|
||||
{
|
||||
setText({});
|
||||
m_mentions.clear();
|
||||
m_cache.clear();
|
||||
m_savedText = QString();
|
||||
clearRelations();
|
||||
}
|
||||
|
||||
@@ -8,22 +8,13 @@
|
||||
#include <QQuickTextDocument>
|
||||
#include <QTextCursor>
|
||||
|
||||
#include "blockcache.h"
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
class RoomMember;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Defines a user mention in the current chat or edit text.
|
||||
*/
|
||||
struct Mention {
|
||||
QTextCursor cursor; /**< Contains the mention's text and position in the text. */
|
||||
QString text; /**< The inserted text of the mention. */
|
||||
int start = 0; /**< Start position of the mention. */
|
||||
int position = 0; /**< End position of the mention. */
|
||||
QString id; /**< The id the mention (used to create link when sending the message). */
|
||||
};
|
||||
|
||||
/**
|
||||
* @class ChatBarCache
|
||||
*
|
||||
@@ -48,14 +39,6 @@ class ChatBarCache : public QObject
|
||||
QML_ELEMENT
|
||||
QML_UNCREATABLE("")
|
||||
|
||||
/**
|
||||
* @brief The text in the chat bar.
|
||||
*
|
||||
* Due to problems with QTextDocument, unlike the other properties here,
|
||||
* text is *not* used to store the text when switching rooms.
|
||||
*/
|
||||
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether the chat bar is currently replying to a message.
|
||||
*/
|
||||
@@ -147,9 +130,8 @@ public:
|
||||
|
||||
explicit ChatBarCache(QObject *parent = nullptr);
|
||||
|
||||
QString text() const;
|
||||
Block::Cache &cache();
|
||||
QString sendText() const;
|
||||
void setText(const QString &text);
|
||||
|
||||
bool isReplying() const;
|
||||
QString replyId() const;
|
||||
@@ -178,11 +160,6 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE void clearRelations();
|
||||
|
||||
/**
|
||||
* @brief Retrieve the mentions for the current chat bar text.
|
||||
*/
|
||||
QList<Mention> *mentions();
|
||||
|
||||
/**
|
||||
* @brief Get the saved chat bar text.
|
||||
*/
|
||||
@@ -201,7 +178,6 @@ public:
|
||||
Q_INVOKABLE void drop(QList<QUrl> urls, const QString &transferPortal);
|
||||
|
||||
Q_SIGNALS:
|
||||
void textChanged();
|
||||
void relationIdChanged(const QString &oldEventId, const QString &newEventId);
|
||||
void threadIdChanged(const QString &oldThreadId, const QString &newThreadId);
|
||||
void attachmentPathChanged();
|
||||
@@ -209,14 +185,12 @@ Q_SIGNALS:
|
||||
void relationAuthorIsPresentChanged();
|
||||
|
||||
private:
|
||||
QString m_text = QString();
|
||||
QString formatMentions() const;
|
||||
Block::Cache m_cache;
|
||||
|
||||
QString m_relationId = QString();
|
||||
RelationType m_relationType = RelationType::None;
|
||||
QString m_threadId = QString();
|
||||
QString m_attachmentPath = QString();
|
||||
QList<Mention> m_mentions;
|
||||
QString m_savedText;
|
||||
|
||||
void clearCache();
|
||||
|
||||
@@ -4,22 +4,16 @@
|
||||
|
||||
#include "chatbarsyntaxhighlighter.h"
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "chattextitemhelper.h"
|
||||
#include "enums/chatbartype.h"
|
||||
|
||||
ChatBarSyntaxHighlighter::ChatBarSyntaxHighlighter(QObject *parent)
|
||||
: QSyntaxHighlighter(parent)
|
||||
{
|
||||
m_theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
||||
connect(m_theme, &Kirigami::Platform::PlatformTheme::colorsChanged, this, [this]() {
|
||||
m_mentionFormat.setForeground(m_theme->linkColor());
|
||||
m_errorFormat.setForeground(m_theme->negativeTextColor());
|
||||
});
|
||||
|
||||
m_mentionFormat.setFontWeight(QFont::Bold);
|
||||
m_mentionFormat.setForeground(m_theme->linkColor());
|
||||
|
||||
m_errorFormat.setForeground(m_theme->negativeTextColor());
|
||||
m_errorFormat.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
|
||||
|
||||
@@ -48,36 +42,4 @@ void ChatBarSyntaxHighlighter::highlightBlock(const QString &text)
|
||||
setFormat(error.first, error.second.size(), m_errorFormat);
|
||||
}
|
||||
}
|
||||
|
||||
if (!room || type == ChatBarType::None) {
|
||||
return;
|
||||
}
|
||||
auto mentions = room->cacheForType(type)->mentions();
|
||||
mentions->erase(std::remove_if(mentions->begin(),
|
||||
mentions->end(),
|
||||
[this](auto &mention) {
|
||||
if (document()->toPlainText().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mention.cursor.position() == 0 && mention.cursor.anchor() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mention.cursor.position() - mention.cursor.anchor() != mention.text.size()) {
|
||||
mention.cursor.setPosition(mention.start);
|
||||
mention.cursor.setPosition(mention.cursor.anchor() + mention.text.size(), QTextCursor::KeepAnchor);
|
||||
}
|
||||
|
||||
if (mention.cursor.selectedText() != mention.text) {
|
||||
return true;
|
||||
}
|
||||
if (currentBlock() == mention.cursor.block()) {
|
||||
mention.start = mention.cursor.anchor();
|
||||
mention.position = mention.cursor.position();
|
||||
setFormat(mention.cursor.selectionStart(), mention.cursor.selectedText().size(), m_mentionFormat);
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
mentions->end());
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ public:
|
||||
|
||||
private:
|
||||
Kirigami::Platform::PlatformTheme *m_theme = nullptr;
|
||||
QTextCharFormat m_mentionFormat;
|
||||
QTextCharFormat m_errorFormat;
|
||||
|
||||
Sonnet::BackgroundChecker *m_checker = new Sonnet::BackgroundChecker(this);
|
||||
|
||||
@@ -7,12 +7,34 @@
|
||||
#include "clipboard.h"
|
||||
#include "neochatroom.h"
|
||||
#include "richformat.h"
|
||||
#include <qtextcursor.h>
|
||||
|
||||
ChatKeyHelper::ChatKeyHelper(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ChatTextItemHelper *ChatKeyHelper::textItem() const
|
||||
{
|
||||
return m_textItem;
|
||||
}
|
||||
|
||||
void ChatKeyHelper::setTextItem(ChatTextItemHelper *textItem)
|
||||
{
|
||||
if (textItem == m_textItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_textItem) {
|
||||
m_textItem->disconnect(this);
|
||||
}
|
||||
m_textItem = textItem;
|
||||
if (m_textItem) {
|
||||
connect(m_textItem, &ChatTextItemHelper::contentsChange, this, &ChatKeyHelper::checkLinkFormat);
|
||||
connect(m_textItem, &ChatTextItemHelper::selectedTextChanged, this, &ChatKeyHelper::checkMouseSelection);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::handleKey(Qt::Key key, Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
switch (key) {
|
||||
@@ -22,6 +44,10 @@ bool ChatKeyHelper::handleKey(Qt::Key key, Qt::KeyboardModifiers modifiers)
|
||||
return up(modifiers);
|
||||
case Qt::Key_Down:
|
||||
return down();
|
||||
case Qt::Key_Left:
|
||||
return left(modifiers);
|
||||
case Qt::Key_Right:
|
||||
return right(modifiers);
|
||||
case Qt::Key_Tab:
|
||||
return tab();
|
||||
case Qt::Key_Delete:
|
||||
@@ -41,10 +67,6 @@ bool ChatKeyHelper::handleKey(Qt::Key key, Qt::KeyboardModifiers modifiers)
|
||||
|
||||
bool ChatKeyHelper::vKey(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (!textItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (modifiers.testFlag(Qt::ControlModifier)) {
|
||||
return pasteImage();
|
||||
}
|
||||
@@ -53,12 +75,12 @@ bool ChatKeyHelper::vKey(Qt::KeyboardModifiers modifiers)
|
||||
|
||||
bool ChatKeyHelper::up(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (!textItem) {
|
||||
if (!m_textItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (modifiers.testFlag(Qt::ControlModifier)) {
|
||||
const auto room = textItem->room();
|
||||
const auto room = m_textItem->room();
|
||||
if (!room) {
|
||||
return false;
|
||||
}
|
||||
@@ -66,12 +88,12 @@ bool ChatKeyHelper::up(Qt::KeyboardModifiers modifiers)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (textItem->isCompleting) {
|
||||
if (m_textItem->isCompleting) {
|
||||
Q_EMIT unhandledUp(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return false;
|
||||
}
|
||||
@@ -84,15 +106,15 @@ bool ChatKeyHelper::up(Qt::KeyboardModifiers modifiers)
|
||||
|
||||
bool ChatKeyHelper::down()
|
||||
{
|
||||
if (!textItem) {
|
||||
if (!m_textItem) {
|
||||
return false;
|
||||
}
|
||||
if (textItem->isCompleting) {
|
||||
if (m_textItem->isCompleting) {
|
||||
Q_EMIT unhandledDown(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return false;
|
||||
}
|
||||
@@ -104,22 +126,54 @@ bool ChatKeyHelper::down()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::tab()
|
||||
bool ChatKeyHelper::left(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (!textItem) {
|
||||
if (!m_textItem) {
|
||||
return false;
|
||||
}
|
||||
if (textItem->isCompleting) {
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return false;
|
||||
}
|
||||
bool ctrlLeft = nextWordLeft(cursor, modifiers);
|
||||
if (ctrlLeft) {
|
||||
return true;
|
||||
}
|
||||
return selectLeft(cursor, modifiers);
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::right(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (!m_textItem) {
|
||||
return false;
|
||||
}
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return false;
|
||||
}
|
||||
bool ctrlRight = nextWordRight(cursor, modifiers);
|
||||
if (ctrlRight) {
|
||||
return true;
|
||||
}
|
||||
return selectRight(cursor, modifiers);
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::tab()
|
||||
{
|
||||
if (!m_textItem) {
|
||||
return false;
|
||||
}
|
||||
if (m_textItem->isCompleting) {
|
||||
Q_EMIT unhandledTab(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return false;
|
||||
}
|
||||
if (cursor.currentList() && textItem->canIndentListMoreAtCursor()) {
|
||||
textItem->indentListMoreAtCursor();
|
||||
if (cursor.currentList() && m_textItem->canIndentListMoreAtCursor()) {
|
||||
m_textItem->indentListMoreAtCursor();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -127,45 +181,45 @@ bool ChatKeyHelper::tab()
|
||||
|
||||
bool ChatKeyHelper::deleteChar()
|
||||
{
|
||||
if (!textItem) {
|
||||
if (!m_textItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull() || cursor.hasSelection()) {
|
||||
return false;
|
||||
}
|
||||
if (cursor.position() >= textItem->document()->characterCount() - textItem->fixedEndChars().length() - 1) {
|
||||
if (cursor.position() >= m_textItem->document()->characterCount() - m_textItem->fixedEndChars().length() - 1) {
|
||||
Q_EMIT unhandledDelete();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return selectRight(cursor);
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::backspace()
|
||||
{
|
||||
if (!textItem) {
|
||||
if (!m_textItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return false;
|
||||
}
|
||||
if (cursor.position() <= textItem->fixedStartChars().length()) {
|
||||
if (cursor.currentList() && textItem->canIndentListLessAtCursor()) {
|
||||
textItem->indentListLessAtCursor();
|
||||
if (cursor.position() <= m_textItem->fixedStartChars().length()) {
|
||||
if (cursor.currentList() && m_textItem->canIndentListLessAtCursor()) {
|
||||
m_textItem->indentListLessAtCursor();
|
||||
return true;
|
||||
}
|
||||
Q_EMIT unhandledBackspace();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return selectLeft(cursor);
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::insertReturn(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (!textItem) {
|
||||
if (!m_textItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -175,7 +229,7 @@ bool ChatKeyHelper::insertReturn(Qt::KeyboardModifiers modifiers)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!shiftPressed && textItem->isCompleting) {
|
||||
if (!shiftPressed && m_textItem->isCompleting) {
|
||||
Q_EMIT unhandledReturn(true);
|
||||
return true;
|
||||
}
|
||||
@@ -185,7 +239,7 @@ bool ChatKeyHelper::insertReturn(Qt::KeyboardModifiers modifiers)
|
||||
return true;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return false;
|
||||
}
|
||||
@@ -205,10 +259,10 @@ bool ChatKeyHelper::insertReturn(Qt::KeyboardModifiers modifiers)
|
||||
|
||||
bool ChatKeyHelper::cancel()
|
||||
{
|
||||
if (!textItem) {
|
||||
if (!m_textItem) {
|
||||
return false;
|
||||
}
|
||||
if (textItem->isCompleting) {
|
||||
if (m_textItem->isCompleting) {
|
||||
Q_EMIT closeCompletion();
|
||||
return true;
|
||||
}
|
||||
@@ -217,7 +271,7 @@ bool ChatKeyHelper::cancel()
|
||||
|
||||
bool ChatKeyHelper::pasteImage()
|
||||
{
|
||||
if (!textItem) {
|
||||
if (!m_textItem) {
|
||||
return false;
|
||||
}
|
||||
const auto savePath = Clipboard().saveImage();
|
||||
@@ -227,4 +281,182 @@ bool ChatKeyHelper::pasteImage()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::selectLeft(QTextCursor &cursor, Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if ((cursor.hasSelection() || !cursor.charFormat().isAnchor()) && !modifiers.testFlag(Qt::ShiftModifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to rearrange the selection from right to left.
|
||||
const auto selectionStart = cursor.selectionStart();
|
||||
cursor.setPosition(cursor.selectionEnd());
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, cursor.position() - selectionStart);
|
||||
|
||||
if (!cursor.charFormat().isAnchor()) {
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
|
||||
m_textItem->setSelection(cursor.selectionEnd(), cursor.selectionStart());
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto hRef = cursor.charFormat().anchorHref();
|
||||
auto currentCharFormat = cursor.charFormat();
|
||||
while (currentCharFormat.isAnchor() && currentCharFormat.anchorHref() == hRef && cursor.position() > 0) {
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
|
||||
currentCharFormat = cursor.charFormat();
|
||||
}
|
||||
|
||||
m_textItem->setSelection(cursor.selectionEnd(), cursor.selectionStart());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::selectRight(QTextCursor &cursor, Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if ((cursor.hasSelection() && !modifiers.testFlag(Qt::ShiftModifier)) || cursor.atBlockEnd()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
||||
if (!cursor.charFormat().isAnchor()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto hRef = cursor.charFormat().anchorHref();
|
||||
auto currentCharFormat = cursor.charFormat();
|
||||
while (currentCharFormat.isAnchor() && currentCharFormat.anchorHref() == hRef && cursor.position() < cursor.block().length() - 1) {
|
||||
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
||||
currentCharFormat = cursor.charFormat();
|
||||
}
|
||||
if (!currentCharFormat.isAnchor()) {
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
|
||||
}
|
||||
|
||||
m_textItem->setSelection(cursor.selectionStart(), cursor.selectionEnd());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::nextWordLeft(QTextCursor &cursor, Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (!modifiers.testFlag(Qt::ControlModifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
|
||||
// Cross any whitespace.
|
||||
while (cursor.selectedText() == u' ') {
|
||||
cursor.setPosition(cursor.selectionStart());
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
|
||||
}
|
||||
if (!cursor.charFormat().isAnchor()) {
|
||||
return false;
|
||||
}
|
||||
// Cross link.
|
||||
while (cursor.charFormat().isAnchor()) {
|
||||
cursor.setPosition(cursor.selectionStart());
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
|
||||
}
|
||||
|
||||
m_textItem->setCursorPosition(cursor.selectionStart());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::nextWordRight(QTextCursor &cursor, Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (!modifiers.testFlag(Qt::ControlModifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
||||
// Cross any whitespace.
|
||||
while (cursor.selectedText() == u' ') {
|
||||
cursor.setPosition(cursor.selectionEnd());
|
||||
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
||||
}
|
||||
if (!cursor.charFormat().isAnchor()) {
|
||||
return false;
|
||||
}
|
||||
// Cross link.
|
||||
while (cursor.charFormat().isAnchor()) {
|
||||
cursor.setPosition(cursor.selectionEnd());
|
||||
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
||||
}
|
||||
m_textItem->setCursorPosition(cursor.selectionEnd());
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChatKeyHelper::checkMouseSelection()
|
||||
{
|
||||
if (!m_textItem) {
|
||||
return;
|
||||
}
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
}
|
||||
if (!cursor.hasSelection()) {
|
||||
return;
|
||||
}
|
||||
bool selectingLink = false;
|
||||
cursor.beginEditBlock();
|
||||
cursor.setPosition(m_textItem->selectionStart());
|
||||
if (cursor.charFormat().isAnchor()) {
|
||||
selectingLink = true;
|
||||
}
|
||||
if (!selectingLink) {
|
||||
cursor.movePosition(QTextCursor::NextCharacter);
|
||||
if (cursor.charFormat().isAnchor()) {
|
||||
selectingLink = true;
|
||||
}
|
||||
}
|
||||
if (!selectingLink) {
|
||||
cursor.setPosition(m_textItem->selectionEnd());
|
||||
if (cursor.charFormat().isAnchor()) {
|
||||
selectingLink = true;
|
||||
}
|
||||
}
|
||||
if (!selectingLink) {
|
||||
return;
|
||||
}
|
||||
// Wind all the way to the left of the link.
|
||||
cursor.setPosition(m_textItem->selectionStart());
|
||||
const auto hRef = cursor.charFormat().anchorHref();
|
||||
auto currentCharFormat = cursor.charFormat();
|
||||
while (currentCharFormat.isAnchor() && currentCharFormat.anchorHref() == hRef && cursor.position() > 0) {
|
||||
cursor.movePosition(QTextCursor::PreviousCharacter);
|
||||
currentCharFormat = cursor.charFormat();
|
||||
}
|
||||
cursor.endEditBlock();
|
||||
selectRight(cursor);
|
||||
}
|
||||
|
||||
void ChatKeyHelper::checkLinkFormat(int position, int charsRemoved, int charsAdded)
|
||||
{
|
||||
if (!m_textItem || charsRemoved > charsAdded || charsAdded - charsRemoved != 1) {
|
||||
return;
|
||||
}
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool nextToLink = false;
|
||||
cursor.setPosition(position);
|
||||
if (cursor.charFormat().isAnchor()) {
|
||||
nextToLink = true;
|
||||
}
|
||||
// Note 2 because a cursor on the left of a link will not show it in the format.
|
||||
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, 2);
|
||||
if (cursor.charFormat().isAnchor()) {
|
||||
nextToLink = true;
|
||||
}
|
||||
if (!nextToLink) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.beginEditBlock();
|
||||
cursor.setPosition(position);
|
||||
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
||||
cursor.setCharFormat({});
|
||||
cursor.endEditBlock();
|
||||
}
|
||||
|
||||
#include "moc_chatkeyhelper.cpp"
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
|
||||
class QTextCursor;
|
||||
|
||||
class ChatTextItemHelper;
|
||||
|
||||
/**
|
||||
@@ -30,7 +32,14 @@ public:
|
||||
*
|
||||
* @sa ChatTextItemHelper
|
||||
*/
|
||||
QPointer<ChatTextItemHelper> textItem;
|
||||
ChatTextItemHelper *textItem() const;
|
||||
|
||||
/**
|
||||
* @brief Set the ChatTextItemHelper that ChatKeyHelper is handling key presses for.
|
||||
*
|
||||
* @sa ChatTextItemHelper
|
||||
*/
|
||||
void setTextItem(ChatTextItemHelper *textItem);
|
||||
|
||||
/**
|
||||
* @brief handle the given key and modifiers.
|
||||
@@ -113,12 +122,18 @@ Q_SIGNALS:
|
||||
void imagePasted(const QString &filePath);
|
||||
|
||||
private:
|
||||
QPointer<ChatTextItemHelper> m_textItem;
|
||||
|
||||
bool vKey(Qt::KeyboardModifiers modifiers);
|
||||
|
||||
bool up(Qt::KeyboardModifiers modifiers);
|
||||
|
||||
bool down();
|
||||
|
||||
bool left(Qt::KeyboardModifiers modifiers);
|
||||
|
||||
bool right(Qt::KeyboardModifiers modifiers);
|
||||
|
||||
bool tab();
|
||||
|
||||
bool deleteChar();
|
||||
@@ -130,4 +145,16 @@ private:
|
||||
bool cancel();
|
||||
|
||||
bool pasteImage();
|
||||
|
||||
bool selectLeft(QTextCursor &cursor, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
|
||||
|
||||
bool selectRight(QTextCursor &cursor, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
|
||||
|
||||
bool nextWordLeft(QTextCursor &cursor, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
|
||||
|
||||
bool nextWordRight(QTextCursor &cursor, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
|
||||
|
||||
void checkMouseSelection();
|
||||
|
||||
void checkLinkFormat(int position, int charsRemoved, int charsAdded);
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <QQuickTextDocument>
|
||||
#include <QTextCursor>
|
||||
#include <QTextDocumentFragment>
|
||||
|
||||
#include <Kirigami/Platform/PlatformTheme>
|
||||
#include <qtextdocument.h>
|
||||
@@ -83,6 +82,7 @@ void ChatTextItemHelper::setTextItem(QQuickItem *textItem)
|
||||
|
||||
if (m_textItem) {
|
||||
connect(m_textItem, SIGNAL(cursorPositionChanged()), this, SLOT(itemCursorPositionChanged()));
|
||||
connect(m_textItem, SIGNAL(selectedTextChanged()), this, SLOT(itemSelectedTextChanged()));
|
||||
connect(m_textItem, SIGNAL(textFormatChanged(QQuickTextEdit::TextFormat)), this, SLOT(itemTextFormatChanged()));
|
||||
if (const auto doc = document()) {
|
||||
connect(doc, &QTextDocument::contentsChanged, this, &ChatTextItemHelper::contentsChanged);
|
||||
@@ -92,7 +92,7 @@ void ChatTextItemHelper::setTextItem(QQuickItem *textItem)
|
||||
connect(doc, &QTextDocument::contentsChange, this, &ChatTextItemHelper::contentsChange);
|
||||
m_highlighter->setDocument(doc);
|
||||
}
|
||||
initializeChars();
|
||||
initialize();
|
||||
}
|
||||
|
||||
Q_EMIT textItemChanged();
|
||||
@@ -133,24 +133,21 @@ void ChatTextItemHelper::setFixedChars(const QString &startChars, const QString
|
||||
}
|
||||
m_fixedStartChars = startChars;
|
||||
m_fixedEndChars = endChars;
|
||||
initializeChars();
|
||||
initialize();
|
||||
}
|
||||
|
||||
QString ChatTextItemHelper::initialText() const
|
||||
QTextDocumentFragment ChatTextItemHelper::initialFragment() const
|
||||
{
|
||||
return m_initialText;
|
||||
return m_initialFragment;
|
||||
}
|
||||
|
||||
void ChatTextItemHelper::setInitialText(const QString &text)
|
||||
void ChatTextItemHelper::setInitialFragment(const QTextDocumentFragment &fragment)
|
||||
{
|
||||
if (text == m_initialText) {
|
||||
return;
|
||||
}
|
||||
m_initialText = text;
|
||||
initializeChars();
|
||||
m_initialFragment = fragment;
|
||||
initialize();
|
||||
}
|
||||
|
||||
void ChatTextItemHelper::initializeChars()
|
||||
void ChatTextItemHelper::initialize()
|
||||
{
|
||||
const auto doc = document();
|
||||
if (!doc) {
|
||||
@@ -166,8 +163,8 @@ void ChatTextItemHelper::initializeChars()
|
||||
|
||||
cursor.beginEditBlock();
|
||||
int finalCursorPos = cursor.position();
|
||||
if (doc->isEmpty() && !m_initialText.isEmpty()) {
|
||||
cursor.insertText(m_initialText);
|
||||
if (doc->isEmpty() && !m_initialFragment.isEmpty()) {
|
||||
cursor.insertFragment(m_initialFragment);
|
||||
finalCursorPos = cursor.position();
|
||||
}
|
||||
|
||||
@@ -391,6 +388,15 @@ void ChatTextItemHelper::setCursorPosition(int pos)
|
||||
m_textItem->setProperty("cursorPosition", pos);
|
||||
}
|
||||
|
||||
void ChatTextItemHelper::setSelection(int selectionStart, int selectionEnd)
|
||||
{
|
||||
if (!m_textItem) {
|
||||
return;
|
||||
}
|
||||
m_selectionJustChanged = true;
|
||||
metaObject()->invokeMethod(m_textItem, "select", Qt::DirectConnection, selectionStart, selectionEnd);
|
||||
}
|
||||
|
||||
void ChatTextItemHelper::setCursorVisible(bool visible)
|
||||
{
|
||||
if (!m_textItem) {
|
||||
@@ -444,6 +450,15 @@ void ChatTextItemHelper::itemCursorPositionChanged()
|
||||
Q_EMIT listChanged();
|
||||
}
|
||||
|
||||
void ChatTextItemHelper::itemSelectedTextChanged()
|
||||
{
|
||||
if (m_selectionJustChanged) {
|
||||
m_selectionJustChanged = false;
|
||||
return;
|
||||
}
|
||||
Q_EMIT selectedTextChanged();
|
||||
}
|
||||
|
||||
void ChatTextItemHelper::mergeFormatOnCursor(RichFormat::Format format, QTextCursor cursor)
|
||||
{
|
||||
if (cursor.isNull()) {
|
||||
@@ -618,6 +633,16 @@ QString ChatTextItemHelper::plainText() const
|
||||
return trim(doc->toPlainText());
|
||||
}
|
||||
|
||||
QTextDocumentFragment ChatTextItemHelper::toFragment() const
|
||||
{
|
||||
auto cursor = textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return {};
|
||||
}
|
||||
cursor.select(QTextCursor::Document);
|
||||
return cursor.selection();
|
||||
}
|
||||
|
||||
QString ChatTextItemHelper::trim(QString string) const
|
||||
{
|
||||
while (string.startsWith(u"\n"_s)) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QQuickItem>
|
||||
#include <QTextDocumentFragment>
|
||||
|
||||
#include "enums/chatbartype.h"
|
||||
#include "enums/richformat.h"
|
||||
@@ -108,16 +109,16 @@ public:
|
||||
void setFixedChars(const QString &startChars, const QString &endChars);
|
||||
|
||||
/**
|
||||
* @brief Any text to initialise the text item with when set.
|
||||
* @brief Any QTextDocumentFragment to initialise the text item with when set.
|
||||
*/
|
||||
QString initialText() const;
|
||||
QTextDocumentFragment initialFragment() const;
|
||||
|
||||
/**
|
||||
* @brief Set the text to initialise the text item with when set.
|
||||
* @brief Set the QTextDocumentFragment to initialise the text item with when set.
|
||||
*
|
||||
* This text will only be set if the text item is empty when set.
|
||||
*/
|
||||
void setInitialText(const QString &text);
|
||||
void setInitialFragment(const QTextDocumentFragment &fragment);
|
||||
|
||||
/**
|
||||
* @brief The underlying QTextDocument.
|
||||
@@ -181,11 +182,26 @@ public:
|
||||
*/
|
||||
QRect cursorRectangle() const;
|
||||
|
||||
/**
|
||||
* @brief The start position of any text selection in the underlying text item.
|
||||
*/
|
||||
int selectionStart() const;
|
||||
|
||||
/**
|
||||
* @brief The end position of any text selection in the underlying text item.
|
||||
*/
|
||||
int selectionEnd() const;
|
||||
|
||||
/**
|
||||
* @brief Set the cursor position of the underlying text item to the given value.
|
||||
*/
|
||||
void setCursorPosition(int pos);
|
||||
|
||||
/**
|
||||
* @brief Set the selection of the underlying text item to the given cursor.
|
||||
*/
|
||||
void setSelection(int selectionStart, int selectionEnd);
|
||||
|
||||
/**
|
||||
* @brief Set the cursor visibility of the underlying text item to the given value.
|
||||
*/
|
||||
@@ -248,6 +264,11 @@ public:
|
||||
*/
|
||||
QString plainText() const;
|
||||
|
||||
/**
|
||||
* @brief Output the text in the text item as a QTextDocumentFragment.
|
||||
*/
|
||||
QTextDocumentFragment toFragment() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief Emitted when the NeoChatRoom used by the syntax highlighter is changed.
|
||||
@@ -301,23 +322,26 @@ Q_SIGNALS:
|
||||
*/
|
||||
void cursorPositionChanged(bool fromContentsChange);
|
||||
|
||||
/**
|
||||
* @brief Emitted when the selected text of the underlying text item is changed.
|
||||
*/
|
||||
void selectedTextChanged();
|
||||
|
||||
private:
|
||||
QPointer<QQuickItem> m_textItem;
|
||||
QPointer<ChatBarSyntaxHighlighter> m_highlighter;
|
||||
|
||||
bool m_contentsJustChanged = false;
|
||||
bool m_selectionJustChanged = false;
|
||||
|
||||
QString m_fixedStartChars = {};
|
||||
QString m_fixedEndChars = {};
|
||||
QString m_initialText = {};
|
||||
void initializeChars();
|
||||
QTextDocumentFragment m_initialFragment = {};
|
||||
void initialize();
|
||||
bool m_initializingChars = false;
|
||||
|
||||
std::optional<int> lineLength(int lineNumber) const;
|
||||
|
||||
int selectionStart() const;
|
||||
int selectionEnd() const;
|
||||
|
||||
void mergeTextFormatOnCursor(RichFormat::Format format, QTextCursor cursor);
|
||||
void mergeStyleFormatOnCursor(RichFormat::Format format, QTextCursor cursor);
|
||||
void mergeListFormatOnCursor(RichFormat::Format format, const QTextCursor &cursor);
|
||||
@@ -328,4 +352,5 @@ private:
|
||||
private Q_SLOTS:
|
||||
void itemTextFormatChanged();
|
||||
void itemCursorPositionChanged();
|
||||
void itemSelectedTextChanged();
|
||||
};
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <QDebug>
|
||||
#include <QTextCursor>
|
||||
|
||||
#include <Kirigami/Platform/PlatformTheme>
|
||||
|
||||
#include "chattextitemhelper.h"
|
||||
#include "completionproxymodel.h"
|
||||
#include "models/actionsmodel.h"
|
||||
@@ -24,35 +26,6 @@ CompletionModel::CompletionModel(QObject *parent)
|
||||
m_emojiModel->addSourceModel(&EmojiModel::instance());
|
||||
}
|
||||
|
||||
NeoChatRoom *CompletionModel::room() const
|
||||
{
|
||||
return m_room;
|
||||
}
|
||||
|
||||
void CompletionModel::setRoom(NeoChatRoom *room)
|
||||
{
|
||||
if (m_room == room) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_room = room;
|
||||
Q_EMIT roomChanged();
|
||||
}
|
||||
|
||||
ChatBarType::Type CompletionModel::type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void CompletionModel::setType(ChatBarType::Type type)
|
||||
{
|
||||
if (type == m_type) {
|
||||
return;
|
||||
}
|
||||
m_type = type;
|
||||
Q_EMIT typeChanged();
|
||||
}
|
||||
|
||||
ChatTextItemHelper *CompletionModel::textItem() const
|
||||
{
|
||||
return m_textItem;
|
||||
@@ -322,29 +295,22 @@ void CompletionModel::insertCompletion(const QString &text, const QUrl &link)
|
||||
}
|
||||
cursor.removeSelectedText();
|
||||
|
||||
const int start = cursor.position();
|
||||
const auto insertString = u"%1 %2"_s.arg(text, link.isEmpty() ? QString() : u" "_s);
|
||||
cursor.insertText(insertString);
|
||||
cursor.setPosition(start);
|
||||
cursor.setPosition(start + text.size(), QTextCursor::KeepAnchor);
|
||||
cursor.setKeepPositionOnInsert(true);
|
||||
cursor.endEditBlock();
|
||||
if (!link.isEmpty()) {
|
||||
pushMention({
|
||||
.cursor = cursor,
|
||||
.text = text,
|
||||
.id = link.toString(),
|
||||
});
|
||||
const auto previousFormat = cursor.charFormat();
|
||||
auto charFormat = previousFormat;
|
||||
if (link.isValid()) {
|
||||
const auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
||||
charFormat = QTextCharFormat();
|
||||
charFormat.setForeground(theme->linkColor());
|
||||
charFormat.setFontWeight(QFont::Bold);
|
||||
charFormat.setAnchor(true);
|
||||
charFormat.setAnchorHref(link.toString());
|
||||
}
|
||||
cursor.insertText(text, charFormat);
|
||||
if (!link.isEmpty()) {
|
||||
cursor.insertText(u" "_s, previousFormat);
|
||||
}
|
||||
cursor.endEditBlock();
|
||||
m_textItem->rehighlight();
|
||||
}
|
||||
|
||||
void CompletionModel::pushMention(const Mention mention) const
|
||||
{
|
||||
if (!m_room || m_type == ChatBarType::None) {
|
||||
return;
|
||||
}
|
||||
m_room->cacheForType(m_type)->mentions()->push_back(mention);
|
||||
}
|
||||
|
||||
#include "moc_completionmodel.cpp"
|
||||
|
||||
@@ -30,16 +30,6 @@ class CompletionModel : public QAbstractListModel
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
/**
|
||||
* @brief The current room that the text document is being handled for.
|
||||
*/
|
||||
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
|
||||
|
||||
/**
|
||||
* @brief The ChatBarType::Type of the chat bar.
|
||||
*/
|
||||
Q_PROPERTY(ChatBarType::Type type READ type WRITE setType NOTIFY typeChanged)
|
||||
|
||||
/**
|
||||
* @brief The QML text Item that completions are being provided for.
|
||||
*/
|
||||
@@ -94,12 +84,6 @@ public:
|
||||
|
||||
explicit CompletionModel(QObject *parent = nullptr);
|
||||
|
||||
NeoChatRoom *room() const;
|
||||
void setRoom(NeoChatRoom *room);
|
||||
|
||||
ChatBarType::Type type() const;
|
||||
void setType(ChatBarType::Type type);
|
||||
|
||||
ChatTextItemHelper *textItem() const;
|
||||
void setTextItem(ChatTextItemHelper *textItem);
|
||||
|
||||
@@ -140,8 +124,6 @@ public:
|
||||
Q_INVOKABLE void insertCompletion(const QString &text, const QUrl &link);
|
||||
|
||||
Q_SIGNALS:
|
||||
void roomChanged();
|
||||
void typeChanged();
|
||||
void textItemChanged();
|
||||
void autoCompletionTypeChanged();
|
||||
void roomListModelChanged();
|
||||
@@ -149,8 +131,6 @@ Q_SIGNALS:
|
||||
void isCompletingChanged();
|
||||
|
||||
private:
|
||||
QPointer<NeoChatRoom> m_room;
|
||||
ChatBarType::Type m_type = ChatBarType::None;
|
||||
QPointer<ChatTextItemHelper> m_textItem;
|
||||
|
||||
bool m_ignoreCurrentCompletion = false;
|
||||
@@ -165,6 +145,4 @@ private:
|
||||
UserListModel *m_userListModel;
|
||||
RoomListModel *m_roomListModel;
|
||||
QConcatenateTablesProxyModel *m_emojiModel;
|
||||
|
||||
void pushMention(const Mention mention) const;
|
||||
};
|
||||
|
||||
@@ -57,122 +57,163 @@ Item {
|
||||
property int rightAnchorMargin: 0
|
||||
|
||||
Layout.fillWidth: true
|
||||
implicitWidth: mediaSizeHelper.currentSize.width
|
||||
implicitHeight: mediaSizeHelper.currentSize.height
|
||||
implicitWidth: container.implicitWidth
|
||||
implicitHeight: container.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
anchors.top: root.top
|
||||
anchors.topMargin: Kirigami.Units.smallSpacing
|
||||
anchors.right: root.right
|
||||
anchors.rightMargin: root.rightAnchorMargin + Kirigami.Units.smallSpacing
|
||||
Item {
|
||||
id: container
|
||||
implicitWidth: mediaSizeHelper.currentSize.width
|
||||
implicitHeight: mediaSizeHelper.currentSize.height
|
||||
|
||||
z: 10
|
||||
RowLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Kirigami.Units.smallSpacing
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: root.rightAnchorMargin + Kirigami.Units.smallSpacing
|
||||
|
||||
QQC2.Button {
|
||||
visible: !_private.hideImage && !root.editable
|
||||
icon.name: "view-hidden"
|
||||
text: i18nc("@action:button", "Hide Image")
|
||||
display: QQC2.Button.IconOnly
|
||||
z: 10
|
||||
onClicked: {
|
||||
_private.hideImage = true;
|
||||
Controller.markImageHidden(root.eventId)
|
||||
|
||||
QQC2.Button {
|
||||
visible: !_private.hideImage && !root.editable
|
||||
icon.name: "view-hidden"
|
||||
text: i18nc("@action:button", "Hide Image")
|
||||
display: QQC2.Button.IconOnly
|
||||
z: 10
|
||||
onClicked: {
|
||||
_private.hideImage = true;
|
||||
Controller.markImageHidden(root.eventId)
|
||||
}
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
QQC2.Button {
|
||||
id: editImageButton
|
||||
visible: root.editable
|
||||
icon.name: "document-edit"
|
||||
text: i18n("Edit")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
|
||||
Component {
|
||||
id: imageEditorPage
|
||||
ImageEditorPage {
|
||||
imagePath: root.componentAttributes.source
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
let imageEditor = (Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(imageEditorPage);
|
||||
imageEditor.newPathChanged.connect(function (newPath) {
|
||||
imageEditor.closeDialog();
|
||||
Message.contentModel?.addAttachment(newPath);
|
||||
});
|
||||
}
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
}
|
||||
QQC2.Button {
|
||||
id: cancelButton
|
||||
visible: root.editable
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
text: i18nc("@action:button", "Remove attachment")
|
||||
icon.name: "dialog-close"
|
||||
onClicked: root.Message.contentModel?.removeAttachment()
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
||||
visible: (_private.imageItem?.status !== Image.Ready ?? true) || _private.hideImage
|
||||
|
||||
color: "#BB000000"
|
||||
|
||||
QQC2.ProgressBar {
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: parent.width * 0.8
|
||||
visible: !_private.hideImage
|
||||
|
||||
from: 0
|
||||
to: 1.0
|
||||
value: _private.imageItem?.progress ?? 0.0
|
||||
}
|
||||
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: root?.componentAttributes.tempInfo?.source ?? ""
|
||||
}
|
||||
}
|
||||
QQC2.Button {
|
||||
id: editImageButton
|
||||
visible: root.editable
|
||||
icon.name: "document-edit"
|
||||
text: i18n("Edit")
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
|
||||
Component {
|
||||
id: imageEditorPage
|
||||
ImageEditorPage {
|
||||
imagePath: root.componentAttributes.source
|
||||
Loader {
|
||||
id: imageLoader
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
|
||||
active: !root.componentAttributes.animated && !_private.hideImage
|
||||
sourceComponent: Image {
|
||||
source: root.componentAttributes.source
|
||||
sourceSize.width: mediaSizeHelper.currentSize.width * Screen.devicePixelRatio
|
||||
sourceSize.height: mediaSizeHelper.currentSize.height * Screen.devicePixelRatio
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
autoTransform: true
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: animatedImageLoader
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
|
||||
active: (root?.componentAttributes.animated ?? false) && !_private.hideImage
|
||||
sourceComponent: AnimatedImage {
|
||||
source: root.componentAttributes.source
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
autoTransform: true
|
||||
|
||||
paused: !QQC2.ApplicationWindow.window.active
|
||||
}
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
}
|
||||
|
||||
QQC2.Button {
|
||||
anchors.centerIn: parent
|
||||
text: i18nc("@action:button", "Show Image")
|
||||
visible: _private.hideImage
|
||||
onClicked: {
|
||||
_private.hideImage = false;
|
||||
Controller.markImageShown(root.eventId);
|
||||
}
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds | TapHandler.WithinBounds
|
||||
onTapped: {
|
||||
root.QQC2.ToolTip.hide();
|
||||
if (root.componentAttributes.animated) {
|
||||
_private.imageItem.paused = true;
|
||||
}
|
||||
if (root.Message.timeline) {
|
||||
root.Message.timeline.interactive = false;
|
||||
}
|
||||
if (!root.componentAttributes.isSticker && !root.editable && !_private.hideImage) {
|
||||
RoomManager.maximizeMedia(root.eventId);
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
let imageEditor = (Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(imageEditorPage);
|
||||
imageEditor.newPathChanged.connect(function (newPath) {
|
||||
imageEditor.closeDialog();
|
||||
Message.contentModel?.addAttachment(newPath);
|
||||
});
|
||||
}
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
}
|
||||
QQC2.Button {
|
||||
id: cancelButton
|
||||
visible: root.editable
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
text: i18nc("@action:button", "Remove attachment")
|
||||
icon.name: "dialog-close"
|
||||
onClicked: root.Message.contentModel?.removeAttachment()
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
||||
visible: (_private.imageItem?.status !== Image.Ready ?? true) || _private.hideImage
|
||||
|
||||
color: "#BB000000"
|
||||
|
||||
QQC2.ProgressBar {
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: parent.width * 0.8
|
||||
visible: !_private.hideImage
|
||||
|
||||
from: 0
|
||||
to: 1.0
|
||||
value: _private.imageItem?.progress ?? 0.0
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: root?.componentAttributes.tempInfo?.source ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: imageLoader
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
active: !root.componentAttributes.animated && !_private.hideImage
|
||||
sourceComponent: Image {
|
||||
source: root.componentAttributes.source
|
||||
sourceSize.width: mediaSizeHelper.currentSize.width * Screen.devicePixelRatio
|
||||
sourceSize.height: mediaSizeHelper.currentSize.height * Screen.devicePixelRatio
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
autoTransform: true
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: animatedImageLoader
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
active: (root?.componentAttributes.animated ?? false) && !_private.hideImage
|
||||
sourceComponent: AnimatedImage {
|
||||
source: root.componentAttributes.source
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
autoTransform: true
|
||||
|
||||
paused: !QQC2.ApplicationWindow.window.active
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,36 +221,7 @@ Item {
|
||||
QQC2.ToolTip.visible: hoverHandler.hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
}
|
||||
|
||||
QQC2.Button {
|
||||
anchors.centerIn: parent
|
||||
text: i18nc("@action:button", "Show Image")
|
||||
visible: _private.hideImage
|
||||
onClicked: {
|
||||
_private.hideImage = false;
|
||||
Controller.markImageShown(root.eventId);
|
||||
}
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds | TapHandler.WithinBounds
|
||||
onTapped: {
|
||||
root.QQC2.ToolTip.hide();
|
||||
if (root.componentAttributes.animated) {
|
||||
_private.imageItem.paused = true;
|
||||
}
|
||||
if (root.Message.timeline) {
|
||||
root.Message.timeline.interactive = false;
|
||||
}
|
||||
if (!root.componentAttributes.isSticker && !root.editable && !_private.hideImage) {
|
||||
RoomManager.maximizeMedia(root.eventId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function downloadAndOpen() {
|
||||
if (_private.downloaded) {
|
||||
|
||||
@@ -73,7 +73,7 @@ QQC2.TextArea {
|
||||
*/
|
||||
property bool isReply: false
|
||||
|
||||
Layout.fillWidth: NeoChatConfig.compactLayout
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: Message.maxContentWidth
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "chatbarmessagecontentmodel.h"
|
||||
|
||||
#include <QTextDocumentFragment>
|
||||
#include <QTimer>
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "chatkeyhelper.h"
|
||||
@@ -24,9 +25,13 @@ ChatBarMessageContentModel::ChatBarMessageContentModel(QObject *parent)
|
||||
: MessageContentModel(parent)
|
||||
, m_markdownHelper(new ChatMarkdownHelper(this))
|
||||
, m_keyHelper(new ChatKeyHelper(this))
|
||||
, m_typingTimer(new QTimer(this))
|
||||
{
|
||||
m_editableActive = true;
|
||||
|
||||
m_typingTimer->setInterval(std::chrono::milliseconds(5000));
|
||||
m_typingTimer->setSingleShot(true);
|
||||
|
||||
connect(this, &ChatBarMessageContentModel::roomChanged, this, [this](NeoChatRoom *oldRoom) {
|
||||
if (m_type == ChatBarType::None || !m_room) {
|
||||
return;
|
||||
@@ -38,7 +43,7 @@ ChatBarMessageContentModel::ChatBarMessageContentModel(QObject *parent)
|
||||
});
|
||||
connect(this, &ChatBarMessageContentModel::focusRowChanged, this, [this]() {
|
||||
m_markdownHelper->setTextItem(focusedTextItem());
|
||||
m_keyHelper->textItem = focusedTextItem();
|
||||
m_keyHelper->setTextItem(focusedTextItem());
|
||||
});
|
||||
connect(this, &ChatBarMessageContentModel::roomChanged, this, [this]() {
|
||||
for (const auto &component : m_components) {
|
||||
@@ -104,7 +109,7 @@ void ChatBarMessageContentModel::initializeModel(const QString &initialText)
|
||||
const auto textItem = new ChatTextItemHelper(this);
|
||||
textItem->setRoom(m_room);
|
||||
textItem->setType(m_type);
|
||||
textItem->setInitialText(initialText);
|
||||
textItem->setInitialFragment(QTextDocumentFragment::fromPlainText(initialText));
|
||||
connectTextItem(textItem);
|
||||
m_components += MessageComponent{
|
||||
.type = MessageComponentType::Text,
|
||||
@@ -125,25 +130,17 @@ void ChatBarMessageContentModel::initializeFromCache()
|
||||
|
||||
clearModel();
|
||||
|
||||
const auto currentCache = m_room->cacheForType(m_type);
|
||||
const auto textSections = (m_type == ChatBarType::Room ? currentCache->text() : currentCache->relationMessage()).split(u"\n\n"_s);
|
||||
if (textSections.length() == 1 && textSections[0].isEmpty()) {
|
||||
const auto ¤tCache = m_room->cacheForType(m_type);
|
||||
const auto &blockCache = currentCache->cache();
|
||||
if (blockCache.isEmpty()) {
|
||||
initializeModel();
|
||||
return;
|
||||
}
|
||||
|
||||
beginResetModel();
|
||||
for (const auto §ion : textSections) {
|
||||
const auto type = MessageComponentType::typeForString(section);
|
||||
auto cleanText = section;
|
||||
if (type == MessageComponentType::Code) {
|
||||
cleanText.remove(0, 4);
|
||||
cleanText.remove(cleanText.length() - 4, 4);
|
||||
} else if (type == MessageComponentType::Quote) {
|
||||
cleanText.remove(0, 2);
|
||||
}
|
||||
insertComponent(rowCount(), type, {}, cleanText);
|
||||
}
|
||||
std::ranges::for_each(blockCache.constBegin(), blockCache.constEnd(), [this](const Block::CacheItem &cacheItem) {
|
||||
insertComponent(rowCount(), cacheItem.type, {}, cacheItem.content);
|
||||
});
|
||||
endResetModel();
|
||||
|
||||
if (currentCache->attachmentPath().length() > 0) {
|
||||
@@ -306,6 +303,7 @@ void ChatBarMessageContentModel::connectTextItem(ChatTextItemHelper *chattextite
|
||||
removeComponent(helper);
|
||||
});
|
||||
connect(chattextitemhelper, &ChatTextItemHelper::contentsChanged, this, &ChatBarMessageContentModel::hasAnyContentChanged);
|
||||
connect(chattextitemhelper, &ChatTextItemHelper::contentsChanged, this, &ChatBarMessageContentModel::handleTyping);
|
||||
}
|
||||
|
||||
ChatTextItemHelper *ChatBarMessageContentModel::textItemForComponent(const MessageComponent &component) const
|
||||
@@ -390,7 +388,7 @@ void ChatBarMessageContentModel::addAttachment(const QUrl &path)
|
||||
}
|
||||
|
||||
ChatBarMessageContentModel::ComponentIt
|
||||
ChatBarMessageContentModel::insertComponent(int row, MessageComponentType::Type type, QVariantMap attributes, const QString &intialText)
|
||||
ChatBarMessageContentModel::insertComponent(int row, MessageComponentType::Type type, QVariantMap attributes, const QTextDocumentFragment &intialFragment)
|
||||
{
|
||||
if (row < 0 || row > rowCount()) {
|
||||
return m_components.end();
|
||||
@@ -398,7 +396,7 @@ ChatBarMessageContentModel::insertComponent(int row, MessageComponentType::Type
|
||||
|
||||
if (MessageComponentType::isTextType(type)) {
|
||||
const auto textItemWrapper = new ChatTextItemHelper(this);
|
||||
textItemWrapper->setInitialText(intialText);
|
||||
textItemWrapper->setInitialFragment(intialFragment);
|
||||
textItemWrapper->setRoom(m_room);
|
||||
textItemWrapper->setType(m_type);
|
||||
if (type == MessageComponentType::Quote) {
|
||||
@@ -523,6 +521,15 @@ void ChatBarMessageContentModel::setSendMessageWithEnter(bool sendMessageWithEnt
|
||||
Q_EMIT sendMessageWithEnterChanged();
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::setSendTypingNotifications(bool sendTypingNotifications)
|
||||
{
|
||||
m_sendTypingNotifications = sendTypingNotifications;
|
||||
if (!m_sendTypingNotifications && m_typingTimer->isActive()) {
|
||||
m_typingTimer->stop();
|
||||
m_room->sendTypingNotification(false);
|
||||
}
|
||||
}
|
||||
|
||||
ChatBarMessageContentModel::ComponentIt ChatBarMessageContentModel::removeComponent(ComponentIt it)
|
||||
{
|
||||
if (it == m_components.end()) {
|
||||
@@ -600,60 +607,8 @@ void ChatBarMessageContentModel::updateCache() const
|
||||
return;
|
||||
}
|
||||
|
||||
m_room->cacheForType(m_type)->setText(messageText());
|
||||
}
|
||||
|
||||
inline QString formatQuote(const QString &input)
|
||||
{
|
||||
QString stringOut;
|
||||
auto splitString = input.split(u"\n\n"_s, Qt::SkipEmptyParts);
|
||||
for (auto &string : splitString) {
|
||||
if (string.startsWith(u'*')) {
|
||||
string.removeFirst();
|
||||
}
|
||||
if (string.startsWith(u'\"')) {
|
||||
string.removeFirst();
|
||||
}
|
||||
if (string.endsWith(u'*')) {
|
||||
string.removeLast();
|
||||
}
|
||||
if (string.endsWith(u'\"')) {
|
||||
string.removeLast();
|
||||
}
|
||||
if (!stringOut.isEmpty()) {
|
||||
stringOut += u"\n"_s;
|
||||
}
|
||||
stringOut += u"> "_s + string;
|
||||
}
|
||||
return stringOut;
|
||||
}
|
||||
|
||||
inline QString formatCode(const QString &input)
|
||||
{
|
||||
return u"```\n%1\n```"_s.arg(input).replace(u"\n\n"_s, u"\n"_s);
|
||||
}
|
||||
|
||||
QString ChatBarMessageContentModel::messageText() const
|
||||
{
|
||||
QString text;
|
||||
for (const auto &component : m_components) {
|
||||
if (MessageComponentType::isTextType(component.type)) {
|
||||
if (const auto textItem = textItemForComponent(component)) {
|
||||
auto newText = textItem->markdownText();
|
||||
newText.replace(QRegularExpression(u"(?<!\n)\n(?!\n)"_s), u" "_s);
|
||||
if (component.type == MessageComponentType::Quote) {
|
||||
newText = formatQuote(newText);
|
||||
} else if (component.type == MessageComponentType::Code) {
|
||||
newText = formatCode(newText);
|
||||
}
|
||||
if (!text.isEmpty()) {
|
||||
text += u"\n\n"_s;
|
||||
}
|
||||
text += newText;
|
||||
}
|
||||
}
|
||||
}
|
||||
return text;
|
||||
m_room->cacheForType(m_type)->cache().clear();
|
||||
m_room->cacheForType(m_type)->cache().fill(m_components);
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::postMessage()
|
||||
@@ -718,4 +673,19 @@ void ChatBarMessageContentModel::clearModel()
|
||||
}
|
||||
}
|
||||
|
||||
void ChatBarMessageContentModel::handleTyping()
|
||||
{
|
||||
if (m_type == ChatBarType::None || !m_room || !m_sendTypingNotifications) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_typingTimer->isActive() && hasAnyContent()) {
|
||||
m_typingTimer->start();
|
||||
m_room->sendTypingNotification(true);
|
||||
} else if (m_typingTimer->isActive() && !hasAnyContent()) {
|
||||
m_typingTimer->stop();
|
||||
m_room->sendTypingNotification(false);
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_chatbarmessagecontentmodel.cpp"
|
||||
|
||||
@@ -82,6 +82,11 @@ class ChatBarMessageContentModel : public MessageContentModel
|
||||
*/
|
||||
Q_PROPERTY(bool hasAnyContent READ hasAnyContent NOTIFY hasAnyContentChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether to send typing notifications to the server when the content changes.
|
||||
*/
|
||||
Q_PROPERTY(bool sendTypingNotifications WRITE setSendTypingNotifications)
|
||||
|
||||
public:
|
||||
explicit ChatBarMessageContentModel(QObject *parent = nullptr);
|
||||
|
||||
@@ -109,6 +114,8 @@ public:
|
||||
bool sendMessageWithEnter() const;
|
||||
void setSendMessageWithEnter(bool sendMessageWithEnter);
|
||||
|
||||
void setSendTypingNotifications(bool sendTypingNotifications);
|
||||
|
||||
Q_INVOKABLE void postMessage();
|
||||
|
||||
bool hasAnyContent() const;
|
||||
@@ -143,16 +150,19 @@ private:
|
||||
QPointer<ChatKeyHelper> m_keyHelper;
|
||||
void connectKeyHelper();
|
||||
|
||||
ComponentIt insertComponent(int row, MessageComponentType::Type type, QVariantMap attributes = {}, const QString &intialText = {});
|
||||
ComponentIt insertComponent(int row, MessageComponentType::Type type, QVariantMap attributes = {}, const QTextDocumentFragment &intialFragment = {});
|
||||
ComponentIt removeComponent(ComponentIt it);
|
||||
void removeComponent(ChatTextItemHelper *textItem);
|
||||
|
||||
void handleBlockTransition(bool up);
|
||||
|
||||
void updateCache() const;
|
||||
QString messageText() const;
|
||||
|
||||
bool m_sendMessageWithEnter = true;
|
||||
bool m_sendTypingNotifications = false;
|
||||
|
||||
void clearModel();
|
||||
|
||||
QTimer *m_typingTimer;
|
||||
void handleTyping();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user