From 1985f29bbd10ce45ea2acee1558faa94a61171dd Mon Sep 17 00:00:00 2001 From: user11 Date: Mon, 9 Sep 2024 12:53:13 +0000 Subject: [PATCH 01/60] Added translation using Weblate (Serbian) --- src/quicksy/res/values-sr/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/quicksy/res/values-sr/strings.xml diff --git a/src/quicksy/res/values-sr/strings.xml b/src/quicksy/res/values-sr/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6b3daec9354f9ae75cdf8d94a67446c6227dd96 --- /dev/null +++ b/src/quicksy/res/values-sr/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 5012c7d21d467ac437f9d46d0d82a5c3fdfb32ab Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 12 Sep 2024 15:35:31 +0200 Subject: [PATCH 02/60] exclude all OnePlus devices instead of just individual devices --- .../services/CallIntegration.java | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/CallIntegration.java b/src/main/java/eu/siacs/conversations/services/CallIntegration.java index adf03d0b7279d097ac76a54a9fb8dbecfa98b652..99fda67df321874e7f9f48a8efa0e3b66bed19b7 100644 --- a/src/main/java/eu/siacs/conversations/services/CallIntegration.java +++ b/src/main/java/eu/siacs/conversations/services/CallIntegration.java @@ -16,6 +16,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -30,6 +31,7 @@ import eu.siacs.conversations.xmpp.jingle.Media; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -37,17 +39,28 @@ import java.util.concurrent.atomic.AtomicBoolean; public class CallIntegration extends Connection { /** - * OnePlus 6 (Android 8.1-11) Device is buggy and always starts the OS call screen even though - * we want to be self managed - * - *

Samsung Galaxy Tab A claims to have FEATURE_CONNECTION_SERVICE but then throws + * Samsung Galaxy Tab A claims to have FEATURE_CONNECTION_SERVICE but then throws * SecurityException when invoking placeCall(). Both Stock and LineageOS have this problem. * *

Lenovo Yoga Smart Tab YT-X705F claims to have FEATURE_CONNECTION_SERVICE but throws * SecurityException */ private static final List BROKEN_DEVICE_MODELS = - Arrays.asList("OnePlus6", "gtaxlwifi", "YT-X705F"); + Arrays.asList("gtaxlwifi", "a5y17lte", "YT-X705F"); + + /** + * all Realme devices at least up to and including Android 11 are broken + * + *

we are relatively sure that old Oppo devices are broken too. We get reports of 'number not + * sent' from Oppo R15x (Android 10) + * + *

OnePlus 6 (Android 8.1-11) Device is buggy and always starts the OS call screen even + * though we want to be self managed + * + *

a bunch of OnePlus devices are broken in other ways + */ + private static final List BROKEN_MANUFACTURES_UP_TO_11 = + Arrays.asList("realme", "oppo", "oneplus"); public static final int DEFAULT_TONE_VOLUME = 60; private static final int DEFAULT_MEDIA_PLAYER_VOLUME = 90; @@ -529,25 +542,18 @@ public class CallIntegration extends Connection { } private static boolean isDeviceModelSupported() { + final var manufacturer = Strings.nullToEmpty(Build.MANUFACTURER).toLowerCase(Locale.ROOT); if (BROKEN_DEVICE_MODELS.contains(Build.DEVICE)) { return false; } - // all Realme devices at least up to and including Android 11 are broken - if ("realme".equalsIgnoreCase(Build.MANUFACTURER) - && Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { - return false; - } - // we are relatively sure that old Oppo devices are broken too. We get reports of 'number - // not sent' from Oppo R15x (Android 10) - if ("OPPO".equalsIgnoreCase(Build.MANUFACTURER) + if (BROKEN_MANUFACTURES_UP_TO_11.contains(manufacturer) && Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { return false; } // we only know of one Umidigi device (BISON_GT2_5G) that doesn't work (audio is not being // routed properly) However with those devices being extremely rare it's impossible to gauge // how many might be effected and no Naomi Wu around to clarify with the company directly - if ("umidigi".equalsIgnoreCase(Build.MANUFACTURER) - && Build.VERSION.SDK_INT <= Build.VERSION_CODES.S) { + if ("umidigi".equals(manufacturer) && Build.VERSION.SDK_INT <= Build.VERSION_CODES.S) { return false; } return true; From fcd6f7c18ac67a0dfc6dc6fab77e7e63cea4e75e Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 21 Sep 2024 13:08:15 +0200 Subject: [PATCH 03/60] initialize emoji compat in application --- .../services/EmojiInitializationService.java | 21 +++++++++++++++++-- .../eu/siacs/conversations/Conversations.java | 2 ++ .../siacs/conversations/ui/XmppActivity.java | 3 --- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/free/java/eu/siacs/conversations/services/EmojiInitializationService.java b/src/free/java/eu/siacs/conversations/services/EmojiInitializationService.java index 2618d380964a0b075dc17c7c99fcf20fb30fb5b3..aae5e64094970c7aace6fa99b6a049c3c7b0ba33 100644 --- a/src/free/java/eu/siacs/conversations/services/EmojiInitializationService.java +++ b/src/free/java/eu/siacs/conversations/services/EmojiInitializationService.java @@ -1,14 +1,31 @@ package eu.siacs.conversations.services; import android.content.Context; +import android.util.Log; +import androidx.annotation.Nullable; import androidx.emoji2.bundled.BundledEmojiCompatConfig; import androidx.emoji2.text.EmojiCompat; +import eu.siacs.conversations.Config; + public class EmojiInitializationService { public static void execute(final Context context) { - EmojiCompat.init(new BundledEmojiCompatConfig(context).setReplaceAll(true)); - } + EmojiCompat.init(new BundledEmojiCompatConfig(context).setReplaceAll(true)) + .registerInitCallback( + new EmojiCompat.InitCallback() { + @Override + public void onInitialized() { + Log.d(Config.LOGTAG, "initialized EmojiCompat"); + super.onInitialized(); + } + @Override + public void onFailed(@Nullable Throwable throwable) { + Log.e(Config.LOGTAG, "failed to initialize EmojiCompat", throwable); + super.onFailed(throwable); + } + }); + } } diff --git a/src/main/java/eu/siacs/conversations/Conversations.java b/src/main/java/eu/siacs/conversations/Conversations.java index 72ed0a72b9ec618d8c779ec9485dcdc2567e0843..f52937dce434a52b7135674f14cb0d628f2dbf1b 100644 --- a/src/main/java/eu/siacs/conversations/Conversations.java +++ b/src/main/java/eu/siacs/conversations/Conversations.java @@ -11,6 +11,7 @@ import androidx.appcompat.app.AppCompatDelegate; import com.google.android.material.color.DynamicColors; import com.google.android.material.color.DynamicColorsOptions; +import eu.siacs.conversations.services.EmojiInitializationService; import eu.siacs.conversations.utils.ExceptionHelper; public class Conversations extends Application { @@ -26,6 +27,7 @@ public class Conversations extends Application { public void onCreate() { super.onCreate(); CONTEXT = this.getApplicationContext(); + EmojiInitializationService.execute(getApplicationContext()); ExceptionHelper.init(getApplicationContext()); applyThemeSettings(); } diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 45c2259f4fd8f38848858a2b4faab90ad3e8c088..c4d6dc4df0ab25b1196be337c0a6ec5dbae1d856 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -16,7 +16,6 @@ import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Point; @@ -68,7 +67,6 @@ import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.BarcodeProvider; -import eu.siacs.conversations.services.EmojiInitializationService; import eu.siacs.conversations.services.QuickConversationsService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder; @@ -485,7 +483,6 @@ public abstract class XmppActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); metrics = getResources().getDisplayMetrics(); - EmojiInitializationService.execute(this); this.isCameraFeatureAvailable = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY); } From f944c9aad09abcd53d89b43d5faa699631d2161c Mon Sep 17 00:00:00 2001 From: user11 Date: Fri, 13 Sep 2024 17:33:30 +0000 Subject: [PATCH 04/60] Translated using Weblate (Serbian) Currently translated at 100.0% (1039 of 1039 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/sr/ --- src/main/res/values-sr/strings.xml | 1075 ++++++++++++++++++++-------- 1 file changed, 767 insertions(+), 308 deletions(-) diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml index 5c9d59b34ded26d6d17817e246da0e5dcd6f9ebd..e943409f41715470d8049f48d7555c1d19b98831 100644 --- a/src/main/res/values-sr/strings.xml +++ b/src/main/res/values-sr/strings.xml @@ -1,13 +1,13 @@ - Поставке - Управљај налозима - Управљај налогом + Подешавања + Подеси налоге + Подеси налог Детаљи контакта - Детаљи групног ћаскања + Детаљи групне преписке Детаљи канала Додај налог - Уреди име + Измени Додај у именик Обриши са списка контаката Блокирај контакт @@ -16,8 +16,8 @@ Одблокирај домен Блокирај учесника Одблокирај учесника - Управљање налозима - Поставке + Подешавање налога + Подешавања Изабери контакт Изабери контакте Подели преко налога @@ -31,8 +31,8 @@ %d непрочитаних порука шаљем… - Дешифрујем поруку, сачекајте… - ОпенПГП шифрована порука + Дешифрујем поруку. Сачекај… + OpenPGP шифрована порука Надимак је већ у употреби Неисправан надимак Администратор @@ -40,9 +40,9 @@ Модератор Учесник Посетилац - Да ли желите да уклоните %s са вашег списка контаката? Преписке са овим контактом неће бити уклоњене. - Желите ли да блокирате поруке од %s? - Желите ли да одблокирате %s и допустите им да вам шаљу поруке? + Желиш да уклониш %s са твог списка контаката? Преписка са овим контактом неће бити уклоњена. + Желиш да блокираш поруке од %s? + Желиш да одблокираш %s и да дозволиш да ти шаље поруке? Блокирати све контакте од %s? Одблокирати све контакте од %s? Контакт блокиран @@ -63,133 +63,142 @@ Одблокирај Сачувај У реду - %1$s је принудно заустављен - Слањем извештаја рада путем вашег ИксМПП налога помажете даљем развоју %1$s. + %1$s је неочекивано заустављен + Слањем извештаја о грешкама путем свог XMPP налога помажеш даљем развоју %1$s апликације. Пошаљи одмах Не питај више - Не могу да се повежем са налогом - Не могу да се повежем са више налога - Тапните овде да бисте управљали вашим налозима - Приложи фајл - Контакт није на вашем списку контаката. Желите ли да га додате? + Није могуће повезати се са налогом + Није могуће повезати се са више налога + Притисни овде да подесиш своје налоге + Накачи фајл + Додај овај контакт који није на твом списку контаката? Додај контакт испорука није успела - Припремам слику за пренос - Припремам слике за пренос - Делим фајлове, сачекајте… - Очисти историјат - Брисање историјата преписки - Желите ли да обришете све поруке из ове преписке? + Припремам слику за слање + Припремам слике за слање + Делим фајлове. Сачекај… + Обриши историјат + Обриши историју преписке + Желиш да обришеш све поруке из ове преписке? \n -\nУпозорење: Ово неће утицати на поруке складиштене на осталим уређајима или серверима. - Обриши датотеку - Желите ли да обришете ову датотеку?\n\nУпозорење: Ово неће утицати на копије ове датотеке складиштене на осталим уређајима или серверима. - Изаберите уређај +\nУпозорење: Ово неће утицати на поруке смештене на осталим уређајима или серверима. + Обриши фајл + Да ли си сигуран/на да желиш да обришеш овај фајл? +\n +\nУпозорење: Ово неће утицати на копије овог фајла смештене на осталим уређајима или серверима. + Изабери уређај Пошаљи нешифровану поруку Пошаљи поруку - Пошаљи поруку за %s + Пошаљи поруку ка %s Пошаљи v\\ОМЕМО шифровану поруку Нови надимак је у употреби Пошаљи нешифровано - Шифровање није успело. Можда немате одговарајући лични кључ. - Отворени кључарник + Дешифровање није успело. Можда немаш одговарајући приватни кључ. + OpenKeychain Поново покрени Инсталирај - Инсталирајте Отворени кључарник + Инсталирај OpenKeychain нудим… чекам… - Нема ОпенПГП кључа - Није могуће шифровати вашу поруку јер контакт није објавио свој јавни кључ.\n\nЗамолите контакт да подеси ОпенПГП. - Нема ОпенПГП кључева - Није могуће шифровати вашу поруку јер контакти нису објавили своје јавне кључеве.\n\nЗамолите контакте да подесе ОпенПГП. + Није пронађен OpenPGP кључ + Није могуће шифровати твоју поруку јер контакт није објавио свој јавни кључ. +\n +\nЗамоли контакт да подеси OpenPGP. + Нису пронађени OpenPGP кључеви + Није могуће шифровати твоју поруку јер контакти нису објавили своје јавне кључеве. +\n +\nЗамоли контакте да подесе OpenPGP. Опште - Прихватај фајлове + Прихватање фајлова Аутоматски прихватај фајлове мање од… - Прилози + Накачени фајлови Обавештење - Вибрирај - Вибрирање кад стигне нова порука - ЛЕД светло - Трептање ЛЕД светла кад стигне нова порука - Звук + Вибрација + Завибрирај кад стигне нова порука + LED обавештења + Затрепери лампицом за обавештења кад стигне нова порука + Мелодија звона Звук обавештења Звук обавештења нових порука - Мелодија долазног позива - Период одгоде - Напредно - Слањем извештаја рада помажете развоју апликације. + Мелодија звона долазног позива + Период тишине + Напредне опције + Слањем извештаја о грешкама помажеш развоју апликације Потврди поруке - Обзнаните контактима када примите и прочитате њихове поруке + Обавести контакте када си примио/ла и прочитао(ла њихове поруке Сучеље - Отворени кључарник је направио грешку. + OpenKeychain је произвео грешку. Лош кључ за шифровање. Прихвати Десила се грешка Грешка - Ваш налог - Шаљи ажурирања присутности - Примај ажурирања присутности - Питај за ажурирања присутности + Твој налог + Шаљи пријаве присутности + Примај пријаве присутности + Питај за пријаве присутности Изабери слику Фотографиши - Унапред дозволи захтев за претплатом + Унапред прихвати захтев за пријавом Изабрани фајл није слика - Не могу преобратити датотеку фотографије - Фајл није нађен - Општа У/И грешка. Можда вам је нестало простора у складишту? - Апликација из које делите ову слику не даје дозволу довољну да се датотека учита.\n\nПоделите слику другим претраживачем датотека. - Апликација из које делите овај садржај не даје довољну дозволу. + Није могуће конвертовати слику + Фајл није пронађен + Општа У/И грешка. Можда ти је понестало слободног простора на уређају? + Апликација којом си одабрао/ла ову слику није дала неопходне дозволе да се фајл исчита. +\n +\nПодели слику користећи други фајл менаџер. + Апликација којом си поделио/ла овај фајл није дала неопходне дозволе. Непознато Привремено искључен На вези Повезивање\u2026 - Ван везе + Није на вези Неовлашћен - Сервер није нађен - Нема везе + Сервер није пронађен + Не постоји веза Регистрација није успела Корисничко име је већ у употреби Регистрација завршена Овај сервер не подржава регистрацију Неисправан регистрациони токен - ТЛС преговарање није успело - Непроверљив домен + TLS преговарање није успело + Домен не може да се овери Нарушавање полисе Некомпатибилан сервер Грешка тока Грешка при отварању тока Нешифровано - ОТР - ОпенПГП + OTR + OpenPGP ОМЕМО Обриши налог Привремено искључи Објави аватар - Објави ОпенПГП јавни кључ - Уклони ОпенПГП кључ - Желите ли заиста да уклоните ваш ОпенПГП кључ из ваше објаве присутности?\nВаши контакти више неће моћи да вам шаљу ОпенПГП шифроване поруке. - ОпенПГП кључ је објављен. + Објави OpenPGP јавни кључ + Уклони OpenPGP јавни кључ + Да ли си сигуран/на да желиш да уклониш свој OpenPGP јавни кључ из своје објаве присутности? +\nТвоји контакти више неће моћи да ти шаљу OpenPGP шифроване поруке. + OpenPGP јавни кључ је објављен. Укључи налог - Брисањем налога бришете и целу историју ваших разговора. + Да ли си сигуран/на да желиш да обришеш свој налог? Брисањем налога бришеш и целу историју својих преписки Сними глас - ИксМПП адреса - Блокирај ИксМПП адресу + XMPP адреса + Блокирај XMPP адресу korisnickoime@primer.com Лозинка - Ово је неисправна ИксМПП адреса - Недовољно меморије. Фотографија је превелика - Желите ли да додате %s у ваш именик? + Ово је неисправна XMPP адреса + Недовољно меморије. Слика је превелика + Да ли желиш да додаш %s у свој именик? Подаци о серверу XEP-0313: МАМ - XEP-0280: копије порука - XEP-0352: индикација стања клијента - XEP-0191: наредба блокирања - XEP-0237: верзионисање ростера - XEP-0198: менаџмент тока - XEP-0215: Проналажење спољњих сервиса - XEP-0163: PEP (аватари/ОМЕМО) - XEP-0363: ХТТП отпремање фајлова - XEP-0357: „push“ + XEP-0280: Message Carbons + XEP-0352: Client State Indication + XEP-0191: Blocking Command + XEP-0237: Roster Versioning + XEP-0198: Stream Management + XEP-0215: External Service Discovery + XEP-0163: PEP (Avatars / OMEMO) + XEP-0363: HTTP File Upload + XEP-0357: Push доступан недоступан Недостају објаве јавног кључа @@ -200,9 +209,9 @@ виђен/а пре %d сати виђен/а јуче виђен/а пре %d дана - Шифрована порука. Инсталирајте Отворени кључарник да је дешифрујете. - Пронаћене су нове ОпенПГП шифроване поруке - ИД ОпенПГП кључа + Шифрована порука. Инсталирај OpenKeychain да је дешифрујеш. + Пронађене су нове OpenPGP шифроване поруке + ID OpenPGP кључа ОМЕМО отисак v\\ОМЕМО отисак ОМЕМО отисак (порекло поруке) @@ -222,37 +231,41 @@ Изабери Контакт већ постоји Придружи се - channel@conference.example.com/nick - channel@conference.example.com + kanal@konferencija.primer.com/nadimak + kanal@konferencija.primer.com Сачувај као обележивач Обриши обележивач - Уклони групно ћаскање + Уклони групну преписку Уклони канал - Да ли сигурно жеите да уклоните ово групно ћаскање?\n\nУпозорење: Групно ћаскање ће бити потпуно обрисано са сервера. - Да ли сигурно жеите да уклоните овај јавни канал?\n\nУпозорење: Канал ће бити потпуно обрисан са сервера. - Не могу уклонити групно ћаскање - Не могу уклонити канал - Уреди предмет групног ћаскања + Да ли си сигуран/на да желиш да уклониш ову групну преписку? +\n +\nУпозорење: Групна преписка ће бити потпуно обрисана са сервера. + Да ли си сигуран/на да желиш да уклониш овај јавни канал? +\n +\nУпозорење: Канал ће бити потпуно обрисан са сервера. + Није могуће уклонити групну преписку + Није могуће уклонити канал + Измени предмет групне преписке Тема - Улазим у групно ћаскање… + Улазим у групну преписку… Напусти - Контакт вас је додао на списак контаката - Додај га - %s је прочитао довде - %s је прочитао/ла довде + Контакт вас је додао на свој списак контаката + Додај га код себе + %s је прочитао/ла довде + %s су прочитали довде %1$s + %2$d других су прочитали довде Сви су прочитали довде Објави - Тапните аватар да изаберете слику из галерије + Притисни аватар да изабереш слику из галерије Објављујем… - Сервер је одбио вашу објаву - Не могу преобратити вашу фотографију - Не могох да сачувам аватар на диск - (или притисните дуго да вратите подразумевани) - Ваш сервер не подржава објаву аватара + Сервер је одбио твоју објаву + Није могуће конвертовати твоју слику + Није могуће сачувати аватар на интерну меморију + (или притисни дуго да вратиш подразумевани) + Твој сервер не подржава објаву аватара шапну - за %s - Пошаљи личну поруку за %s + ка %s + Пошаљи приватну поруку ка %s Повежи Овај налог већ постоји Следеће @@ -260,63 +273,67 @@ Прескочи Искључи обавештења Укључи - Групно ћаскање захтева лозинку - Унесите лозинку - Најпре захтевајте ажурирање присутности од вашег контакта.\n\nОво ће омогућити да се одреди који клијент ваш контакт користи. - Захтевај одмах + Групна преписка захтева лозинку + Унеси лозинку + Прво затражи пријаве присутности од твог контакта. +\n +\nОво ће омогућити да се установи апликација коју твој контакт користи. + Затражи одмах Занемари - Упозорење: Слањем овога без обостраног ажурирања присутности може изазвати неочекиване проблеме.\n\nИдите у „Детаљи контакта” да потврдите вашу претплату за присутност. + Упозорење: Слање овога без обостране пријаве присутности може изазвати неочекиване проблеме. +\n +\nИди у „Детаљи контакта” да потврдиш своје пријаве присутности. Безбедност - Дозволи исправљање порука - Дозвољава вашим контактима да ретроактивно уређују њихове поруке - Поставке за стручњаке - Будите пажљиви са овим + Преправљање порука + Дозволи својим контактима да ретроактивно измењују своје поруке + Стручна подешавања + Буди пажљив/а са овим О %s Тихи сати Време почетка Време завршетка Укључи тихе сате - Обавештења ће бити ућуткана за време тихих сати + Обавештења ће бити утишана за време тихих сати Остало - ОМЕМО отисак копиран на клипборд - Забрањен вам је приступ овом групном ћаскању - Ово групно ћаскање је само за чланове + OMEMO отисак копиран у клипборд + Забрањен ти је приступ овој групној преписци + Ова групна преписка је само за чланове Ограничење ресурса - Шутнути сте из овог групног ћаскања - Групно ћаскање је угашено - Више нисте у овом групном ћаскању - преко налога %s - код домаћина %s - Проверавам %s на ХТТП домаћину - Нисте повезани. Покушајте поново касније + Избачен/а си из ове групне преписке + Групнa преписка је угашена + Ниси више у овој групној преписци + користећи налог %s + хостовано на %s + Проверавам %s на HTTP серверу + Ниси повезан/а. Покушај поново касније Провери величину %s - Провери величину %1$s na %2$s + Провери величину %1$s на %2$s Опције поруке Цитирај - Налепи као навод - Копирај изворни УРЛ + Налепи као цитат + Копирај оригинални линк Пошаљи поново - УРЛ фајла - УРЛ је копиран на клипборд - ИксМПП адреса копирана на клипборд - Порука грешке копирана на клипборд + Линк ка фајлу + Линк је копиран у клипборд + XMPP адреса копирана у клипборд + Текст грешке копиран у клипборд веб адреса - Очитај 2Д бар-кôд - Прикажи 2Д бар-кôд + Очитај QR кôд + Прикажи QR кôд Прикажи списак блокираних Детаљи налога Потврди Покушај поново Сервис у првом плану - Спречава оперативни систем да прекине вашу везу - Направите резерву - Резерва ће бити складиштена у %s - Правим резерву - Ваша резерва је направљена - Резерве су складиштене у %s - Учитавам резерву - Ваша резерва је учитана - Не заборавите да омогућите налог + Спречава оперативни систем да прекине твоју везу + Направи резервну копију + Резервна копија ће бити смештена у %s + Правим резервну копију + Твоја резервна копија је направљена + Резервне копије су смештене у %s + Враћам резервну копију + Твоја резервна копија је враћена + Не заборави да омогућиш налог. Изабери фајл Примам %1$s (%2$d%% завршено) Преузми %s @@ -324,96 +341,97 @@ фајл Отвори %s шаљем (%1$d%% завршено) - Припремам датотеку за пренос + Припремам фајл за слање %s понуђен за преузимање Прекини пренос - не могу поделити датотеку - пренос датотеке је прекинут - Датотека је обрисана - Нема апликације за отварање датотеке - Нема апликације за отварање везе - Нема апликације за приказ контакта + није могуће поделити фајл + пренос фајла је прекинут + Фајл је обрисан + Није пронађена апликација за отварање фајла + Није пронађена апликација за отварање линка + Није пронађена апликација за приказ контакта Динамичке ознаке - Приказ ознака испод контаката + Прикажи ознаке испод контаката Укључи обавештења - Сервер групног ћаскања није нађен - Не могу направити групно ћаскање + Није пронађен сервер групне преписке + Није могуће направити групну преписку Аватар налога - Копирај ОМЕМО отисак на клипборд + Копирај OMEMO отисак у клипборд Поново генериши ОМЕМО кључ - Очисти уређаје - Нема употребљивих кључева за овај контакт.\nПроверите да ли сте одобрили узајамно ажурирање присутности. - Нешто је пошло по злу + Почисти уређаје + Нема употребљивих кључева за овај контакт. +\nПровери да ли обоје имате пријаву присутности. + Нешто није како треба Добављам историјат са сервера Нема више историјата на серверу Ажурирам… Лозинка промењена! - Не могох да променим лозинку + Није могуће променити лозинку Промени лозинку - Текућа лозинка + Тренутна лозинка Нова лозинка Лозинка не може бити празна Укључи све налоге Искључи све налоге - Изврши радњу са + Изврши радњу користећи Без припадности - Ван везе - Изгнаник + Није на вези + Забрањен/а Члан Напредни режим - Одобри админ. привилегије - Укини админ. привилегије + Одобри чланске привилегије + Укини чланске привилегије Одобри админ. привилегије Одобри админ. привилегије Одобри власничке привилегије Укини власничке привилегије - Уклони из групног ћаскања + Уклони из групне преписке Уклони из канала - Не могох да изменим припадност за %s - Забрани приступ групном ћаскању - Забрани приступ каналу - Покушавате да уклоните %s из јавног канала. Ово се за стално постиже једино забраном приступа кориснику. - Забрани одмах - Не могох да изменим улогу за %s - Поставке приватног групног ћаскања - Поставке јавног канала - Лична, само чланови - Начините ИксМПП адресу видљиву свима - Начините канал модерисаним - Не учествујете - Опције групног ћаскања измењене! - Не могу да изменим опције групног ћаскања - никад - до даљњег + Није могуће променити припадност за %s + Избаци из групне преписке + Избаци из канала + Покушаваш да уклониш %s из јавног канала. Ово се постиже једино трајним избацивањем корисника. + Избаци одмах + Није могуће променити улогу за %s + Подешавања приватне групне преписке + Подешавања јавног канала + Приватно, само чланови + Учини XMPP адресе видљиве свима + Учини канал модерисаним + Не учествујеш + Опције групне преписке измењене! + Није могуће изменити опције групне преписке + Никад + До даљњег Одложи Одговори Означи прочитаним Унос - Ентер шаље - Прикажи Ентер тастер - Промени тастер за емотиконе у ентер тастер + Enter шаље + Прикажи Enter дугме + Промени дугме за емотиконе у Enter дугме звук видео слика - ПДФ документ - Апликација за Андроид + PDF документ + Аndroid апликација Контакт Аватар је објављен! Шаљем %s Нудим %s Сакриј неповезане %s куца… - %s престаде да куца + %s је престао/ла да куца %s куцају… - %s престаше да куцају - Обавештења о куцању - Обзнаните контактима када им куцате поруке + %s су престали да куцају + Индикатори куцања + Дозволи својим контактима да знају када им куцаш поруке Пошаљи локацију Прикажи локацију - Нема апликације за приказ локације + Није пронађена апликација за приказ локације Локација - Напустили сте групно ћаскање - Напустили сте јавни канал + Напустиo/ла си групну преписку + Напустиo/ла си јавни канал Не поуздај се у системска сертификациона тела Сви сертификати морају ручно да се одобре Уклони сертификате @@ -431,52 +449,52 @@ Ниједна Недавно коришћена Изаберите брзу радњу - Тражи контакте - Пошаљи личну поруку - %1$s је напустио/ла групно ћаскање + Претражи контакте + Пошаљи приватну поруку + %1$s је напустио/ла групну преписку Корисничко име Корисничко име Ово није исправно корисничко име - Преузимање није успело: сервер није нађен - Преузимање није успело: фајл није нађен - Преузимање није успело: не могох да се повежем са домаћином - Преузимање није успело: не могох да упишем фајл + Преузимање није успело: сервер није пронађен + Преузимање није успело: фајл није пронађен + Преузимање није успело: није могуће повезивање са сервером + Преузимање није успело: није могуће уписивање фајла Тор мрежа недоступна - Неуспех свезивања + Неуспех везивања Сервер није одговоран за овај домен Оштећен - Доступност - Увек када је уређај закљчан - Прикажи ме одсутним када је уређај закљчан - Заузет у нечујном режиму - Прикажи ме заузетум у нечујном режиму - Вибрација је нечујни режим - Прикажи ме заузетум у режиму вибрације - Проширене поставке повезивања - Приказ домаћина и порта у поставкама налога + Присутност + Одсутан/на кад је уређај закључан + Прикажи ме одсутним/ом када је уређај закључан + Заузет/а у нечујном режиму + Прикажи ме заузетим/ом у нечујном режиму + Третирај вибрацију као нечујни режим + Прикажи ме заузетим/ом у режиму вибрације + Назив сервера и порт + Прикажи додатна подешавања везе при отварању налога xmpp.primer.com - Пријавите се сертификатом - Не могу прочитати сертификат - Поставке архивисања - Серверске поставке архивисања - Добављам поставке архивисања, сачекајте… - Не могу да добавим поставке архивисања - КЕПЧА је обавезна - Унесите текст са слике изнад + Пријави се сертификатом + Није могуће ишчитати сертификат + Подешавања архивирања + Серверска подешавања архивирања + Добављам подешавања архивирања. Сачекај… + Није могуће добавити подешавања архивирања + CAPTCHA је обавезан + Унеси текст са слике изнад Неповерљив ланац сертификата - ИксМПП адреса се не слаже са сертификатом + XMPP адреса се не слаже са сертификатом Обнови сертификат - Грешка добављања ОМЕМО кључа! + Грешка у добављању OMEMO кључа! Оверен ОМЕМО кључ помоћу сертификата! - Ваш уређај не подржава избор сертификата клијента! + Твој уређај не подржава одабране клијентске сертификате! Повезивање Повежи се преко Тора - Тунеловање свих веза кроз Тор мрежу. Захтева Орбот - Име домаћина + Спроведи сав саобраћај кроз Тор мрежу. Захтева Орбот + Назив сервера Порт Серверска или .onion адреса Ово није исправан број порта - Ово није исправно име домаћина + Ово није исправан назив сервера %1$d од %2$d налога повезано %d порука @@ -484,101 +502,101 @@ %d порука Учитај још порука - Датотека подељена са %s + Фајл подељен са %s Слика подељена са %s Слике подељене са %s Текст подељен са %s - Дозволите да %1$s приступи спољној меморији - Дозволите да %1$s приступи камери - Синхронизуј са контактима - Обавештења за све поруке - Обавести само када ме помињу + Дозволи да %1$s приступи спољној меморији + Дозволи да %1$s приступи камери + Интеграција са имеником + Обавести ме за све поруке + Обавести ме само када ме неко спомене Обавештења искључена Обавештења паузирана Компресија слике - увек + Увек Само велике слике Оптимизација батерије је укључена Искључи - Назначена површина је превелика + Означена површина је превелика (Нема активираних налога) - Ово поље је захтевано - Исправи поруку - Пошаљи исправљену поруку - Искључили сте овај налог - Безбедносна грешка: неисправан приступ датотеци! - Нема апликације за дељење ресурса - Подели везу помоћу… - Сложи се и настави - Ваша цела ИксМПП адреса ће бити: %s + Ово поље је обавезно + Преправи поруку + Пошаљи преправљену поруку + Искључио/ла си овај налог + Безбедносна грешка: неисправан приступ фајлу! + Није пронађена апликација за дељење линкова + Подели линк користећи… + Слажем се, настави + Твоја пуна XMPP адреса ће бити: %s Направи налог - Користићу сопствени провајдер - Одредите ваше корисничко име - Ручно мењај доступност - Поставите присутност при измени ваше поруке стања. - Порука стања - Слободан за ћаскање + Користићу свог провајдера + Одабери своје корисничко име + Ручно мењај присутност + Постави присутност при измени своје статусне поруке. + Статусна порука + Слободан/на за преписку На вези - Одсутан - Недоступан - Заузет - Безбедна лозинка је направљена - Ваш уређај не подржава искључивање оптимизације батерије - Регистрација није успела: покушајте поново касније - Регистрација није успела: лозинка преслаба - Додај учеснике - Правим групно ћаскање… - Пошаљи поново + Одсутан/на + Недоступан/на + Заузет/а + Јака лозинка је направљена + Твој уређај не подржава искључивање оптимизације батерије + Регистрација није успела: покушај поново касније + Регистрација није успела: лозинка превише слаба + Одабери учеснике + Правим групну преписку… + Позови поново Искључи Кратак Средњи Дуг - Објави употребу - Обзнаните контакте кад користите Конверзацију + Последњи пут виђен/а + Дозволи својим контактима да виде када си последњи пут користио/ла апликацију Приватност Тема - Избор палете боја - Аутопатски - Светла - Тамна - Не могу да се повежем са Отвореним кључарником + Изабери палету боја + Аутоматски + Светли + Тамни + Није могуће повезати се на OpenKeychain Овај уређај више није у употреби Рачунар Мобилни телефон Таблет Веб прегледач Конзола - Захтевано је плаћање - Дозволите приступ интернету + Плаћање је обавезно + Дозволи приступ интернету Ја - Контакт пита за претплату на ажурирање присутности + Контакт пита за пријаву присутности Дозволи Нема дозвола за приступ %s - Удаљени сервер није нађен + Удаљени сервер није пронађен Удаљени сервер се не одазива - Не могу да ажурирам налог - Пријавите ову ИксМПП адресу због нежељених порука. + Није могуће ажурирати налог + Пријави ову XMPP адресу због нежељених порука. Обриши ОМЕМО идентитете Обриши изабране кључеве - Морате бити повезани да бисте објавили ваш аватар. - Прикажи поруку грешке - Порука грешке - Чувар протока укључен - Ваш уређај не подржава искључење „Уштеде података” за %1$s. - Не могу да направим привремену датотеку - Овај уређај је оверен. + Мораш бити повезан/а да би објавио/ла свој аватар. + Прикажи текст грешке + Текст грешке + Уштеда података укључена + Твој уређај не подржава искључивање уштеде података за %1$s. + Није могуће направити привремени фајл + Овај уређај је оверен Копирај отисак Оверени отисци - Користи камеру за очитавање контактова бар-кôда - Сачекајте на добављање кључева + Употреби камеру за очитавање бар-кôда контакта + Сачекај да се добаве кључеви Подели као бар-кôд - Подели као ИксМПП УРИ - Подели као ХТТП везу - Слепо веруј и пре провере - Непоуздан - Неисправан 2Д бар-кôд - Очисти кеш - Очисти лично складиште + Подели као XMPP линк + Подели као HTTP линк + Слепо одобри пре овере + Неодобрен + Неисправан QR кôд + Почисти кеш + Почисти приватно складиште Овери ОМЕМО кључеве Прикажи неактивне Сакриј неактивне @@ -617,9 +635,9 @@ Шифрујем поруку Компресујем видео Контакт блокиран. - Обавештења од непознатих - Примљена порука од незнанца - Блокирај странца + Обавештења од непознатих особа + Примљена порука од непознате особе + Блокирај непознату особу Блокирај читав домен на вези сада Покушај дешифровање поново @@ -630,11 +648,11 @@ Јуче делимично Сними видео - Копирај на клипборд - Порука копирана на клипборд + Копирај у клипборд + Порука копирана у клипборд Порука Нацрт: - ОМЕМО ће увек бити у употреби за један-на-један и приватна групна ћаскања. + OMEMO ће увек бити у употреби за један-на-један и приватне групне преписке. Направи пречицу Подразумевано укључено Подразумевано искључено @@ -642,26 +660,467 @@ Дељење локације је искључено Копирај локацију Подели локацију - Упутства + Путоказ Подели локацију Прикажи локацију - Дели - Сачекајте… - Тражи поруке + Подели + Сачекај… + Претражи поруке Погледај преписку Копирај веб адресу - Аватар групног ћаскања - Домаћин не подржава аватар групног ћаскања - Само власник може да промени аватар групног ћаскања + Аватар групне преписке + Сервер не подржава аватаре за групне преписке + Само власник може да промени аватар групне преписке Име контакта Надимак Име - Име је опционо - Назив групног ћаскања - Ово групно ћаскање је обрисано + Навођење имена није обавезно + Назив групне преписке + Ова групна преписка је обрисана Поруке Поруке Тихе поруке Видео компресија - Заузет + Заузет/а + Шифровано користећи OMEMO + Овери %s + Претражи земље + Овај број телефона је тренутно пријављен са другим уређајем. + Покрени Orbot + Ниједна продавница апликација није инсталирана. + е-књига + Правим јавни канал… + Власници могу да измене тему. + Админи могу да измене тему. + Власници могу да позову некога. + Дозволи било коме да позове неког + Било ко може да позове некога. + XMPP адресе су видљиве било коме. + Тренутни видео позив + Одлазни позив + Паузирај снимак + Push сервер + Одјављен/а + + %1$d пропуштен позив од %2$s + %1$d пропуштена позива од %2$s + %1$d пропуштених позива од %2$s + + Звони + Већ си одобрио/ла отисак овог контакта. Кликом на “Готово” само потврђујеш да је %s део ове групне преписке. + Шаљи извештаје о неочекиваним заустављањима апликације + Искључи одмах + ОМЕМО ће подразумевано бити употребљен за нове преписке. + OMEMO ће морати експлицитно да се укључује на нове преписке. + Није успело дешифровање OMEMO поруке. + Фиксирај позицију + Употреби plugin за дељење локације уместо уграђене мапе + Plugin за дељење локације + На екрану “Нова преписка” отвори тастатуру и постави позицију у поље за претрагу + Прикажи садржај + Учесници + Прегледач садржаја + Conversations профилна слика + Отвори користећи… + Не покушавај да вратиш резервну копију коју ниси направио/ла сам! + Направи јавни канал + Дозволи било коме да измени тему + Подели резервне копије + Групне Преписке и Канали + Опозван позив + Поновно успостављање позива + Поновно успостављање видео позива + Нешифровано + Неуспеле испоруке + Додатне опције + Обичан текстуални документ + Регистрације налога нису подржане + Светли/тамни режим + Дозволи скриншотове + Приказуј садржај апликације у прегледу недавних апликација и дозволи прављење скриншотова + E2E шифровање, Слепо одобрење пре овере, MITM детекција + + %1$d пропуштен позив од %2$d контаката + %1$d пропуштена позива од %2$d контаката + %1$d пропуштених позива од %2$d контаката + + + Порука није могла да се испоручи + Поруке нису могле да се испоруче + Порука није могло да се испоручи + + Направи једну, Закажи аутоматске + Направи једну резервну копију + Аутоматске резервне копије + Обавештења преко целог екрана + Дозволи овој апликацији да приказује обавештења о долазним позивима која заузимају цео екран када је уређај закључан. + Неподржана операција + Полиса приватности + Интеграција са имеником није расположива + Пријави се + Нема употребљивих кључева за овај контакт. +\nНови кључеви не могу да се добаве са сервера. Можда нешто није у реду са сервером твог контакта? + Избаци уређај из листе одобрених + Да ли свеједно желиш да се повежеш? + Детаљи сертификата: + Једном + Премотај до краја + Одфиксирај позицију + HTTP дељење фајлова за S3 + Савет: У неким случајевима ово може да се среди обостраним додавањем у именик. + Назад + Да + Аутоматски налепљен могући PIN из клипборда. + Унеси свој 6-оцифрени PIN. + Оверавам… + Тражим SMS… + PIN који си унео/ла није тачан. + PIN који смо ти послали је истекао. + Непозната грешка са мрежом. + Непознат одговор од сервера. + Није могуће успостављање безбедне везе. + Није могуће пронаћи сервер. + Није могуће повезивање на сервер. + Неисправан кориснички унос + Нема мрежне везе. + Унеси своје име да би људи који те немају у свом именику знали ко си. + Унеси своје име + Твоје име + Притисни дугме за измену да би подесио/ла своје име. + Одбиј захтев + Накачи + Помоћ + Пређи на преписку + Твој микрофон није расположив + Можеш да обављаш само један позив у исто време. + Врати се у тренутни позив + Није могуће пребацити камеру + Закачи на врх + Откачи са врха + GPX рута + Није могуће изменити поруку + XMPP налог + Ниједан активан налог не подржава ову функцију + Прављење резервне копије је започето. Добићеш обавештење када се заврши. + Није могуће укључити видео. + Привремена грешка у аутентификацији + Обриши аватар + Позиви су искључени када се користи Тор + Пређи на видео + Одбиј + Тастатура + Различите позадинске боје за послате и примљене поруке + Архивирај преписку + Нова преписка + Уклони преписку из листе + Постави “autojoin” заставицу при уласку или изласку из MUC-а и реагуј на измене од стране других клијената. + Порука није шифрована за овај уређај. + Некомпатибилан клијент + Quicksy тражи твоју сагласност да користи твоје податке + Твој уређај примењује јаку оптимизацију батерије за %1$s што може довести до кашњења обавештења или чак губитка порука. +\n +\nСада ћеш добити упит да је искључиш. + Припремљено је упутство за отварање налога на conversations.im. +\nАко одабереш conversations.im као провајдера можеш да комуницираш са корисницима других провајдера тако што им проследиш своју пуну XMPP адресу. + Разнобојни балончићи преписке + Недостатак пермисија за обављање позива + Валидирај назив сервера користећи DNSSEC + Ова категорија обавештења се користи за трајни приказ обавештења да %1$s ради. + Желиш да уклониш обележивач за %s? + Претражи групне преписке + Желиш да уклониш обележивач за %s и да архивираш преписку? + Прихвати име сервера које се не подудара? + XEP-0388: Extensible SASL Profile + Да ли си сигуран/на да желиш да уклониш све остале уређаје из OMEMO објаве? Следећи пут када се твоји уређаји повежу, објавиће се сами, али можда неће примити поруке које су послате у међувремену. + %1$s обрађује твој именик локално, на твом уређају, да ти прикаже имена и профилне слике за одговарајуће контакте на XMPP-у. +\n +\nНикакви подаци из твог именика не излазе ван твог уређаја! + Придружи се на разговор + Није могуће сачувати подешавање канала + Резервна копија + Одлазни позив (%s) · %s + Поново генериши своје OMEMO кључеве. Сви твоји контакти ће морати поново да те овере. Употреби ову опцију само у крајњем случају. + Сертификат не садржи XMPP адресу + QR кôд читач захтева приступ камери + Послали смо ти нови SMS са 6-оцифреним кодом. + Сервер нема могућност генерисања позивница + Твој оперативни систем ограничава позадински приступ интернету за %1$s. Да би могао/ла да примаш обавештења о новим порукама, требало би да омогућиш неограничен приступ за %1$s када је укључена штедња преноса података. +\n%1$s ће свакако покушати да уштеди на преносу података када год је то могуће. + Поруке се не добављају услед локалног периода ретенције. + Обавести о порукама и позивима од непознатих особа. + Да ли си сигуран/на да желиш да обуставиш процедуру регистрације? + Привремено недоступан. Покушај поново касније. + Оригинални (некомпресован) + Одабери налог + Врати резервну копију + Проналазак канала користи страни сервис <a href=https://search.jabber.network>search.jabber.network</a>.<br><br>Коришћење ове функције ће послати твоју IP адресу и термине претраге том сервису. Погледај њихову <a href=https://search.jabber.network/privacy>Полису Приватности</a> за више информација. + Високи (720p) + Quicksy ће послати SMS поруку (могућа је наплата од стране оператера) да овери твој број телефона. Унеси свој позивни број и број телефона: + Сервер не може да се аутентификује као \"%s\". Сертификат је валидан само за: + Да ли си сигуран/на да желиш да искључиш OMEMO шифровање за ову преписку? +\nОво ће омогућити твом администратору сервера да чита твоје поруке, али је можда једини начин да комуницираш са људима који користе застареле клијенте. + Причекај (%s) + Овај канал већ постоји + XMPP адресе су видљиве админима. + Видео је укључен. Притисни да искључиш. + Ова група обавештења се користи за приказ обавештења која не би требало да пусте било какав звук. На пример, у току активности на другом уређају (Период тишине). + Фајл изостављен услед нарушавања безбедности. + Није могуће обрисати налог са сервера + Позив користи звучник. + Неважећи позивни број + Овај канал ће јавно објавити твоју XMPP адресу + + %d пропуштен позив + %d пропуштена позива + %d пропуштених позива + + Одјави се + Подели користећи… + Апликација за дељење није дозволила пермисију за приступ овом фајлу. + Долазни позив (%s) · %s + Пошаљи шифровану поруку + %1$s користи <b>OpenKeychain</b> за шифровање и дешифровање порука и управљање твојим јавним кључевима.<br><br>Лиценциран је под GPLv3+ и доступан је на F-Droid и Google Play продавницама.<br><br><small>(После поново покрени %1$s.)</small> + Временски период током којег су обавештења утишана након примећене активности на једном од твојих других уређаја. + Забрани скриншотове + Сакриј садржај апликације у прегледу недавних апликација и блокирај скриншотове + Синхронизуј обележивачe + Напустио/ла си ову групну преписку из техничких разлога + Користи Enter дугме за слање порука. Увек можеш да пошаљеш поруку са Ctrl+Enter, чак и када је ова опција угашена. + векторска слика + мултимедијални фајл + Аудиокњига + Преузимање није успело: Неисправан фајл + Савет: Употреби “Изабери фајл” уместо “Изабери слику” за слање појединачних слика без компресије, без обзира на ову опцију. + Очисти кеш фолдер (који користи апликација за камеру) + OMEMO шифровање + Динамичке боје + број телефона + Локални сервер + jabber.network + Дозволи приватне поруке + Прихвати позивнице за групне преписке од непознатих особа + Позивнице од непознатих особа + Преписка је архивирана + Велика слова + + Погледај %1$dог учесника + Погледај %1$d учесника + Погледај %1$d учесника + + Твој аватар. Притисни да одабереш нови аватар из галерије. + Изађи + Сними гласовну поруку + Пусти снимак + Додај контакт, направи или се придружи у групну преписку, или пронађи канале + Није пронађена апликација + Позови на Conversations + Није могуће ишчитати позивницу + Није могуће искључити видео. + Није пронађена XMPP адреса + Одбиј захтев за прелазак на видео + Тема, Боје, Скриншотови, Унос + Безбедност + Релеј обавештења за UnifiedPush-компатибилне апликације + Обавештења + Величина фајлова, Компресија слика, Видео квалитет + Период тишине, Мелодија звона, Вибрација, Непознате особе + Слање + Примање + Аутоматско преузимање + Позив користи bluetooth. + Видео је искључен. Притисни да укључиш. + XEP-0386: Bind 2 + Групне преписке + Твој уређај примењује јаку оптимизацију батерије за %1$s што може довести до кашњења обавештења или чак губитка порука. +\nПрепорука је да је искључиш. + Одјавио/ла си се из овог налога + Добродошао/ла на Quicksy! + Поново повежи на други сервер + Оверио/ла си све OMEMO кључеве које поседујеш + Бар-кôд не садржи отиске за ову преписку. + Очисти приватно складиште где се чувају фајлови (могу поново да се преузму са сервера) + Одобри нове уређаје од неоверених контаката, али питај за потврду нових уређаја за оверене контакте. + Слепо одобрени OMEMO кључеви, у смислу да би то могао да буде неко други или је неко упао. + Испратио/ла сам овај линк из поузданог извора + Оверићеш OMEMO кључеве за свој налог. Ово је безбедно само ако си испратио/ла овај линк из поузданог извора где си само ти могао/ла да објавиш овај линк. + Настави + Оверићеш OMEMO кључеве за %1$s кликом на линк. Ово је безбедно само ако си испратио/ла овај линк из поузданог извора где је само %2$s могао/ла да објави овај линк. + Да ли си сигуран/на да желиш да уклониш оверу за овај уређај? +\nОвај уређај и поруке са њега ће бити означене као “Неоверене”. + Одговарајуће преписке су архивиране. + Ослабљен SASL механизам + Није пронађена апликација за отварање сајта + “Heads-up” обавештења + Приказуј “heads-up” обавештења + Серверски сертификати који садрже валидиран назив сервера се сматрају овереним + Приватне поруке су искључене + Серверски сертификат није потписан од стране неког познатог сертификационог тела. + Премотај на доле након слања поруке + Измени Статусну Поруку + Измени статусну поруку + Није могуће добавити листу уређаја + Искључи шифровање + %1$s не може да шаље шифроване поруке ка %2$s. Могуће је да твој контакт користи застарели сервер или клијент који не подржава OMEMO. + Није могуће добавити кључеве за шифровање + Није могуће покренути снимање + Дозволи да %1$s приступи микрофону + GIF + Копирај XMPP адресу + Директна претрага + Није могуће сачувати снимак + Сервис у првом плану + Статусне Информације + Проблеми у повезивању + Ова категорија обавештења се користи за приказ обавештења у случају да постоји проблем са повезивањем на налог. + Позиви + Долазни позиви + Одлазни позиви + Пропуштени позиви + Неуспеле испоруке + Подешавања обавештења за поруке + Подешавања обавештења за долазне позиве + Хитност, Звук, Вибрација + Видео Квалитет + Нижи квалитет значи да су фајлови мањи + Средњи (360p) + прекинуто + Већ правиш нацрт поруке. + Функција није имплементирана + Одабери земљу + Овери свој број телефона + Оверићемо број телефона

%s

Да ли је ово у реду, или би хтео/ла да измениш број?
+ %s није важећи број телефона. + Унеси свој број телефона. + Послали смо ти SMS на %s. + Унеси 6-оцифрени PIN испод. + Поново пошаљи SMS + Поново пошаљи SMS (%s) + Не + Нешто није како треба у обради твог захтева. + Покушај поново за %s + Ограничен/а си услед учесталих покушаја + Превише покушаја + Користиш застарелу верзију ове апликације. + Освежи + Инсталирај Orbot + Врати + Унеси своју лозинку за налог %s да вратиш резервну копију. + Не употребљавај функцију враћања резервне копије ради клонирања инсталације (за рад у паралели). Враћање резервне копије је предвиђено само за миграције или у случају да си изгубио/ла оригинални уређај. + Није могуће вратити резервну копију. + Није могуће дешифровати резервну копију. Да ли је лозинка исправна? + Резервна копија и Враћање + Унеси XMPP адресу + Направи групну преписку + Придружи се на јавни канал + Направи приватну групну преписку + Име канала + XMPP адреса + Унеси име канала + Унеси XMPP адресу + Ово је XMPP адреса. Унеси име. + Придружио/ла си се на постојећи канал + Било ко може да измени тему. + Овај јавни канал нема учеснике. Позови своје контакте или употреби дугме за дељење како би објавио/ла његову XMPP адресу. + Ова приватна групна преписка нема учеснике. + Подеси привилегије + Претражи учеснике + Фајл је превелики + Пронађи канале + Претражи канале + Потенцијално нарушавање приватности! + Већ имам налог + Додај постојећи налог + Региструј нов налог + Ово изгледа као адреса домена + Додај свеједно + Ово изгледа као адреса канала + Conversations резервне копије + Догађај + Отвори резервну копију + Фајл који си одабрао/ла није Conversations резервна копија + Покушаваш да увезеш резервну копију застарелог формата + Овај налог је већ подешен + Унеси лозинку за овај налог + Није могуће извршити ову радњу + Придружи се на јавни канал… + Већина корисника би требало да одабере ‘jabber.network’ за боље предлоге из целокупног јавног XMPP екосистема. + Начин проналаска канала + О апликацији + Укључи неки налог + Обави позив + Долазни позив + Долазни видео позив + Пређи на видео позив? + Унеси додатне руте? + Повезујем + Повезан + Поновно повезивање + Прихватање позива + Завршавање позива + Јави се + Одбиј + Проналажење уређаја + Контакт није доступан + Није могуће успоставити позив + Прекид везе + Грешка у апликацији + Прекини везу + Тренутни позив + Искључи Тор да би обављао/ла позиве + Долазни позив + Пропуштен позив · %s + Одлазни позив · %s + Пропуштен позив + Аудио позив + Видео позив + Све преписке + Ова преписка + UnifiedPush дистрибутер + Налог кроз који ће “push” поруке бити примљене. + Ниједан (искључен) + Обриши налог са сервера + Сакриј обавештење + Твој контакт користи неоверене уређаје. Очитај његов/њен QR кôд да би извршио/ла оверу и спречио/ла активне MITM нападе. + Користиш неоверене уређаје. Очитај QR кôд на својим другим уређајима да би извршио/ла оверу и спречио/ла активне MITM нападе. + Пријави спам + Пријави спам и блокирај спамера + Твој аватар + Аватар за %s + Шифровано користећи OpenPGP + Интеграција позива није расположива! + Обриши и Архивирај преписку + Покрени преписку + Ниједан клијентски сертификат није одабран! + Сучеље + Изглед + E2E шифровање + Сертификациона тела + Поуздај се у системске CA сертификате + Захтевај везивање канала + Везивање канала може да детектује неке “machine-in-the-middle” нападе + Веза ка серверу + Оперативни Систем + Интеракција + На уређају + Када ради као UnifiedPush дистрибутер, трајна, поуздана и економична XMPP веза ће бити употребљена да “пробуди” другу UnifiedPush-компатибилну апликацију, попут Tusky, Ltt.rs, FluffyChat и других. + Индикатори куцања, Последњи пут виђен/а, Присутност + Назив сервера и порт, Тор + Назив сервера и порт, Тор, Проналажење канала + Обавештења о учествовању + Апликација + Повећај величину слова у порукама + Измени надимак + Обриши OpenPGP кључ + Измени назив и тему + Промени подешавање + Промени подешавања обавештења + Позив користи слушалицу. Притисни да пребациш на звучник. + Позив користи слушалицу. + Позив користи жичане слушалице + Позив користи звучник, Притисни да пребациш на слушалицу. + Пребаци камеру + Механизам за пријаву + Проблем са овером + Прихвати непознат сертификат? + Системске боје (Material You)
\ No newline at end of file From 4df6a4966c9134efe5745c567929f1bcfc022537 Mon Sep 17 00:00:00 2001 From: user11 Date: Fri, 13 Sep 2024 13:50:26 +0000 Subject: [PATCH 05/60] Translated using Weblate (Serbian) Currently translated at 100.0% (13 of 13 strings) Translation: Conversations/Android App (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-conversations/sr/ --- src/conversations/res/values-sr/strings.xml | 22 +++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/conversations/res/values-sr/strings.xml b/src/conversations/res/values-sr/strings.xml index 3bbef8725fd0c659f4d3d9056e2d2e46f5d9acfb..f6ad6f27c894d2982308e3440b0f80fb25768734 100644 --- a/src/conversations/res/values-sr/strings.xml +++ b/src/conversations/res/values-sr/strings.xml @@ -1,10 +1,20 @@ - Одаберите вашег ИксМПП провајдера - Користи conversations.im + Одабери свог XMPP провајдера + Одабери conversations.im Направи нови налог - Да ли већ имате ИксМПП налог? Извесно је да га имате ако користите неки ИксМПП клијент или сте раније користили Конверзацију. Ако немате, сада можете направити нови ИксМПП налог.\nСавет: неки поштански провајдери такође омогућавају и ИксМПП налоге. - ИксМПП је мрежа брзих порука, независна од провајдера. Овај клијент можете користити уз било који сервер по вашем избору. -\nДа бисмо вам олакшали, омогућили смо креирање налога на conversations.im; провајдеру специјално прилаг.ођеном за коришћење уз Конверзацију - Ваша серверска позивница + Да ли већ имаш XMPP налог? Могуће је да имаш ако већ користиш неки други XMPP клијент или ако си раније користио/ла Conversations. Ако немаш, можеш сада да направиш нови XMPP налог. +\nУспут: поједини имејл провајдери пружају и XMPP налоге. + XMPP је мрежа за инстант поруке, независна од провајдера. Ову апликацију можеш да користиш уз било који XMPP сервер по свом избору. +\nРади погодности, омогућили смо лако креирање налога на conversations.im - провајдер посебно прилагођен за коришћење уз Conversations. + Твоја позивница на сервер + Позван/а си на %1$s. Спровешћемо те кроз поступак прављења налога. +\nАко одабереш %1$s као провајдера можеш да комуницираш са корисницима других провајдера тако што им проследиш своју пуну XMPP адресу. + Неисправно форматиран провизиони кôд + Притисни дугме за дељење како би свом контакту послао/ла позивницу на %1$s. + Ако је твој контакт у близини, може да скенира кôд у наставку како би прихватио твоју позивницу. + Пријави се на %1$s и разговарај са мном: %2$s + Подели позивницу са… + Позван/а си на %1$s. Корисничко име је већ одабрано за тебе. Спровешћемо те кроз поступак прављења налога. +\nМожеш да комуницираш са корисницима других провајдера тако што им проследиш своју пуну XMPP адресу. \ No newline at end of file From 733e84d7f55ca4aafb124b20de2d7cb8e5eda128 Mon Sep 17 00:00:00 2001 From: Besnik_b Date: Fri, 13 Sep 2024 19:18:25 +0000 Subject: [PATCH 06/60] Translated using Weblate (Albanian) Currently translated at 100.0% (70 of 70 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/sq/ --- fastlane/metadata/android/sq/changelogs/4211704.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 fastlane/metadata/android/sq/changelogs/4211704.txt diff --git a/fastlane/metadata/android/sq/changelogs/4211704.txt b/fastlane/metadata/android/sq/changelogs/4211704.txt new file mode 100644 index 0000000000000000000000000000000000000000..c52c0bb4447cdcbc34cc6a7a6723a8730be611d8 --- /dev/null +++ b/fastlane/metadata/android/sq/changelogs/4211704.txt @@ -0,0 +1,3 @@ +* Ofro vlera më të larta pranimi automatik kartelash +* Dhënie e më tepër hollësish te “Hollësi shërbyesi” +* Ndreqje të metash të ndryshme From ba11ea8488f0864b64e2cba806afd320230fd391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Sat, 14 Sep 2024 13:47:04 +0000 Subject: [PATCH 07/60] Translated using Weblate (Estonian) Currently translated at 100.0% (13 of 13 strings) Translation: Conversations/Android App (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-conversations/et/ --- src/conversations/res/values-et/strings.xml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/conversations/res/values-et/strings.xml b/src/conversations/res/values-et/strings.xml index a6b3daec9354f9ae75cdf8d94a67446c6227dd96..da46388b7fa294e1f802c1251859994014a8bf19 100644 --- a/src/conversations/res/values-et/strings.xml +++ b/src/conversations/res/values-et/strings.xml @@ -1,2 +1,20 @@ - \ No newline at end of file + + Vali oma XMPP-teenusepakkuja + Loo uus kasutajakonto + Kas sul juba on XMPP-konto olemas? Kui sa oled varem kasutanud Conversationsit või mõnda muud XMPP-klienti, siis see tõesti võib nii olla. Kui aga mitte, siis võid XMPP-konto kohe luua. +\nVihje: Ka mitmed e-postiteenuse pakkujad pakuvad ka XMPP-teenuseid. + XMPP on teenusepakkujast sõltumatu sõnumivõrk. Sa võid kasutada seda rakendust ükspuha missuguse XMPP-serveriga. +\nAga mugavuse nimel oleme teinud lihtsaks kasutajakonto loomise conversations.im serverisse, mis on Conversationsiga hästi sobituv teenusepakkuja. + Sa oled saanud kutse kasutama serverit %1$s. Järgnevaga aitame sind kasutajakonto loomise kõikides sammudes. +\nKui valid serveriks %1$s, siis jagades oma XMPP-aadressi saad suhelda kõikide teiste XMPP kasutajatega. + Sa oled saanud kutse kasutama serverit %1$s. Kasutajanimi on juba sulle valitud. Järgnevaga aitame sind kasutajakonto loomise kõikides sammudes. +\nJagades oma XMPP-aadressi saad suhelda kõikide teiste XMPP kasutajatega kõikides teistes serverites. + Kasuta conversations.im teenust + Sinu kutse serveri kasutajaks + Vigaselt vormindatud eeltäidetud kutse kood + Klõpsi „Jaga“ nuppu ja saada oma kontaktile kutse kasutamaks serverit %1$s. + Kui teine osapool on lähedal, siis ta saab kutse vastuvõtmiseks skaneerida järgnevat koodi. + Liitu serveriga %1$s ja vestle minuga: %2$s + Jaga kutset… + \ No newline at end of file From 6417f95d0012aaab9f469b35a1837343c4ef0ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Sat, 14 Sep 2024 14:18:27 +0000 Subject: [PATCH 08/60] Translated using Weblate (Estonian) Currently translated at 0.2% (3 of 1039 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/et/ --- src/main/res/values-et/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/res/values-et/strings.xml b/src/main/res/values-et/strings.xml index a6b3daec9354f9ae75cdf8d94a67446c6227dd96..5bb71fb456d67e6cb42789c0eacb1d1710e52a52 100644 --- a/src/main/res/values-et/strings.xml +++ b/src/main/res/values-et/strings.xml @@ -1,2 +1,4 @@ - \ No newline at end of file + + Seadistused + \ No newline at end of file From 6d929972df78bcfa9bb4513feafeedb9d38b2294 Mon Sep 17 00:00:00 2001 From: "lucasmz.dev" Date: Sun, 15 Sep 2024 13:02:57 +0000 Subject: [PATCH 09/60] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (1039 of 1039 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/pt_BR/ --- src/main/res/values-pt-rBR/strings.xml | 76 +++++++++++++------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml index 6a6a1f60b2f2a2d9bd6cf6a4cdfc1db4aa143b11..1eab24375b642d59398a7f7c64ea5c898672cf79 100644 --- a/src/main/res/values-pt-rBR/strings.xml +++ b/src/main/res/values-pt-rBR/strings.xml @@ -40,7 +40,7 @@ Moderador Participante Visitante - Gostaria de remover %s da sua lista de contatos? O chat com este contato não será removido. + Gostaria de remover %s da sua lista de contatos? A conversa com este contato não será removida. Deseja bloquear o recebimento de mensagens de %s? Deseja desbloquear o recebimento de mensagens de %s? Bloquear todos os contatos de %s? @@ -78,9 +78,9 @@ Preparando para enviar as imagens Compartilhando arquivos. Por favor, aguarde… Limpar o histórico - Limpar histórico do chat - Deseja excluir todas as mensagens dessa conversa? -\n + Limpar histórico da conversa + Deseja excluir todas as mensagens desta conversa? +\n \nAtenção: Isso não afetará mensagens armazenadas em outros dispositivos ou servidores. Excluir arquivo Deseja realmente excluir este arquivo? @@ -179,7 +179,7 @@ Tem certeza que deseja remover sua chave pública OpenPGP do seu anúncio de presença?\nSeus contatos não poderão mais enviar mensagens criptografadas com o OpenPGP para você. A chave pública do OpenPGP foi publicada. Habilitar a conta - Tem certeza de que deseja excluir sua conta? Excluir sua conta apaga todo o seu histórico do chat + Tem certeza de que deseja excluir sua conta? Excluir sua conta apaga todo o seu histórico de conversa Gravar voz Endereço XMPP Bloquear endereço XMPP @@ -235,9 +235,11 @@ canal@conferencia.exemplo.com Salvar como favorito Excluir o favorito - Destruir a conversa em grupo + Destruir conversa em grupo Destruir o canal - Deseja realmente destruir essa conversa em grupo?\n\nAtenção: A conversa em grupo será completamente removida do servidor. + Deseja realmente destruir esta conversa em grupo? +\n +\nAtenção: A conversa em grupo será completamente removida do servidor. Tem certeza que deseja destruir esse canal público?\n\nAtenção: O canal será removido completamente do servidor. Não foi possível destruir a conversa em grupo Não foi possível destruir o canal @@ -269,11 +271,11 @@ Pular Desabilitar notificações Habilitar - Essa conversa em grupo exige uma senha + Esta conversa em grupo exige uma senha Digite a senha Por favor, primeiro solicite atualizações de presença do seu contato. \n -\nIsso determinará qual cliente de chat o seu contato está usando. +\nIsso determinará qual app de conversa o seu contato está usando. Solicitar agora Ignorar Aviso: Enviar isso sem atualizações mútuas de presença pode provocar problemas inesperados.\n\nVerifique nos detalhes do contato suas inscrições de presença. @@ -293,12 +295,12 @@ Define a flag \"autojoin\" ao entrar ou sair de uma sala e reage a modificações feitas por outros clientes. Impressão digital OMEMO copiada para a área de transferência Você foi banido desta conversa em grupo - Somente membros podem entrar nessa conversa em grupo + Esta conversa em grupo é somente para membros Restrição de recursos Você foi retirado desta conversa em grupo A conversa em grupo foi encerrada Você não está mais nesta conversa em grupo - Você saiu desta conversa em grupo devido a razões técnicas + Você saiu desta conversa em grupo devido à razões técnicas usando a conta %s hospedado em %s Verificando %s no host HTTP @@ -350,7 +352,7 @@ Rótulos dinâmicos Exibe rótulos de somente-leitura abaixo dos contatos Habilitar notificações - Não foi encontrado nenhum servidor de conversas em grupo + Nenhum servidor de conversas em grupo encontrado Não foi possível criar a conversa em grupo Avatar da conta Copiar a impressão digital OMEMO para a área de transferência @@ -431,7 +433,7 @@ Exibir localização Não foi encontrado nenhum aplicativo para exibir a localização Localização - Deixar a conversa em grupo privada + Sair da conversa em grupo privada Deixar o canal público Não confiar nas CAs do sistema Todos os certificados devem ser aprovados manualmente @@ -465,7 +467,7 @@ Falha na associação O servidor não responde por esse domínio Quebrado - Dispôr + Disponibilidade \"Afastado\" quando o dispositivo estiver travado Exibe como Afastado quando o dispositivo estiver travado \"Ocupado\" no modo silencioso @@ -533,7 +535,7 @@ Este campo é necessário Corrigir Enviar a mensagem corrigida - Você já confiou na impressão digital desse contato. Ao selecionar \"Concluído\" você está apenas confirmando que %s é parte deste chat em grupo. + Você já confiou na impressão digital desse contato. Ao selecionar \"Concluído\" você está apenas confirmando que %s é parte desta conversa em grupo. Você desabilitou essa conta Erro de segurança: Acesso inválido ao arquivo! Não foi encontrado nenhum aplicativo para compartilhar a URI @@ -545,8 +547,8 @@ Criar conta Usar meu próprio provedor Selecione seu nome de usuário - Gerenciar o dispôr a dedo - Defina seu dispôr ao editar a sua mensagem de estado. + Gerenciar a disponibilidade manualmente + Defina sua disponibilidade ao editar a sua mensagem de status. Mensagem de status Livre para conversar Conectado @@ -704,14 +706,14 @@ Não foi possível obter a lista de dispositivos Não foi possível obter as chaves de criptografia Dica: Em alguns casos isso pode ser resolvido adicionando-se um ao outro na lista de contatos. - Tem certeza que deseja desabilitar a criptografia OMEMO neste chat? + Tem certeza que deseja desativar a criptografia OMEMO para esta conversa? \nIsso permitirá que o administrador do seu servidor seja capaz de ler suas mensagens. Por outro lado, pode ser a única forma de se comunicar com pessoas usando clientes desatualizados. Desabilitar agora Rascunho: Criptografia OMEMO OMEMO será sempre utilizado em conversas um-para-um e de grupos privados. - OMEMO será utilizado por padrão em novos chats. - OMEMO deverá ser explicitamente ativado para novos chats. + OMEMO será utilizado por padrão em novas conversas. + OMEMO deverá ser explicitamente ativado para novas conversas. Criar atalho Ligado por padrão Desligado por padrão @@ -732,14 +734,14 @@ Permita o acesso do %1$s ao microfone Pesquisar mensagens GIF - Visualizar chat + Visualizar conversa Plugin de Compartilhamento de Localização Usar o Plugin de Compartilhamento de Localização ao invés do mapa integrado Copiar endereço web Copiar endereço XMPP Compartilhamento de arquivos via HTTP para S3 Pesquisa direta - Na tela \"Novo chat\", abra o teclado e coloque o cursor no campo de pesquisa + Na tela \"Nova conversa\", abra o teclado e coloque o cursor no campo de pesquisa Avatar de conversa em grupo O host não suporta avatares de conversa em grupo Somente o proprietário pode alterar o avatar da conversa em grupo @@ -953,8 +955,8 @@ Desafixar do topo Trilha GPX Não foi possível corrigir a mensagem - Todos os chats - Este chat + Todos as conversas + Esta conversa Seu avatar Avatar para %s Criptografada com OMEMO @@ -994,10 +996,10 @@ Recusar requisição de mudança para vídeo Enviar relatórios de erro Gostaria de remover o favorito de %s e arquivar a conversa? - Exclua o chat depois + Exclua esta conversa depois Compartilhar com… Arquivar conversa - Novo chat + Nova conversa Enviar mensagem criptografada Desconectado Gostaria de remover o favorito de %s? @@ -1006,11 +1008,11 @@ Seu contato tem dispositivos não verificados. Escaneie o Código QR dele para fazer uma verificação e impedir ataques MITM. Sair Você está usando dispositivos não verificados. Escaneie o Código QR em outro dispositivo para fazer a verificação, e impedir ataques MITM. - Trocar para o chat + Trocar para conversa Interface Tema, Cores, Capturas de tela, Entrada Segurança - Encriptação E2E, Confiar cegamente antes da verificação, Detecção de MITM + Criptografia de ponta-a-ponta, confiança cega antes da verificação, detecção de MITM Notificações Tamanho do arquivo, Compressão de imagem, Qualidade de vídeo Confiar nos certificados CA do sistema @@ -1023,7 +1025,7 @@ Reportar spam Reportar e bloquear o spammer A integração de chamada não está disponível! - Iniciar chat + Iniciar conversa Nenhum certificado de cliente selecionado! Enviando Recebendo @@ -1041,7 +1043,7 @@ Autoridades de certificação Esconder notificação Ao atuar como um distribuidor UnifiedPush, a conexão persistente, estável, e amigável à bateria do XMPP será usada para alertar outros apps compatíveis com o UnifiedPush, como o Tusky, Ltt.RS, FluffyChat, e mais. - Chats correspondentes arquivados. + Conversas correspondentes arquivadas. Não tente restaurar backups que você não criou! O contato não está disponível O vídeo está ativado. Toque para desativar. @@ -1052,11 +1054,11 @@ Criar um único backup Audiobook Você desconectou desta conta - Bolhas de chat coloridas + Bolhas de conversa coloridas Cores de fundo distintas para mensagens enviadas e recebidas Convites de estranhos - Aceitar convites de estranhos para chat em grupo - Chat arquivado + Aceitar convites de estranhos para conversas em grupo + Conversa arquivada Texto grande Aumentar o tamanho do texto em bolhas de mensagem Seu avatar. Toque para selecionar um novo avatar da galeria. @@ -1066,12 +1068,12 @@ O vídeo está desativado. Toque para ativar. XEP-0386: Vinculação 2 XEP-0388: Perfil SASL extensível - Chats em grupo - Pesquisar chats em grupo + Conversas em grupo + Pesquisar conversas em grupo O Quicksy pede seu consentimento ao usar seus dados Reconectar em outro host Sem permissão para fazer uma ligação - Este código de barras não contém impressões digitais para este chat. + Este código de barras não contém impressões digitais para esta conversa. Cores dinâmicas Cores do sistema (Material You) Você está tentando importar um backup com um formato desatualizado @@ -1101,7 +1103,7 @@ Mostrar o conteúdo do app no alternador de apps e permitir que a tela seja capturada Exigir vínculo do canal A vinculação de canal pode detectar alguns ataques de máquina-no-meio - Notificações de digitação, Visto por último, Dispôr + Notificações de digitação, Visto por Último, Disponibilidade Nome do host e porta, Tor Nome do host e porta, Tor, Descoberta de Canais Teclado From 9b8b23bdf707aa91d728bb19aab216f33b356481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Sat, 14 Sep 2024 14:27:30 +0000 Subject: [PATCH 10/60] Translated using Weblate (Estonian) Currently translated at 3.9% (41 of 1039 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/et/ --- src/main/res/values-et/strings.xml | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/main/res/values-et/strings.xml b/src/main/res/values-et/strings.xml index 5bb71fb456d67e6cb42789c0eacb1d1710e52a52..ec802993cc1766a2fef828e426921a8b52a05a50 100644 --- a/src/main/res/values-et/strings.xml +++ b/src/main/res/values-et/strings.xml @@ -1,4 +1,45 @@ Seadistused + Muuda nime + Lisa aadressiraamatusse + Vali kontaktid + 1 minut tagasi + Kontaktandmed + Rühmavestluse üksikasjad + Kanali teave + Kustuta serveri kontaktiloendist + Blokeeri kontakt + Halda kasutajakontosid + Blokeeri domeen + Külaline + Lisa konto + Eemalda domeeni blokeering + Blokeeri osaleja + Jaga kasutajakontoga + %d minutit tagasi + saadame… + Omanik + Moderaator + Osaleja + Halda kasutajakontot + Arhiveeri vestlus + Eemalda kontakti blokeering + Eemalda osaleja blokeering + Halda kasutajakontosid + Seadistused + Jaga… + Vali kontakt + Blokeeringute loend + Uus vestlus + just nüüd + Dekrüptime sõnumit. Palun oota… + OpenPGP abil krüptitud sõnum + Hüüdnimi on juba kasutusel + Vigane hüüdnimi + Peakasutaja + + %d lugemata vestlus + %d lugemata vestlust + \ No newline at end of file From 02895d1326e98f08ccbd517638aaf7c667eb4d20 Mon Sep 17 00:00:00 2001 From: "lucasmz.dev" Date: Sun, 15 Sep 2024 12:35:45 +0000 Subject: [PATCH 11/60] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-conversations/pt_BR/ --- .../android/pt-BR/full_description.txt | 39 +++++++++++++++++++ .../android/pt-BR/short_description.txt | 1 + 2 files changed, 40 insertions(+) create mode 100644 src/conversations/fastlane/metadata/android/pt-BR/full_description.txt create mode 100644 src/conversations/fastlane/metadata/android/pt-BR/short_description.txt diff --git a/src/conversations/fastlane/metadata/android/pt-BR/full_description.txt b/src/conversations/fastlane/metadata/android/pt-BR/full_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..e4a6318952a5a5f7d1d5cdf5c06852233cbd6659 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/pt-BR/full_description.txt @@ -0,0 +1,39 @@ +Fácil de usar, estável, e bem otimizado. Com suporte à imagens, conversas em grupo, e criptografia de ponta-a-ponta. + +Base do design: + +* Ser o mais bonito e fácil de usar possível sem sacrificar privacidade ou segurança +* Depender de protocolos existentes e bem estabelecidos +* Não precisar de uma conta Google ou especificamente do Google Cloud Messaging (GCM) +* Usar o mínimo de permissões possíveis + +Recursos: + +* Criptografia de ponta-a-ponta com OMEMO ou OpenPGP. +* Envio e recebimento de imagens +* Chamadas de áudio e vídeo criptografadas (DTLS-SRTP) +* UI intuitiva que segue as regras do Android Design +* Imagens / Avatares para seus Contatos +* Sincroniza com o cliente desktop +* Conferências (com suporte a favoritos) +* Integração com livro de endereços +* Múltiplas contas / caixa de entrada unificada +* Baixo uso da bateria + +O Conversations faz com que seja fácil criar uma conta no servidor conversations.im. Mesmo assim, o Conversations funcionará com qualquer outro servidor XMPP. Muitos servidores XMPP são mantidos por voluntários e são gratuitos. + +Recursos XMPP: + +O Conversations funciona com qualquer servidor XMPP por aí. Porém, o XMPP é um protocolo extensível. Estas extensões são padronizadas, nos chamados XEPs. O Conversations suporta alguns desses para tornar a experiência do usuário melhor. Existe uma chance que seu servidor XMPP atual não suporta estas extensões. Por causa disso, para tirar melhor proveito do Conversations, você pode considerar alterar para um servidor XMPP que as suporta - ou melhor ainda - manter seu próprio servidor XMPP para você e seus amigos. + +Estas XEPs são - atualmente: + +* XEP-0065: Bytestreams SOCKS5 (ou mod_proxy65). Será usado para transferir arquivos caso ambas partes estão atrás de um firewall ou NAT. +* XEP-0163: Protocolo de Eventos Pessoais para avatares +* XEP-0191: O comando de bloquear permite que bloqueie spam ou contatos sem removê-los de sua lista. +* XEP-0198: Gerenciamento de Streams permite que o XMPP sobreviva a pequenas interrupções ou mudanças na conexão TCP. +* XEP-0280: Carbonos de Mensagem que automaticamente sincroniza as mensagens que envia no computador e permite que você troque de cliente facilmente do seu celular para seu computador e ao contrário em uma conversa. +* XEP-0237: Controle de Versões da Lista principalmente para economizar banda larga em conexões móveis ruins +* XEP-0313: Gerenciamento do Histórico de Mensagens para sincronizar o histórico de mensagens com o servidor. Recupere mensagens enviadas enquanto o Conversations estava off-line. +* XEP-0352: Indicação do Estado do Cliente permite que o servidor saiba quando o Conversations está ou não em segundo plano. Permite que o servidor economize banda larga. +* XEP-0363: Envio de Arquivos HTTP permite que compartilhe arquivos em conferências e com contatos off-line. Requer um componente adicional em seu servidor. diff --git a/src/conversations/fastlane/metadata/android/pt-BR/short_description.txt b/src/conversations/fastlane/metadata/android/pt-BR/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..043bfde950bfe4461a13e3fa8789aa987483037b --- /dev/null +++ b/src/conversations/fastlane/metadata/android/pt-BR/short_description.txt @@ -0,0 +1 @@ +Mensageiro XMPP criptografado, fácil de usar, para o seu dispositivo móvel From 44b97564b795f8c3f86a233cc62bd1a3fa8db677 Mon Sep 17 00:00:00 2001 From: "lucasmz.dev" Date: Sun, 15 Sep 2024 12:37:43 +0000 Subject: [PATCH 12/60] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Quicksy) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-quicksy/pt_BR/ --- .../metadata/android/pt-BR/full_description.txt | 13 +++++++++++++ .../metadata/android/pt-BR/short_description.txt | 1 + 2 files changed, 14 insertions(+) create mode 100644 src/quicksy/fastlane/metadata/android/pt-BR/full_description.txt create mode 100644 src/quicksy/fastlane/metadata/android/pt-BR/short_description.txt diff --git a/src/quicksy/fastlane/metadata/android/pt-BR/full_description.txt b/src/quicksy/fastlane/metadata/android/pt-BR/full_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..5d4c87541883fe6da5cf298758581623eee06daa --- /dev/null +++ b/src/quicksy/fastlane/metadata/android/pt-BR/full_description.txt @@ -0,0 +1,13 @@ +O Quicksy é uma modificação do cliente Jabber/XMPP popular Conversations, com descoberta automática de contatos. + +Você se registra com seu número de telefone e o Quicksy automaticamente--com base nos números de telefone em seus contatos--irá sugerir possíveis contatos para você. + +Em baixo do capô, o Quicksy é um cliente Jabber completo que permite que você se comunique com qualquer usuário em qualquer servidor que esteja federando publicamente. Do mesmo modo, usuários do Quicksy podem ser contatados facilmente adicionando +numerodetelefone@quicksy.im à sua lista de contatos. + +Tirando a sincronização com os contatos, a interface do usuário é o mais perto possível do Conversations. Isto permite que usuários eventualmente migrem do Quicksy para o Conversations sem precisar aprender novamente como o app funciona. + +Contatos sugeridos consistem de outros usuários do Quicksy e usuários regulares do Jabber/XMPP que inscreveram seu ID Jabber no Diretório do Quicksy (https://quicksy.im/#get-listed). + +AVISO: Para entrar (https://quicksy.im/enter/) seu ID Jabber no Diretório do Quicksy, uma taxa única será cobrada. + +Leia a Política de Privacidade (https://quicksy.im/#privacy) para mais informações. diff --git a/src/quicksy/fastlane/metadata/android/pt-BR/short_description.txt b/src/quicksy/fastlane/metadata/android/pt-BR/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..a7659fda0a276242a1d7d563b2ccaedd8d97eb08 --- /dev/null +++ b/src/quicksy/fastlane/metadata/android/pt-BR/short_description.txt @@ -0,0 +1 @@ +Jabber/XMPP com uma entrada e descoberta mais fácil From 233cf8ac555cca4d65f8f15d84d44e747eb4ba8e Mon Sep 17 00:00:00 2001 From: user11 Date: Sat, 14 Sep 2024 16:19:10 +0000 Subject: [PATCH 13/60] Translated using Weblate (Serbian) Currently translated at 100.0% (9 of 9 strings) Translation: Conversations/Android App (Quicksy) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-quicksy/sr/ --- src/quicksy/res/values-sr/strings.xml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/quicksy/res/values-sr/strings.xml b/src/quicksy/res/values-sr/strings.xml index a6b3daec9354f9ae75cdf8d94a67446c6227dd96..0f15a8fb566f8521c314d1e2b1cb63e0633be375 100644 --- a/src/quicksy/res/values-sr/strings.xml +++ b/src/quicksy/res/values-sr/strings.xml @@ -1,2 +1,12 @@ - \ No newline at end of file + + Временски период током којег је Quicksy утишан након што примети активност на другом уређају + Обавести све своје контакте када користиш Quicksy + Quicksy профилна слика + Quicksy није доступан у твојој земљи. + Није могуће оверити идентитет сервера. + Непозната безбедносна грешка. + Нема одзива приликом повезивања на сервер. + Слањем извештаја о грешкама помажеш даљем развоју Quicksy-ја + Да би наставио/ла да примаш обавештења, чак и када је екран угашен, требало би да додаш Quicksy у листу заштићених апликација. + \ No newline at end of file From 2883903bf216b4156a6069640151438913d79357 Mon Sep 17 00:00:00 2001 From: user11 Date: Sat, 14 Sep 2024 16:15:38 +0000 Subject: [PATCH 14/60] Translated using Weblate (Serbian) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-conversations/sr/ --- .../metadata/android/sr/full_description.txt | 39 +++++++++++++++++++ .../metadata/android/sr/short_description.txt | 1 + 2 files changed, 40 insertions(+) create mode 100644 src/conversations/fastlane/metadata/android/sr/full_description.txt create mode 100644 src/conversations/fastlane/metadata/android/sr/short_description.txt diff --git a/src/conversations/fastlane/metadata/android/sr/full_description.txt b/src/conversations/fastlane/metadata/android/sr/full_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..10f602f71998e6e17c4b4cbfa9d271cc2d285c98 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/sr/full_description.txt @@ -0,0 +1,39 @@ +Лагана за коришћење, поуздана, са малом потрошњом батерије. Има уграђену подршку за слике, групне преписке и e2e шифровање. + +Приципи дизајна: + +* Леп изглед и једноставност коришћења, без компромитовања безбедности и приватности +* Ослања се на постојеће, добро установљене протоколе +* Не захтева Google налог нити конкретно Google Cloud Messaging (GCM) +* Захтева минималан број дозвола + +Способности: + +* E2E шифровање уз OMEMO или OpenPGP +* Слање и примање слика +* Шифровани аудио и видео позиви (DTLS-SRTP) +* Интуитивно корисничко сучеље које прати смернице Android дизајна +* Слике / аватари за твоје контакте +* Синхронизација са десктоп клијентима +* Конференције (уз подршку за обележивачe) +* Интеграција са имеником +* Више истовремених налога / обједињени inbox +* Веома мали утицај на потрошњу батерије + +Conversations омогућава веома лако отварање налога на бесплатном серверу conversations.im. Поред тога, Conversations може да ради и уз било који други XMPP сервер. Многе XMPP сервере одржавају добровољци и бесплатни су за коришћење. + +XMPP способности: + +Conversations ради уз сваки XMPP сервер. Међутим XMPP је проширив протокол. Ова проширења су такође стандардизована у такозваним XEP-овима. Conversations има подршку за неколико тих проширења ради побољшања свеопштег корисничког искуства. Постоји шанса да твој тренутни XMPP сервер не подржава ова проширења. Да би максимално искористио/ла Conversations требало би да размислиш или о преласку на XMPP сервер који подржава ова проширења или - још боље - да успоставиш сопствени XMPP сервер за тебе и твоје пријатеље. + +Ови XEP-ови су - за сада: + +* XEP-0065: SOCKS5 Bytestreams (или mod_proxy65). Користи се за пребацивање фајлова ако су обе стране иза firewall-а (NAT). +* XEP-0163: Personal Eventing Protocol за аватаре +* XEP-0191: Blocking command омогућава blacklist-овање спамера или блокирање контаката без њиховог уклањања из твог списка. +* XEP-0198: Stream Management омогућава да XMPP преживи мање прекиде на мрежи и промене у TCP веза. +* XEP-0280: Message Carbons који аутоматски синхронизује поруке које шаљеш на свој десктоп клијент и са тим ти омогућава да се лако пребациш са мобилног клијента на десктоп клијент и обратно у оквиру исте преписке. +* XEP-0237: Roster Versioning углавном за уштеду количине пренетих података на непоузданим мобилним везама +* XEP-0313: Message Archive Management синхронизује историју порука са сервером. Усаглашава поруке које су послате док Conversations није био на вези. +* XEP-0352: Client State Indication обавештава сервер да ли је Conversations у позадини или не. Омогућава серверу да уштеди количину пренетих података спречавањем слања непотребних пакета. +* XEP-0363: HTTP File Upload омогућава дељење фајлова у конференцијама и са контактима који нису на вези. Захтева додатну компоненту на твом серверу. diff --git a/src/conversations/fastlane/metadata/android/sr/short_description.txt b/src/conversations/fastlane/metadata/android/sr/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9096599feeda36e38005a2131515f8785213f3b --- /dev/null +++ b/src/conversations/fastlane/metadata/android/sr/short_description.txt @@ -0,0 +1 @@ +Шифрована и лагана XMPP апликација за инстант поруке за твој мобилни телефон From 4a36aff4059937ea1e56c6aaec558a2465ff09dd Mon Sep 17 00:00:00 2001 From: user11 Date: Sat, 14 Sep 2024 16:20:43 +0000 Subject: [PATCH 15/60] Translated using Weblate (Serbian) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Quicksy) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-quicksy/sr/ --- .../metadata/android/sr/full_description.txt | 14 ++++++++++++++ .../metadata/android/sr/short_description.txt | 1 + 2 files changed, 15 insertions(+) create mode 100644 src/quicksy/fastlane/metadata/android/sr/full_description.txt create mode 100644 src/quicksy/fastlane/metadata/android/sr/short_description.txt diff --git a/src/quicksy/fastlane/metadata/android/sr/full_description.txt b/src/quicksy/fastlane/metadata/android/sr/full_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e00427ec7c9228f8945bbab3b40c501b7147cd7 --- /dev/null +++ b/src/quicksy/fastlane/metadata/android/sr/full_description.txt @@ -0,0 +1,14 @@ +Quicksy је варијанта популарног Jabber/XMPP клијента Conversations са аутоматским проналаском контаката. + +Пријавиш се својим бројем телефона и Quicksy ће ти аутоматски, на основу бројева телефона у твом именику, предложити могуће контакте. + +"Испод хаубе" Quicksy је комплетан Jabber клијент који ти омогућава да комуницираш са било којим корисником на било којем јавно федеративном серверу. Такође, Quicksy корисници могу бити контактирани од споља само додавањем +phonenumber@quicksy.im у твоју листу контаката. + +Поред синхронизације контаката, корисничко сучеље је с намером максимално близу Conversations клијенту. Ово корисницима омогућава да у неком тренутку пређу са Quicksy на Conversations без да морају поново да уче како апликација ради. + +Предложени контакти се састоје од других Quicksy корисника и уобичајених Jabber/XMPP корисника који су унели свој Jabber ID у Quicksy директоријум (https://quicksy.im/#get-listed). + +УСПУТ: Да унесеш (https://quicksy.im/enter/) свој Jabber ID у Quicksy директоријум +неопходна је једнократна новчана накнада за регистрацију. + +Прочитај Полису Приватности (https://quicksy.im/#privacy) за више детаља. diff --git a/src/quicksy/fastlane/metadata/android/sr/short_description.txt b/src/quicksy/fastlane/metadata/android/sr/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7d9a89cc3de50daa003fafc48c474eacef92e63 --- /dev/null +++ b/src/quicksy/fastlane/metadata/android/sr/short_description.txt @@ -0,0 +1 @@ +Jabber/XMPP са лаким приступом и лаким проналаском From f8f05dcc5c4908bf9aef4dc654623071d30de071 Mon Sep 17 00:00:00 2001 From: "lucasmz.dev" Date: Wed, 18 Sep 2024 03:22:27 +0000 Subject: [PATCH 16/60] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Quicksy) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-quicksy/pt_BR/ --- .../fastlane/metadata/android/pt-BR/full_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quicksy/fastlane/metadata/android/pt-BR/full_description.txt b/src/quicksy/fastlane/metadata/android/pt-BR/full_description.txt index 5d4c87541883fe6da5cf298758581623eee06daa..afde8ae3ad8c50ea63f26aefa8e7382a05aa20fa 100644 --- a/src/quicksy/fastlane/metadata/android/pt-BR/full_description.txt +++ b/src/quicksy/fastlane/metadata/android/pt-BR/full_description.txt @@ -8,6 +8,6 @@ Tirando a sincronização com os contatos, a interface do usuário é o mais per Contatos sugeridos consistem de outros usuários do Quicksy e usuários regulares do Jabber/XMPP que inscreveram seu ID Jabber no Diretório do Quicksy (https://quicksy.im/#get-listed). -AVISO: Para entrar (https://quicksy.im/enter/) seu ID Jabber no Diretório do Quicksy, uma taxa única será cobrada. +AVISO: Para entrar seu ID Jabber no Diretório do Quicksy (https://quicksy.im/enter/), uma taxa única será cobrada. Leia a Política de Privacidade (https://quicksy.im/#privacy) para mais informações. From ca8c47589542b103c269c43a8ba90a2829145109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Thu, 19 Sep 2024 13:53:15 +0000 Subject: [PATCH 17/60] Translated using Weblate (Estonian) Currently translated at 10.4% (109 of 1039 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/et/ --- src/main/res/values-et/strings.xml | 72 ++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/main/res/values-et/strings.xml b/src/main/res/values-et/strings.xml index ec802993cc1766a2fef828e426921a8b52a05a50..c04021a59c503075a68289c9d6c27c2ee8df665f 100644 --- a/src/main/res/values-et/strings.xml +++ b/src/main/res/values-et/strings.xml @@ -42,4 +42,76 @@ %d lugemata vestlus %d lugemata vestlust + Kas sa soovid, et kasutaja %s blokeering oleks eemaldatud ja ta saaks sulle sõnumeid saata? + Kas soovid blokeerida kõik kasutajad domeenist %s? + Kas soovid eemaldada blokeeringu kõikidelt kasutajatelt domeenist %s? + Blokeeritud + Kas sa soovid eemaldada %s järjehoidja? + Registreeri serveris uues kasutajakonto + Muuda salasõna serveris + Jaga… + Saada kutse kasutajale + Kutsu + Kontaktid + Kontakt + Katkesta + Seadista + Lisa + Muuda + Kustuta + Blokeeri + Eemalda blokeering + Salvesta + Sobib + %1$s on kokku jooksnud + Kui kasutad oma XMPP kontot ja saadad meile oma nutiseadme pinujälje, siis aitad meid %1$s rakenduse arendamisel. + Saada nüüd + Ära küsi enam kunagi + Kasutajakontoga ei saanud ühendust + Mitme kasutajakontoga ei saanud ühendust + Kasutajakontode kaldamiseks klõpsi + Kas soovid selle puuduva kontakti oma kontaktide loendisse lisada? + Lisa kontakt + Valmistume pildi saatmiseks + Valmistume piltide saatmiseks + Jagame faile. Palun oota… + Tühjenda ajalugu + Tühjenda vestluse ajalugu + Kas sa soovid eemaldada kõik selle vestluse sõnumid? +\n +\nHoiatus: See ei mõjuta muudes seadmetes ja serverites salvestatud samade sõnumite koopiaid. + Kustuta fail + Kas sa soovid selle faili? +\n +\nHoiatus: See ei mõjuta muudes seadmetes ja serverites salvestatud sama faili koopiaid. + Kustuta vestus hiljem + Vali seade + Saada sõnum krüptimata tekstina + Saada sõnum + Saada sõnum kasutajale %s + Saada krüptitud sõnum + Saada v\\OMEMO-krüptitud sõnum + Uus hüüdnimi on juba kasutusel + Saada sõnum krüptimata tekstina + Dekrüptimine ei õnnestunud. Võib-olla pole sul õiget privaatvõtit. + OpenKeychain + Üldist + Failide vastuvõtmine + Võta automaatselt vastu failid, mis on väiksemad kui… + Manused + Teavitus + LRD-märgutuli + Sõnumi saabumisel vilguta LED-märgutuld + Helin + Teavituse heli + Uute sõnumite märguhelin + Saabuvate kõnede helin + Värinaalarm + Anna uuest sõnumit märku värinaalarmiga + Kas sa soovid %s eemaldada oma kontaktide loendist? Selle toiminguga ei eemaldata temaga peetud vestlust. + Kontakt on blokeeritud + Kas sa soovid eemaldada %s järjehoidja ja selle vestluse arhiveerida? + Lisa fail + Kas sa soovid, et kasutaja %s oleks blokeeritud ega saaks sulle sõnumeid saata? + kohaletoimetamine ei õnnestunud \ No newline at end of file From 6fabe5b7c7115b0049e48f4360b0cfe5363882c7 Mon Sep 17 00:00:00 2001 From: LucasMZ Date: Sun, 15 Sep 2024 10:36:45 -0300 Subject: [PATCH 18/60] NAT and firewall are not interchangable While NAT can seem like one in a certain way, it ultimately isn't one and comes from an IPv4-only thought process and doesn't include how IPv6 works --- README.md | 2 +- .../fastlane/metadata/android/en-US/full_description.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d786660bf22def23ec1baff6573eef36405d7896..f82e1b18287ef04ec45ee86c9e6ef089acee2815 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ should consider either switching to an XMPP server that does or — even better run your own XMPP server for you and your friends. These XEP's are: * [XEP-0065: SOCKS5 Bytestreams](http://xmpp.org/extensions/xep-0065.html) will be used to transfer - files if both parties are behind a firewall (NAT). + files if both parties are behind a firewall or NAT. * [XEP-0163: Personal Eventing Protocol](http://xmpp.org/extensions/xep-0163.html) for avatars and OMEMO. * [XEP-0191: Blocking command](http://xmpp.org/extensions/xep-0191.html) lets you blacklist spammers or block contacts without removing them from your roster. diff --git a/src/conversations/fastlane/metadata/android/en-US/full_description.txt b/src/conversations/fastlane/metadata/android/en-US/full_description.txt index e30ca25c1ab6358fbc2fc3aa8758bd8c17ece282..bec4c377b4daa6a9f50c5fbfaa2bda0451caf60f 100644 --- a/src/conversations/fastlane/metadata/android/en-US/full_description.txt +++ b/src/conversations/fastlane/metadata/android/en-US/full_description.txt @@ -28,7 +28,7 @@ Conversations works with every XMPP server out there. However XMPP is an extensi These XEPs are - as of now: -* XEP-0065: SOCKS5 Bytestreams (or mod_proxy65). Will be used to transfer files if both parties are behind a firewall (NAT). +* XEP-0065: SOCKS5 Bytestreams (or mod_proxy65). Will be used to transfer files if both parties are behind a firewall or NAT. * XEP-0163: Personal Eventing Protocol for avatars * XEP-0191: Blocking command lets you blacklist spammers or block contacts without removing them from your roster. * XEP-0198: Stream Management allows XMPP to survive small network outages and changes of the underlying TCP connection. From dbf773b20378192b328a4b2d410dfa3450d2d143 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 21 Sep 2024 16:39:48 +0200 Subject: [PATCH 19/60] minor code clean up --- .../persistance/DatabaseBackend.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 3eb48a1c94c5c80f39dc97dfb0ea584d374733ba..e6ef09ad056fde58ab216fe552a1dfe8b4b428e8 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -1004,34 +1004,38 @@ public class DatabaseBackend extends SQLiteOpenHelper { } public boolean updateAccount(Account account) { - SQLiteDatabase db = this.getWritableDatabase(); - String[] args = {account.getUuid()}; - final int rows = db.update(Account.TABLENAME, account.getContentValues(), Account.UUID + "=?", args); + final var db = this.getWritableDatabase(); + final String[] args = {account.getUuid()}; + final int rows = + db.update(Account.TABLENAME, account.getContentValues(), Account.UUID + "=?", args); return rows == 1; } - public boolean deleteAccount(Account account) { - SQLiteDatabase db = this.getWritableDatabase(); - String[] args = {account.getUuid()}; + public boolean deleteAccount(final Account account) { + final var db = this.getWritableDatabase(); + final String[] args = {account.getUuid()}; final int rows = db.delete(Account.TABLENAME, Account.UUID + "=?", args); return rows == 1; } - public boolean updateMessage(Message message, boolean includeBody) { - SQLiteDatabase db = this.getWritableDatabase(); - String[] args = {message.getUuid()}; - ContentValues contentValues = message.getContentValues(); + public boolean updateMessage(final Message message, final boolean includeBody) { + final var db = this.getWritableDatabase(); + final String[] args = {message.getUuid()}; + final var contentValues = message.getContentValues(); contentValues.remove(Message.UUID); if (!includeBody) { contentValues.remove(Message.BODY); } - return db.update(Message.TABLENAME, message.getContentValues(), Message.UUID + "=?", args) == 1; + final int rows = db.update(Message.TABLENAME, contentValues, Message.UUID + "=?", args); + return rows == 1; } - public boolean updateMessage(Message message, String uuid) { - SQLiteDatabase db = this.getWritableDatabase(); - String[] args = {uuid}; - return db.update(Message.TABLENAME, message.getContentValues(), Message.UUID + "=?", args) == 1; + public boolean updateMessage(final Message message, final String uuid) { + final var db = this.getWritableDatabase(); + final String[] args = {uuid}; + final int rows = + db.update(Message.TABLENAME, message.getContentValues(), Message.UUID + "=?", args); + return rows == 1; } public void readRoster(Roster roster) { From d9dc869dba3565b3788d2d866df2a31b521b0f83 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 21 Sep 2024 16:41:20 +0200 Subject: [PATCH 20/60] update various dependencies --- build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 43f8afbb3d60c9acdb9d50124a1e1b520570eb06..8398fb69c602333faf04f4ff73e9c9386314327c 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ configurations { } dependencies { - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.2' implementation project(':libs:annotation') annotationProcessor project(':libs:annotation-processor') @@ -39,7 +39,7 @@ dependencies { implementation 'androidx.viewpager:viewpager:1.0.0' - playstoreImplementation('com.google.firebase:firebase-messaging:24.0.0') { + playstoreImplementation('com.google.firebase:firebase-messaging:24.0.1') { exclude group: 'com.google.firebase', module: 'firebase-core' exclude group: 'com.google.firebase', module: 'firebase-analytics' exclude group: 'com.google.firebase', module: 'firebase-measurement-connector' @@ -54,10 +54,10 @@ dependencies { implementation "androidx.preference:preference:1.2.1" implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'com.google.android.material:material:1.12.0' - implementation 'androidx.work:work-runtime:2.9.0' + implementation 'androidx.work:work-runtime:2.9.1' - implementation "androidx.emoji2:emoji2:1.4.0" - freeImplementation "androidx.emoji2:emoji2-bundled:1.4.0" + implementation "androidx.emoji2:emoji2:1.5.0" + freeImplementation "androidx.emoji2:emoji2-bundled:1.5.0" implementation 'org.bouncycastle:bcmail-jdk18on:1.78.1' implementation 'com.google.zxing:core:3.5.3' From a0de7d1b18c884b5eaa9e8ff16764f7cae02eb3c Mon Sep 17 00:00:00 2001 From: nautilusx Date: Sat, 21 Sep 2024 14:31:15 +0000 Subject: [PATCH 21/60] Translated using Weblate (German) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-conversations/de/ --- .../fastlane/metadata/android/de-DE/full_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/fastlane/metadata/android/de-DE/full_description.txt b/src/conversations/fastlane/metadata/android/de-DE/full_description.txt index d6b5d4b1ec2b42d2e38fdf952857969004b39384..755334362c87d92d3e93b24ec2e19e3b51cc1de0 100644 --- a/src/conversations/fastlane/metadata/android/de-DE/full_description.txt +++ b/src/conversations/fastlane/metadata/android/de-DE/full_description.txt @@ -28,7 +28,7 @@ Conversations funktioniert mit jedem XMPP-Server. XMPP ist jedoch ein erweiterba Diese XEPs sind es derzeit: -* XEP-0065: SOCKS5 Bytestreams (oder mod_proxy65). Wird für die Übertragung von Dateien verwendet, wenn sich beide Parteien hinter einer Firewall (NAT) befinden. +* XEP-0065: SOCKS5 Bytestreams (oder mod_proxy65). Wird für die Übertragung von Dateien verwendet, wenn sich beide Parteien hinter einer Firewall oder NAT befinden. * XEP-0163: Personal Eventing Protocol für Profilbilder * XEP-0191: Mit dem Blockierungsbefehl kannst du Spammer auf eine schwarze Liste setzen oder Kontakte blockieren, ohne sie aus deiner Liste zu entfernen. * XEP-0198: Stream Management ermöglicht es XMPP, kleinere Netzwerkausfälle und Änderungen der zugrunde liegenden TCP-Verbindung zu überstehen. From 2ded281bfc756c361f984042a5b603060784465d Mon Sep 17 00:00:00 2001 From: SomeTr Date: Sat, 21 Sep 2024 12:42:50 +0000 Subject: [PATCH 22/60] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-conversations/uk/ --- .../fastlane/metadata/android/uk/full_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/fastlane/metadata/android/uk/full_description.txt b/src/conversations/fastlane/metadata/android/uk/full_description.txt index 39971ed5571be157835f2e2b959d96f74a5c7f55..80f67afb1e8f0fba01ed571258a43ef1a9a8caa0 100644 --- a/src/conversations/fastlane/metadata/android/uk/full_description.txt +++ b/src/conversations/fastlane/metadata/android/uk/full_description.txt @@ -28,7 +28,7 @@ Conversations працює з будь-яким сервером XMPP. Прот На даний час підтримуються такі XEP: -* XEP-0065: SOCKS5 Bytestreams (або mod_proxy65). Використовується для передачі файлів, якщо обидві сторони знаходяться за брандмауером (NAT). +* XEP-0065: SOCKS5 Bytestreams (або mod_proxy65). Використовується для передачі файлів, якщо обидві сторони знаходяться за брандмауером або NAT. * XEP-0163: персональний протокол подій для аватарів * XEP-0191: команда блокування дозволяє Вам заносити спамерів у чорний список або блокувати контакти, не видаляючи їх зі свого списку. * XEP-0198: керування потоками дозволяє XMPP витримувати невеликі перебої в мережі та зміни основного TCP-з'єднання. From 685739ef1ea9000b321e830a7523d2b70ca8d941 Mon Sep 17 00:00:00 2001 From: Outbreak2096 Date: Sat, 21 Sep 2024 14:16:39 +0000 Subject: [PATCH 23/60] Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-conversations/zh_Hans/ --- .../fastlane/metadata/android/zh-CN/full_description.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conversations/fastlane/metadata/android/zh-CN/full_description.txt b/src/conversations/fastlane/metadata/android/zh-CN/full_description.txt index 87d4ecea0ae5c85b1e7cf7e9a3bac6aed32590e4..96cdff57cae47da73f7643f6506dd5c325c8e16e 100644 --- a/src/conversations/fastlane/metadata/android/zh-CN/full_description.txt +++ b/src/conversations/fastlane/metadata/android/zh-CN/full_description.txt @@ -20,7 +20,7 @@ * 多账号/统一消息栏 * 对电池寿命的影响非常小 -Conversations 使在免费的 conversations.im 服务器上创建账号变得非常简单。不过,Conversations 也适用于任何其他 XMPP 服务器。许多 XMPP 服务器都是由志愿者免费运行的。 +您可以很容易地使用 Conversations 在免费的 conversations.im 服务器上创建账号。不过,Conversations 也适用于任何其他 XMPP 服务器。许多 XMPP 服务器由志愿者免费运行。 XMPP 功能: @@ -28,7 +28,7 @@ Conversations 适用于所有 XMPP 服务器。然而,XMPP 是一种可扩展 到目前为止,这些 XMPP 扩展协议是: -* XEP-0065:SOCKS5 字节流(或 mod_proxy65)。如果双方都在防火墙(NAT)后面,将用于传输文件。 +* XEP-0065:SOCKS5 字节流(或 mod_proxy65)。如果双方都在防火墙或 NAT 后面,将用于传输文件。 * XEP-0163:个人事件协议(头像) * XEP-0191:屏蔽命令可让您将垃圾消息发送者列入黑名单或屏蔽的联系人中,而不会将其从花名册中删除。 * XEP-0198:流管理允许 XMPP 在小规模网络中断和底层 TCP 连接发生变化时继续运行。 From 6a8fbaadb8b45e96f776f29efac97b46926be3da Mon Sep 17 00:00:00 2001 From: Outbreak2096 Date: Sat, 21 Sep 2024 14:20:10 +0000 Subject: [PATCH 24/60] Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 100.0% (70 of 70 strings) Translation: Conversations/App Store Metadata (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/zh_Hans/ --- fastlane/metadata/android/zh-CN/changelogs/4211704.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 fastlane/metadata/android/zh-CN/changelogs/4211704.txt diff --git a/fastlane/metadata/android/zh-CN/changelogs/4211704.txt b/fastlane/metadata/android/zh-CN/changelogs/4211704.txt new file mode 100644 index 0000000000000000000000000000000000000000..8499115544947f042f1f944c1a06cddb46cb8448 --- /dev/null +++ b/fastlane/metadata/android/zh-CN/changelogs/4211704.txt @@ -0,0 +1,3 @@ +* 提供更大的自动下载文件的大小 +* 在“服务器信息”中提供更多信息 +* 各种错误修复 From 18120b87547c070570ab2ee10585374632f12ab4 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 21 Sep 2024 16:49:44 +0200 Subject: [PATCH 25/60] version bump to 2.16.7 --- CHANGELOG.md | 4 ++++ build.gradle | 4 ++-- fastlane/metadata/android/en-US/changelogs/4211804.txt | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/4211804.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index d64e76c2803a52e9f82b408e40487fe8fe078d13..b5d72e162f7f1b7103e1eedf4cdfb0dd140484f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### Version 2.16.7 + +* Add timeout to call initiation + ### Version 2.16.6 * Offer higher automatic file accept values diff --git a/build.gradle b/build.gradle index 8398fb69c602333faf04f4ff73e9c9386314327c..42f9857e15b2e53ebedbf1115be6d25be6f59a4b 100644 --- a/build.gradle +++ b/build.gradle @@ -102,8 +102,8 @@ android { defaultConfig { minSdkVersion 23 targetSdkVersion 34 - versionCode 42117 - versionName "2.16.6" + versionCode 42118 + versionName "2.16.7" archivesBaseName += "-$versionName" applicationId "eu.siacs.conversations" resValue "string", "applicationId", applicationId diff --git a/fastlane/metadata/android/en-US/changelogs/4211804.txt b/fastlane/metadata/android/en-US/changelogs/4211804.txt new file mode 100644 index 0000000000000000000000000000000000000000..96986442d5be591179014a447b36eba54d696060 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/4211804.txt @@ -0,0 +1 @@ +* Add timeout to call initiation From 2d3863f2376e39eebd03b3af6d70bb0dcd54966b Mon Sep 17 00:00:00 2001 From: ghose Date: Sun, 22 Sep 2024 07:21:52 +0000 Subject: [PATCH 26/60] Translated using Weblate (Galician) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-conversations/gl/ --- .../fastlane/metadata/android/gl-ES/full_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/fastlane/metadata/android/gl-ES/full_description.txt b/src/conversations/fastlane/metadata/android/gl-ES/full_description.txt index 9bdcf9042de371fcd868b9cf9e7d5ad8bc155e57..7b17cefd23514a819a846ba14be545c4c1097b0b 100644 --- a/src/conversations/fastlane/metadata/android/gl-ES/full_description.txt +++ b/src/conversations/fastlane/metadata/android/gl-ES/full_description.txt @@ -29,7 +29,7 @@ Conversations da soporte a un par delas que axudan a mellorar a experiencia de u Estes XEPs son - neste intre: -* XEP-0065: SOCKS5 Bytestreams (ou mod_proxy65). Usado para a transferencia de ficheiros se as dúas partes están detrás dun cortalumes (NAT). +* XEP-0065: SOCKS5 Bytestreams (ou mod_proxy65). Usado para a transferencia de ficheiros se as dúas partes están detrás dun cortalumes ou NAT. * XEP-0163: Personal Eventing Protocol para os avatares * XEP-0191: O bloqueo de ordes permiteche bloquear spammer ou contactos sen eliminalos das túas listaxes. * XEP-0198: Stream Management permite que XMPP sobreviva a caídas da rede e cambios na conexión TCP. From b5ed39f7d2516cdc0277e21ece4b89de6b0fbf33 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Sun, 22 Sep 2024 09:30:56 +0000 Subject: [PATCH 27/60] Translated using Weblate (Polish) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-conversations/pl/ --- .../fastlane/metadata/android/pl-PL/full_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/fastlane/metadata/android/pl-PL/full_description.txt b/src/conversations/fastlane/metadata/android/pl-PL/full_description.txt index 442e1e8263a4a57ba82f80f6b310bdb36ed53cef..e3635e96bf5574195a5a3e46560bd55896f127e2 100644 --- a/src/conversations/fastlane/metadata/android/pl-PL/full_description.txt +++ b/src/conversations/fastlane/metadata/android/pl-PL/full_description.txt @@ -28,7 +28,7 @@ Conversations działa z każdym dostępnym serwerem XMPP, jednak XMPP to rozsze Obecnie są obsługiwane następujące rozszerzenia: -* XEP-0065: SOCKS5 Bytestreams (lub mod_proxy65). Będzie używany do przesyłania plików jeżeli obie strony znajdują się za zaporą (NAT); +* XEP-0065: SOCKS5 Bytestreams (lub mod_proxy65). Będzie używany do przesyłania plików jeżeli obie strony znajdują się za zaporą lub NAT; * XEP-0163: Personal Eventing Protocol dla awatarów; * XEP-0191: Blocking Command umożliwia ochronę przed spamerami lub blokowanie bez usuwanie ich z rostera; * XEP-0198: Stream Management pozwala na przetrwanie krótkich braków połączenia z siecią oraz zmian używanego połączenia TCP; From 43c92e7a41b98e6b1c46c82c42908a26220118db Mon Sep 17 00:00:00 2001 From: Stephan-P Date: Sun, 22 Sep 2024 03:09:05 +0000 Subject: [PATCH 28/60] Translated using Weblate (Dutch) Currently translated at 100.0% (2 of 2 strings) Translation: Conversations/App Store Metadata (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata-conversations/nl/ --- .../fastlane/metadata/android/nl-NL/full_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/fastlane/metadata/android/nl-NL/full_description.txt b/src/conversations/fastlane/metadata/android/nl-NL/full_description.txt index 3d12812f9cb3e361709c6a42382032b4e8752877..9261da0288eddb7f5029d38b9a927fb6986dc2c5 100644 --- a/src/conversations/fastlane/metadata/android/nl-NL/full_description.txt +++ b/src/conversations/fastlane/metadata/android/nl-NL/full_description.txt @@ -28,7 +28,7 @@ Conversations werkt met elke bestaande XMPP-server. XMPP is echter een uitbreidb Deze XEP's zijn - vanaf nu: -* XEP-0065: SOCKS5 Bytestreams (or mod_proxy65). Wordt gebruikt om bestanden over te dragen als beide partijen achter een firewall zitten (NAT). +* XEP-0065: SOCKS5 Bytestreams (or mod_proxy65). Wordt gebruikt om bestanden over te dragen als beide partijen achter een firewall of NAT zitten. * XEP-0163: Personal Eventing Protocol for avatars * XEP-0191: Blocking command laat je spammers op de zwarte lijst zetten of contacten blokkeren zonder ze uit je selectie te verwijderen. * XEP-0198: Stream Management stelt XMPP in staat om kleine netwerkuitval en veranderingen van de onderliggende TCP-verbinding te overleven. From 99e5add0b098d7537e870a4cedbc921a672834b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Mon, 23 Sep 2024 05:31:33 +0000 Subject: [PATCH 29/60] Translated using Weblate (Estonian) Currently translated at 11.4% (119 of 1039 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/et/ --- src/main/res/values-et/strings.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/res/values-et/strings.xml b/src/main/res/values-et/strings.xml index c04021a59c503075a68289c9d6c27c2ee8df665f..02465e529f16863b9dbd7bf3b6a08bffa323c9a0 100644 --- a/src/main/res/values-et/strings.xml +++ b/src/main/res/values-et/strings.xml @@ -114,4 +114,18 @@ Lisa fail Kas sa soovid, et kasutaja %s oleks blokeeritud ega saaks sulle sõnumeid saata? kohaletoimetamine ei õnnestunud + %1$s kasutab sõnumite krüptimiseks ja dekrüptimiseks ning sinu avalike võtmete haldamiseks rakendust <b>OpenKeychain</b>.<br><br>Ta on litsentseeritud GPLv3+ alusel ning leidub nii F-Droidi kui Google Play rakendustepoodides.<br><br><small>(Palun käivita %1$s hiljem uuesti.)</small> + Käivita uuesti + Paigalda + Palun paigalda rakendus OpenKeychain + pakume… + ootame… + OpenPGP võtit ei leidu + Kuna sõnumi saaja pole avaldanud oma avalikku võtit, siis sinu sõnumi krüptimine ei õnnestu. +\n +\nPalu, et ta seadistaks OpenPGP. + OpenPGP võtmeid ei leidu + Kuna sõnumi saajad pole avaldanud oma avalikke võtmeid, siis sinu sõnumi krüptimine ei õnnestu. +\n +\nPalu, et nad seadistaks OpenPGP. \ No newline at end of file From 41057ffc6597c70aeaa88667b09e31278c4c37b0 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 21 Sep 2024 18:22:29 +0200 Subject: [PATCH 30/60] add DB columns for occupant id and reactions --- .../conversations/entities/Bookmark.java | 8 +- .../entities/IndividualMessage.java | 51 +++++++------ .../siacs/conversations/entities/Message.java | 73 ++++++++++++------- .../conversations/entities/MucOptions.java | 6 ++ .../conversations/entities/Reaction.java | 43 +++++++++++ .../conversations/parser/MessageParser.java | 11 ++- .../persistance/DatabaseBackend.java | 8 +- .../services/XmppConnectionService.java | 3 +- 8 files changed, 144 insertions(+), 59 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/entities/Reaction.java diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index eb8f3328dd64c8d9f8240f011f69320b2f1d94f9..72abd718d5dcf637f16be479ecf2e56ee32a08f6 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -9,7 +9,6 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import java.lang.ref.WeakReference; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -61,11 +60,11 @@ public class Bookmark extends Element implements ListItem { return bookmarks; } - public static Map parseFromPubsub(Element pubsub, Account account) { - if (pubsub == null) { + public static Map parseFromPubSub(final Element pubSub, final Account account) { + if (pubSub == null) { return Collections.emptyMap(); } - final Element items = pubsub.findChild("items"); + final Element items = pubSub.findChild("items"); if (items != null && Namespace.BOOKMARKS2.equals(items.getAttribute("node"))) { final Map bookmarks = new HashMap<>(); for(Element item : items.getChildren()) { @@ -99,6 +98,7 @@ public class Bookmark extends Element implements ListItem { } final Bookmark bookmark = new Bookmark(account); bookmark.jid = InvalidJid.getNullForInvalid(item.getAttributeAsJid("id")); + // TODO verify that we only use bare jids and ignore full jids if (bookmark.jid == null) { return null; } diff --git a/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java b/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java index 8f416a301aae5799ca52ab585e6f3092d48ce37b..f13d0e25458d4c495d4a745494856af9cc37b60b 100644 --- a/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java +++ b/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java @@ -31,6 +31,7 @@ package eu.siacs.conversations.entities; import android.database.Cursor; +import java.util.Collection; import java.util.Set; import eu.siacs.conversations.ui.adapter.MessageAdapter; @@ -43,8 +44,8 @@ public class IndividualMessage extends Message { super(conversation); } - private IndividualMessage(Conversational conversation, String uuid, String conversationUUid, Jid counterpart, Jid trueCounterpart, String body, long timeSent, int encryption, int status, int type, boolean carbon, String remoteMsgId, String relativeFilePath, String serverMsgId, String fingerprint, boolean read, String edited, boolean oob, String errorMessage, Set readByMarkers, boolean markable, boolean deleted, String bodyLanguage) { - super(conversation, uuid, conversationUUid, counterpart, trueCounterpart, body, timeSent, encryption, status, type, carbon, remoteMsgId, relativeFilePath, serverMsgId, fingerprint, read, edited, oob, errorMessage, readByMarkers, markable, deleted, bodyLanguage); + private IndividualMessage(Conversational conversation, String uuid, String conversationUUid, Jid counterpart, Jid trueCounterpart, String body, long timeSent, int encryption, int status, int type, boolean carbon, String remoteMsgId, String relativeFilePath, String serverMsgId, String fingerprint, boolean read, String edited, boolean oob, String errorMessage, Set readByMarkers, boolean markable, boolean deleted, String bodyLanguage, String occupantId, Collection reactions) { + super(conversation, uuid, conversationUUid, counterpart, trueCounterpart, body, timeSent, encryption, status, type, carbon, remoteMsgId, relativeFilePath, serverMsgId, fingerprint, read, edited, oob, errorMessage, readByMarkers, markable, deleted, bodyLanguage, occupantId, reactions); } @Override @@ -73,7 +74,7 @@ public class IndividualMessage extends Message { public static Message fromCursor(Cursor cursor, Conversational conversation) { Jid jid; try { - String value = cursor.getString(cursor.getColumnIndex(COUNTERPART)); + String value = cursor.getString(cursor.getColumnIndexOrThrow(COUNTERPART)); if (value != null) { jid = Jid.of(value); } else { @@ -86,7 +87,7 @@ public class IndividualMessage extends Message { } Jid trueCounterpart; try { - String value = cursor.getString(cursor.getColumnIndex(TRUE_COUNTERPART)); + String value = cursor.getString(cursor.getColumnIndexOrThrow(TRUE_COUNTERPART)); if (value != null) { trueCounterpart = Jid.of(value); } else { @@ -96,28 +97,30 @@ public class IndividualMessage extends Message { trueCounterpart = null; } return new IndividualMessage(conversation, - cursor.getString(cursor.getColumnIndex(UUID)), - cursor.getString(cursor.getColumnIndex(CONVERSATION)), + cursor.getString(cursor.getColumnIndexOrThrow(UUID)), + cursor.getString(cursor.getColumnIndexOrThrow(CONVERSATION)), jid, trueCounterpart, - cursor.getString(cursor.getColumnIndex(BODY)), - cursor.getLong(cursor.getColumnIndex(TIME_SENT)), - cursor.getInt(cursor.getColumnIndex(ENCRYPTION)), - cursor.getInt(cursor.getColumnIndex(STATUS)), - cursor.getInt(cursor.getColumnIndex(TYPE)), - cursor.getInt(cursor.getColumnIndex(CARBON)) > 0, - cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)), - cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)), - cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID)), - cursor.getString(cursor.getColumnIndex(FINGERPRINT)), - cursor.getInt(cursor.getColumnIndex(READ)) > 0, - cursor.getString(cursor.getColumnIndex(EDITED)), - cursor.getInt(cursor.getColumnIndex(OOB)) > 0, - cursor.getString(cursor.getColumnIndex(ERROR_MESSAGE)), - ReadByMarker.fromJsonString(cursor.getString(cursor.getColumnIndex(READ_BY_MARKERS))), - cursor.getInt(cursor.getColumnIndex(MARKABLE)) > 0, - cursor.getInt(cursor.getColumnIndex(DELETED)) > 0, - cursor.getString(cursor.getColumnIndex(BODY_LANGUAGE)) + cursor.getString(cursor.getColumnIndexOrThrow(BODY)), + cursor.getLong(cursor.getColumnIndexOrThrow(TIME_SENT)), + cursor.getInt(cursor.getColumnIndexOrThrow(ENCRYPTION)), + cursor.getInt(cursor.getColumnIndexOrThrow(STATUS)), + cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)), + cursor.getInt(cursor.getColumnIndexOrThrow(CARBON)) > 0, + cursor.getString(cursor.getColumnIndexOrThrow(REMOTE_MSG_ID)), + cursor.getString(cursor.getColumnIndexOrThrow(RELATIVE_FILE_PATH)), + cursor.getString(cursor.getColumnIndexOrThrow(SERVER_MSG_ID)), + cursor.getString(cursor.getColumnIndexOrThrow(FINGERPRINT)), + cursor.getInt(cursor.getColumnIndexOrThrow(READ)) > 0, + cursor.getString(cursor.getColumnIndexOrThrow(EDITED)), + cursor.getInt(cursor.getColumnIndexOrThrow(OOB)) > 0, + cursor.getString(cursor.getColumnIndexOrThrow(ERROR_MESSAGE)), + ReadByMarker.fromJsonString(cursor.getString(cursor.getColumnIndexOrThrow(READ_BY_MARKERS))), + cursor.getInt(cursor.getColumnIndexOrThrow(MARKABLE)) > 0, + cursor.getInt(cursor.getColumnIndexOrThrow(DELETED)) > 0, + cursor.getString(cursor.getColumnIndexOrThrow(BODY_LANGUAGE)), + cursor.getString(cursor.getColumnIndexOrThrow(OCCUPANT_ID)), + Reaction.fromString(cursor.getString(cursor.getColumnIndexOrThrow(REACTIONS))) ); } } diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index a359cf34c2cff3970879992301bae33d9539294d..372165b70e5a73404e1840f1016eeb23988c25a0 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -16,6 +16,8 @@ import org.json.JSONException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -86,6 +88,8 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable public static final String READ_BY_MARKERS = "readByMarkers"; public static final String MARKABLE = "markable"; public static final String DELETED = "deleted"; + public static final String OCCUPANT_ID = "occupantId"; + public static final String REACTIONS = "reactions"; public static final String ME_COMMAND = "/me "; public static final String ERROR_MESSAGE_CANCELLED = "eu.siacs.conversations.cancelled"; @@ -117,6 +121,8 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable private String axolotlFingerprint = null; private String errorMessage = null; private Set readByMarkers = new CopyOnWriteArraySet<>(); + private String occupantId; + private Collection reactions = Collections.emptyList(); private Boolean isGeoUri = null; private Boolean isEmojisOnly = null; @@ -155,7 +161,9 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable null, false, false, - null); + null, + null, + Collections.emptyList()); } public Message(Conversation conversation, int status, int type, final String remoteMsgId) { @@ -180,7 +188,9 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable null, false, false, - null); + null, + null, + Collections.emptyList()); } protected Message(final Conversational conversation, final String uuid, final String conversationUUid, final Jid counterpart, @@ -189,7 +199,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable final String remoteMsgId, final String relativeFilePath, final String serverMsgId, final String fingerprint, final boolean read, final String edited, final boolean oob, final String errorMessage, final Set readByMarkers, - final boolean markable, final boolean deleted, final String bodyLanguage) { + final boolean markable, final boolean deleted, final String bodyLanguage, final String occupantId, final Collection reactions) { this.conversation = conversation; this.uuid = uuid; this.conversationUuid = conversationUUid; @@ -213,32 +223,37 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable this.markable = markable; this.deleted = deleted; this.bodyLanguage = bodyLanguage; + this.occupantId = occupantId; + this.reactions = reactions; } public static Message fromCursor(Cursor cursor, Conversation conversation) { return new Message(conversation, - cursor.getString(cursor.getColumnIndex(UUID)), - cursor.getString(cursor.getColumnIndex(CONVERSATION)), - fromString(cursor.getString(cursor.getColumnIndex(COUNTERPART))), - fromString(cursor.getString(cursor.getColumnIndex(TRUE_COUNTERPART))), - cursor.getString(cursor.getColumnIndex(BODY)), - cursor.getLong(cursor.getColumnIndex(TIME_SENT)), - cursor.getInt(cursor.getColumnIndex(ENCRYPTION)), - cursor.getInt(cursor.getColumnIndex(STATUS)), - cursor.getInt(cursor.getColumnIndex(TYPE)), - cursor.getInt(cursor.getColumnIndex(CARBON)) > 0, - cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)), - cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)), - cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID)), - cursor.getString(cursor.getColumnIndex(FINGERPRINT)), - cursor.getInt(cursor.getColumnIndex(READ)) > 0, - cursor.getString(cursor.getColumnIndex(EDITED)), - cursor.getInt(cursor.getColumnIndex(OOB)) > 0, - cursor.getString(cursor.getColumnIndex(ERROR_MESSAGE)), - ReadByMarker.fromJsonString(cursor.getString(cursor.getColumnIndex(READ_BY_MARKERS))), - cursor.getInt(cursor.getColumnIndex(MARKABLE)) > 0, - cursor.getInt(cursor.getColumnIndex(DELETED)) > 0, - cursor.getString(cursor.getColumnIndex(BODY_LANGUAGE)) + cursor.getString(cursor.getColumnIndexOrThrow(UUID)), + cursor.getString(cursor.getColumnIndexOrThrow(CONVERSATION)), + fromString(cursor.getString(cursor.getColumnIndexOrThrow(COUNTERPART))), + fromString(cursor.getString(cursor.getColumnIndexOrThrow(TRUE_COUNTERPART))), + cursor.getString(cursor.getColumnIndexOrThrow(BODY)), + cursor.getLong(cursor.getColumnIndexOrThrow(TIME_SENT)), + cursor.getInt(cursor.getColumnIndexOrThrow(ENCRYPTION)), + cursor.getInt(cursor.getColumnIndexOrThrow(STATUS)), + cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)), + cursor.getInt(cursor.getColumnIndexOrThrow(CARBON)) > 0, + cursor.getString(cursor.getColumnIndexOrThrow(REMOTE_MSG_ID)), + cursor.getString(cursor.getColumnIndexOrThrow(RELATIVE_FILE_PATH)), + cursor.getString(cursor.getColumnIndexOrThrow(SERVER_MSG_ID)), + cursor.getString(cursor.getColumnIndexOrThrow(FINGERPRINT)), + cursor.getInt(cursor.getColumnIndexOrThrow(READ)) > 0, + cursor.getString(cursor.getColumnIndexOrThrow(EDITED)), + cursor.getInt(cursor.getColumnIndexOrThrow(OOB)) > 0, + cursor.getString(cursor.getColumnIndexOrThrow(ERROR_MESSAGE)), + ReadByMarker.fromJsonString(cursor.getString(cursor.getColumnIndexOrThrow(READ_BY_MARKERS))), + cursor.getInt(cursor.getColumnIndexOrThrow(MARKABLE)) > 0, + cursor.getInt(cursor.getColumnIndexOrThrow(DELETED)) > 0, + cursor.getString(cursor.getColumnIndexOrThrow(BODY_LANGUAGE)), + cursor.getString(cursor.getColumnIndexOrThrow(OCCUPANT_ID)), + Reaction.fromString(cursor.getString(cursor.getColumnIndexOrThrow(REACTIONS))) + ); } @@ -270,7 +285,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable @Override public ContentValues getContentValues() { - ContentValues values = new ContentValues(); + final var values = new ContentValues(); values.put(UUID, uuid); values.put(CONVERSATION, conversationUuid); if (counterpart == null) { @@ -305,6 +320,8 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable values.put(MARKABLE, markable ? 1 : 0); values.put(DELETED, deleted ? 1 : 0); values.put(BODY_LANGUAGE, bodyLanguage); + values.put(OCCUPANT_ID, occupantId); + values.put(REACTIONS, Reaction.toString(this.reactions)); return values; } @@ -708,6 +725,10 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable return oob; } + public void setOccupantId(final String id) { + this.occupantId = id; + } + public static class MergeSeparator { } diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 0f6580005da1e6fe8e261b20b572026285c27958..7c0c5a8741f6c218ccccae90b78b64143d54a6b7 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -11,6 +11,7 @@ import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.utils.JidHelper; import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.forms.Data; @@ -226,6 +227,11 @@ public class MucOptions { return getFeatures().contains("http://jabber.org/protocol/muc#stable_id"); } + public boolean occupantId() { + final var features = getFeatures(); + return features.contains(Namespace.OCCUPANT_ID); + } + public User deleteUser(Jid jid) { User user = findUserByFullJid(jid); if (user != null) { diff --git a/src/main/java/eu/siacs/conversations/entities/Reaction.java b/src/main/java/eu/siacs/conversations/entities/Reaction.java new file mode 100644 index 0000000000000000000000000000000000000000..c8b1f8b9bef5b66ccb85aff02c34e6a9f14db613 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/entities/Reaction.java @@ -0,0 +1,43 @@ +package eu.siacs.conversations.entities; + +import com.google.common.base.Strings; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +import eu.siacs.conversations.xmpp.Jid; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +public class Reaction { + + private static final Gson GSON = new Gson(); + + public final String reaction; + public final Jid jid; + public final String occupantId; + + public Reaction(final String reaction, final Jid jid, final String occupantId) { + this.reaction = reaction; + this.jid = jid; + this.occupantId = occupantId; + } + + + public static String toString(final Collection reactions) { + return (reactions == null || reactions.isEmpty()) ? null : GSON.toJson(reactions); + } + + public static Collection fromString(final String asString) { + if ( Strings.isNullOrEmpty(asString)) { + return Collections.emptyList(); + } + try { + return GSON.fromJson(asString,new TypeToken>(){}.getType()); + } catch (final JsonSyntaxException e) { + return Collections.emptyList(); + } + } +} diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 3f40fde3306dee22787764f9a80cdf1359b700cb..fc741e26fce95484f1aeedb4ad416377da4b87fc 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -54,6 +54,7 @@ import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.carbons.Received; import im.conversations.android.xmpp.model.carbons.Sent; import im.conversations.android.xmpp.model.forward.Forwarded; +import im.conversations.android.xmpp.model.occupant.OccupantId; public class MessageParser extends AbstractParser implements Consumer { @@ -631,8 +632,14 @@ public class MessageParser extends AbstractParser implements Consumer= 52) { + db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.OCCUPANT_ID + " TEXT"); + db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.REACTIONS + " TEXT"); + } } private void canonicalizeJids(SQLiteDatabase db) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index b7935c3b5362027c51f4251a716df9c25a96d71a..44d84438ed559d19e8b3a6874b1bd8b0afbce3ca 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -155,7 +155,6 @@ import eu.siacs.conversations.xml.LocalizedContent; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.InvalidJid; import eu.siacs.conversations.xmpp.Jid; -import eu.siacs.conversations.xmpp.OnBindListener; import eu.siacs.conversations.xmpp.OnContactStatusChanged; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnMessageAcknowledged; @@ -1836,7 +1835,7 @@ public class XmppConnectionService extends Service { sendIqPacket(account, retrieve, (response) -> { if (response.getType() == Iq.Type.RESULT) { final Element pubsub = response.findChild("pubsub", Namespace.PUBSUB); - final Map bookmarks = Bookmark.parseFromPubsub(pubsub, account); + final Map bookmarks = Bookmark.parseFromPubSub(pubsub, account); processBookmarksInitial(account, bookmarks, true); } }); From 68c473af12a6a0347f28f5d097d545454ede8911 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 21 Sep 2024 18:44:09 +0200 Subject: [PATCH 31/60] take occupant id into account for edits --- src/main/java/eu/siacs/conversations/entities/Message.java | 4 ++++ .../java/eu/siacs/conversations/parser/MessageParser.java | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 372165b70e5a73404e1840f1016eeb23988c25a0..d0630df0386fc1f9a939caf0c41738c51d176f38 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -729,6 +729,10 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable this.occupantId = id; } + public String getOccupantId() { + return this.occupantId; + } + public static class MergeSeparator { } diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index fc741e26fce95484f1aeedb4ad416377da4b87fc..879a2416d6a5930647007fd971ff5792617b937c 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -676,9 +676,14 @@ public class MessageParser extends AbstractParser implements Consumer Date: Sun, 22 Sep 2024 13:16:33 +0200 Subject: [PATCH 32/60] bump webrtc to m129 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 42f9857e15b2e53ebedbf1115be6d25be6f59a4b..22bf2b6fd53e6970ad005d7abe54a1c47a170838 100644 --- a/build.gradle +++ b/build.gradle @@ -87,7 +87,7 @@ dependencies { implementation 'com.google.guava:guava:32.1.3-android' quicksyImplementation 'io.michaelrocks:libphonenumber-android:8.13.35' - implementation 'im.conversations.webrtc:webrtc-android:119.0.1' + implementation 'im.conversations.webrtc:webrtc-android:129.0.0' } ext { From 52bbb3e9df1b2b712afc38dec9fcf2854647dd54 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 22 Sep 2024 16:16:41 +0200 Subject: [PATCH 33/60] remove invalid debug build options --- build.gradle | 5 ----- 1 file changed, 5 deletions(-) diff --git a/build.gradle b/build.gradle index 22bf2b6fd53e6970ad005d7abe54a1c47a170838..60f80071c2c958d13a0e0156f2fa9642fea4273d 100644 --- a/build.gradle +++ b/build.gradle @@ -202,11 +202,6 @@ android { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } - debug { - shrinkResources true - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } } From 4931039aee6eea5aec713f01711bc2f1a4713374 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 25 Sep 2024 09:47:39 +0200 Subject: [PATCH 34/60] catch browser not found in OK dialog --- .../siacs/conversations/ui/XmppActivity.java | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index c4d6dc4df0ab25b1196be337c0a6ec5dbae1d856..c27238838a13cfc72747032d9290d4f111b5aa22 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -177,9 +177,11 @@ public abstract class XmppActivity extends ActionBarActivity { } protected void hideToast() { - if (mToast != null) { - mToast.cancel(); + final var toast = this.mToast; + if (toast == null) { + return; } + toast.cancel(); } protected void replaceToast(String msg) { @@ -261,23 +263,28 @@ public abstract class XmppActivity extends ActionBarActivity { XmppConnectionService.class)); finish(); }); - builder.setPositiveButton(getString(R.string.install), + builder.setPositiveButton( + getString(R.string.install), (dialog, which) -> { - Uri uri = Uri - .parse("market://details?id=org.sufficientlysecure.keychain"); - Intent marketIntent = new Intent(Intent.ACTION_VIEW, - uri); - PackageManager manager = getApplicationContext() - .getPackageManager(); - List infos = manager - .queryIntentActivities(marketIntent, 0); - if (infos.size() > 0) { - startActivity(marketIntent); + final Uri uri = + Uri.parse("market://details?id=org.sufficientlysecure.keychain"); + Intent marketIntent = new Intent(Intent.ACTION_VIEW, uri); + PackageManager manager = getApplicationContext().getPackageManager(); + final var infos = manager.queryIntentActivities(marketIntent, 0); + if (infos.isEmpty()) { + final var website = Uri.parse("http://www.openkeychain.org/"); + final Intent browserIntent = new Intent(Intent.ACTION_VIEW, website); + try { + startActivity(browserIntent); + } catch (final ActivityNotFoundException e) { + Toast.makeText( + this, + R.string.application_found_to_open_website, + Toast.LENGTH_LONG) + .show(); + } } else { - uri = Uri.parse("http://www.openkeychain.org/"); - Intent browserIntent = new Intent( - Intent.ACTION_VIEW, uri); - startActivity(browserIntent); + startActivity(marketIntent); } finish(); }); From fff53c45479bf103078ac3bba0d3d41110a74fc0 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 25 Sep 2024 09:48:14 +0200 Subject: [PATCH 35/60] handle rare case of power manager not available --- .../services/XmppConnectionService.java | 6 ++- .../conversations/utils/WakeLockHelper.java | 42 ++++++++++--------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 44d84438ed559d19e8b3a6874b1bd8b0afbce3ca..b42ee55a2ecf1e8dc46a4efbab1ba4f5e6767001 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1249,7 +1249,11 @@ public class XmppConnectionService extends Service { } final PowerManager powerManager = getSystemService(PowerManager.class); - this.wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Conversations:Service"); + if (powerManager != null) { + this.wakeLock = + powerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "Conversations:Service"); + } toggleForegroundService(); updateUnreadCountBadge(); diff --git a/src/main/java/eu/siacs/conversations/utils/WakeLockHelper.java b/src/main/java/eu/siacs/conversations/utils/WakeLockHelper.java index 9fb38ef86eede1658e50a74f074d29cb26676f51..3ddb5738b6122792c628953ce15f1295b6e267ec 100644 --- a/src/main/java/eu/siacs/conversations/utils/WakeLockHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/WakeLockHelper.java @@ -36,24 +36,28 @@ import eu.siacs.conversations.Config; public class WakeLockHelper { - public static void acquire(final PowerManager.WakeLock wakeLock) { - try { - wakeLock.acquire(2000); - } catch (final RuntimeException e) { - Log.d(Config.LOGTAG, "unable to acquire wake lock", e); - } - } + public static void acquire(final PowerManager.WakeLock wakeLock) { + if (wakeLock == null) { + Log.d(Config.LOGTAG, "could not acquire WakeLock. PowerManager was null"); + return; + } + try { + wakeLock.acquire(2000); + } catch (final RuntimeException e) { + Log.d(Config.LOGTAG, "Could not acquire WakeLock", e); + } + } - public static void release(final PowerManager.WakeLock wakeLock) { - if (wakeLock == null) { - return; - } - try { - if (wakeLock.isHeld()) { - wakeLock.release(); - } - } catch (final RuntimeException e) { - Log.d(Config.LOGTAG, "unable to release wake lock", e); - } - } + public static void release(final PowerManager.WakeLock wakeLock) { + if (wakeLock == null) { + return; + } + try { + if (wakeLock.isHeld()) { + wakeLock.release(); + } + } catch (final RuntimeException e) { + Log.d(Config.LOGTAG, "unable to release wake lock", e); + } + } } From cf02f37c0f1e088820eba4c00aed44b59ba6ef02 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 25 Sep 2024 20:36:04 +0200 Subject: [PATCH 36/60] rudimentary 'XEP-0444: Message Reactions' support --- build.gradle | 7 +- .../conversations/entities/Conversation.java | 11 ++ .../siacs/conversations/entities/Message.java | 12 ++ .../conversations/entities/MucOptions.java | 9 ++ .../conversations/entities/Reaction.java | 149 +++++++++++++++++- .../generator/MessageGenerator.java | 18 +++ .../conversations/parser/AbstractParser.java | 4 +- .../conversations/parser/MessageParser.java | 63 +++++++- .../conversations/parser/PresenceParser.java | 6 +- .../services/XmppConnectionService.java | 48 ++++++ .../conversations/ui/BindingAdapters.java | 117 ++++++++++++++ .../ui/ContactDetailsActivity.java | 7 +- .../ui/ConversationFragment.java | 35 ++-- .../siacs/conversations/ui/XmppActivity.java | 38 +++++ .../ui/adapter/ListItemAdapter.java | 6 +- .../ui/adapter/MessageAdapter.java | 37 ++++- .../jingle/JingleFileTransferConnection.java | 1 + .../res/drawable/ic_add_reaction_24dp.xml | 12 ++ src/main/res/layout/dialog_add_reaction.xml | 18 +++ src/main/res/layout/item_emoji_button.xml | 8 + src/main/res/layout/item_message_received.xml | 43 +++-- src/main/res/layout/item_message_sent.xml | 43 +++-- .../{list_item_tag.xml => item_tag.xml} | 0 src/main/res/menu/message_context.xml | 5 + src/main/res/values/strings.xml | 2 + 25 files changed, 644 insertions(+), 55 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/ui/BindingAdapters.java create mode 100644 src/main/res/drawable/ic_add_reaction_24dp.xml create mode 100644 src/main/res/layout/dialog_add_reaction.xml create mode 100644 src/main/res/layout/item_emoji_button.xml rename src/main/res/layout/{list_item_tag.xml => item_tag.xml} (100%) diff --git a/build.gradle b/build.gradle index 60f80071c2c958d13a0e0156f2fa9642fea4273d..e1fc3a11742c86c5dec65936df14994d2ef932e3 100644 --- a/build.gradle +++ b/build.gradle @@ -53,11 +53,12 @@ dependencies { implementation 'androidx.cardview:cardview:1.0.0' implementation "androidx.preference:preference:1.2.1" implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' - implementation 'com.google.android.material:material:1.12.0' + implementation 'com.google.android.material:material:1.13.0-alpha06' implementation 'androidx.work:work-runtime:2.9.1' implementation "androidx.emoji2:emoji2:1.5.0" freeImplementation "androidx.emoji2:emoji2-bundled:1.5.0" + implementation "androidx.emoji2:emoji2-emojipicker:1.5.0" implementation 'org.bouncycastle:bcmail-jdk18on:1.78.1' implementation 'com.google.zxing:core:3.5.3' @@ -102,8 +103,8 @@ android { defaultConfig { minSdkVersion 23 targetSdkVersion 34 - versionCode 42118 - versionName "2.16.7" + versionCode 42119 + versionName "2.17.0-beta" archivesBaseName += "-$versionName" applicationId "eu.siacs.conversations" resValue "string", "applicationId", applicationId diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 223a48efa238dfdacb02b0139e20bab2a88e17c5..f2b17015f85c84e4afa5c2fbec20b1e679b65a85 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -394,6 +394,17 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl return null; } + public Message findMessageWithUuidOrRemoteId(final String id) { + synchronized (this.messages) { + for (final Message message : this.messages) { + if (id.equals(message.getUuid()) || id.equals(message.getRemoteMsgId())) { + return message; + } + } + } + return null; + } + public Message findMessageWithRemoteIdAndCounterpart(String id, Jid counterpart, boolean received, boolean carbon) { synchronized (this.messages) { for (int i = this.messages.size() - 1; i >= 0; --i) { diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index d0630df0386fc1f9a939caf0c41738c51d176f38..75efa1f3a6147110d951c9d71a591bcc5b0282ed 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -733,6 +733,18 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable return this.occupantId; } + public Collection getReactions() { + return this.reactions; + } + + public Reaction.Aggregated getAggregatedReactions() { + return Reaction.aggregated(this.reactions); + } + + public void setReactions(final Collection reactions) { + this.reactions = reactions; + } + public static class MergeSeparator { } diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 7c0c5a8741f6c218ccccae90b78b64143d54a6b7..0acca4600d7df8d3fd7cb5f8364dd9a024985b7c 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -764,6 +764,7 @@ public class MucOptions { private Avatar avatar; private final MucOptions options; private ChatState chatState = Config.DEFAULT_CHAT_STATE; + private String occupantId; public User(MucOptions options, Jid fullJid) { this.options = options; @@ -927,5 +928,13 @@ public class MucOptions { public String getAvatarName() { return getConversation().getName().toString(); } + + public void setOccupantId(final String occupantId) { + this.occupantId = occupantId; + } + + public String getOccupantId() { + return this.occupantId; + } } } diff --git a/src/main/java/eu/siacs/conversations/entities/Reaction.java b/src/main/java/eu/siacs/conversations/entities/Reaction.java index c8b1f8b9bef5b66ccb85aff02c34e6a9f14db613..eff7be74b096c1acc7c6020a992d452e025009b4 100644 --- a/src/main/java/eu/siacs/conversations/entities/Reaction.java +++ b/src/main/java/eu/siacs/conversations/entities/Reaction.java @@ -1,43 +1,178 @@ package eu.siacs.conversations.entities; +import androidx.annotation.NonNull; + +import com.google.common.base.MoreObjects; import com.google.common.base.Strings; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimaps; +import com.google.common.collect.Ordering; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; import eu.siacs.conversations.xmpp.Jid; +import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; public class Reaction { - private static final Gson GSON = new Gson(); + public static final List SUGGESTIONS = + Arrays.asList( + "\u2764\uFE0F", + "\uD83D\uDC4D", + "\uD83D\uDC4E", + "\uD83D\uDE02", + "\uD83D\uDE2E", + "\uD83D\uDE22"); + + private static final Gson GSON; + + static { + GSON = new GsonBuilder().registerTypeAdapter(Jid.class, new JidTypeAdapter()).create(); + } public final String reaction; - public final Jid jid; + public final boolean received; + public final Jid from; + public final Jid trueJid; public final String occupantId; - public Reaction(final String reaction, final Jid jid, final String occupantId) { + public Reaction( + final String reaction, + boolean received, + final Jid from, + final Jid trueJid, + final String occupantId) { this.reaction = reaction; - this.jid = jid; + this.received = received; + this.from = from; + this.trueJid = trueJid; this.occupantId = occupantId; } - public static String toString(final Collection reactions) { return (reactions == null || reactions.isEmpty()) ? null : GSON.toJson(reactions); } public static Collection fromString(final String asString) { - if ( Strings.isNullOrEmpty(asString)) { + if (Strings.isNullOrEmpty(asString)) { return Collections.emptyList(); } try { - return GSON.fromJson(asString,new TypeToken>(){}.getType()); + return GSON.fromJson(asString, new TypeToken>() {}.getType()); } catch (final JsonSyntaxException e) { return Collections.emptyList(); } } + + public static Collection withOccupantId( + final Collection existing, + final Collection reactions, + final boolean received, + final Jid from, + final Jid trueJid, + final String occupantId) { + final ImmutableList.Builder builder = new ImmutableList.Builder<>(); + builder.addAll(Collections2.filter(existing, e -> !occupantId.equals(e.occupantId))); + builder.addAll( + Collections2.transform( + reactions, r -> new Reaction(r, received, from, trueJid, occupantId))); + return builder.build(); + } + + @NonNull + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("reaction", reaction) + .add("received", received) + .add("from", from) + .add("trueJid", trueJid) + .add("occupantId", occupantId) + .toString(); + } + + public static Collection withFrom( + final Collection existing, + final Collection reactions, + final boolean received, + final Jid from) { + final ImmutableList.Builder builder = new ImmutableList.Builder<>(); + builder.addAll( + Collections2.filter(existing, e -> !from.asBareJid().equals(e.from.asBareJid()))); + builder.addAll( + Collections2.transform( + reactions, r -> new Reaction(r, received, from, null, null))); + return builder.build(); + } + + private static class JidTypeAdapter extends TypeAdapter { + @Override + public void write(final JsonWriter out, final Jid value) throws IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value.toEscapedString()); + } + } + + @Override + public Jid read(final JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } else if (in.peek() == JsonToken.STRING) { + final String value = in.nextString(); + return Jid.ofEscaped(value); + } + throw new IOException("Unexpected token"); + } + } + + public static Aggregated aggregated(final Collection reactions) { + final Map aggregatedReactions = + Maps.transformValues( + Multimaps.index(reactions, r -> r.reaction).asMap(), Collection::size); + final List> sortedList = + Ordering.from( + Comparator.comparingInt( + (Map.Entry o) -> o.getValue())) + .reverse() + .immutableSortedCopy(aggregatedReactions.entrySet()); + return new Aggregated( + sortedList, + ImmutableSet.copyOf( + Collections2.transform( + Collections2.filter(reactions, r -> !r.received), + r -> r.reaction))); + } + + public static final class Aggregated { + + public final List> reactions; + public final Set ourReactions; + + private Aggregated( + final List> reactions, Set ourReactions) { + this.reactions = reactions; + this.ourReactions = ourReactions; + } + } } diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index f3823dee04c2848d6280e58e9b4a453f5386c790..ff5dddb0f7e4f6fd0f4e31362957a139dd491f38 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -2,6 +2,7 @@ package eu.siacs.conversations.generator; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.Locale; import java.util.TimeZone; @@ -22,6 +23,8 @@ import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager; import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection; import eu.siacs.conversations.xmpp.jingle.Media; import eu.siacs.conversations.xmpp.jingle.stanzas.Reason; +import im.conversations.android.xmpp.model.reactions.Reaction; +import im.conversations.android.xmpp.model.reactions.Reactions; public class MessageGenerator extends AbstractGenerator { private static final String OMEMO_FALLBACK_MESSAGE = "I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo"; @@ -167,6 +170,21 @@ public class MessageGenerator extends AbstractGenerator { return packet; } + public im.conversations.android.xmpp.model.stanza.Message reaction(final Conversational conversation, final String reactingTo, final Collection ourReactions) { + final boolean groupChat = conversation.getMode() == Conversational.MODE_MULTI; + final Jid to = conversation.getJid().asBareJid(); + final im.conversations.android.xmpp.model.stanza.Message packet = new im.conversations.android.xmpp.model.stanza.Message(); + packet.setType(groupChat ? im.conversations.android.xmpp.model.stanza.Message.Type.GROUPCHAT : im.conversations.android.xmpp.model.stanza.Message.Type.CHAT); + packet.setTo(to); + final var reactions = packet.addExtension(new Reactions()); + reactions.setId(reactingTo); + for(final String ourReaction : ourReactions) { + reactions.addExtension(new Reaction(ourReaction)); + } + packet.addChild("store", "urn:xmpp:hints"); + return packet; + } + public im.conversations.android.xmpp.model.stanza.Message conferenceSubject(Conversation conversation, String subject) { im.conversations.android.xmpp.model.stanza.Message packet = new im.conversations.android.xmpp.model.stanza.Message(); packet.setType(im.conversations.android.xmpp.model.stanza.Message.Type.GROUPCHAT); diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java index 2e2cb26843ff7ddc2402b958fe656155cc1fed37..ac42857fd1dc96866a9cd011c6c38cf87679d2ee 100644 --- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java +++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java @@ -137,7 +137,7 @@ public abstract class AbstractParser { return parseItem(conference,item, null); } - public static MucOptions.User parseItem(Conversation conference, Element item, Jid fullJid) { + public static MucOptions.User parseItem(final Conversation conference, Element item, Jid fullJid) { final String local = conference.getJid().getLocal(); final String domain = conference.getJid().getDomain().toEscapedString(); String affiliation = item.getAttribute("affiliation"); @@ -150,7 +150,7 @@ public abstract class AbstractParser { fullJid = null; } } - Jid realJid = item.getAttributeAsJid("jid"); + final Jid realJid = item.getAttributeAsJid("jid"); MucOptions.User user = new MucOptions.User(conference.getMucOptions(), fullJid); if (InvalidJid.isValid(realJid)) { user.setRealJid(realJid); diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 879a2416d6a5930647007fd971ff5792617b937c..5f05f0a73276e5a50a51611f8f9c88e279fce34d 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -32,6 +32,7 @@ import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversational; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; +import eu.siacs.conversations.entities.Reaction; import eu.siacs.conversations.entities.ReadByMarker; import eu.siacs.conversations.entities.ReceiptRequest; import eu.siacs.conversations.entities.RtpSessionStatus; @@ -55,6 +56,7 @@ import im.conversations.android.xmpp.model.carbons.Received; import im.conversations.android.xmpp.model.carbons.Sent; import im.conversations.android.xmpp.model.forward.Forwarded; import im.conversations.android.xmpp.model.occupant.OccupantId; +import im.conversations.android.xmpp.model.reactions.Reactions; public class MessageParser extends AbstractParser implements Consumer { @@ -430,7 +432,8 @@ public class MessageParser extends AbstractParser implements Consumer f; f = getForwardedMessagePacket(original, Received.class); f = f == null ? getForwardedMessagePacket(original, Sent.class) : f; @@ -447,6 +450,7 @@ public class MessageParser extends AbstractParser implements Consumer reactions) { + if (message.getConversation() instanceof Conversation conversation) { + final String reactToId; + final Collection combinedReactions; + if (conversation.getMode() == Conversational.MODE_MULTI) { + final var self = conversation.getMucOptions().getSelf(); + final String occupantId = self.getOccupantId(); + if (Strings.isNullOrEmpty(occupantId)) { + Log.d(Config.LOGTAG, "occupant id not found for reaction in MUC"); + return false; + } + reactToId = message.getServerMsgId(); + combinedReactions = + Reaction.withOccupantId( + message.getReactions(), + reactions, + false, + self.getFullJid(), + conversation.getAccount().getJid(), + occupantId); + } else { + if (message.isCarbon() || message.getStatus() == Message.STATUS_RECEIVED) { + reactToId = message.getRemoteMsgId(); + } else { + reactToId = message.getUuid(); + } + combinedReactions = + Reaction.withFrom( + message.getReactions(), + reactions, + false, + conversation.getAccount().getJid()); + } + if (Strings.isNullOrEmpty(reactToId)) { + return false; + } + final var reactionMessage = + mMessageGenerator.reaction(conversation, reactToId, reactions); + sendMessagePacket(conversation.getAccount(), reactionMessage); + message.setReactions(combinedReactions); + updateMessage(message, false); + return true; + } else { + return false; + } + } + public MemorizingTrustManager getMemorizingTrustManager() { return this.mMemorizingTrustManager; } diff --git a/src/main/java/eu/siacs/conversations/ui/BindingAdapters.java b/src/main/java/eu/siacs/conversations/ui/BindingAdapters.java new file mode 100644 index 0000000000000000000000000000000000000000..6f6b4e8bebba341dbc61ca9c81ec7cb747167b95 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/BindingAdapters.java @@ -0,0 +1,117 @@ +package eu.siacs.conversations.ui; + +import android.view.View; + +import com.google.android.material.chip.Chip; +import com.google.android.material.chip.ChipGroup; +import com.google.android.material.color.MaterialColors; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableSet; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Reaction; + +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.function.Consumer; + +public class BindingAdapters { + + public static void setReactionsOnReceived( + final ChipGroup chipGroup, + final Reaction.Aggregated reactions, + final Consumer> onModifiedReactions, + final Runnable addReaction) { + setReactions(chipGroup, reactions, true, onModifiedReactions, addReaction); + } + + public static void setReactionsOnSent( + final ChipGroup chipGroup, + final Reaction.Aggregated reactions, + final Consumer> onModifiedReactions) { + setReactions(chipGroup, reactions, false, onModifiedReactions, null); + } + + private static void setReactions( + final ChipGroup chipGroup, + final Reaction.Aggregated aggregated, + final boolean onReceived, + final Consumer> onModifiedReactions, + final Runnable addReaction) { + final var context = chipGroup.getContext(); + final List> reactions = aggregated.reactions; + if (reactions == null || reactions.isEmpty()) { + chipGroup.setVisibility(View.GONE); + } else { + chipGroup.removeAllViews(); + chipGroup.setVisibility(View.VISIBLE); + for (final Map.Entry reaction : reactions) { + final var emoji = reaction.getKey(); + final var count = reaction.getValue(); + final Chip chip = new Chip(chipGroup.getContext()); + chip.setEnsureMinTouchTargetSize(false); + chip.setChipStartPadding(0.0f); + chip.setChipEndPadding(0.0f); + if (count == 1) { + chip.setText(emoji); + } else { + chip.setText(String.format(Locale.ENGLISH, "%s %d", emoji, count)); + } + final boolean oneOfOurs = aggregated.ourReactions.contains(emoji); + // received = surface; sent = surface high matches bubbles + if (oneOfOurs) { + chip.setChipBackgroundColor( + MaterialColors.getColorStateListOrNull( + context, + com.google.android.material.R.attr + .colorSurfaceContainerHighest)); + } else { + chip.setChipBackgroundColor( + MaterialColors.getColorStateListOrNull( + context, + com.google.android.material.R.attr.colorSurfaceContainerLow)); + } + chip.setOnClickListener( + v -> { + if (oneOfOurs) { + onModifiedReactions.accept( + ImmutableSet.copyOf( + Collections2.filter( + aggregated.ourReactions, + r -> !r.equals(emoji)))); + } else { + onModifiedReactions.accept( + new ImmutableSet.Builder() + .addAll(aggregated.ourReactions) + .add(emoji) + .build()); + } + }); + chipGroup.addView(chip); + } + if (onReceived) { + final Chip chip = new Chip(chipGroup.getContext()); + chip.setChipIconResource(R.drawable.ic_add_reaction_24dp); + chip.setChipStrokeColor( + MaterialColors.getColorStateListOrNull( + chipGroup.getContext(), + com.google.android.material.R.attr.colorTertiary)); + chip.setChipBackgroundColor( + MaterialColors.getColorStateListOrNull( + chipGroup.getContext(), + com.google.android.material.R.attr.colorTertiaryContainer)); + chip.setChipIconTint( + MaterialColors.getColorStateListOrNull( + chipGroup.getContext(), + com.google.android.material.R.attr.colorOnTertiaryContainer)); + chip.setEnsureMinTouchTargetSize(false); + chip.setTextEndPadding(0.0f); + chip.setTextStartPadding(0.0f); + chip.setOnClickListener(v -> addReaction.run()); + chipGroup.addView(chip); + } + } + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index 3b27ed76ee14b1c8d1e5f0cf048d0918fc17ce48..80b82763c4805a5768bc7c1c3c822a3ceb75a838 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -28,7 +28,6 @@ import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import androidx.core.view.ViewCompat; import androidx.databinding.DataBindingUtil; @@ -521,7 +520,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp final ImmutableList.Builder viewIdBuilder = new ImmutableList.Builder<>(); for (final ListItem.Tag tag : tagList) { final String name = tag.getName(); - final TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag, binding.tags, false); + final TextView tv = (TextView) inflater.inflate(R.layout.item_tag, binding.tags, false); tv.setText(name); tv.setBackgroundTintList(ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(this,XEP0392Helper.rgbFromNick(name)))); final int id = ViewCompat.generateViewId(); @@ -533,7 +532,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp final TextView tv = (TextView) inflater.inflate( - R.layout.list_item_tag, binding.tags, false); + R.layout.item_tag, binding.tags, false); tv.setText(R.string.blocked); tv.setBackgroundTintList(ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(tv.getContext(), ContextCompat.getColor(tv.getContext(),R.color.gray_800)))); final int id = ViewCompat.generateViewId(); @@ -546,7 +545,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp final TextView tv = (TextView) inflater.inflate( - R.layout.list_item_tag, binding.tags, false); + R.layout.item_tag, binding.tags, false); UIHelper.setStatus(tv, status); final int id = ViewCompat.generateViewId(); tv.setId(id); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 06f66d637805a3f3b10dd8e7e7c846b8b3c29b6a..3d4b54e621fbd0ce3b7b1459f17ccafb4667aed9 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -1310,20 +1310,21 @@ public class ConversationFragment extends XmppFragment || t instanceof HttpDownloadConnection); activity.getMenuInflater().inflate(R.menu.message_context, menu); menu.setHeaderTitle(R.string.message_options); + final MenuItem addReaction = menu.findItem(R.id.action_add_reaction); final MenuItem reportAndBlock = menu.findItem(R.id.action_report_and_block); - MenuItem openWith = menu.findItem(R.id.open_with); - MenuItem copyMessage = menu.findItem(R.id.copy_message); - MenuItem copyLink = menu.findItem(R.id.copy_link); - MenuItem quoteMessage = menu.findItem(R.id.quote_message); - MenuItem retryDecryption = menu.findItem(R.id.retry_decryption); - MenuItem correctMessage = menu.findItem(R.id.correct_message); - MenuItem shareWith = menu.findItem(R.id.share_with); - MenuItem sendAgain = menu.findItem(R.id.send_again); - MenuItem copyUrl = menu.findItem(R.id.copy_url); - MenuItem downloadFile = menu.findItem(R.id.download_file); - MenuItem cancelTransmission = menu.findItem(R.id.cancel_transmission); - MenuItem deleteFile = menu.findItem(R.id.delete_file); - MenuItem showErrorMessage = menu.findItem(R.id.show_error_message); + final MenuItem openWith = menu.findItem(R.id.open_with); + final MenuItem copyMessage = menu.findItem(R.id.copy_message); + final MenuItem copyLink = menu.findItem(R.id.copy_link); + final MenuItem quoteMessage = menu.findItem(R.id.quote_message); + final MenuItem retryDecryption = menu.findItem(R.id.retry_decryption); + final MenuItem correctMessage = menu.findItem(R.id.correct_message); + final MenuItem shareWith = menu.findItem(R.id.share_with); + final MenuItem sendAgain = menu.findItem(R.id.send_again); + final MenuItem copyUrl = menu.findItem(R.id.copy_url); + final MenuItem downloadFile = menu.findItem(R.id.download_file); + final MenuItem cancelTransmission = menu.findItem(R.id.cancel_transmission); + final MenuItem deleteFile = menu.findItem(R.id.delete_file); + final MenuItem showErrorMessage = menu.findItem(R.id.show_error_message); final boolean unInitiatedButKnownSize = MessageUtils.unInitiatedButKnownSize(m); final boolean showError = m.getStatus() == Message.STATUS_SEND_FAILED @@ -1340,6 +1341,7 @@ public class ConversationFragment extends XmppFragment reportAndBlock.setVisible(true); } } + addReaction.setVisible(!showError && !m.isDeleted()); if (!m.isFileOrImage() && !encrypted && !m.isGeoUri() @@ -1466,6 +1468,9 @@ public class ConversationFragment extends XmppFragment case R.id.action_report_and_block: reportMessage(selectedMessage); return true; + case R.id.action_add_reaction: + addReaction(selectedMessage); + return true; default: return super.onContextItemSelected(item); } @@ -2127,6 +2132,10 @@ public class ConversationFragment extends XmppFragment } } + private void addReaction(final Message message) { + activity.addReaction(message, reactions -> activity.xmppConnectionService.sendReactions(message, reactions)); + } + private void reportMessage(final Message message) { BlockContactDialog.show(activity, conversation.getContact(), message.getServerMsgId()); } diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index c27238838a13cfc72747032d9290d4f111b5aa22..25d334915d86710184c0d3742b1505b011556cb0 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -53,18 +53,21 @@ import androidx.databinding.DataBindingUtil; import com.google.android.material.color.MaterialColors; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableSet; import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.BuildConfig; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.PgpEngine; +import eu.siacs.conversations.databinding.DialogAddReactionBinding; import eu.siacs.conversations.databinding.DialogQuickeditBinding; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Presences; +import eu.siacs.conversations.entities.Reaction; import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.BarcodeProvider; import eu.siacs.conversations.services.QuickConversationsService; @@ -85,8 +88,11 @@ import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.concurrent.RejectedExecutionException; +import java.util.function.Consumer; public abstract class XmppActivity extends ActionBarActivity { @@ -291,6 +297,38 @@ public abstract class XmppActivity extends ActionBarActivity { builder.create().show(); } + public void addReaction(final Message message, Consumer> callback) { + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); + final var layoutInflater = this.getLayoutInflater(); + final DialogAddReactionBinding viewBinding = + DataBindingUtil.inflate(layoutInflater, R.layout.dialog_add_reaction, null, false); + builder.setView(viewBinding.getRoot()); + final var dialog = builder.create(); + for (final String emoji : Reaction.SUGGESTIONS) { + final Button button = + (Button) + layoutInflater.inflate( + R.layout.item_emoji_button, viewBinding.emojis, false); + viewBinding.emojis.addView(button); + button.setText(emoji); + button.setOnClickListener( + v -> { + final var aggregated = message.getAggregatedReactions(); + if (aggregated.ourReactions.contains(emoji)) { + callback.accept(aggregated.ourReactions); + } else { + final ImmutableSet.Builder reactionBuilder = + new ImmutableSet.Builder<>(); + reactionBuilder.addAll(aggregated.ourReactions); + reactionBuilder.add(emoji); + callback.accept(reactionBuilder.build()); + } + dialog.dismiss(); + }); + } + dialog.show(); + } + protected void deleteAccount(final Account account) { this.deleteAccount(account, null); } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java index 4f9311392978e6d6980fb7d04b5f51ad51ba70af..290c52079d9a39476b56d63eb1bfb29f5fc72981 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java @@ -93,7 +93,7 @@ public class ListItemAdapter extends ArrayAdapter { final ImmutableList.Builder viewIdBuilder = new ImmutableList.Builder<>(); for (final ListItem.Tag tag : tags) { final String name = tag.getName(); - final TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag, viewHolder.tags, false); + final TextView tv = (TextView) inflater.inflate(R.layout.item_tag, viewHolder.tags, false); tv.setText(name); tv.setBackgroundTintList(ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(getContext(),XEP0392Helper.rgbFromNick(name)))); tv.setOnClickListener(this.onTagTvClick); @@ -107,7 +107,7 @@ public class ListItemAdapter extends ArrayAdapter { final TextView tv = (TextView) inflater.inflate( - R.layout.list_item_tag, viewHolder.tags, false); + R.layout.item_tag, viewHolder.tags, false); tv.setText(R.string.blocked); tv.setBackgroundTintList(ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(tv.getContext(),ContextCompat.getColor(tv.getContext(),R.color.gray_800)))); final int id = ViewCompat.generateViewId(); @@ -120,7 +120,7 @@ public class ListItemAdapter extends ArrayAdapter { final TextView tv = (TextView) inflater.inflate( - R.layout.list_item_tag, viewHolder.tags, false); + R.layout.item_tag, viewHolder.tags, false); UIHelper.setStatus(tv, status); final int id = ViewCompat.generateViewId(); tv.setId(id); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index e422aac15d50d658c8d7b7d822a6178c1985936f..caa0d3667bf930dcffda0ff3376db6b1efbb54b1 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -15,10 +15,12 @@ import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import android.util.DisplayMetrics; +import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.ArrayAdapter; +import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; @@ -33,17 +35,24 @@ import androidx.annotation.Nullable; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.widget.ImageViewCompat; +import androidx.databinding.DataBindingUtil; +import androidx.emoji2.emojipicker.EmojiViewItem; +import androidx.emoji2.emojipicker.RecentEmojiProvider; import com.google.android.material.button.MaterialButton; +import com.google.android.material.chip.ChipGroup; import com.google.android.material.color.MaterialColors; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.FingerprintStatus; +import eu.siacs.conversations.databinding.DialogAddReactionBinding; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversational; @@ -56,6 +65,7 @@ import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.NotificationService; import eu.siacs.conversations.ui.Activities; +import eu.siacs.conversations.ui.BindingAdapters; import eu.siacs.conversations.ui.ConversationFragment; import eu.siacs.conversations.ui.ConversationsActivity; import eu.siacs.conversations.ui.XmppActivity; @@ -77,12 +87,14 @@ import eu.siacs.conversations.utils.TimeFrameUtils; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.mam.MamReference; +import kotlin.coroutines.Continuation; import java.net.URI; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Locale; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -767,6 +779,7 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.time = view.findViewById(R.id.message_time); viewHolder.indicatorReceived = view.findViewById(R.id.indicator_received); viewHolder.audioPlayer = view.findViewById(R.id.audio_player); + viewHolder.reactions = view.findViewById(R.id.reactions); break; case RECEIVED: view = @@ -783,6 +796,7 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.indicatorReceived = view.findViewById(R.id.indicator_received); viewHolder.encryption = view.findViewById(R.id.message_encryption); viewHolder.audioPlayer = view.findViewById(R.id.audio_player); + viewHolder.reactions = view.findViewById(R.id.reactions); break; case STATUS: view = @@ -1059,13 +1073,33 @@ public class MessageAdapter extends ArrayAdapter { CryptoHelper.encryptionTypeToText(message.getEncryption())); } } + BindingAdapters.setReactionsOnReceived( + viewHolder.reactions, + message.getAggregatedReactions(), + reactions -> sendReactions(message, reactions), + () -> addReaction(message)); + } else if (type == SENT) { + BindingAdapters.setReactionsOnSent( + viewHolder.reactions, + message.getAggregatedReactions(), + reactions -> sendReactions(message, reactions)); } displayStatus(viewHolder, message, type, bubbleColor); - return view; } + private void sendReactions(final Message message, final Collection reactions) { + if (activity.xmppConnectionService.sendReactions(message, reactions)) { + return; + } + Toast.makeText(activity, R.string.could_not_add_reaction, Toast.LENGTH_LONG).show(); + } + + private void addReaction(final Message message) { + activity.addReaction(message, reactions -> activity.xmppConnectionService.sendReactions(message,reactions)); + } + private void promptOpenKeychainInstall(View view) { activity.showInstallPgpDialog(); } @@ -1260,5 +1294,6 @@ public class MessageAdapter extends ArrayAdapter { protected ImageView contact_picture; protected TextView status_message; protected TextView encryption; + protected ChipGroup reactions; } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java index cb8e1d48da2eea7e4184252f101e8026156ba1a0..712b7ccb2fa1bec643de6554d64155d65ef91f92 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java @@ -589,6 +589,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection } terminateTransport(); final State target = reasonToState(wrapper.reason); + // TODO check if we were already terminated transitionOrThrow(target); finish(); } diff --git a/src/main/res/drawable/ic_add_reaction_24dp.xml b/src/main/res/drawable/ic_add_reaction_24dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..f0f431b5b707b5d8908b7f20dd7d1edeb3e2dd47 --- /dev/null +++ b/src/main/res/drawable/ic_add_reaction_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/layout/dialog_add_reaction.xml b/src/main/res/layout/dialog_add_reaction.xml new file mode 100644 index 0000000000000000000000000000000000000000..4eda335e28bb81040dc78443985edd032887e113 --- /dev/null +++ b/src/main/res/layout/dialog_add_reaction.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/layout/item_emoji_button.xml b/src/main/res/layout/item_emoji_button.xml new file mode 100644 index 0000000000000000000000000000000000000000..0e1711f7c1af7bb335450f5921d117dcb15bad2b --- /dev/null +++ b/src/main/res/layout/item_emoji_button.xml @@ -0,0 +1,8 @@ + +