Compare commits

...

102 commits

Author SHA1 Message Date
Evgeny
16cf91902c
blog: update v6.3 blog post (#5735) 2025-03-09 20:18:58 +00:00
Evgeny Poberezkin
ed625347bd
ios: v6.3, build 269 2025-03-09 16:08:49 +00:00
Stanislav Dmitrenko
4bd95c8e4e
ios: fix random crashes in chat on iOS 18 (#5734) 2025-03-09 11:22:47 +00:00
Evgeny
9dfa68bf57
blog: update v6.3 release post (#5733)
* blog: update v6.3 release post

* update post, server page

* update

* headers
2025-03-08 23:28:33 +00:00
sh
3188d9f087
docs: add reproducibility section (#5732) 2025-03-08 20:53:27 +00:00
Evgeny Poberezkin
89dddab060
6.3: ios 268, android 279, desktop 96 2025-03-07 18:18:43 +00:00
Stanislav Dmitrenko
f31372a771
android, desktop: fix link preview (#5725)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-03-07 17:10:57 +00:00
Stanislav Dmitrenko
3412ceba01
android, desktop: fix group members duplicates (#5727)
* android, desktop: fix group members duplicates

* optimization

* use groupMemberId as key

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-03-07 16:49:55 +00:00
Stanislav Dmitrenko
27f63dafaa
ui: option to remove messages of removed members (#5717)
* ui: removing messages of removed members

* android

* fix android

* fix ios and refactor

* refactor android

* update

* update2

* remove ts

* android new logic

* refactor

* remove spaghetti

* if

* android

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-03-07 15:08:00 +00:00
Evgeny Poberezkin
e2d488266c
core: 6.3.0.8 (simplexmq 6.3.0.8) 2025-03-07 14:59:00 +00:00
spaced4ndy
430e212a9e
core: name limit (#5724)
* core: name limit

* ios

* trim spaces, test
2025-03-07 14:38:06 +00:00
spaced4ndy
47adbe2813
ui: fix strings, update translations (#5718)
* ios: fix strings

* update translations

* update report ru translations

* remove unnecessary localizations

* update ru translations

* update android translations

* import translations

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-03-07 12:50:44 +00:00
Stanislav Dmitrenko
cc2a45bdaf
android, desktop: expand moderated messages (#5722) 2025-03-07 11:16:56 +00:00
Stanislav Dmitrenko
ad4adf66ec
ios: fix small scroll on new message (#5721)
* ios: fix small scroll on new message

* added inset in calculation of offset
2025-03-07 09:19:37 +00:00
Evgeny
f53b21f8c6
ui: translations (#5719)
* Translated using Weblate (Portuguese)

Currently translated at 40.5% (946 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pt/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2334 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2334 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (2334 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (German)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Czech)

Currently translated at 99.7% (2328 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2334 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Czech)

Currently translated at 99.8% (2331 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Czech)

Currently translated at 100.0% (2334 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Arabic)

Currently translated at 27.2% (563 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ar/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (2334 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Russian)

Currently translated at 98.6% (2302 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* Translated using Weblate (Russian)

Currently translated at 100.0% (2334 of 2334 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 92.5% (2167 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pt_BR/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 92.5% (2168 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pt_BR/

* Translated using Weblate (Arabic)

Currently translated at 28.7% (593 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ar/

* Translated using Weblate (Arabic)

Currently translated at 29.5% (610 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ar/

* Translated using Weblate (German)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Russian)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* Translated using Weblate (Russian)

Currently translated at 96.9% (2002 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Russian)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* Translated using Weblate (Russian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Spanish)

Currently translated at 99.8% (2339 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 99.8% (2061 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2342 of 2342 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2065 of 2065 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* process localizations

---------

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: zenobit <zenobit@disroot.org>
Co-authored-by: Gholamy-Muh <Algholamym@gmail.com>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: noname <zhuk2@duck.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: João Moreira <jyj@gmx.ie>
Co-authored-by: J R <jr@simplex.chat>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
2025-03-07 08:21:17 +00:00
Evgeny
2d203c1a18
Translated using Weblate (Russian) (#5720)
Currently translated at 100.0% (258 of 258 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ru/

Co-authored-by: noname <zhuk2@duck.com>
2025-03-07 08:04:16 +00:00
Evgeny
a6631ce629
core: delete members with messages (#5711)
* core: delete members with messages (WIP)

* remove messages

* fix, test

* update query plans
2025-03-07 07:47:32 +00:00
spaced4ndy
5bef7349d8
ios: fix crash on migration to device (#5716)
* ios: fix crash on migration to device

* fix

* remove logs

* changes

* logs

* changes

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2025-03-07 07:06:39 +00:00
Evgeny Poberezkin
37050a99c9
android, desktop: add Catalan UI languages 2025-03-06 23:02:47 +00:00
Evgeny
ca31c9a5e9
blog: v6.3 announcement (#5714) 2025-03-06 22:59:32 +00:00
Stanislav Dmitrenko
a0560a5ad0
ios: fix search (#5715) 2025-03-06 11:28:26 +00:00
Stanislav Dmitrenko
a3a27b250c
ios: small fixes (#5712)
* ios: small fixes

* main thread

* fix crash

* fix member opening

* dismissing sheets in order

* theoretical fix of some crashes

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-03-06 10:31:05 +00:00
Stanislav Dmitrenko
7a3663f1e0
android, desktop: hovered item in chat (#5684)
* android, desktop: hovered item in chat

* circle background for button

* icon size

* change

* change

* comment

* refactor
2025-03-06 09:42:14 +00:00
Stanislav Dmitrenko
9dac472191
android, desktop: bulk actions with group members (#5708)
* android, desktop: bulk actions with group members

* fix layout

* fix update

* fix responsivenes when closing selecting bar

* events

* unused

* role
2025-03-05 15:01:44 +00:00
Evgeny
8c7df76c24
directory: command to disable all spam filters (#5709)
* directory: command to disable all spam filters

* correct syntax

* move deviceName to core opts
2025-03-05 11:20:30 +00:00
spaced4ndy
3425bd0826
ui: fix "View conditions" view on onboarding offering to accept conditions when no operators are selected (#5710)
* ios: fix "View conditions" view on onboarding

* kotlin
2025-03-05 07:42:59 +00:00
Stanislav Dmitrenko
257208a99b
ios: fix toolbar in chatList on iOS 15 (#5707) 2025-03-04 11:20:14 +00:00
Evgeny Poberezkin
8140710660
6.3-beta.7: ios 267, android 278, desktop 95 2025-03-03 23:23:25 +00:00
Evgeny
518ab2cd3e
website: translations (#5706)
* blocked words

* blocked words

* XGrpLinkReject

* core: 6.3.0.6 (simplexmq 6.3.0.6)

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

* core: communicate group join rejection (#5661)

* ui: rejected group previews (#5665)

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (258 of 258 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/hu/

* Translated using Weblate (Czech)

Currently translated at 100.0% (258 of 258 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/cs/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (258 of 258 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (258 of 258 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (258 of 258 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/hu/

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: zenobit <zenobit@users.noreply.hosted.weblate.org>
2025-03-03 22:13:45 +00:00
Evgeny
d2e60503f9
ui: translations (#5705)
* cli: remove multiple members (#5656)

* cli: remove multiple members

* accept all members joining via link as observers (do NOT release)

* blocked words

* blocked words

* XGrpLinkReject

* core: 6.3.0.6 (simplexmq 6.3.0.6)

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

* core: communicate group join rejection (#5661)

* ui: rejected group previews (#5665)

* Translated using Weblate (German)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (German)

Currently translated at 100.0% (2061 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2061 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2061 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Korean)

Currently translated at 64.4% (1500 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ko/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2061 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Vietnamese)

Currently translated at 99.7% (2323 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Vietnamese)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2061 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Arabic)

Currently translated at 15.3% (316 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ar/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2061 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Czech)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2061 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Croatian)

Currently translated at 61.2% (1425 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hr/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2061 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2061 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Croatian)

Currently translated at 63.8% (1487 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hr/

* Translated using Weblate (Arabic)

Currently translated at 17.6% (363 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ar/

* Translated using Weblate (Russian)

Currently translated at 97.5% (2271 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* Translated using Weblate (Catalan)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ca/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2328 of 2328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2061 of 2061 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* import/export localizations

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: robbie.med <161779148+robbie-med@users.noreply.github.com>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: Gholamy-Muh <Algholamym@gmail.com>
Co-authored-by: zenobit <zenobit@users.noreply.hosted.weblate.org>
Co-authored-by: Nenad <nenadmirkovic00@gmail.com>
Co-authored-by: Full name <androposhtar1029@gmail.com>
Co-authored-by: fran secs <fransecs@gmail.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
2025-03-03 22:09:56 +00:00
Evgeny Poberezkin
7c2153762f
ios: update core library 2025-03-03 21:21:25 +00:00
Evgeny Poberezkin
0a97218440
core: 6.3.0.7 (simplexmq 6.3.0.7) 2025-03-03 20:57:47 +00:00
Stanislav Dmitrenko
2788a1dbb3
ios: fix showing first unread (#5703) 2025-03-03 20:53:23 +00:00
Stanislav Dmitrenko
1ddf7a62ad
ios: fix running in simulator (#5704) 2025-03-03 20:53:08 +00:00
Evgeny Poberezkin
8b030075d7
core: update query plans 2025-03-03 19:58:00 +00:00
Evgeny
b2de37a9fb
core: member acceptance (#5678)
* core: member acceptance

* migration

* move hook

* core: support sending direct messages to members (#5680)

* fix compilation, todos

* fix test

* predicates

* comment

* extend hook

* wip

* wip

* wip

* wip

* fix test

* mute output

* schema

* better query

* plans

* fix test

* directory

* captcha

* captcha works

* remove column, add UI types and group status icon

* fix test

* query plans

* exclude messages of pending members from history

* commands for filter settings

* core: separately delete pending approval members; other apis validation (#5699)

* accepted status

* send captcha messages as replies

* fix blocked words

* simpler filter info

* info about /filter and /role after group registration

* update query plans

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2025-03-03 18:57:29 +00:00
spaced4ndy
27bf19c2b1
ui: updated conditions (#5700)
* ios: updated conditions ui

* view

* kotlin

* show Updated conditions via review button

* same for android

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-03-03 16:26:05 +00:00
Evgeny
3d076a89e7
core: update privacy policy for the apps (#5696) 2025-03-03 16:09:25 +00:00
Evgeny
7471fd2af5
docs: update privacy policy (#5646)
* docs: update privacy policy

* remove OSI requirement

* update
2025-03-02 22:44:26 +00:00
Stanislav Dmitrenko
50232fd179
android, desktop: go to forwarded item or search result (#5666)
* android, desktop: go to forwarded item or search result

* changes

* reactions back

* button appearance

* indentation

* change

* rename variable

* rename function

* rename variable

* rename variable

* fix scroll position
2025-02-28 18:55:49 +00:00
Stanislav Dmitrenko
1b757911fa
ui: batch apis for members (#5681)
* ui: batch apis for members

* ios

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-28 18:55:17 +00:00
spaced4ndy
dcea008fb9
core: batch apis - remove, block, change role of members (#5674)
* core: core: batch remove members

* order

* foldr

* list

* style

* batch block

* change role

* test

* if
2025-02-28 18:43:39 +00:00
Stanislav Dmitrenko
dce8502165
android: allow to enter passphrase in case of error reading it (#5683)
* android: allow to enter passphrase in case of error reading it

* change

* refactor

* strings

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-28 15:57:41 +00:00
Stanislav Dmitrenko
fefddb3b5a
ios: go to forwarded item or search result (#5679)
* ios: go to forwarded item or search result

* react on touch

* changes
2025-02-28 14:45:24 +00:00
Evgeny
b482d4d812
core: fix search in chat (#5677) 2025-02-27 07:38:40 +00:00
spaced4ndy
1fcb352db4
ui: rejected group previews (#5665) 2025-02-26 09:27:43 +00:00
spaced4ndy
f701ffa4e0
core: communicate group join rejection (#5661) 2025-02-26 09:25:54 +00:00
Evgeny
511ff1d35c
cli: remove multiple members (#5656)
* cli: remove multiple members

* accept all members joining via link as observers (do NOT release)

* blocked words

* blocked words

* XGrpLinkReject

* core: 6.3.0.6 (simplexmq 6.3.0.6)

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2025-02-26 09:25:54 +00:00
Evgeny Poberezkin
981901d587
6.3-beta.6: ios 266, android 277, desktop 94 2025-02-24 22:06:52 +00:00
Evgeny
a5334b36f8
ui: translations (#5663)
* Translated using Weblate (German)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (German)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Czech)

Currently translated at 92.0% (2130 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Polish)

Currently translated at 90.3% (1850 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Persian)

Currently translated at 77.2% (1788 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (Romanian)

Currently translated at 34.5% (799 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ro/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/id/

* Translated using Weblate (Catalan)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ca/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Turkish)

Currently translated at 90.8% (2102 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2314 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (French)

Currently translated at 99.0% (2292 of 2314 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Italian)

Currently translated at 99.8% (2323 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Catalan)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ca/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Croatian)

Currently translated at 60.8% (1415 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hr/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2326 of 2326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2047 of 2047 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* import/export

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: idk <rusek.jonas69@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Jester Hodl <jesterhodl@jesterhodl.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Goudarz Jafari <goudarz.jafari@gmail.com>
Co-authored-by: Cosmin <cosminfrancu@gmail.com>
Co-authored-by: Rafi <rafimuhmad90@protonmail.com>
Co-authored-by: fran secs <fransecs@gmail.com>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: Doğaç Tanrıverdi <d.tnrvrdi@proton.me>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: Karlos Sagan <weblate.ljq5x@passmail.net>
Co-authored-by: Nenad <nenadmirkovic00@gmail.com>
2025-02-24 20:23:20 +00:00
Evgeny
b494c43706
website: translations (#5664)
* Translated using Weblate (Dutch)

Currently translated at 100.0% (258 of 258 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (258 of 258 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

---------

Co-authored-by: M1K4 <oomikaoo@gmail.com>
2025-02-24 18:34:27 +00:00
Stanislav Dmitrenko
c972298dd2
ui: drop filter when no such tags exist (#5662)
* ui: drop filter when no such tags exist

* ios

* android/desktop

* change

* change

* ios

* change

* change

* ios

* android

* ios
2025-02-24 18:31:41 +00:00
Stanislav Dmitrenko
b96b6c70d2
android, desktop: fix showing big gifs (opens in viewer) (#5660) 2025-02-24 09:28:46 +00:00
Stanislav Dmitrenko
4f00f9efa0
android, desktop: correct width of quoted message with link view (#5659) 2025-02-24 08:12:12 +00:00
Stanislav Dmitrenko
c81fa7e6b0
android, desktop: marking chat read fix (#5658)
* android, desktop: marking chat read fix

* comments
2025-02-24 07:50:30 +00:00
Evgeny Poberezkin
41ccb14bfa
core: 6.3.0.6 (simplexmq 6.3.0.6) 2025-02-23 23:31:16 +00:00
Stanislav Dmitrenko
bf37c0762e
ios: fix height of compose view field when having a draft (#5655)
* ios: fix height of compose view field when having a draft

* changes

* simplified layout

* changes

* button size 29 -> 31

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-22 12:15:33 +00:00
spaced4ndy
bc9885675d
android, desktop: what's new for v6.3 (#5654) 2025-02-21 16:09:22 +04:00
spaced4ndy
dd13450443
ios: what's new for v6.3 (#5651)
* ios: what's new for v6.3

* update

* space

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-21 09:46:40 +00:00
Stanislav Dmitrenko
e59967b0d6
android, desktop: link previews with posters (#5652)
* android, desktop: link previews with posters

* slash
2025-02-21 08:50:04 +00:00
Stanislav Dmitrenko
b27e964d0c
desktop: closing modals when connected to remote host (#5650) 2025-02-21 08:20:02 +00:00
Stanislav Dmitrenko
ca3687488f
ios: equal scrolling speed to top/bottom and fix of scroll loop (#5649) 2025-02-20 20:46:22 +00:00
Stanislav Dmitrenko
676583d3c3
ios: enhancements to floating buttons (#5644)
* ios: enhancements to floating buttons

* nearBottom

* timeout

* changes

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-20 10:39:04 +00:00
Stanislav Dmitrenko
dc980ae88f
ios: loading progress moved to chat list (#5639)
* ios: loading progress moved to chat list

* place

* changes

* large spinner, smaller timeout

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-19 16:13:20 +00:00
Stanislav Dmitrenko
ec519afb3f
ios: fixed unread counters (#5640) 2025-02-18 20:44:24 +00:00
Stanislav Dmitrenko
9d1329498b
ios: open chat on first unread, "scroll" to quoted items that were not loaded (#5392)
* ios: open chat on first unread, "scroll" to quoted items that were not loaded

* more changes

* changes

* unused

* fix reveal logic

* debug

* changes

* test

* Revert "test"

This reverts commit 553be124d5.

* change

* change

* changes

* changes

* changes

* commented deceleration logic

* changes

* fixes

* optimized item identifiers to use merged item directly

* fixed counters

* encreased initial and preload counters

* fix initial loading and trimming items

* optimize

* allow marking read

* 10 instead of 5

* performance

* one more parameter in hash

* disable trimming

* performance

* performance - in background

* optimization

* next/prev

* changes

* markread

* finally

* less logs

* read

* change after merge

* trimming, edge cases

* wait until items loaded

* Revert "wait until items loaded"

This reverts commit 895218b978.

* progress indicator

* optimization

* disable scroll helper

* experiment

* Revert "experiment"

This reverts commit c952c9e623.

* jump

* no read

* layoutIfNeeded

* changes

* EndlessScrollView

* read

* changes

* changes

* changes

* reduce time to open a chat (by ~300ms)

* open from the first unread when clicking member chat

* refactored and removed unused code

* handling search emptiness to scroll to correct position

* changes

* read state maintain

* remove protocol

* avoid parsing chatId

* pass chat

* changes

* remove reveal

* refactor spaghetti

* remove ItemsScrollModel

* rename

* remove setUpdateListener

* unused

* optimization

* scrollToTop

* fix

* scrollbar working again

* scrollToBottom

* fix

* scrollBar hiding when not many items on screen

* small safer change

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-17 18:21:40 +00:00
spaced4ndy
704bab171d
docs: member limits rfc (#5635) 2025-02-17 17:41:27 +04:00
sh
f2430cc57f
flatpak: update metainfo (#5634) 2025-02-17 11:25:39 +00:00
Evgeny Poberezkin
5a0821f9fc
6.3-beta.5: ios 265, android 276, desktop 93 2025-02-15 21:44:38 +00:00
Evgeny Poberezkin
85409db1cc
Merge branch 'stable' 2025-02-15 20:56:49 +00:00
Evgeny Poberezkin
cb3ace5f71
6.2.5: ios 264, android 274, desktop 92 2025-02-15 20:39:43 +00:00
Evgeny Poberezkin
88bb387b1b
core: 6.3.0.5 (simplexmq 6.3.0.5) 2025-02-15 17:15:25 +00:00
Evgeny
7c5966df70
core: fix postgres test (#5631) 2025-02-15 17:09:11 +00:00
Evgeny
1f8755f941
core: update simplexmq (avoid deleting shared message bodies) (#5630)
* core: update simplexmq (avoid deleting shared message bodies)

* simplexmq, plans

* simplexmq

* output in failing test

* stabilize test
2025-02-15 16:18:34 +00:00
Evgeny Poberezkin
e9893989df
Merge branch 'stable' 2025-02-14 23:59:41 +00:00
Evgeny Poberezkin
87569e379a
core: 6.2.5.0 2025-02-14 23:39:24 +00:00
Evgeny
dfe5a4464b
desktop, android: fix parser for reactions (#5629)
* desktop, android: fix parser for reactions

* core: restrict API to known reactions
2025-02-14 23:37:06 +00:00
spaced4ndy
a90f255df5
core: adapt simplexmq api for shared msg body (via MsgReq markers) (#5626)
* core: shared msg body 2

* WIP

* compiles

* refactor

* refactor

* refactor

* format

* simplexmq

* refactor

* refactor ChatMsgReq

* agent query plans

* simpler

* test

* test

* fix test

* agent plans

* simplexmq

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-14 20:12:32 +00:00
Evgeny Poberezkin
8dbebbe3d6
6.3-beta.4: ios 263, android 273, desktop 91 2025-02-10 21:56:24 +00:00
Evgeny Poberezkin
47997fd90b
ios: support opening SimpleX links from camera and other apps 2025-02-10 21:36:55 +00:00
Evgeny Poberezkin
0e40d4b5ff
ios: export localizations 2025-02-10 17:55:35 +00:00
Evgeny
d39b4863b4
website: translations (#5614)
* Translated using Weblate (Polish)

Currently translated at 100.0% (258 of 258 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Translated using Weblate (Polish)

Currently translated at 100.0% (258 of 258 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

---------

Co-authored-by: Jester Hodl <jesterhodl@jesterhodl.com>
2025-02-10 15:38:49 +00:00
Evgeny Poberezkin
e06741c936
core: 6.3.0.4 (simplexmq 6.3.0.4) 2025-02-10 15:34:07 +00:00
Stanislav Dmitrenko
e7361cf025
ui: archive multiple reports (#5619)
* android, desktop: archive multiple reports

* ios

* change

* changes

* fix changing counter

* fix changing counter2

* fix changing counter3

* unused

* fix android

* android notification

* simplify

* ios notification

* orange

* orange

* core: update api

* buttons

* ios api

* android api

* fix 4 buttons

* buttons and check for member active status

* android colors and member active

* show delete group button when not in the group anymore

* title

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-10 15:07:14 +00:00
Evgeny Poberezkin
c5bb2c4ca2
website: update livestream link 2025-02-10 09:13:23 +00:00
Evgeny
3267eb2b27
ui: translations (#5613)
* Translated using Weblate (German)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (German)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Croatian)

Currently translated at 37.5% (863 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hr/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 98.4% (1975 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/id/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 96.2% (2211 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 98.3% (2260 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Vietnamese)

Currently translated at 100.0% (2297 of 2297 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (German)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Spanish)

Currently translated at 99.8% (2297 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Croatian)

Currently translated at 39.6% (911 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hr/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/

* Translated using Weblate (Bulgarian)

Currently translated at 74.7% (1500 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/

* Translated using Weblate (Bulgarian)

Currently translated at 97.5% (2244 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Croatian)

Currently translated at 46.7% (1076 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hr/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Croatian)

Currently translated at 49.6% (1142 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hr/

* Translated using Weblate (Croatian)

Currently translated at 2.6% (53 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hr/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Catalan)

Currently translated at 100.0% (2300 of 2300 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ca/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Bulgarian)

Currently translated at 97.4% (2245 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (German)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Russian)

Currently translated at 96.8% (1943 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Korean)

Currently translated at 64.1% (1478 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ko/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Indonesian)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/id/

* Translated using Weblate (Croatian)

Currently translated at 52.0% (1199 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hr/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Croatian)

Currently translated at 52.4% (1208 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hr/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2007 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Polish)

Currently translated at 92.5% (2131 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Polish)

Currently translated at 91.4% (1835 of 2007 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Vietnamese)

Currently translated at 100.0% (2303 of 2303 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* import/export localizations

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Nenad <nenadmirkovic00@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Rafi <rafimuhmad90@protonmail.com>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: 109247019824 <109247019824@users.noreply.hosted.weblate.org>
Co-authored-by: fran secs <fransecs@gmail.com>
Co-authored-by: Near <roma.baldin@gmail.com>
Co-authored-by: suhyuk kim <kimsuhyuk@gmail.com>
Co-authored-by: Jester Hodl <jesterhodl@jesterhodl.com>
2025-02-10 09:07:55 +00:00
Evgeny Poberezkin
9533772aa2
build: update query plans 2025-02-10 09:07:20 +00:00
Evgeny
205ced1c1d
core, ui: report preference (#5620)
* core: report preference

* fix tests

* ios: disable reports toggle until 6.4

* android, desktop: reports preference

* ui: section

* boolean
2025-02-10 09:06:16 +00:00
Evgeny
ff35643533
core: api to archive reports (#5618)
* core: api to archive reports

* fix queries

* query plans

* fix test
2025-02-09 19:16:30 +00:00
Evgeny
9c28a51fee
core: fix mentions "disappearing" on reactions (#5617) 2025-02-09 12:39:48 +00:00
spaced4ndy
75388b997e
desktop: run with postgres backend (#5604)
* desktop: postgres

* update

* update

* params, instruction

* script passes (app doesn't build)

* fix script
2025-02-09 11:06:05 +00:00
Stanislav Dmitrenko
75685df2e8
android: restart the app on update (#5616) 2025-02-09 11:01:55 +00:00
Stanislav Dmitrenko
38c5c19b17
android: fix entering characters while sending a message (#5615) 2025-02-09 10:27:40 +00:00
Evgeny Poberezkin
a91599543e
website: livestream group link 2025-02-08 22:45:55 +00:00
Evgeny Poberezkin
83984e482c
core: update simplexmq 2025-02-08 19:05:15 +00:00
spaced4ndy
e4d6a8822c
core, ios: check notifications token status, offer to re-register token (#5610)
* core: api to check token

* ios

* update library

* refactor

* texts

* errors

* check active token on start

* text

* Revert "check active token on start"

This reverts commit c7b6e51f94.

* update simplexmq

* offer re-register

* text

* update simplexmq

* offer on check

* rework

* text

* unset test result

* simplexmq

* alerts

* invalid reasons

* rework alert

* update simplexmq

* fix

* simplexmq

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-07 13:41:15 +00:00
Evgeny Poberezkin
dac8389263
6.3-beta.3: ios 262, android 272, desktop 90 2025-02-05 22:21:34 +00:00
Evgeny Poberezkin
6b7c4509fe
android, desktop: fix footer of web port setting 2025-02-05 21:54:51 +00:00
Stanislav Dmitrenko
e6ddbc1172
ios: faster member suggestions (#5609) 2025-02-05 21:32:22 +00:00
Evgeny Poberezkin
5b947b3130
core: 6.3.0.3 2025-02-05 17:57:04 +00:00
Stanislav Dmitrenko
a622cb91f9
ios: fix members ruins layout of ComposeView (#5607)
* ios: fix members ruins layout of ComposeView

* change to func

* filter

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-02-05 15:22:32 +00:00
Evgeny
844b24be9d
core: forward reports only to moderators and above roles (#5605)
* core: do not forward reports

* test

* core: forward reports only to moderators and above roles (#5606)

* core: forward reports only to moderators and above roles

* test

* name

* name

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2025-02-05 09:40:42 +00:00
238 changed files with 21469 additions and 6399 deletions

View file

@ -123,6 +123,16 @@ This section applies only to the experimental group directory operated by Simple
[SimpleX Directory](/docs/DIRECTORY.md) stores: your search requests, the messages and the members profiles in the registered groups. You can connect to SimpleX Directory via [this address](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).
#### Public groups and content channels
You may participate in a public group and receive content from a public channel (Group). In case you send messages or comments to the Group, you grant a license:
- to all recipients:
- to share your messages with the new Group members and outside of the group, e.g. via quoting (replying), forwarding and copy-pasting your message. When your message is deleted or marked as deleted, the copies of your message will not be deleted.
- to retain a copy of your messages according to the Group settings (e.g., the Group may allow irreversible message deletion from the recipient devices for a limited period of time, or it may only allow to edit and mark messages as deleted on recipient devices). Deleting message from the recipient devices or marking message as deleted revokes the license to share the message.
- to Group owners: to share your messages with the new Group members as history of the Group. Currently, the Group history shared with the new members is limited to 100 messages.
Group owners may use chat relays or automated bots (Chat Relays) to re-broadcast member messages to all members, for efficiency. The Chat Relays may be operated by the group owners, by preset operators or by 3rd parties. The Chat Relays have access to and will retain messages in line with Group settings, for technical functioning of the Group. Neither you nor group owners grant any content license to Chat Relay operators.
#### User Support
The app includes support contact operated by SimpleX Chat Ltd. If you contact support, any personal data you share is kept only for the purposes of researching the issue and contacting you about your case. We recommend contacting support [via chat](https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23%2F%3Fv%3D1%26dh%3DMCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion) when it is possible, and avoid sharing any personal information.
@ -131,9 +141,9 @@ The app includes support contact operated by SimpleX Chat Ltd. If you contact su
Preset server operators will not share the information on their servers with each other, other than aggregate usage statistics.
Preset server operators will not provide general access to their servers or the data on their servers to each other.
Preset server operators must not provide general access to their servers or the data on their servers to each other.
Preset server operators will provide non-administrative access to control port of preset servers to SimpleX Chat Ltd, for the purposes of removing identified illegal content. This control port access only allows deleting known links and files, and access to aggregate statistics, but does NOT allow enumerating any information on the servers.
Preset server operators will provide non-administrative access to control port of preset servers to SimpleX Chat Ltd, for the purposes of removing illegal content identified in publicly accessible resources (contact and group addresses, and downloadable files). This control port access only allows deleting known links and files, and accessing aggregate server-wide statistics, but does NOT allow enumerating any information on the servers or accessing statistics related to specific users.
### Information Preset Server Operators May Share
@ -148,7 +158,7 @@ The cases when the preset server operators may share the data temporarily stored
- To detect, prevent, or otherwise address fraud, security, or technical issues.
- To protect against harm to the rights, property, or safety of software users, operators of preset servers, or the public as required or permitted by law.
At the time of updating this document, the preset server operators have never provided or have been requested the access to the preset relay servers or any information from the servers by any third parties. If the preset server operators are ever requested to provide such access or information, they will follow the due legal process to limit any information shared with the third parties to the minimally required by law.
By the time of updating this document, the preset server operators were not served with any enforceable requests and did not provide any information from the servers to any third parties. If the preset server operators are ever requested to provide such access or information, they will follow the due legal process to limit any information shared with the third parties to the minimally required by law.
Preset server operators will publish information they are legally allowed to share about such requests in the [Transparency reports](./docs/TRANSPARENCY.md).
@ -190,7 +200,18 @@ You accept the Conditions of Use of Software and Infrastructure ("Conditions") b
**Legal usage**. You agree to use SimpleX Chat Applications only for legal purposes. You will not use (or assist others in using) the Applications in ways that: 1) violate or infringe the rights of Software users, SimpleX Chat Ltd, other preset server operators, or others, including privacy, publicity, intellectual property, or other proprietary rights; 2) involve sending illegal communications, e.g. spam. While server operators cannot access content or identify messages or groups, in some cases the links to the illegal communications can be shared publicly on social media or websites. Preset server operators reserve the right to remove such links from the preset servers and disrupt the conversations that send illegal content via their servers, whether they were reported by the users or discovered by the operators themselves.
**Damage to SimpleX Chat Ltd and Preset Server Operators**. You must not (or assist others to) access, use, modify, distribute, transfer, or exploit SimpleX Chat Applications in unauthorized manners, or in ways that harm Software users, SimpleX Chat Ltd, other preset server operators, their Infrastructure, or any other systems. For example, you must not 1) access preset operators' Infrastructure or systems without authorization, in any way other than by using the Software; 2) disrupt the integrity or performance of preset operators' Infrastructure; 3) collect information about the users in any manner; or 4) sell, rent, or charge for preset operators' Infrastructure. This does not prohibit you from providing your own Infrastructure to others, whether free or for a fee, as long as you do not violate these Conditions and AGPLv3 license, including the requirement to publish any modifications of the relay server software.
**Damage to SimpleX Chat Ltd and Preset Server Operators**. You must not (or assist others to) access, use, modify, distribute, transfer, or exploit SimpleX Chat Applications in unauthorized manners, or in ways that harm Software users, SimpleX Chat Ltd, other preset server operators, their Infrastructure, or any other systems. For example, you must not 1) access preset operators' Infrastructure or systems without authorization, in any way other than by using the Software or by using a 3rd party client applications that satisfies the requirements of the Conditions of use (see the next section); 2) disrupt the integrity or performance of preset operators' Infrastructure; 3) collect information about the users in any manner; or 4) sell, rent, or charge for preset operators' Infrastructure. This does not prohibit you from providing your own Infrastructure to others, whether free or for a fee, as long as you do not violate these Conditions and AGPLv3 license, including the requirement to publish any modifications of the relay server software.
**3rd party client applications**. You may use a 3rd party application (App) to access preset operators' Infrastructure or systems, provided that this App:
- is compatible with the protocol specifications not older than 1 year,
- provides user-to-user messaging only or enables automated chat bots sending messages requested by users (in case of bots, it must be made clear to the users that these are automated bots),
- implements the same limits, rules and restrictions as Software,
- requires that the users accept the same Conditions of use of preset operators' Infrastructure as in Software prior to providing access to this Infrastructure,
- displays the notice that it is the App for using SimpleX network,
- provides its source code under open-source license accessible to the users via the App interface. In case the App uses the source code of Software, the App's source code must be provided under AGPLv3 license, and in case it is developed without using Software code its source code must be provided under any widely recognized free open-source license,
- does NOT use the branding of SimpleX Chat Ltd without the permission,
- does NOT pretend to be Software,
- complies with these Conditions of use.
**Keeping your data secure**. SimpleX Chat is the first communication software that aims to be 100% private by design - server software neither has the ability to access your messages, nor it has information about who you communicate with. That means that you are solely responsible for keeping your device, your user profile and any data safe and secure. If you lose your phone or remove the Software from the device, you will not be able to recover the lost data, unless you made a back up. To protect the data you need to make regular backups, as using old backups may disrupt your communication with some of the contacts. SimpleX Chat Ltd and other preset server operators are not responsible for any data loss.
@ -222,4 +243,4 @@ You accept the Conditions of Use of Software and Infrastructure ("Conditions") b
**Ending these conditions**. You may end these Conditions with SimpleX Chat Ltd and preset server operators at any time by deleting the Applications from your devices and discontinuing use of the Infrastructure of SimpleX Chat Ltd and preset server operators. The provisions related to Licenses, Disclaimers, Limitation of Liability, Resolving dispute, Availability, Changes to the conditions, Enforcing the conditions, and Ending these conditions will survive termination of your relationship with SimpleX Chat Ltd and/or preset server operators.
Updated November 14, 2024
Updated March 3, 2025

View file

@ -234,6 +234,10 @@ You can use SimpleX with your own servers and still communicate with people usin
Recent and important updates:
[Mar 8, 2025. SimpleX Chat v6.3: new user experience and safety in public groups](./blog/20250308-simplex-chat-v6-3-new-user-experience-safety-in-public-groups.md)
[Jan 14, 2025. SimpleX network: large groups and privacy-preserving content moderation](./blog/20250114-simplex-network-large-groups-privacy-preserving-content-moderation.md)
[Dec 10, 2024. SimpleX network: preset servers operated by Flux, business chats and more with v6.2 of the apps](./20241210-simplex-network-v6-2-servers-by-flux-business-chats.md)
[Oct 14, 2024. SimpleX network: security review of protocols design by Trail of Bits, v6.1 released with better calls and user experience.](./blog/20241014-simplex-network-v6-1-security-review-better-calls-user-experience.md)
@ -305,12 +309,13 @@ What is already implemented:
15. Manual messaging queue rotations to move conversation to another SMP relay.
16. Sending end-to-end encrypted files using [XFTP protocol](https://simplex.chat/blog/20230301-simplex-file-transfer-protocol.html).
17. Local files encryption.
18. [Reproducible server builds](./docs/SERVER.md#reproduce-builds).
We plan to add:
1. Automatic message queue rotation and redundancy. Currently the queues created between two users are used until the queue is manually changed by the user or contact is deleted. We are planning to add automatic queue rotation to make these identifiers temporary and rotate based on some schedule TBC (e.g., every X messages, or every X hours/days).
2. Message "mixing" - adding latency to message delivery, to protect against traffic correlation by message time.
3. Reproducible builds this is the limitation of the development stack, but we will be investing into solving this problem. Users can still build all applications and services from the source code.
3. Reproducible clients builds this is a complex problem, but we are aiming to have it in 2025 at least partially.
4. Recipients' XFTP relays to reduce traffic and conceal IP addresses from the relays chosen, and potentially controlled, by another party.
## For developers

View file

@ -288,8 +288,10 @@ struct ContentView: View {
}
prefShowLANotice = true
connectViaUrl()
showReRegisterTokenAlert()
}
.onChange(of: chatModel.appOpenUrl) { _ in connectViaUrl() }
.onChange(of: chatModel.reRegisterTknStatus) { _ in showReRegisterTokenAlert() }
.sheet(item: $noticesSheetItem) { item in
switch item {
case let .whatsNew(updatedConditions):
@ -315,6 +317,12 @@ struct ContentView: View {
.onContinueUserActivity("INStartCallIntent", perform: processUserActivity)
.onContinueUserActivity("INStartAudioCallIntent", perform: processUserActivity)
.onContinueUserActivity("INStartVideoCallIntent", perform: processUserActivity)
.onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { userActivity in
if let url = userActivity.webpageURL {
logger.debug("onContinueUserActivity.NSUserActivityTypeBrowsingWeb: \(url)")
chatModel.appOpenUrl = url
}
}
}
private func setConditionsNotified_() async {
@ -468,6 +476,21 @@ struct ContentView: View {
}
}
func showReRegisterTokenAlert() {
dismissAllSheets() {
let m = ChatModel.shared
if let errorTknStatus = m.reRegisterTknStatus, let token = chatModel.deviceToken {
chatModel.reRegisterTknStatus = nil
AlertManager.shared.showAlert(Alert(
title: Text("Notifications error"),
message: Text(tokenStatusInfo(errorTknStatus, register: true)),
primaryButton: .default(Text("Register")) { reRegisterToken(token: token) },
secondaryButton: .cancel()
))
}
}
}
private func showPlanAndConnectAlert(_ alert: PlanAndConnectAlert) {
AlertManager.shared.showAlert(planAndConnectAlert(alert, dismiss: false))
}

View file

@ -53,11 +53,18 @@ class ItemsModel: ObservableObject {
var itemAdded = false {
willSet { publisher.send() }
}
// set listener here that will be notified on every add/delete of a chat item
let chatState = ActiveChatState()
var chatItemsChangesListener: RecalculatePositions = RecalculatePositions()
// Publishes directly to `objectWillChange` publisher,
// this will cause reversedChatItems to be rendered without throttling
@Published var isLoading = false
@Published var showLoadingProgress = false
@Published var showLoadingProgress: ChatId? = nil
private var navigationTimeoutTask: Task<Void, Never>? = nil
private var loadChatTask: Task<Void, Never>? = nil
init() {
publisher
@ -67,33 +74,41 @@ class ItemsModel: ObservableObject {
}
func loadOpenChat(_ chatId: ChatId, willNavigate: @escaping () -> Void = {}) {
let navigationTimeout = Task {
navigationTimeoutTask?.cancel()
loadChatTask?.cancel()
navigationTimeoutTask = Task {
do {
try await Task.sleep(nanoseconds: 250_000000)
await MainActor.run {
willNavigate()
ChatModel.shared.chatId = chatId
willNavigate()
}
} catch {}
}
let progressTimeout = Task {
do {
try await Task.sleep(nanoseconds: 1500_000000)
await MainActor.run { showLoadingProgress = true }
} catch {}
}
Task {
if let chat = ChatModel.shared.getChat(chatId) {
await MainActor.run { self.isLoading = true }
// try? await Task.sleep(nanoseconds: 5000_000000)
await loadChat(chat: chat)
navigationTimeout.cancel()
progressTimeout.cancel()
loadChatTask = Task {
await MainActor.run { self.isLoading = true }
// try? await Task.sleep(nanoseconds: 1000_000000)
await loadChat(chatId: chatId)
if !Task.isCancelled {
await MainActor.run {
self.isLoading = false
self.showLoadingProgress = false
willNavigate()
ChatModel.shared.chatId = chatId
self.showLoadingProgress = nil
}
}
}
}
func loadOpenChatNoWait(_ chatId: ChatId, _ openAroundItemId: ChatItem.ID? = nil) {
navigationTimeoutTask?.cancel()
loadChatTask?.cancel()
loadChatTask = Task {
// try? await Task.sleep(nanoseconds: 1000_000000)
await loadChat(chatId: chatId, openAroundItemId: openAroundItemId, clearItems: openAroundItemId == nil)
if !Task.isCancelled {
await MainActor.run {
if openAroundItemId == nil {
ChatModel.shared.chatId = chatId
}
}
}
}
@ -124,11 +139,9 @@ class ChatTagsModel: ObservableObject {
}
}
}
if case let .presetTag(tag) = tm.activeFilter, (newPresetTags[tag] ?? 0) == 0 {
activeFilter = nil
}
presetTags = newPresetTags
unreadTags = newUnreadTags
clearActiveChatFilterIfNeeded()
}
func updateChatFavorite(favorite: Bool, wasFavorite: Bool) {
@ -137,9 +150,7 @@ class ChatTagsModel: ObservableObject {
presetTags[.favorites] = (count ?? 0) + 1
} else if !favorite && wasFavorite, let count {
presetTags[.favorites] = max(0, count - 1)
if case .presetTag(.favorites) = activeFilter, (presetTags[.favorites] ?? 0) == 0 {
activeFilter = nil
}
clearActiveChatFilterIfNeeded()
}
}
@ -163,6 +174,7 @@ class ChatTagsModel: ObservableObject {
}
}
}
clearActiveChatFilterIfNeeded()
}
func markChatTagRead(_ chat: Chat) -> Void {
@ -193,7 +205,17 @@ class ChatTagsModel: ObservableObject {
func changeGroupReportsTag(_ by: Int = 0) {
if by == 0 { return }
presetTags[.groupReports] = (presetTags[.groupReports] ?? 0) + by
presetTags[.groupReports] = max(0, (presetTags[.groupReports] ?? 0) + by)
clearActiveChatFilterIfNeeded()
}
func clearActiveChatFilterIfNeeded() {
let clear = switch activeFilter {
case let .presetTag(tag): (presetTags[tag] ?? 0) == 0
case let .userTag(tag): !userTags.contains(tag)
case .unread, nil: false
}
if clear { activeFilter = nil }
}
}
@ -253,6 +275,7 @@ final class ChatModel: ObservableObject {
@Published var deletedChats: Set<String> = []
// current chat
@Published var chatId: String?
@Published var openAroundItemId: ChatItem.ID? = nil
var chatItemStatuses: Dictionary<Int64, CIStatus> = [:]
@Published var chatToTop: String?
@Published var groupMembers: [GMember] = []
@ -267,6 +290,7 @@ final class ChatModel: ObservableObject {
@Published var deviceToken: DeviceToken?
@Published var savedToken: DeviceToken?
@Published var tokenRegistered = false
@Published var reRegisterTknStatus: NtfTknStatus? = nil
@Published var tokenStatus: NtfTknStatus?
@Published var notificationMode = NotificationsMode.off
@Published var notificationServer: String?
@ -545,6 +569,7 @@ final class ChatModel: ObservableObject {
ci.meta.itemStatus = status
}
im.reversedChatItems.insert(ci, at: hasLiveDummy ? 1 : 0)
im.chatItemsChangesListener.added((ci.id, ci.isRcvNew), hasLiveDummy ? 1 : 0)
im.itemAdded = true
ChatItemDummyModel.shared.sendUpdate()
return true
@ -590,14 +615,54 @@ final class ChatModel: ObservableObject {
// remove from current chat
if chatId == cInfo.id {
if let i = getChatItemIndex(cItem) {
_ = withAnimation {
im.reversedChatItems.remove(at: i)
withAnimation {
let item = im.reversedChatItems.remove(at: i)
im.chatItemsChangesListener.removed([(item.id, i, item.isRcvNew)], im.reversedChatItems.reversed())
}
}
}
VoiceItemState.stopVoiceInChatView(cInfo, cItem)
}
func removeMemberItems(_ removedMember: GroupMember, byMember: GroupMember, _ groupInfo: GroupInfo) {
// this should not happen, only another member can "remove" user, user can only "leave" (another event).
if byMember.groupMemberId == groupInfo.membership.groupMemberId {
logger.debug("exiting removeMemberItems")
return
}
if chatId == groupInfo.id {
for i in 0..<im.reversedChatItems.count {
if let updatedItem = removedUpdatedItem(im.reversedChatItems[i]) {
_updateChatItem(at: i, with: updatedItem)
}
}
} else if let chat = getChat(groupInfo.id),
chat.chatItems.count > 0,
let updatedItem = removedUpdatedItem(chat.chatItems[0]) {
chat.chatItems = [updatedItem]
}
func removedUpdatedItem(_ item: ChatItem) -> ChatItem? {
let newContent: CIContent
if case .groupSnd = item.chatDir, removedMember.groupMemberId == groupInfo.membership.groupMemberId {
newContent = .sndModerated
} else if case let .groupRcv(groupMember) = item.chatDir, groupMember.groupMemberId == removedMember.groupMemberId {
newContent = .rcvModerated
} else {
return nil
}
var updatedItem = item
updatedItem.meta.itemDeleted = .moderated(deletedTs: Date.now, byGroupMember: byMember)
if groupInfo.fullGroupPreferences.fullDelete.on {
updatedItem.content = newContent
}
if item.isActiveReport {
decreaseGroupReportsCounter(groupInfo.id)
}
return updatedItem
}
}
func nextChatItemData<T>(_ chatItemId: Int64, previous: Bool, map: @escaping (ChatItem) -> T?) -> T? {
guard var i = im.reversedChatItems.firstIndex(where: { $0.id == chatItemId }) else { return nil }
if previous {
@ -640,6 +705,7 @@ final class ChatModel: ObservableObject {
let cItem = ChatItem.liveDummy(chatInfo.chatType)
withAnimation {
im.reversedChatItems.insert(cItem, at: 0)
im.chatItemsChangesListener.added((cItem.id, cItem.isRcvNew), 0)
im.itemAdded = true
}
return cItem
@ -659,71 +725,23 @@ final class ChatModel: ObservableObject {
im.reversedChatItems.first?.isLiveDummy == true
}
func markChatItemsRead(_ cInfo: ChatInfo) {
func markAllChatItemsRead(_ cInfo: ChatInfo) {
// update preview
_updateChat(cInfo.id) { chat in
self.decreaseUnreadCounter(user: self.currentUser!, chat: chat)
self.updateFloatingButtons(unreadCount: 0)
ChatTagsModel.shared.markChatTagRead(chat)
chat.chatStats = ChatStats()
}
// update current chat
if chatId == cInfo.id {
markCurrentChatRead()
}
}
private func markCurrentChatRead(fromIndex i: Int = 0) {
var j = i
while j < im.reversedChatItems.count {
markChatItemRead_(j)
j += 1
}
}
private func updateFloatingButtons(unreadCount: Int) {
let fbm = ChatView.FloatingButtonModel.shared
fbm.totalUnread = unreadCount
fbm.objectWillChange.send()
}
func markChatItemsRead(_ cInfo: ChatInfo, aboveItem: ChatItem? = nil) {
if let cItem = aboveItem {
if chatId == cInfo.id, let i = getChatItemIndex(cItem) {
markCurrentChatRead(fromIndex: i)
_updateChat(cInfo.id) { chat in
var unreadBelow = 0
var unreadMentionsBelow = 0
var j = i - 1
while j >= 0 {
let meta = self.im.reversedChatItems[j].meta
if case .rcvNew = meta.itemStatus {
unreadBelow += 1
if meta.userMention {
unreadMentionsBelow += 1
}
}
j -= 1
}
// update preview
let markedCount = chat.chatStats.unreadCount - unreadBelow
let markedMentionsCount = chat.chatStats.unreadMentions - unreadMentionsBelow
if markedCount > 0 || markedMentionsCount > 0 {
let wasUnread = chat.unreadTag
chat.chatStats.unreadCount -= markedCount
chat.chatStats.unreadMentions -= markedMentionsCount
ChatTagsModel.shared.updateChatTagRead(chat, wasUnread: wasUnread)
let by = chat.chatInfo.chatSettings?.enableNtfs == .mentions ? markedMentionsCount : markedCount
self.decreaseUnreadCounter(user: self.currentUser!, by: by)
self.updateFloatingButtons(unreadCount: chat.chatStats.unreadCount)
}
}
var i = 0
while i < im.reversedChatItems.count {
markChatItemRead_(i)
i += 1
}
} else {
markChatItemsRead(cInfo)
im.chatItemsChangesListener.read(nil, im.reversedChatItems.reversed())
}
}
func markChatUnread(_ cInfo: ChatInfo, unreadChat: Bool = true) {
_updateChat(cInfo.id) { chat in
let wasUnread = chat.unreadTag
@ -745,16 +763,25 @@ final class ChatModel: ObservableObject {
if chatId == cInfo.id {
chatItemStatuses = [:]
im.reversedChatItems = []
im.chatItemsChangesListener.cleared()
}
}
func markChatItemsRead(_ cInfo: ChatInfo, _ itemIds: [ChatItem.ID], _ mentionsRead: Int) {
if self.chatId == cInfo.id {
for itemId in itemIds {
if let i = im.reversedChatItems.firstIndex(where: { $0.id == itemId }) {
var unreadItemIds: Set<ChatItem.ID> = []
var i = 0
var ids = Set(itemIds)
while i < im.reversedChatItems.count && !ids.isEmpty {
let item = im.reversedChatItems[i]
if ids.contains(item.id) && item.isRcvNew {
markChatItemRead_(i)
unreadItemIds.insert(item.id)
ids.remove(item.id)
}
i += 1
}
im.chatItemsChangesListener.read(unreadItemIds, im.reversedChatItems.reversed())
}
self.unreadCollector.changeUnreadCounter(cInfo.id, by: -itemIds.count, unreadMentions: -mentionsRead)
}
@ -782,9 +809,6 @@ final class ChatModel: ObservableObject {
}
func changeUnreadCounter(_ chatId: ChatId, by count: Int, unreadMentions: Int) {
if chatId == ChatModel.shared.chatId {
ChatView.FloatingButtonModel.shared.totalUnread += count
}
let (unread, mentions) = self.unreadCounts[chatId] ?? (0, 0)
self.unreadCounts[chatId] = (unread + count, mentions + unreadMentions)
subject.send()
@ -917,7 +941,7 @@ final class ChatModel: ObservableObject {
}
func decreaseGroupReportsCounter(_ chatId: ChatId, by: Int = 1) {
changeGroupReportsCounter(chatId, -1)
changeGroupReportsCounter(chatId, -by)
}
private func changeGroupReportsCounter(_ chatId: ChatId, _ by: Int = 0) {
@ -978,12 +1002,17 @@ final class ChatModel: ObservableObject {
// returns the previous member in the same merge group and the count of members in this group
func getPrevHiddenMember(_ member: GroupMember, _ range: ClosedRange<Int>) -> (GroupMember?, Int) {
let items = im.reversedChatItems
var prevMember: GroupMember? = nil
var memberIds: Set<Int64> = []
for i in range {
if case let .groupRcv(m) = im.reversedChatItems[i].chatDir {
if prevMember == nil && m.groupMemberId != member.groupMemberId { prevMember = m }
memberIds.insert(m.groupMemberId)
if i < items.count {
if case let .groupRcv(m) = items[i].chatDir {
if prevMember == nil && m.groupMemberId != member.groupMemberId { prevMember = m }
memberIds.insert(m.groupMemberId)
}
} else {
logger.error("getPrevHiddenMember: index >= count of reversed items: \(i) vs \(items.count), range: \(String(describing: range))")
}
}
return (prevMember, memberIds.count)

View file

@ -328,38 +328,27 @@ func apiGetChatTagsAsync() async throws -> [ChatTag] {
let loadItemsPerPage = 50
func apiGetChat(type: ChatType, id: Int64, search: String = "") async throws -> Chat {
let r = await chatSendCmd(.apiGetChat(type: type, id: id, pagination: .last(count: loadItemsPerPage), search: search))
if case let .apiChat(_, chat) = r { return Chat.init(chat) }
func apiGetChat(chatId: ChatId, pagination: ChatPagination, search: String = "") async throws -> (Chat, NavigationInfo) {
let r = await chatSendCmd(.apiGetChat(chatId: chatId, pagination: pagination, search: search))
if case let .apiChat(_, chat, navInfo) = r { return (Chat.init(chat), navInfo ?? NavigationInfo()) }
throw r
}
func apiGetChatItems(type: ChatType, id: Int64, pagination: ChatPagination, search: String = "") async throws -> [ChatItem] {
let r = await chatSendCmd(.apiGetChat(type: type, id: id, pagination: pagination, search: search))
if case let .apiChat(_, chat) = r { return chat.chatItems }
throw r
func loadChat(chat: Chat, search: String = "", clearItems: Bool = true) async {
await loadChat(chatId: chat.chatInfo.id, search: search, clearItems: clearItems)
}
func loadChat(chat: Chat, search: String = "", clearItems: Bool = true, replaceChat: Bool = false) async {
do {
let cInfo = chat.chatInfo
let m = ChatModel.shared
let im = ItemsModel.shared
func loadChat(chatId: ChatId, search: String = "", openAroundItemId: ChatItem.ID? = nil, clearItems: Bool = true) async {
let m = ChatModel.shared
let im = ItemsModel.shared
await MainActor.run {
m.chatItemStatuses = [:]
if clearItems {
await MainActor.run { im.reversedChatItems = [] }
im.reversedChatItems = []
ItemsModel.shared.chatItemsChangesListener.cleared()
}
let chat = try await apiGetChat(type: cInfo.chatType, id: cInfo.apiId, search: search)
await MainActor.run {
im.reversedChatItems = chat.chatItems.reversed()
m.updateChatInfo(chat.chatInfo)
if (replaceChat) {
m.replaceChat(chat.chatInfo.id, chat)
}
}
} catch let error {
logger.error("loadChat error: \(responseError(error))")
}
await apiLoadMessages(chatId, openAroundItemId != nil ? .around(chatItemId: openAroundItemId!, count: loadItemsPerPage) : (search == "" ? .initial(count: loadItemsPerPage) : .last(count: loadItemsPerPage)), im.chatState, search, openAroundItemId, { 0...0 })
}
func apiGetChatItemInfo(type: ChatType, id: Int64, itemId: Int64) async throws -> ChatItemInfo {
@ -516,6 +505,18 @@ func apiDeleteMemberChatItems(groupId: Int64, itemIds: [Int64]) async throws ->
throw r
}
func apiArchiveReceivedReports(groupId: Int64) async throws -> ChatResponse {
let r = await chatSendCmd(.apiArchiveReceivedReports(groupId: groupId), bgDelay: msgDelay)
if case .groupChatItemsDeleted = r { return r }
throw r
}
func apiDeleteReceivedReports(groupId: Int64, itemIds: [Int64], mode: CIDeleteMode) async throws -> [ChatItemDeletion] {
let r = await chatSendCmd(.apiDeleteReceivedReports(groupId: groupId, itemIds: itemIds, mode: mode), bgDelay: msgDelay)
if case let .chatItemsDeleted(_, chatItemDeletions, _) = r { return chatItemDeletions }
throw r
}
func apiGetNtfToken() -> (DeviceToken?, NtfTknStatus?, NotificationsMode, String?) {
let r = chatSendCmdSync(.apiGetNtfToken)
switch r {
@ -542,7 +543,12 @@ func registerToken(token: DeviceToken) {
Task {
do {
let status = try await apiRegisterToken(token: token, notificationMode: mode)
await MainActor.run { m.tokenStatus = status }
await MainActor.run {
m.tokenStatus = status
if !status.workingToken {
m.reRegisterTknStatus = status
}
}
} catch let error {
logger.error("registerToken apiRegisterToken error: \(responseError(error))")
}
@ -550,10 +556,49 @@ func registerToken(token: DeviceToken) {
}
}
func tokenStatusInfo(_ status: NtfTknStatus, register: Bool) -> String {
String.localizedStringWithFormat(NSLocalizedString("Token status: %@.", comment: "token status"), status.text)
+ "\n" + status.info(register: register)
}
func reRegisterToken(token: DeviceToken) {
let m = ChatModel.shared
let mode = m.notificationMode
logger.debug("reRegisterToken \(mode.rawValue)")
Task {
do {
let status = try await apiRegisterToken(token: token, notificationMode: mode)
await MainActor.run {
m.tokenStatus = status
showAlert(
status.workingToken
? NSLocalizedString("Notifications status", comment: "alert title")
: NSLocalizedString("Notifications error", comment: "alert title"),
message: tokenStatusInfo(status, register: false)
)
}
} catch let error {
logger.error("reRegisterToken apiRegisterToken error: \(responseError(error))")
await MainActor.run {
showAlert(
NSLocalizedString("Error registering for notifications", comment: "alert title"),
message: responseError(error)
)
}
}
}
}
func apiVerifyToken(token: DeviceToken, nonce: String, code: String) async throws {
try await sendCommandOkResp(.apiVerifyToken(token: token, nonce: nonce, code: code))
}
func apiCheckToken(token: DeviceToken) async throws -> NtfTknStatus {
let r = await chatSendCmd(.apiCheckToken(token: token))
if case let .ntfTokenStatus(status) = r { return status }
throw r
}
func apiDeleteToken(token: DeviceToken) async throws {
try await sendCommandOkResp(.apiDeleteToken(token: token))
}
@ -813,7 +858,7 @@ func apiSetConnectionIncognito(connId: Int64, incognito: Bool) async throws -> P
func apiChangeConnectionUser(connId: Int64, userId: Int64) async throws -> PendingContactConnection? {
let r = await chatSendCmd(.apiChangeConnectionUser(connId: connId, userId: userId))
if case let .connectionUserChanged(_, _, toConnection, _) = r {return toConnection}
throw r
}
@ -1468,7 +1513,7 @@ func markChatRead(_ chat: Chat) async {
let cInfo = chat.chatInfo
try await apiChatRead(type: cInfo.chatType, id: cInfo.apiId)
await MainActor.run {
withAnimation { ChatModel.shared.markChatItemsRead(cInfo) }
withAnimation { ChatModel.shared.markAllChatItemsRead(cInfo) }
}
}
if chat.chatStats.unreadChat {
@ -1543,21 +1588,21 @@ func apiJoinGroup(_ groupId: Int64) async throws -> JoinGroupResult {
}
}
func apiRemoveMember(_ groupId: Int64, _ memberId: Int64) async throws -> GroupMember {
let r = await chatSendCmd(.apiRemoveMember(groupId: groupId, memberId: memberId), bgTask: false)
if case let .userDeletedMember(_, _, member) = r { return member }
func apiRemoveMembers(_ groupId: Int64, _ memberIds: [Int64], _ withMessages: Bool = false) async throws -> [GroupMember] {
let r = await chatSendCmd(.apiRemoveMembers(groupId: groupId, memberIds: memberIds, withMessages: withMessages), bgTask: false)
if case let .userDeletedMembers(_, _, members, withMessages) = r { return members }
throw r
}
func apiMemberRole(_ groupId: Int64, _ memberId: Int64, _ memberRole: GroupMemberRole) async throws -> GroupMember {
let r = await chatSendCmd(.apiMemberRole(groupId: groupId, memberId: memberId, memberRole: memberRole), bgTask: false)
if case let .memberRoleUser(_, _, member, _, _) = r { return member }
func apiMembersRole(_ groupId: Int64, _ memberIds: [Int64], _ memberRole: GroupMemberRole) async throws -> [GroupMember] {
let r = await chatSendCmd(.apiMembersRole(groupId: groupId, memberIds: memberIds, memberRole: memberRole), bgTask: false)
if case let .membersRoleUser(_, _, members, _) = r { return members }
throw r
}
func apiBlockMemberForAll(_ groupId: Int64, _ memberId: Int64, _ blocked: Bool) async throws -> GroupMember {
let r = await chatSendCmd(.apiBlockMemberForAll(groupId: groupId, memberId: memberId, blocked: blocked), bgTask: false)
if case let .memberBlockedForAllUser(_, _, member, _) = r { return member }
func apiBlockMembersForAll(_ groupId: Int64, _ memberIds: [Int64], _ blocked: Bool) async throws -> [GroupMember] {
let r = await chatSendCmd(.apiBlockMembersForAll(groupId: groupId, memberIds: memberIds, blocked: blocked), bgTask: false)
if case let .membersBlockedForAllUser(_, _, members, _) = r { return members }
throw r
}
@ -2090,42 +2135,13 @@ func processReceivedMsg(_ res: ChatResponse) async {
} else {
m.removeChatItem(item.deletedChatItem.chatInfo, item.deletedChatItem.chatItem)
}
if item.deletedChatItem.chatItem.isActiveReport {
m.decreaseGroupReportsCounter(item.deletedChatItem.chatInfo.id)
}
}
}
case let .groupChatItemsDeleted(user, groupInfo, chatItemIDs, _, member_):
if !active(user) {
do {
let users = try listUsers()
await MainActor.run {
m.users = users
}
} catch {
logger.error("Error loading users: \(error)")
}
return
}
let im = ItemsModel.shared
let cInfo = ChatInfo.group(groupInfo: groupInfo)
await MainActor.run {
m.decreaseGroupReportsCounter(cInfo.id, by: chatItemIDs.count)
}
var notFound = chatItemIDs.count
for ci in im.reversedChatItems {
if chatItemIDs.contains(ci.id) {
let deleted = if case let .groupRcv(groupMember) = ci.chatDir, let member_, groupMember.groupMemberId != member_.groupMemberId {
CIDeleted.moderated(deletedTs: Date.now, byGroupMember: member_)
} else {
CIDeleted.deleted(deletedTs: Date.now)
}
await MainActor.run {
var newItem = ci
newItem.meta.itemDeleted = deleted
_ = m.upsertChatItem(cInfo, newItem)
}
notFound -= 1
if notFound == 0 { break }
}
}
await groupChatItemsDeleted(user, groupInfo, chatItemIDs, member_)
case let .receivedGroupInvitation(user, groupInfo, _, _):
if active(user) {
await MainActor.run {
@ -2145,7 +2161,7 @@ func processReceivedMsg(_ res: ChatResponse) async {
}
case let .groupLinkConnecting(user, groupInfo, hostMember):
if !active(user) { return }
await MainActor.run {
m.updateGroup(groupInfo)
if let hostConn = hostMember.activeConn {
@ -2171,16 +2187,22 @@ func processReceivedMsg(_ res: ChatResponse) async {
_ = m.upsertGroupMember(groupInfo, member)
}
}
case let .deletedMemberUser(user, groupInfo, _): // TODO update user member
case let .deletedMemberUser(user, groupInfo, member, withMessages): // TODO update user member
if active(user) {
await MainActor.run {
m.updateGroup(groupInfo)
if withMessages {
m.removeMemberItems(groupInfo.membership, byMember: member, groupInfo)
}
}
}
case let .deletedMember(user, groupInfo, _, deletedMember):
case let .deletedMember(user, groupInfo, byMember, deletedMember, withMessages):
if active(user) {
await MainActor.run {
_ = m.upsertGroupMember(groupInfo, deletedMember)
if withMessages {
m.removeMemberItems(deletedMember, byMember: byMember, groupInfo)
}
}
}
case let .leftMember(user, groupInfo, member):
@ -2468,6 +2490,43 @@ func chatItemSimpleUpdate(_ user: any UserLike, _ aChatItem: AChatItem) async {
}
}
func groupChatItemsDeleted(_ user: UserRef, _ groupInfo: GroupInfo, _ chatItemIDs: Set<Int64>, _ member_: GroupMember?) async {
let m = ChatModel.shared
if !active(user) {
do {
let users = try listUsers()
await MainActor.run {
m.users = users
}
} catch {
logger.error("Error loading users: \(error)")
}
return
}
let im = ItemsModel.shared
let cInfo = ChatInfo.group(groupInfo: groupInfo)
await MainActor.run {
m.decreaseGroupReportsCounter(cInfo.id, by: chatItemIDs.count)
}
var notFound = chatItemIDs.count
for ci in im.reversedChatItems {
if chatItemIDs.contains(ci.id) {
let deleted = if case let .groupRcv(groupMember) = ci.chatDir, let member_, groupMember.groupMemberId != member_.groupMemberId {
CIDeleted.moderated(deletedTs: Date.now, byGroupMember: member_)
} else {
CIDeleted.deleted(deletedTs: Date.now)
}
await MainActor.run {
var newItem = ci
newItem.meta.itemDeleted = deleted
_ = m.upsertChatItem(cInfo, newItem)
}
notFound -= 1
if notFound == 0 { break }
}
}
}
func refreshCallInvitations() async throws {
let m = ChatModel.shared
let callInvitations = try await apiGetCallInvitations()

View file

@ -361,7 +361,7 @@ struct ActiveCallOverlay: View {
HStack {
Text(call.encryptionStatus)
if let connInfo = call.connectionInfo {
Text("(") + Text(connInfo.text) + Text(")")
Text(verbatim: "(") + Text(connInfo.text) + Text(verbatim: ")")
}
}
}
@ -390,7 +390,7 @@ struct ActiveCallOverlay: View {
HStack {
Text(call.encryptionStatus)
if let connInfo = call.connectionInfo {
Text("(") + Text(connInfo.text) + Text(")")
Text(verbatim: "(") + Text(connInfo.text) + Text(verbatim: ")")
}
}
}

View file

@ -684,17 +684,23 @@ struct ChatTTLOption: View {
) {
progressIndicator = true
Task {
let m = ChatModel.shared
do {
try await setChatTTL(chatType: chat.chatInfo.chatType, id: chat.chatInfo.apiId, ttl)
await loadChat(chat: chat, clearItems: true, replaceChat: true)
await loadChat(chat: chat, clearItems: true)
await MainActor.run {
progressIndicator = false
currentChatItemTTL = chatItemTTL
if ItemsModel.shared.reversedChatItems.isEmpty && m.chatId == chat.id,
let chat = m.getChat(chat.id) {
chat.chatItems = []
m.replaceChat(chat.id, chat)
}
}
}
catch let error {
logger.error("setChatTTL error \(responseError(error))")
await loadChat(chat: chat, clearItems: true, replaceChat: true)
await loadChat(chat: chat, clearItems: true)
await MainActor.run {
chatItemTTL = currentChatItemTTL
progressIndicator = false

View file

@ -293,16 +293,16 @@ struct CIFileView_Previews: PreviewProvider {
file: nil
)
Group {
ChatItemView(chat: Chat.sampleData, chatItem: sentFile)
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample())
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileName: "some_long_file_name_here", fileStatus: .rcvInvitation))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvAccepted))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvCancelled))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileSize: 1_000_000_000, fileStatus: .rcvInvitation))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(text: "Hello there", fileStatus: .rcvInvitation))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", fileStatus: .rcvInvitation))
ChatItemView(chat: Chat.sampleData, chatItem: fileChatItemWtFile)
ChatItemView(chat: Chat.sampleData, chatItem: sentFile, scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileName: "some_long_file_name_here", fileStatus: .rcvInvitation), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvAccepted), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvCancelled), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileSize: 1_000_000_000, fileStatus: .rcvInvitation), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(text: "Hello there", fileStatus: .rcvInvitation), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", fileStatus: .rcvInvitation), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: fileChatItemWtFile, scrollToItemId: { _ in })
}
.environment(\.revealed, false)
.previewLayout(.fixed(width: 360, height: 360))

View file

@ -12,6 +12,7 @@ import SimpleXChat
struct CIImageView: View {
@EnvironmentObject var m: ChatModel
let chatItem: ChatItem
var scrollToItemId: ((ChatItem.ID) -> Void)? = nil
var preview: UIImage?
let maxWidth: CGFloat
var imgWidth: CGFloat?
@ -25,7 +26,7 @@ struct CIImageView: View {
if let uiImage = getLoadedImage(file) {
Group { if smallView { smallViewImageView(uiImage) } else { imageView(uiImage) } }
.fullScreenCover(isPresented: $showFullScreenImage) {
FullScreenMediaView(chatItem: chatItem, image: uiImage, showView: $showFullScreenImage)
FullScreenMediaView(chatItem: chatItem, scrollToItemId: scrollToItemId, image: uiImage, showView: $showFullScreenImage)
}
.if(!smallView) { view in
view.modifier(PrivacyBlur(blurred: $blurred))

View file

@ -21,9 +21,8 @@ struct CIMemberCreatedContactView: View {
if let contactId = groupMember.memberContactId {
memberCreatedContactView(openText: "Open")
.onTapGesture {
dismissAllSheets(animated: true)
DispatchQueue.main.async {
ItemsModel.shared.loadOpenChat("@\(contactId)")
ItemsModel.shared.loadOpenChat("@\(contactId)") {
dismissAllSheets(animated: true)
}
}
} else {

View file

@ -161,13 +161,13 @@ struct CIRcvDecryptionError: View {
let why = Text(decryptErrorReason)
switch msgDecryptError {
case .ratchetHeader:
message = Text("\(msgCount) messages failed to decrypt.") + Text("\n") + why
message = Text("\(msgCount) messages failed to decrypt.") + textNewLine + why
case .tooManySkipped:
message = Text("\(msgCount) messages skipped.") + Text("\n") + why
message = Text("\(msgCount) messages skipped.") + textNewLine + why
case .ratchetEarlier:
message = Text("\(msgCount) messages failed to decrypt.") + Text("\n") + why
message = Text("\(msgCount) messages failed to decrypt.") + textNewLine + why
case .other:
message = Text("\(msgCount) messages failed to decrypt.") + Text("\n") + why
message = Text("\(msgCount) messages failed to decrypt.") + textNewLine + why
case .ratchetSync:
message = Text("Encryption re-negotiation failed.")
}

View file

@ -498,10 +498,10 @@ struct CIVoiceView_Previews: PreviewProvider {
duration: 30,
allowMenu: Binding.constant(true)
)
ChatItemView(chat: Chat.sampleData, chatItem: sentVoiceMessage, allowMenu: .constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(), allowMenu: .constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), allowMenu: .constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: voiceMessageWtFile, allowMenu: .constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: sentVoiceMessage, scrollToItemId: { _ in }, allowMenu: .constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(), scrollToItemId: { _ in }, allowMenu: .constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), scrollToItemId: { _ in }, allowMenu: .constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: voiceMessageWtFile, scrollToItemId: { _ in }, allowMenu: .constant(true))
}
.previewLayout(.fixed(width: 360, height: 360))
}

View file

@ -92,11 +92,11 @@ struct FramedCIVoiceView_Previews: PreviewProvider {
file: CIFile.getSample(fileStatus: .sndComplete)
)
Group {
ChatItemView(chat: Chat.sampleData, chatItem: sentVoiceMessage)
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(text: "Hello there"))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(text: "Hello there", fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."))
ChatItemView(chat: Chat.sampleData, chatItem: voiceMessageWithQuote)
ChatItemView(chat: Chat.sampleData, chatItem: sentVoiceMessage, scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(text: "Hello there"), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(text: "Hello there", fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: voiceMessageWithQuote, scrollToItemId: { _ in })
}
.environment(\.revealed, false)
.previewLayout(.fixed(width: 360, height: 360))

File diff suppressed because one or more lines are too long

View file

@ -13,8 +13,8 @@ import AVKit
struct FullScreenMediaView: View {
@EnvironmentObject var m: ChatModel
@EnvironmentObject var scrollModel: ReverseListScrollModel
@State var chatItem: ChatItem
var scrollToItemId: ((ChatItem.ID) -> Void)?
@State var image: UIImage?
@State var player: AVPlayer? = nil
@State var url: URL? = nil
@ -71,7 +71,7 @@ struct FullScreenMediaView: View {
let w = abs(t.width)
if t.height > 60 && t.height > w * 2 {
showView = false
scrollModel.scrollToItem(id: chatItem.id)
scrollToItemId?(chatItem.id)
} else if w > 60 && w > abs(t.height) * 2 && !scrolling {
let previous = t.width > 0
scrolling = true

View file

@ -31,8 +31,8 @@ struct IntegrityErrorItemView: View {
case .msgBadHash:
AlertManager.shared.showAlert(Alert(
title: Text("Bad message hash"),
message: Text("The hash of the previous message is different.") + Text("\n") +
Text(decryptErrorReason) + Text("\n") +
message: Text("The hash of the previous message is different.") + textNewLine +
Text(decryptErrorReason) + textNewLine +
Text("Please report it to the developers.")
))
case .msgBadId: msgBadIdAlert()
@ -47,7 +47,7 @@ struct IntegrityErrorItemView: View {
message: Text("""
The ID of the next message is incorrect (less or equal to the previous).
It can happen because of some bug or when the connection is compromised.
""") + Text("\n") +
""") + textNewLine +
Text("Please report it to the developers.")
))
}

View file

@ -21,7 +21,7 @@ private let typingIndicators: [Text] = [
]
private func typing(_ w: Font.Weight = .light) -> Text {
Text(".").fontWeight(w)
Text(verbatim: ".").fontWeight(w)
}
struct MsgContentView: View {
@ -88,7 +88,7 @@ struct MsgContentView: View {
}
private func reserveSpaceForMeta(_ mt: CIMeta) -> Text {
(rightToLeft ? Text("\n") : Text(verbatim: " ")) + ciMetaText(mt, chatTTL: chat.chatInfo.timedMessagesTTL, encrypted: nil, colorMode: .transparent, showViaProxy: showSentViaProxy, showTimesamp: showTimestamp)
(rightToLeft ? textNewLine : Text(verbatim: " ")) + ciMetaText(mt, chatTTL: chat.chatInfo.timedMessagesTTL, encrypted: nil, colorMode: .transparent, showViaProxy: showSentViaProxy, showTimesamp: showTimestamp)
}
}
@ -117,7 +117,7 @@ func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: St
if let s = sender {
let t = Text(s)
return (preview ? t : t.fontWeight(.medium)) + Text(": ") + res
return (preview ? t : t.fontWeight(.medium)) + Text(verbatim: ": ") + res
} else {
return res
}
@ -170,7 +170,7 @@ private func formatText(_ ft: FormattedText, _ preview: Bool, showSecret: Bool,
}
private func mentionText(_ name: String) -> Text {
Text(name.contains(" @") ? "@'\(name)'" : "@\(name)").fontWeight(.semibold)
Text(verbatim: name.contains(" @") ? "@'\(name)'" : "@\(name)").fontWeight(.semibold)
}
private func linkText(_ s: String, _ link: String, _ preview: Bool, prefix: String, color: Color = Color(uiColor: uiLinkColor), uiColor: UIColor = uiLinkColor) -> Text {

View file

@ -354,8 +354,9 @@ struct ChatItemInfoView: View {
Button {
Task {
await MainActor.run {
ItemsModel.shared.loadOpenChat(forwardedFromItem.chatInfo.id)
dismiss()
ItemsModel.shared.loadOpenChat(forwardedFromItem.chatInfo.id) {
dismiss()
}
}
}
} label: {

View file

@ -35,18 +35,21 @@ struct ChatItemView: View {
@Environment(\.showTimestamp) var showTimestamp: Bool
@Environment(\.revealed) var revealed: Bool
var chatItem: ChatItem
var scrollToItemId: (ChatItem.ID) -> Void
var maxWidth: CGFloat = .infinity
@Binding var allowMenu: Bool
init(
chat: Chat,
chatItem: ChatItem,
scrollToItemId: @escaping (ChatItem.ID) -> Void,
showMember: Bool = false,
maxWidth: CGFloat = .infinity,
allowMenu: Binding<Bool> = .constant(false)
) {
self.chat = chat
self.chatItem = chatItem
self.scrollToItemId = scrollToItemId
self.maxWidth = maxWidth
_allowMenu = allowMenu
}
@ -90,6 +93,7 @@ struct ChatItemView: View {
return FramedItemView(
chat: chat,
chatItem: chatItem,
scrollToItemId: scrollToItemId,
preview: preview,
maxWidth: maxWidth,
imgWidth: adjustedMaxWidth,
@ -244,15 +248,15 @@ func chatEventText(_ ci: ChatItem, _ secondaryColor: Color) -> Text {
struct ChatItemView_Previews: PreviewProvider {
static var previews: some View {
Group{
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello"))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directRcv, .now, "hello there too"))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂"))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂"))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂🙂"))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getDeletedContentSample())
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete), itemDeleted: .deleted(deletedTs: .now)))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂", .sndSent(sndProgress: .complete), itemLive: true)).environment(\.revealed, true)
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete), itemLive: true)).environment(\.revealed, true)
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello"), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directRcv, .now, "hello there too"), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂"), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂"), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂🙂"), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getDeletedContentSample(), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete), itemDeleted: .deleted(deletedTs: .now)), scrollToItemId: { _ in })
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂", .sndSent(sndProgress: .complete), itemLive: true), scrollToItemId: { _ in }).environment(\.revealed, true)
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete), itemLive: true), scrollToItemId: { _ in }).environment(\.revealed, true)
}
.environment(\.revealed, false)
.previewLayout(.fixed(width: 360, height: 70))
@ -272,7 +276,8 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
content: .rcvIntegrityError(msgError: .msgSkipped(fromMsgId: 1, toMsgId: 2)),
quotedItem: nil,
file: nil
)
),
scrollToItemId: { _ in }
)
ChatItemView(
chat: Chat.sampleData,
@ -282,7 +287,8 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
content: .rcvDecryptionError(msgDecryptError: .ratchetHeader, msgCount: 2),
quotedItem: nil,
file: nil
)
),
scrollToItemId: { _ in }
)
ChatItemView(
chat: Chat.sampleData,
@ -292,7 +298,8 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
content: .rcvGroupInvitation(groupInvitation: CIGroupInvitation.getSample(status: .pending), memberRole: .admin),
quotedItem: nil,
file: nil
)
),
scrollToItemId: { _ in }
)
ChatItemView(
chat: Chat.sampleData,
@ -302,7 +309,8 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
content: .rcvGroupEvent(rcvGroupEvent: .memberAdded(groupMemberId: 1, profile: Profile.sampleData)),
quotedItem: nil,
file: nil
)
),
scrollToItemId: { _ in }
)
ChatItemView(
chat: Chat.sampleData,
@ -312,7 +320,8 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
content: ciFeatureContent,
quotedItem: nil,
file: nil
)
),
scrollToItemId: { _ in }
)
}
.environment(\.revealed, true)

View file

@ -0,0 +1,342 @@
//
// ChatItemsLoader.swift
// SimpleX (iOS)
//
// Created by Stanislav Dmitrenko on 17.12.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SimpleXChat
import SwiftUI
let TRIM_KEEP_COUNT = 200
func apiLoadMessages(
_ chatId: ChatId,
_ pagination: ChatPagination,
_ chatState: ActiveChatState,
_ search: String = "",
_ openAroundItemId: ChatItem.ID? = nil,
_ visibleItemIndexesNonReversed: @MainActor () -> ClosedRange<Int> = { 0 ... 0 }
) async {
let chat: Chat
let navInfo: NavigationInfo
do {
(chat, navInfo) = try await apiGetChat(chatId: chatId, pagination: pagination, search: search)
} catch let error {
logger.error("apiLoadMessages error: \(responseError(error))")
return
}
let chatModel = ChatModel.shared
// For .initial allow the chatItems to be empty as well as chatModel.chatId to not match this chat because these values become set after .initial finishes
let paginationIsInitial = switch pagination { case .initial: true; default: false }
let paginationIsLast = switch pagination { case .last: true; default: false }
// When openAroundItemId is provided, chatId can be different too
if ((chatModel.chatId != chat.id || chat.chatItems.isEmpty) && !paginationIsInitial && !paginationIsLast && openAroundItemId == nil) || Task.isCancelled {
return
}
let unreadAfterItemId = chatState.unreadAfterItemId
let oldItems = Array(ItemsModel.shared.reversedChatItems.reversed())
var newItems: [ChatItem] = []
switch pagination {
case .initial:
let newSplits: [Int64] = if !chat.chatItems.isEmpty && navInfo.afterTotal > 0 { [chat.chatItems.last!.id] } else { [] }
if chatModel.getChat(chat.id) == nil {
chatModel.addChat(chat)
}
await MainActor.run {
chatModel.chatItemStatuses.removeAll()
ItemsModel.shared.reversedChatItems = chat.chatItems.reversed()
chatModel.updateChatInfo(chat.chatInfo)
chatState.splits = newSplits
if !chat.chatItems.isEmpty {
chatState.unreadAfterItemId = chat.chatItems.last!.id
}
chatState.totalAfter = navInfo.afterTotal
chatState.unreadTotal = chat.chatStats.unreadCount
chatState.unreadAfter = navInfo.afterUnread
chatState.unreadAfterNewestLoaded = navInfo.afterUnread
}
case let .before(paginationChatItemId, _):
newItems.append(contentsOf: oldItems)
let indexInCurrentItems = oldItems.firstIndex(where: { $0.id == paginationChatItemId })
guard let indexInCurrentItems else { return }
let (newIds, _) = mapItemsToIds(chat.chatItems)
let wasSize = newItems.count
let visibleItemIndexes = await MainActor.run { visibleItemIndexesNonReversed() }
let modifiedSplits = removeDuplicatesAndModifySplitsOnBeforePagination(
unreadAfterItemId, &newItems, newIds, chatState.splits, visibleItemIndexes
)
let insertAt = max((indexInCurrentItems - (wasSize - newItems.count) + modifiedSplits.trimmedIds.count), 0)
newItems.insert(contentsOf: chat.chatItems, at: insertAt)
let newReversed: [ChatItem] = newItems.reversed()
await MainActor.run {
ItemsModel.shared.reversedChatItems = newReversed
chatState.splits = modifiedSplits.newSplits
chatState.moveUnreadAfterItem(modifiedSplits.oldUnreadSplitIndex, modifiedSplits.newUnreadSplitIndex, oldItems)
}
case let .after(paginationChatItemId, _):
newItems.append(contentsOf: oldItems)
let indexInCurrentItems = oldItems.firstIndex(where: { $0.id == paginationChatItemId })
guard let indexInCurrentItems else { return }
let mappedItems = mapItemsToIds(chat.chatItems)
let newIds = mappedItems.0
let (newSplits, unreadInLoaded) = removeDuplicatesAndModifySplitsOnAfterPagination(
mappedItems.1, paginationChatItemId, &newItems, newIds, chat, chatState.splits
)
let indexToAdd = min(indexInCurrentItems + 1, newItems.count)
let indexToAddIsLast = indexToAdd == newItems.count
newItems.insert(contentsOf: chat.chatItems, at: indexToAdd)
let new: [ChatItem] = newItems
let newReversed: [ChatItem] = newItems.reversed()
await MainActor.run {
ItemsModel.shared.reversedChatItems = newReversed
chatState.splits = newSplits
chatState.moveUnreadAfterItem(chatState.splits.first ?? new.last!.id, new)
// loading clear bottom area, updating number of unread items after the newest loaded item
if indexToAddIsLast {
chatState.unreadAfterNewestLoaded -= unreadInLoaded
}
}
case .around:
let newSplits: [Int64]
if openAroundItemId == nil {
newItems.append(contentsOf: oldItems)
newSplits = await removeDuplicatesAndUpperSplits(&newItems, chat, chatState.splits, visibleItemIndexesNonReversed)
} else {
newSplits = []
}
// currently, items will always be added on top, which is index 0
newItems.insert(contentsOf: chat.chatItems, at: 0)
let newReversed: [ChatItem] = newItems.reversed()
await MainActor.run {
ItemsModel.shared.reversedChatItems = newReversed
chatState.splits = [chat.chatItems.last!.id] + newSplits
chatState.unreadAfterItemId = chat.chatItems.last!.id
chatState.totalAfter = navInfo.afterTotal
chatState.unreadTotal = chat.chatStats.unreadCount
chatState.unreadAfter = navInfo.afterUnread
if let openAroundItemId {
chatState.unreadAfterNewestLoaded = navInfo.afterUnread
ChatModel.shared.openAroundItemId = openAroundItemId
ChatModel.shared.chatId = chatId
} else {
// no need to set it, count will be wrong
// chatState.unreadAfterNewestLoaded = navInfo.afterUnread
}
}
case .last:
newItems.append(contentsOf: oldItems)
removeDuplicates(&newItems, chat)
newItems.append(contentsOf: chat.chatItems)
let items = newItems
await MainActor.run {
ItemsModel.shared.reversedChatItems = items.reversed()
chatModel.updateChatInfo(chat.chatInfo)
chatState.unreadAfterNewestLoaded = 0
}
}
}
private class ModifiedSplits {
let oldUnreadSplitIndex: Int
let newUnreadSplitIndex: Int
let trimmedIds: Set<Int64>
let newSplits: [Int64]
init(oldUnreadSplitIndex: Int, newUnreadSplitIndex: Int, trimmedIds: Set<Int64>, newSplits: [Int64]) {
self.oldUnreadSplitIndex = oldUnreadSplitIndex
self.newUnreadSplitIndex = newUnreadSplitIndex
self.trimmedIds = trimmedIds
self.newSplits = newSplits
}
}
private func removeDuplicatesAndModifySplitsOnBeforePagination(
_ unreadAfterItemId: Int64,
_ newItems: inout [ChatItem],
_ newIds: Set<Int64>,
_ splits: [Int64],
_ visibleItemIndexes: ClosedRange<Int>
) -> ModifiedSplits {
var oldUnreadSplitIndex: Int = -1
var newUnreadSplitIndex: Int = -1
var lastSplitIndexTrimmed: Int? = nil
var allowedTrimming = true
var index = 0
/** keep the newest [TRIM_KEEP_COUNT] items (bottom area) and oldest [TRIM_KEEP_COUNT] items, trim others */
let trimLowerBound = visibleItemIndexes.upperBound + TRIM_KEEP_COUNT
let trimUpperBound = newItems.count - TRIM_KEEP_COUNT
let trimRange = trimUpperBound >= trimLowerBound ? trimLowerBound ... trimUpperBound : -1 ... -1
var trimmedIds = Set<Int64>()
let prevTrimLowerBound = visibleItemIndexes.upperBound + TRIM_KEEP_COUNT + 1
let prevTrimUpperBound = newItems.count - TRIM_KEEP_COUNT
let prevItemTrimRange = prevTrimUpperBound >= prevTrimLowerBound ? prevTrimLowerBound ... prevTrimUpperBound : -1 ... -1
var newSplits = splits
newItems.removeAll(where: {
let invisibleItemToTrim = trimRange.contains(index) && allowedTrimming
let prevItemWasTrimmed = prevItemTrimRange.contains(index) && allowedTrimming
// may disable it after clearing the whole split range
if !splits.isEmpty && $0.id == splits.first {
// trim only in one split range
allowedTrimming = false
}
let indexInSplits = splits.firstIndex(of: $0.id)
if let indexInSplits {
lastSplitIndexTrimmed = indexInSplits
}
if invisibleItemToTrim {
if prevItemWasTrimmed {
trimmedIds.insert($0.id)
} else {
newUnreadSplitIndex = index
// prev item is not supposed to be trimmed, so exclude current one from trimming and set a split here instead.
// this allows to define splitRange of the oldest items and to start loading trimmed items when user scrolls in the opposite direction
if let lastSplitIndexTrimmed {
var new = newSplits
new[lastSplitIndexTrimmed] = $0.id
newSplits = new
} else {
newSplits = [$0.id] + newSplits
}
}
}
if unreadAfterItemId == $0.id {
oldUnreadSplitIndex = index
}
index += 1
return (invisibleItemToTrim && prevItemWasTrimmed) || newIds.contains($0.id)
})
// will remove any splits that now becomes obsolete because items were merged
newSplits = newSplits.filter { split in !newIds.contains(split) && !trimmedIds.contains(split) }
return ModifiedSplits(oldUnreadSplitIndex: oldUnreadSplitIndex, newUnreadSplitIndex: newUnreadSplitIndex, trimmedIds: trimmedIds, newSplits: newSplits)
}
private func removeDuplicatesAndModifySplitsOnAfterPagination(
_ unreadInLoaded: Int,
_ paginationChatItemId: Int64,
_ newItems: inout [ChatItem],
_ newIds: Set<Int64>,
_ chat: Chat,
_ splits: [Int64]
) -> ([Int64], Int) {
var unreadInLoaded = unreadInLoaded
var firstItemIdBelowAllSplits: Int64? = nil
var splitsToRemove: Set<Int64> = []
let indexInSplitRanges = splits.firstIndex(of: paginationChatItemId)
// Currently, it should always load from split range
let loadingFromSplitRange = indexInSplitRanges != nil
var splitsToMerge: [Int64] = if let indexInSplitRanges, loadingFromSplitRange && indexInSplitRanges + 1 <= splits.count {
Array(splits[indexInSplitRanges + 1 ..< splits.count])
} else {
[]
}
newItems.removeAll(where: { new in
let duplicate = newIds.contains(new.id)
if loadingFromSplitRange && duplicate {
if splitsToMerge.contains(new.id) {
splitsToMerge.removeAll(where: { $0 == new.id })
splitsToRemove.insert(new.id)
} else if firstItemIdBelowAllSplits == nil && splitsToMerge.isEmpty {
// we passed all splits and found duplicated item below all of them, which means no splits anymore below the loaded items
firstItemIdBelowAllSplits = new.id
}
}
if duplicate && new.isRcvNew {
unreadInLoaded -= 1
}
return duplicate
})
var newSplits: [Int64] = []
if firstItemIdBelowAllSplits != nil {
// no splits anymore, all were merged with bottom items
newSplits = []
} else {
if !splitsToRemove.isEmpty {
var new = splits
new.removeAll(where: { splitsToRemove.contains($0) })
newSplits = new
}
let enlargedSplit = splits.firstIndex(of: paginationChatItemId)
if let enlargedSplit {
// move the split to the end of loaded items
var new = splits
new[enlargedSplit] = chat.chatItems.last!.id
newSplits = new
}
}
return (newSplits, unreadInLoaded)
}
private func removeDuplicatesAndUpperSplits(
_ newItems: inout [ChatItem],
_ chat: Chat,
_ splits: [Int64],
_ visibleItemIndexesNonReversed: @MainActor () -> ClosedRange<Int>
) async -> [Int64] {
if splits.isEmpty {
removeDuplicates(&newItems, chat)
return splits
}
var newSplits = splits
let visibleItemIndexes = await MainActor.run { visibleItemIndexesNonReversed() }
let (newIds, _) = mapItemsToIds(chat.chatItems)
var idsToTrim: [BoxedValue<Set<Int64>>] = []
idsToTrim.append(BoxedValue(Set()))
var index = 0
newItems.removeAll(where: {
let duplicate = newIds.contains($0.id)
if (!duplicate && visibleItemIndexes.lowerBound > index) {
idsToTrim.last?.boxedValue.insert($0.id)
}
if visibleItemIndexes.lowerBound > index, let firstIndex = newSplits.firstIndex(of: $0.id) {
newSplits.remove(at: firstIndex)
// closing previous range. All items in idsToTrim that ends with empty set should be deleted.
// Otherwise, the last set should be excluded from trimming because it is in currently visible split range
idsToTrim.append(BoxedValue(Set()))
}
index += 1
return duplicate
})
if !idsToTrim.last!.boxedValue.isEmpty {
// it has some elements to trim from currently visible range which means the items shouldn't be trimmed
// Otherwise, the last set would be empty
idsToTrim.removeLast()
}
let allItemsToDelete = idsToTrim.compactMap { set in set.boxedValue }.joined()
if !allItemsToDelete.isEmpty {
newItems.removeAll(where: { allItemsToDelete.contains($0.id) })
}
return newSplits
}
// ids, number of unread items
private func mapItemsToIds(_ items: [ChatItem]) -> (Set<Int64>, Int) {
var unreadInLoaded = 0
var ids: Set<Int64> = Set()
var i = 0
while i < items.count {
let item = items[i]
ids.insert(item.id)
if item.isRcvNew {
unreadInLoaded += 1
}
i += 1
}
return (ids, unreadInLoaded)
}
private func removeDuplicates(_ newItems: inout [ChatItem], _ chat: Chat) {
let (newIds, _) = mapItemsToIds(chat.chatItems)
newItems.removeAll { newIds.contains($0.id) }
}

View file

@ -0,0 +1,459 @@
//
// ChatItemsMerger.swift
// SimpleX (iOS)
//
// Created by Stanislav Dmitrenko on 02.12.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct MergedItems: Hashable, Equatable {
let items: [MergedItem]
let splits: [SplitRange]
// chat item id, index in list
let indexInParentItems: Dictionary<Int64, Int>
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.hashValue == rhs.hashValue
}
func hash(into hasher: inout Hasher) {
hasher.combine("\(items.hashValue)")
}
static func create(_ items: [ChatItem], _ revealedItems: Set<Int64>, _ chatState: ActiveChatState) -> MergedItems {
if items.isEmpty {
return MergedItems(items: [], splits: [], indexInParentItems: [:])
}
let unreadCount = chatState.unreadTotal
let unreadAfterItemId = chatState.unreadAfterItemId
let itemSplits = chatState.splits
var mergedItems: [MergedItem] = []
// Indexes of splits here will be related to reversedChatItems, not chatModel.chatItems
var splitRanges: [SplitRange] = []
var indexInParentItems = Dictionary<Int64, Int>()
var index = 0
var unclosedSplitIndex: Int? = nil
var unclosedSplitIndexInParent: Int? = nil
var visibleItemIndexInParent = -1
var unreadBefore = unreadCount - chatState.unreadAfterNewestLoaded
var lastRevealedIdsInMergedItems: BoxedValue<[Int64]>? = nil
var lastRangeInReversedForMergedItems: BoxedValue<ClosedRange<Int>>? = nil
var recent: MergedItem? = nil
while index < items.count {
let item = items[index]
let prev = index >= 1 ? items[index - 1] : nil
let next = index + 1 < items.count ? items[index + 1] : nil
let category = item.mergeCategory
let itemIsSplit = itemSplits.contains(item.id)
if item.id == unreadAfterItemId {
unreadBefore = unreadCount - chatState.unreadAfter
}
if item.isRcvNew {
unreadBefore -= 1
}
let revealed = item.mergeCategory == nil || revealedItems.contains(item.id)
if recent != nil, case let .grouped(items, _, _, _, mergeCategory, unreadIds, _, _) = recent, mergeCategory == category, let first = items.boxedValue.first, !revealedItems.contains(first.item.id) && !itemIsSplit {
let listItem = ListItem(item: item, prevItem: prev, nextItem: next, unreadBefore: unreadBefore)
items.boxedValue.append(listItem)
if item.isRcvNew {
unreadIds.boxedValue.insert(item.id)
}
if let lastRevealedIdsInMergedItems, let lastRangeInReversedForMergedItems {
if revealed {
lastRevealedIdsInMergedItems.boxedValue.append(item.id)
}
lastRangeInReversedForMergedItems.boxedValue = lastRangeInReversedForMergedItems.boxedValue.lowerBound ... index
}
} else {
visibleItemIndexInParent += 1
let listItem = ListItem(item: item, prevItem: prev, nextItem: next, unreadBefore: unreadBefore)
if item.mergeCategory != nil {
if item.mergeCategory != prev?.mergeCategory || lastRevealedIdsInMergedItems == nil {
lastRevealedIdsInMergedItems = BoxedValue(revealedItems.contains(item.id) ? [item.id] : [])
} else if revealed, let lastRevealedIdsInMergedItems {
lastRevealedIdsInMergedItems.boxedValue.append(item.id)
}
lastRangeInReversedForMergedItems = BoxedValue(index ... index)
recent = MergedItem.grouped(
items: BoxedValue([listItem]),
revealed: revealed,
revealedIdsWithinGroup: lastRevealedIdsInMergedItems!,
rangeInReversed: lastRangeInReversedForMergedItems!,
mergeCategory: item.mergeCategory,
unreadIds: BoxedValue(item.isRcvNew ? Set(arrayLiteral: item.id) : Set()),
startIndexInReversedItems: index,
hash: listItem.genHash(revealedItems.contains(prev?.id ?? -1), revealedItems.contains(next?.id ?? -1))
)
} else {
lastRangeInReversedForMergedItems = nil
recent = MergedItem.single(
item: listItem,
startIndexInReversedItems: index,
hash: listItem.genHash(revealedItems.contains(prev?.id ?? -1), revealedItems.contains(next?.id ?? -1))
)
}
mergedItems.append(recent!)
}
if itemIsSplit {
// found item that is considered as a split
if let unclosedSplitIndex, let unclosedSplitIndexInParent {
// it was at least second split in the list
splitRanges.append(SplitRange(itemId: items[unclosedSplitIndex].id, indexRangeInReversed: unclosedSplitIndex ... index - 1, indexRangeInParentItems: unclosedSplitIndexInParent ... visibleItemIndexInParent - 1))
}
unclosedSplitIndex = index
unclosedSplitIndexInParent = visibleItemIndexInParent
} else if index + 1 == items.count, let unclosedSplitIndex, let unclosedSplitIndexInParent {
// just one split for the whole list, there will be no more, it's the end
splitRanges.append(SplitRange(itemId: items[unclosedSplitIndex].id, indexRangeInReversed: unclosedSplitIndex ... index, indexRangeInParentItems: unclosedSplitIndexInParent ... visibleItemIndexInParent))
}
indexInParentItems[item.id] = visibleItemIndexInParent
index += 1
}
return MergedItems(
items: mergedItems,
splits: splitRanges,
indexInParentItems: indexInParentItems
)
}
// Use this check to ensure that mergedItems state based on currently actual state of global
// splits and reversedChatItems
func isActualState() -> Bool {
let im = ItemsModel.shared
// do not load anything if global splits state is different than in merged items because it
// will produce undefined results in terms of loading and placement of items.
// Same applies to reversedChatItems
return indexInParentItems.count == im.reversedChatItems.count &&
splits.count == im.chatState.splits.count &&
// that's just an optimization because most of the time only 1 split exists
((splits.count == 1 && splits[0].itemId == im.chatState.splits[0]) || splits.map({ split in split.itemId }).sorted() == im.chatState.splits.sorted())
}
}
enum MergedItem: Identifiable, Hashable, Equatable {
// equatable and hashable implementations allows to see the difference and correctly scroll to items we want
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.hash == rhs.hash
}
var id: Int64 { newest().item.id }
func hash(into hasher: inout Hasher) {
hasher.combine(hash)
}
var hash: String {
switch self {
case .single(_, _, let hash): hash + " 1"
case .grouped(let items, _, _, _, _, _, _, let hash): hash + " \(items.boxedValue.count)"
}
}
// the item that is always single, cannot be grouped and always revealed
case single(
item: ListItem,
startIndexInReversedItems: Int,
hash: String
)
/** The item that can contain multiple items or just one depending on revealed state. When the whole group of merged items is revealed,
* there will be multiple [Grouped] items with revealed flag set to true. When the whole group is collapsed, it will be just one instance
* of [Grouped] item with all grouped items inside [items]. In other words, number of [MergedItem] will always be equal to number of
* visible items in ChatView's EndlessScrollView */
case grouped (
items: BoxedValue<[ListItem]>,
revealed: Bool,
// it stores ids for all consecutive revealed items from the same group in order to hide them all on user's action
// it's the same list instance for all Grouped items within revealed group
/** @see reveal */
revealedIdsWithinGroup: BoxedValue<[Int64]>,
rangeInReversed: BoxedValue<ClosedRange<Int>>,
mergeCategory: CIMergeCategory?,
unreadIds: BoxedValue<Set<Int64>>,
startIndexInReversedItems: Int,
hash: String
)
func revealItems(_ reveal: Bool, _ revealedItems: Binding<Set<Int64>>) {
if case .grouped(let items, _, let revealedIdsWithinGroup, _, _, _, _, _) = self {
var newRevealed = revealedItems.wrappedValue
var i = 0
if reveal {
while i < items.boxedValue.count {
newRevealed.insert(items.boxedValue[i].item.id)
i += 1
}
} else {
while i < revealedIdsWithinGroup.boxedValue.count {
newRevealed.remove(revealedIdsWithinGroup.boxedValue[i])
i += 1
}
revealedIdsWithinGroup.boxedValue.removeAll()
}
revealedItems.wrappedValue = newRevealed
}
}
var startIndexInReversedItems: Int {
get {
switch self {
case let .single(_, startIndexInReversedItems, _): startIndexInReversedItems
case let .grouped(_, _, _, _, _, _, startIndexInReversedItems, _): startIndexInReversedItems
}
}
}
func hasUnread() -> Bool {
switch self {
case let .single(item, _, _): item.item.isRcvNew
case let .grouped(_, _, _, _, _, unreadIds, _, _): !unreadIds.boxedValue.isEmpty
}
}
func newest() -> ListItem {
switch self {
case let .single(item, _, _): item
case let .grouped(items, _, _, _, _, _, _, _): items.boxedValue[0]
}
}
func oldest() -> ListItem {
switch self {
case let .single(item, _, _): item
case let .grouped(items, _, _, _, _, _, _, _): items.boxedValue[items.boxedValue.count - 1]
}
}
func lastIndexInReversed() -> Int {
switch self {
case .single: startIndexInReversedItems
case let .grouped(items, _, _, _, _, _, _, _): startIndexInReversedItems + items.boxedValue.count - 1
}
}
}
struct SplitRange {
let itemId: Int64
/** range of indexes inside reversedChatItems where the first element is the split (it's index is [indexRangeInReversed.first])
* so [0, 1, 2, -100-, 101] if the 3 is a split, SplitRange(indexRange = 3 .. 4) will be this SplitRange instance
* (3, 4 indexes of the splitRange with the split itself at index 3)
* */
let indexRangeInReversed: ClosedRange<Int>
/** range of indexes inside LazyColumn where the first element is the split (it's index is [indexRangeInParentItems.first]) */
let indexRangeInParentItems: ClosedRange<Int>
}
struct ListItem: Hashable {
let item: ChatItem
let prevItem: ChatItem?
let nextItem: ChatItem?
// how many unread items before (older than) this one (excluding this one)
let unreadBefore: Int
private func chatDirHash(_ chatDir: CIDirection?) -> Int {
guard let chatDir else { return 0 }
return switch chatDir {
case .directSnd: 0
case .directRcv: 1
case .groupSnd: 2
case let .groupRcv(mem): "\(mem.groupMemberId) \(mem.displayName) \(mem.memberStatus.rawValue) \(mem.memberRole.rawValue) \(mem.image?.hash ?? 0)".hash
case .localSnd: 4
case .localRcv: 5
}
}
// using meta.hashValue instead of parts takes much more time so better to use partial meta here
func genHash(_ prevRevealed: Bool, _ nextRevealed: Bool) -> String {
"\(item.meta.itemId) \(item.meta.updatedAt.hashValue) \(item.meta.itemEdited) \(item.meta.itemDeleted?.hashValue ?? 0) \(item.meta.itemTimed?.hashValue ?? 0) \(item.meta.itemStatus.hashValue) \(item.meta.sentViaProxy ?? false) \(item.mergeCategory?.hashValue ?? 0) \(chatDirHash(item.chatDir)) \(item.reactions.hashValue) \(item.meta.isRcvNew) \(item.text.hash) \(item.file?.hashValue ?? 0) \(item.quotedItem?.itemId ?? 0) \(unreadBefore) \(prevItem?.id ?? 0) \(chatDirHash(prevItem?.chatDir)) \(prevItem?.mergeCategory?.hashValue ?? 0) \(prevRevealed) \(nextItem?.id ?? 0) \(chatDirHash(nextItem?.chatDir)) \(nextItem?.mergeCategory?.hashValue ?? 0) \(nextRevealed)"
}
}
class ActiveChatState {
var splits: [Int64] = []
var unreadAfterItemId: Int64 = -1
// total items after unread after item (exclusive)
var totalAfter: Int = 0
var unreadTotal: Int = 0
// exclusive
var unreadAfter: Int = 0
// exclusive
var unreadAfterNewestLoaded: Int = 0
func moveUnreadAfterItem(_ toItemId: Int64?, _ nonReversedItems: [ChatItem]) {
guard let toItemId else { return }
let currentIndex = nonReversedItems.firstIndex(where: { $0.id == unreadAfterItemId })
let newIndex = nonReversedItems.firstIndex(where: { $0.id == toItemId })
guard let currentIndex, let newIndex else {
return
}
unreadAfterItemId = toItemId
let unreadDiff = newIndex > currentIndex
? -nonReversedItems[currentIndex + 1..<newIndex + 1].filter { $0.isRcvNew }.count
: nonReversedItems[newIndex + 1..<currentIndex + 1].filter { $0.isRcvNew }.count
unreadAfter += unreadDiff
}
func moveUnreadAfterItem(_ fromIndex: Int, _ toIndex: Int, _ nonReversedItems: [ChatItem]) {
if fromIndex == -1 || toIndex == -1 {
return
}
unreadAfterItemId = nonReversedItems[toIndex].id
let unreadDiff = toIndex > fromIndex
? -nonReversedItems[fromIndex + 1..<toIndex + 1].filter { $0.isRcvNew }.count
: nonReversedItems[toIndex + 1..<fromIndex + 1].filter { $0.isRcvNew }.count
unreadAfter += unreadDiff
}
func clear() {
splits = []
unreadAfterItemId = -1
totalAfter = 0
unreadTotal = 0
unreadAfter = 0
unreadAfterNewestLoaded = 0
}
}
class BoxedValue<T: Hashable>: Equatable, Hashable {
static func == (lhs: BoxedValue<T>, rhs: BoxedValue<T>) -> Bool {
lhs.boxedValue == rhs.boxedValue
}
func hash(into hasher: inout Hasher) {
hasher.combine("\(self)")
}
var boxedValue : T
init(_ value: T) {
self.boxedValue = value
}
}
@MainActor
func visibleItemIndexesNonReversed(_ listState: EndlessScrollView<MergedItem>.ListState, _ mergedItems: MergedItems) -> ClosedRange<Int> {
let zero = 0 ... 0
let items = mergedItems.items
if items.isEmpty {
return zero
}
let newest = items.count > listState.firstVisibleItemIndex ? items[listState.firstVisibleItemIndex].startIndexInReversedItems : nil
let oldest = items.count > listState.lastVisibleItemIndex ? items[listState.lastVisibleItemIndex].lastIndexInReversed() : nil
guard let newest, let oldest else {
return zero
}
let size = ItemsModel.shared.reversedChatItems.count
let range = size - oldest ... size - newest
if range.lowerBound < 0 || range.upperBound < 0 {
return zero
}
// visible items mapped to their underlying data structure which is ItemsModel.shared.reversedChatItems.reversed()
return range
}
class RecalculatePositions {
private var chatState: ActiveChatState { get { ItemsModel.shared.chatState } }
func read(_ itemIds: Set<Int64>?, _ newItems: [ChatItem]) {
guard let itemIds else {
// special case when the whole chat became read
chatState.unreadTotal = 0
chatState.unreadAfter = 0
return
}
var unreadAfterItemIndex: Int = -1
// since it's more often that the newest items become read, it's logical to loop from the end of the list to finish it faster
var i = newItems.count - 1
var ids = itemIds
// intermediate variables to prevent re-setting state value a lot of times without reason
var newUnreadTotal = chatState.unreadTotal
var newUnreadAfter = chatState.unreadAfter
while i >= 0 {
let item = newItems[i]
if item.id == chatState.unreadAfterItemId {
unreadAfterItemIndex = i
}
if ids.contains(item.id) {
// was unread, now this item is read
if (unreadAfterItemIndex == -1) {
newUnreadAfter -= 1
}
newUnreadTotal -= 1
ids.remove(item.id)
if ids.isEmpty {
break
}
}
i -= 1
}
chatState.unreadTotal = newUnreadTotal
chatState.unreadAfter = newUnreadAfter
}
func added(_ item: (Int64, Bool), _ index: Int) {
if item.1 {
chatState.unreadAfter += 1
chatState.unreadTotal += 1
}
}
func removed(_ itemIds: [(Int64, Int, Bool)], _ newItems: [ChatItem]) {
var newSplits: [Int64] = []
for split in chatState.splits {
let index = itemIds.firstIndex(where: { (delId, _, _) in delId == split })
// deleted the item that was right before the split between items, find newer item so it will act like the split
if let index {
let idx = itemIds[index].1 - itemIds.filter { (_, delIndex, _) in delIndex <= index }.count
let newSplit = newItems.count > idx && idx >= 0 ? newItems[idx].id : nil
// it the whole section is gone and splits overlap, don't add it at all
if let newSplit, !newSplits.contains(newSplit) {
newSplits.append(newSplit)
}
} else {
newSplits.append(split)
}
}
chatState.splits = newSplits
let index = itemIds.firstIndex(where: { (delId, _, _) in delId == chatState.unreadAfterItemId })
// unread after item was removed
if let index {
let idx = itemIds[index].1 - itemIds.filter { (_, delIndex, _) in delIndex <= index }.count
var newUnreadAfterItemId = newItems.count > idx && idx >= 0 ? newItems[idx].id : nil
let newUnreadAfterItemWasNull = newUnreadAfterItemId == nil
if newUnreadAfterItemId == nil {
// everything on top (including unread after item) were deleted, take top item as unread after id
newUnreadAfterItemId = newItems.first?.id
}
if let newUnreadAfterItemId {
chatState.unreadAfterItemId = newUnreadAfterItemId
chatState.totalAfter -= itemIds.filter { (_, delIndex, _) in delIndex > index }.count
chatState.unreadTotal -= itemIds.filter { (_, delIndex, isRcvNew) in delIndex <= index && isRcvNew }.count
chatState.unreadAfter -= itemIds.filter { (_, delIndex, isRcvNew) in delIndex > index && isRcvNew }.count
if newUnreadAfterItemWasNull {
// since the unread after item was moved one item after initial position, adjust counters accordingly
if newItems.first?.isRcvNew == true {
chatState.unreadTotal += 1
chatState.unreadAfter -= 1
}
}
} else {
// all items were deleted, 0 items in chatItems
chatState.unreadAfterItemId = -1
chatState.totalAfter = 0
chatState.unreadTotal = 0
chatState.unreadAfter = 0
}
} else {
chatState.totalAfter -= itemIds.count
}
}
func cleared() { chatState.clear() }
}

View file

@ -0,0 +1,165 @@
//
// ChatScrollHelpers.swift
// SimpleX (iOS)
//
// Created by Stanislav Dmitrenko on 20.12.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
func loadLastItems(_ loadingMoreItems: Binding<Bool>, loadingBottomItems: Binding<Bool>, _ chat: Chat) {
if ItemsModel.shared.chatState.totalAfter == 0 {
return
}
loadingMoreItems.wrappedValue = true
loadingBottomItems.wrappedValue = true
Task {
try? await Task.sleep(nanoseconds: 500_000000)
if ChatModel.shared.chatId != chat.chatInfo.id {
await MainActor.run {
loadingMoreItems.wrappedValue = false
}
return
}
await apiLoadMessages(chat.chatInfo.id, ChatPagination.last(count: 50), ItemsModel.shared.chatState)
await MainActor.run {
loadingMoreItems.wrappedValue = false
loadingBottomItems.wrappedValue = false
}
}
}
class PreloadState {
static let shared = PreloadState()
var prevFirstVisible: Int64 = Int64.min
var prevItemsCount: Int = 0
var preloading: Bool = false
}
func preloadIfNeeded(
_ allowLoadMoreItems: Binding<Bool>,
_ ignoreLoadingRequests: Binding<Int64?>,
_ listState: EndlessScrollView<MergedItem>.ListState,
_ mergedItems: BoxedValue<MergedItems>,
loadItems: @escaping (Bool, ChatPagination) async -> Bool
) {
let state = PreloadState.shared
guard !listState.isScrolling && !listState.isAnimatedScrolling,
state.prevFirstVisible != listState.firstVisibleItemIndex || state.prevItemsCount != mergedItems.boxedValue.indexInParentItems.count,
!state.preloading,
listState.totalItemsCount > 0
else {
return
}
state.prevFirstVisible = listState.firstVisibleItemId as! Int64
state.prevItemsCount = mergedItems.boxedValue.indexInParentItems.count
state.preloading = true
let allowLoadMore = allowLoadMoreItems.wrappedValue
Task {
defer {
state.preloading = false
}
await preloadItems(mergedItems.boxedValue, allowLoadMore, listState, ignoreLoadingRequests) { pagination in
await loadItems(false, pagination)
}
}
}
func preloadItems(
_ mergedItems: MergedItems,
_ allowLoadMoreItems: Bool,
_ listState: EndlessScrollView<MergedItem>.ListState,
_ ignoreLoadingRequests: Binding<Int64?>,
_ loadItems: @escaping (ChatPagination) async -> Bool)
async {
let allowLoad = allowLoadMoreItems || mergedItems.items.count == listState.lastVisibleItemIndex + 1
let remaining = ChatPagination.UNTIL_PRELOAD_COUNT
let firstVisibleIndex = listState.firstVisibleItemIndex
if !(await preloadItemsBefore()) {
await preloadItemsAfter()
}
func preloadItemsBefore() async -> Bool {
let splits = mergedItems.splits
let lastVisibleIndex = listState.lastVisibleItemIndex
var lastIndexToLoadFrom: Int? = findLastIndexToLoadFromInSplits(firstVisibleIndex, lastVisibleIndex, remaining, splits)
let items: [ChatItem] = ItemsModel.shared.reversedChatItems.reversed()
if splits.isEmpty && !items.isEmpty && lastVisibleIndex > mergedItems.items.count - remaining {
lastIndexToLoadFrom = items.count - 1
}
let loadFromItemId: Int64?
if allowLoad, let lastIndexToLoadFrom {
let index = items.count - 1 - lastIndexToLoadFrom
loadFromItemId = index >= 0 ? items[index].id : nil
} else {
loadFromItemId = nil
}
guard let loadFromItemId, ignoreLoadingRequests.wrappedValue != loadFromItemId else {
return false
}
let sizeWas = items.count
let firstItemIdWas = items.first?.id
let triedToLoad = await loadItems(ChatPagination.before(chatItemId: loadFromItemId, count: ChatPagination.PRELOAD_COUNT))
if triedToLoad && sizeWas == ItemsModel.shared.reversedChatItems.count && firstItemIdWas == ItemsModel.shared.reversedChatItems.last?.id {
ignoreLoadingRequests.wrappedValue = loadFromItemId
}
return triedToLoad
}
func preloadItemsAfter() async {
let splits = mergedItems.splits
let split = splits.last(where: { $0.indexRangeInParentItems.contains(firstVisibleIndex) })
// we're inside a splitRange (top --- [end of the splitRange --- we're here --- start of the splitRange] --- bottom)
let reversedItems: [ChatItem] = ItemsModel.shared.reversedChatItems
if let split, split.indexRangeInParentItems.lowerBound + remaining > firstVisibleIndex {
let index = split.indexRangeInReversed.lowerBound
if index >= 0 {
let loadFromItemId = reversedItems[index].id
_ = await loadItems(ChatPagination.after(chatItemId: loadFromItemId, count: ChatPagination.PRELOAD_COUNT))
}
}
}
}
func oldestPartiallyVisibleListItemInListStateOrNull(_ listState: EndlessScrollView<MergedItem>.ListState) -> ListItem? {
if listState.lastVisibleItemIndex < listState.items.count {
return listState.items[listState.lastVisibleItemIndex].oldest()
} else {
return listState.items.last?.oldest()
}
}
private func findLastIndexToLoadFromInSplits(_ firstVisibleIndex: Int, _ lastVisibleIndex: Int, _ remaining: Int, _ splits: [SplitRange]) -> Int? {
for split in splits {
// before any split
if split.indexRangeInParentItems.lowerBound > firstVisibleIndex {
if lastVisibleIndex > (split.indexRangeInParentItems.lowerBound - remaining) {
return split.indexRangeInReversed.lowerBound - 1
}
break
}
let containsInRange = split.indexRangeInParentItems.contains(firstVisibleIndex)
if containsInRange {
if lastVisibleIndex > (split.indexRangeInParentItems.upperBound - remaining) {
return split.indexRangeInReversed.upperBound
}
break
}
}
return nil
}
/// Disable animation on iOS 15
func withConditionalAnimation<Result>(
_ animation: Animation? = .default,
_ body: () throws -> Result
) rethrows -> Result {
if #available(iOS 16.0, *) {
try withAnimation(animation, body)
} else {
try body()
}
}

File diff suppressed because it is too large Load diff

View file

@ -325,6 +325,7 @@ struct ComposeView: View {
@ObservedObject var chat: Chat
@Binding var composeState: ComposeState
@Binding var keyboardVisible: Bool
@Binding var keyboardHiddenDate: Date
@Binding var selectedRange: NSRange
@State var linkUrl: URL? = nil
@ -392,7 +393,7 @@ struct ComposeView: View {
}
.disabled(composeState.attachmentDisabled || !chat.userCanSend || (chat.chatInfo.contact?.nextSendGrpInv ?? false))
.frame(width: 25, height: 25)
.padding(.bottom, 12)
.padding(.bottom, 16)
.padding(.leading, 12)
.tint(theme.colors.primary)
if case let .group(g) = chat.chatInfo,
@ -434,6 +435,7 @@ struct ComposeView: View {
timedMessageAllowed: chat.chatInfo.featureEnabled(.timedMessages),
onMediaAdded: { media in if !media.isEmpty { chosenMedia = media }},
keyboardVisible: $keyboardVisible,
keyboardHiddenDate: $keyboardHiddenDate,
sendButtonColor: chat.chatInfo.incognito
? .indigo.opacity(colorScheme == .dark ? 1 : 0.7)
: theme.colors.primary
@ -1280,6 +1282,7 @@ struct ComposeView_Previews: PreviewProvider {
chat: chat,
composeState: $composeState,
keyboardVisible: Binding.constant(true),
keyboardHiddenDate: Binding.constant(Date.now),
selectedRange: $selectedRange
)
.environmentObject(ChatModel())
@ -1287,6 +1290,7 @@ struct ComposeView_Previews: PreviewProvider {
chat: chat,
composeState: $composeState,
keyboardVisible: Binding.constant(true),
keyboardHiddenDate: Binding.constant(Date.now),
selectedRange: $selectedRange
)
.environmentObject(ChatModel())

View file

@ -16,19 +16,14 @@ struct NativeTextEditor: UIViewRepresentable {
@Binding var disableEditing: Bool
@Binding var height: CGFloat
@Binding var focused: Bool
@Binding var lastUnfocusedDate: Date
@Binding var placeholder: String?
@Binding var selectedRange: NSRange
let onImagesAdded: ([UploadContent]) -> Void
private let minHeight: CGFloat = 37
static let minHeight: CGFloat = 39
private let defaultHeight: CGFloat = {
let field = CustomUITextField(parent: nil, height: Binding.constant(0))
field.textContainerInset = UIEdgeInsets(top: 8, left: 5, bottom: 6, right: 4)
return min(max(field.sizeThatFits(CGSizeMake(field.frame.size.width, CGFloat.greatestFiniteMagnitude)).height, 37), 360).rounded(.down)
}()
func makeUIView(context: Context) -> UITextView {
func makeUIView(context: Context) -> CustomUITextField {
let field = CustomUITextField(parent: self, height: _height)
field.backgroundColor = .clear
field.text = text
@ -38,10 +33,9 @@ struct NativeTextEditor: UIViewRepresentable {
if !disableEditing {
text = newText
field.textAlignment = alignment(text)
updateFont(field)
field.updateFont()
// Speed up the process of updating layout, reduce jumping content on screen
updateHeight(field)
self.height = field.frame.size.height
field.updateHeight()
} else {
field.text = text
}
@ -49,67 +43,47 @@ struct NativeTextEditor: UIViewRepresentable {
onImagesAdded(images)
}
}
field.setOnFocusChangedListener { focused = $0 }
field.setOnFocusChangedListener {
focused = $0
if !focused {
lastUnfocusedDate = .now
}
}
field.delegate = field
field.textContainerInset = UIEdgeInsets(top: 8, left: 5, bottom: 6, right: 4)
field.setPlaceholderView()
updateFont(field)
updateHeight(field)
field.updateFont()
field.updateHeight(updateBindingNow: false)
return field
}
func updateUIView(_ field: UITextView, context: Context) {
func updateUIView(_ field: CustomUITextField, context: Context) {
if field.markedTextRange == nil && field.text != text {
field.text = text
field.textAlignment = alignment(text)
updateFont(field)
updateHeight(field)
field.updateFont()
field.updateHeight(updateBindingNow: false)
}
let castedField = field as! CustomUITextField
if castedField.placeholder != placeholder {
castedField.placeholder = placeholder
if field.placeholder != placeholder {
field.placeholder = placeholder
}
if field.selectedRange != selectedRange {
field.selectedRange = selectedRange
}
}
private func updateHeight(_ field: UITextView) {
let maxHeight = min(360, field.font!.lineHeight * 12)
// When having emoji in text view and then removing it, sizeThatFits shows previous size (too big for empty text view), so using work around with default size
let newHeight = field.text == ""
? defaultHeight
: min(max(field.sizeThatFits(CGSizeMake(field.frame.size.width, CGFloat.greatestFiniteMagnitude)).height, minHeight), maxHeight).rounded(.down)
if field.frame.size.height != newHeight {
field.frame.size = CGSizeMake(field.frame.size.width, newHeight)
(field as! CustomUITextField).invalidateIntrinsicContentHeight(newHeight)
}
}
private func updateFont(_ field: UITextView) {
let newFont = isShortEmoji(field.text)
? (field.text.count < 4 ? largeEmojiUIFont : mediumEmojiUIFont)
: UIFont.preferredFont(forTextStyle: .body)
if field.font != newFont {
field.font = newFont
}
}
}
private func alignment(_ text: String) -> NSTextAlignment {
isRightToLeft(text) ? .right : .left
}
private class CustomUITextField: UITextView, UITextViewDelegate {
class CustomUITextField: UITextView, UITextViewDelegate {
var parent: NativeTextEditor?
var height: Binding<CGFloat>
var newHeight: CGFloat = 0
var onTextChanged: (String, [UploadContent]) -> Void = { newText, image in }
var onFocusChanged: (Bool) -> Void = { focused in }
private let placeholderLabel: UILabel = UILabel()
init(parent: NativeTextEditor?, height: Binding<CGFloat>) {
@ -135,11 +109,44 @@ private class CustomUITextField: UITextView, UITextViewDelegate {
invalidateIntrinsicContentSize()
}
override var intrinsicContentSize: CGSize {
if height.wrappedValue != newHeight {
DispatchQueue.main.asyncAfter(deadline: .now(), execute: { self.height.wrappedValue = self.newHeight })
func updateHeight(updateBindingNow: Bool = true) {
let maxHeight = min(360, font!.lineHeight * 12)
let newHeight = min(max(sizeThatFits(CGSizeMake(frame.size.width, CGFloat.greatestFiniteMagnitude)).height, NativeTextEditor.minHeight), maxHeight).rounded(.down)
if self.newHeight != newHeight {
frame.size = CGSizeMake(frame.size.width, newHeight)
invalidateIntrinsicContentHeight(newHeight)
if updateBindingNow {
self.height.wrappedValue = newHeight
} else {
DispatchQueue.main.async {
self.height.wrappedValue = newHeight
}
}
}
return CGSizeMake(0, newHeight)
}
func updateFont() {
let newFont = isShortEmoji(text)
? (text.count < 4 ? largeEmojiUIFont : mediumEmojiUIFont)
: UIFont.preferredFont(forTextStyle: .body)
if font != newFont {
font = newFont
// force apply new font because it has problem with doing it when the field had two emojis
if text.count == 0 {
text = " "
text = ""
}
}
}
override func layoutSubviews() {
super.layoutSubviews()
updateHeight()
}
override var intrinsicContentSize: CGSize {
CGSizeMake(0, newHeight)
}
func setOnTextChangedListener(onTextChanged: @escaping (String, [UploadContent]) -> Void) {
@ -265,6 +272,7 @@ struct NativeTextEditor_Previews: PreviewProvider{
disableEditing: Binding.constant(false),
height: Binding.constant(100),
focused: Binding.constant(false),
lastUnfocusedDate: Binding.constant(.now),
placeholder: Binding.constant("Placeholder"),
selectedRange: Binding.constant(NSRange(location: 0, length: 0)),
onImagesAdded: { _ in }

View file

@ -32,8 +32,9 @@ struct SendMessageView: View {
@State private var holdingVMR = false
@Namespace var namespace
@Binding var keyboardVisible: Bool
@Binding var keyboardHiddenDate: Date
var sendButtonColor = Color.accentColor
@State private var teHeight: CGFloat = 42
@State private var teHeight: CGFloat = NativeTextEditor.minHeight
@State private var teFont: Font = .body
@State private var sendButtonSize: CGFloat = 29
@State private var sendButtonOpacity: CGFloat = 1
@ -44,53 +45,54 @@ struct SendMessageView: View {
@UserDefault(DEFAULT_LIVE_MESSAGE_ALERT_SHOWN) private var liveMessageAlertShown = false
var body: some View {
ZStack {
let composeShape = RoundedRectangle(cornerSize: CGSize(width: 20, height: 20))
HStack(alignment: .bottom) {
ZStack(alignment: .leading) {
if case .voicePreview = composeState.preview {
Text("Voice message…")
.font(teFont.italic())
.multilineTextAlignment(.leading)
.foregroundColor(theme.colors.secondary)
.padding(.horizontal, 10)
.padding(.vertical, 8)
.frame(maxWidth: .infinity)
} else {
NativeTextEditor(
text: $composeState.message,
disableEditing: $composeState.inProgress,
height: $teHeight,
focused: $keyboardVisible,
placeholder: Binding(get: { composeState.placeholder }, set: { _ in }),
selectedRange: $selectedRange,
onImagesAdded: onMediaAdded
)
.allowsTightening(false)
.fixedSize(horizontal: false, vertical: true)
}
}
if progressByTimeout {
ProgressView()
.scaleEffect(1.4)
.frame(width: 31, height: 31, alignment: .center)
.padding([.bottom, .trailing], 3)
} else {
VStack(alignment: .trailing) {
if teHeight > 100 && !composeState.inProgress {
deleteTextButton()
Spacer()
}
composeActionButtons()
}
.frame(height: teHeight, alignment: .bottom)
}
let composeShape = RoundedRectangle(cornerSize: CGSize(width: 20, height: 20))
ZStack(alignment: .leading) {
if case .voicePreview = composeState.preview {
Text("Voice message…")
.font(teFont.italic())
.multilineTextAlignment(.leading)
.foregroundColor(theme.colors.secondary)
.padding(.horizontal, 10)
.padding(.vertical, 8)
.padding(.trailing, 32)
.frame(maxWidth: .infinity)
} else {
NativeTextEditor(
text: $composeState.message,
disableEditing: $composeState.inProgress,
height: $teHeight,
focused: $keyboardVisible,
lastUnfocusedDate: $keyboardHiddenDate,
placeholder: Binding(get: { composeState.placeholder }, set: { _ in }),
selectedRange: $selectedRange,
onImagesAdded: onMediaAdded
)
.padding(.trailing, 32)
.allowsTightening(false)
.fixedSize(horizontal: false, vertical: true)
}
.padding(.vertical, 1)
.background(theme.colors.background)
.clipShape(composeShape)
.overlay(composeShape.strokeBorder(.secondary, lineWidth: 0.5).opacity(0.7))
}
.overlay(alignment: .topTrailing, content: {
if !progressByTimeout && teHeight > 100 && !composeState.inProgress {
deleteTextButton()
}
})
.overlay(alignment: .bottomTrailing, content: {
if progressByTimeout {
ProgressView()
.scaleEffect(1.4)
.frame(width: 31, height: 31, alignment: .center)
.padding([.bottom, .trailing], 4)
} else {
composeActionButtons()
// required for intercepting clicks
.background(.white.opacity(0.000001))
}
})
.padding(.vertical, 1)
.background(theme.colors.background)
.clipShape(composeShape)
.overlay(composeShape.strokeBorder(.secondary, lineWidth: 0.5).opacity(0.7))
.onChange(of: composeState.message, perform: { text in updateFont(text) })
.onChange(of: composeState.inProgress) { inProgress in
if inProgress {
@ -169,7 +171,7 @@ struct SendMessageView: View {
!composeState.sendEnabled ||
composeState.inProgress
)
.frame(width: 29, height: 29)
.frame(width: 31, height: 31)
.padding([.bottom, .trailing], 4)
}
@ -192,7 +194,7 @@ struct SendMessageView: View {
composeState.endLiveDisabled ||
disableSendButton
)
.frame(width: 29, height: 29)
.frame(width: 31, height: 31)
.contextMenu{
sendButtonContextMenuItems()
}
@ -269,7 +271,7 @@ struct SendMessageView: View {
.foregroundColor(theme.colors.primary)
}
.disabled(disabled)
.frame(width: 29, height: 29)
.frame(width: 31, height: 31)
.padding([.bottom, .trailing], 4)
._onButtonGesture { down in
if down {
@ -325,7 +327,7 @@ struct SendMessageView: View {
.foregroundColor(theme.colors.secondary)
}
.disabled(composeState.inProgress)
.frame(width: 29, height: 29)
.frame(width: 31, height: 31)
.padding([.bottom, .trailing], 4)
}
@ -410,7 +412,7 @@ struct SendMessageView: View {
.foregroundColor(theme.colors.primary)
}
.disabled(composeState.inProgress)
.frame(width: 29, height: 29)
.frame(width: 31, height: 31)
.padding([.bottom, .trailing], 4)
}
@ -441,7 +443,8 @@ struct SendMessageView_Previews: PreviewProvider {
selectedRange: $selectedRange,
sendMessage: { _ in },
onMediaAdded: { _ in },
keyboardVisible: Binding.constant(true)
keyboardVisible: Binding.constant(true),
keyboardHiddenDate: Binding.constant(Date.now)
)
}
VStack {
@ -452,7 +455,8 @@ struct SendMessageView_Previews: PreviewProvider {
selectedRange: $selectedRangeEditing,
sendMessage: { _ in },
onMediaAdded: { _ in },
keyboardVisible: Binding.constant(true)
keyboardVisible: Binding.constant(true),
keyboardHiddenDate: Binding.constant(Date.now)
)
}
}

View file

@ -0,0 +1,698 @@
//
// EndlessScrollView.swift
// SimpleX (iOS)
//
// Created by Stanislav Dmitrenko on 25.01.2025.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
struct ScrollRepresentable<Content: View, ScrollItem>: UIViewControllerRepresentable where ScrollItem : Identifiable, ScrollItem: Hashable {
let scrollView: EndlessScrollView<ScrollItem>
let content: (Int, ScrollItem) -> Content
func makeUIViewController(context: Context) -> ScrollController {
ScrollController.init(scrollView: scrollView, content: content)
}
func updateUIViewController(_ controller: ScrollController, context: Context) {}
class ScrollController: UIViewController {
let scrollView: EndlessScrollView<ScrollItem>
fileprivate var items: [ScrollItem] = []
fileprivate var content: ((Int, ScrollItem) -> Content)!
fileprivate init(scrollView: EndlessScrollView<ScrollItem>, content: @escaping (Int, ScrollItem) -> Content) {
self.scrollView = scrollView
self.content = content
super.init(nibName: nil, bundle: nil)
self.view = scrollView
scrollView.createCell = createCell
scrollView.updateCell = updateCell
}
required init?(coder: NSCoder) { fatalError() }
private func createCell(_ index: Int, _ items: [ScrollItem], _ cellsToReuse: inout [UIView]) -> UIView {
let item: ScrollItem? = index >= 0 && index < items.count ? items[index] : nil
let cell: UIView
if #available(iOS 16.0, *), false {
let c: UITableViewCell = cellsToReuse.isEmpty ? UITableViewCell() : cellsToReuse.removeLast() as! UITableViewCell
if let item {
c.contentConfiguration = UIHostingConfiguration { self.content(index, item) }
.margins(.all, 0)
.minSize(height: 1) // Passing zero will result in system default of 44 points being used
}
cell = c
} else {
let c = cellsToReuse.isEmpty ? HostingCell<Content>() : cellsToReuse.removeLast() as! HostingCell<Content>
if let item {
c.set(content: self.content(index, item), parent: self)
}
cell = c
}
cell.isHidden = false
cell.backgroundColor = .clear
let size = cell.systemLayoutSizeFitting(CGSizeMake(scrollView.bounds.width, CGFloat.greatestFiniteMagnitude))
cell.frame.size.width = scrollView.bounds.width
cell.frame.size.height = size.height
return cell
}
private func updateCell(cell: UIView, _ index: Int, _ items: [ScrollItem]) {
let item = items[index]
if #available(iOS 16.0, *), false {
(cell as! UITableViewCell).contentConfiguration = UIHostingConfiguration { self.content(index, item) }
.margins(.all, 0)
.minSize(height: 1) // Passing zero will result in system default of 44 points being used
} else {
if let cell = cell as? HostingCell<Content> {
cell.set(content: self.content(index, item), parent: self)
} else {
fatalError("Unexpected Cell Type for: \(item)")
}
}
let size = cell.systemLayoutSizeFitting(CGSizeMake(scrollView.bounds.width, CGFloat.greatestFiniteMagnitude))
cell.frame.size.width = scrollView.bounds.width
cell.frame.size.height = size.height
cell.setNeedsLayout()
}
}
}
class EndlessScrollView<ScrollItem>: UIScrollView, UIScrollViewDelegate, UIGestureRecognizerDelegate where ScrollItem : Identifiable, ScrollItem: Hashable {
/// Stores actual state of the scroll view and all elements drawn on the screen
let listState: ListState = ListState()
/// Just some random big number that will probably be enough to scrolling down and up without reaching the end
var initialOffset: CGFloat = 100000000
/// Default item id when no items in the visible items list. Something that will never be in real data
fileprivate static var DEFAULT_ITEM_ID: any Hashable { get { Int64.min } }
/// Storing an offset that was already used for laying down content to be able to see the difference
var prevProcessedOffset: CGFloat = 0
/// When screen is being rotated, it's important to track the view size and adjust scroll offset accordingly because the view doesn't know that the content
/// starts from bottom and ends at top, not vice versa as usual
var oldScreenHeight: CGFloat = 0
/// Not 100% correct height of the content since the items loaded lazily and their dimensions are unkown until they are on screen
var estimatedContentHeight: ContentHeight = ContentHeight()
/// Specify here the value that is small enough to NOT see any weird animation when you scroll to items. Minimum expected item size is ok. Scroll speed depends on it too
var averageItemHeight: CGFloat = 30
/// This is used as a multiplier for difference between current index and scrollTo index using [averageItemHeight] as well. Increase it to get faster speed
var scrollStepMultiplier: CGFloat = 0.37
/// Adds content padding to top
var insetTop: CGFloat = 100
/// Adds content padding to bottom
var insetBottom: CGFloat = 100
var scrollToItemIndexDelayed: Int? = nil
/// The second scroll view that is used only for purpose of displaying scroll bar with made-up content size and scroll offset that is gathered from main scroll view, see [estimatedContentHeight]
let scrollBarView: UIScrollView = UIScrollView(frame: .zero)
/// Stores views that can be used to hold new content so it will be faster to replace something than to create the whole view from scratch
var cellsToReuse: [UIView] = []
/// Enable debug to see hundreds of logs
var debug: Bool = false
var createCell: (Int, [ScrollItem], inout [UIView]) -> UIView? = { _, _, _ in nil }
var updateCell: (UIView, Int, [ScrollItem]) -> Void = { cell, _, _ in }
override init(frame: CGRect) {
super.init(frame: frame)
self.delegate = self
}
required init?(coder: NSCoder) { fatalError() }
class ListState: NSObject {
/// Will be called on every change of the items array, visible items, and scroll position
var onUpdateListener: () -> Void = {}
/// Items that were used to lay out the screen
var items: [ScrollItem] = [] {
didSet {
onUpdateListener()
}
}
/// It is equai to the number of [items]
var totalItemsCount: Int {
items.count
}
/// The items with their positions and other useful information. Only those that are visible on screen
var visibleItems: [EndlessScrollView<ScrollItem>.VisibleItem] = []
/// Index in [items] of the first item on screen. This is intentiallty not derived from visible items because it's is used as a starting point for laying out the screen
var firstVisibleItemIndex: Int = 0
/// Unique item id of the first visible item on screen
var firstVisibleItemId: any Hashable = EndlessScrollView<ScrollItem>.DEFAULT_ITEM_ID
/// Item offset of the first item on screen. Most of the time it's non-positive but it can be positive as well when a user produce overscroll effect on top/bottom of the scroll view
var firstVisibleItemOffset: CGFloat = -100
/// Index of the last visible item on screen
var lastVisibleItemIndex: Int {
visibleItems.last?.index ?? 0
}
/// Whether there is a non-animated scroll to item in progress or not
var isScrolling: Bool = false
/// Whether there is an animated scroll to item in progress or not
var isAnimatedScrolling: Bool = false
override init() {
super.init()
}
}
class VisibleItem {
let index: Int
let item: ScrollItem
let view: UIView
var offset: CGFloat
init(index: Int, item: ScrollItem, view: UIView, offset: CGFloat) {
self.index = index
self.item = item
self.view = view
self.offset = offset
}
}
class ContentHeight {
/// After that you should see overscroll effect. When scroll positon is far from
/// top/bottom items, these values are estimated based on items count multiplied by averageItemHeight or real item height (from visible items). Example:
/// [ 10, 9, 8, 7, (6, 5, 4, 3), 2, 1, 0] - 6, 5, 4, 3 are visible and have know heights but others have unknown height and for them averageItemHeight will be used to calculate the whole content height
var topOffsetY: CGFloat = 0
var bottomOffsetY: CGFloat = 0
var virtualScrollOffsetY: CGFloat = 0
/// How much distance were overscolled on top which often means to show sticky scrolling that should scroll back to real position after a users finishes dragging the scrollView
var overscrolledTop: CGFloat = 0
/// Adds content padding to bottom and top
var inset: CGFloat = 100
/// Estimated height of the contents of scroll view
var height: CGFloat {
get { bottomOffsetY - topOffsetY }
}
/// Estimated height of the contents of scroll view + distance of overscrolled effect. It's only updated when number of item changes to prevent jumping of scroll bar
var virtualOverscrolledHeight: CGFloat {
get {
bottomOffsetY - topOffsetY + overscrolledTop - inset * 2
}
}
func update(
_ contentOffset: CGPoint,
_ listState: ListState,
_ averageItemHeight: CGFloat,
_ updateStaleHeight: Bool
) {
let lastVisible = listState.visibleItems.last
let firstVisible = listState.visibleItems.first
guard let last = lastVisible, let first = firstVisible else {
topOffsetY = contentOffset.y
bottomOffsetY = contentOffset.y
virtualScrollOffsetY = 0
overscrolledTop = 0
return
}
topOffsetY = last.view.frame.origin.y - CGFloat(listState.totalItemsCount - last.index - 1) * averageItemHeight - self.inset
bottomOffsetY = first.view.frame.origin.y + first.view.bounds.height + CGFloat(first.index) * averageItemHeight + self.inset
virtualScrollOffsetY = contentOffset.y - topOffsetY
overscrolledTop = max(0, last.index == listState.totalItemsCount - 1 ? last.view.frame.origin.y - contentOffset.y : 0)
}
}
var topY: CGFloat {
get { contentOffset.y }
}
var bottomY: CGFloat {
get { contentOffset.y + bounds.height }
}
override func layoutSubviews() {
super.layoutSubviews()
if contentSize.height == 0 {
setup()
}
let newScreenHeight = bounds.height
if newScreenHeight != oldScreenHeight && oldScreenHeight != 0 {
contentOffset.y += oldScreenHeight - newScreenHeight
scrollBarView.frame = CGRectMake(frame.width - 10, self.insetTop, 10, frame.height - self.insetTop - self.insetBottom)
}
oldScreenHeight = newScreenHeight
adaptItems(listState.items, false)
if let index = scrollToItemIndexDelayed {
scrollToItem(index)
scrollToItemIndexDelayed = nil
}
}
private func setup() {
contentSize = CGSizeMake(frame.size.width, initialOffset * 2)
prevProcessedOffset = initialOffset
contentOffset = CGPointMake(0, initialOffset)
showsVerticalScrollIndicator = false
scrollBarView.showsHorizontalScrollIndicator = false
panGestureRecognizer.delegate = self
addGestureRecognizer(scrollBarView.panGestureRecognizer)
superview!.addSubview(scrollBarView)
}
func updateItems(_ items: [ScrollItem], _ forceReloadVisible: Bool = false) {
if !Thread.isMainThread {
fatalError("Use main thread to update items")
}
if bounds.height == 0 {
self.listState.items = items
// this function requires to have valid bounds and it will be called again once it has them
return
}
adaptItems(items, forceReloadVisible)
snapToContent(animated: false)
}
/// [forceReloadVisible]: reloads every item that was visible regardless of hashValue changes
private func adaptItems(_ items: [ScrollItem], _ forceReloadVisible: Bool, overridenOffset: CGFloat? = nil) {
let start = Date.now
// special case when everything was removed
if items.isEmpty {
listState.visibleItems.forEach { item in item.view.removeFromSuperview() }
listState.visibleItems = []
listState.firstVisibleItemId = EndlessScrollView<ScrollItem>.DEFAULT_ITEM_ID
listState.firstVisibleItemIndex = 0
listState.firstVisibleItemOffset = -insetTop
estimatedContentHeight.update(contentOffset, listState, averageItemHeight, true)
scrollBarView.contentSize = .zero
scrollBarView.contentOffset = .zero
prevProcessedOffset = contentOffset.y
// this check is just to prevent didSet listener from firing on the same empty array, no use for this
if !self.listState.items.isEmpty {
self.listState.items = items
}
return
}
let contentOffsetY = overridenOffset ?? contentOffset.y
var oldVisible = listState.visibleItems
var newVisible: [VisibleItem] = []
let offsetsDiff = contentOffsetY - prevProcessedOffset
var shouldBeFirstVisible = items.firstIndex(where: { item in item.id == listState.firstVisibleItemId as! ScrollItem.ID }) ?? 0
var wasFirstVisibleItemOffset = listState.firstVisibleItemOffset
var alreadyChangedIndexWhileScrolling = false
var allowOneMore = false
var nextOffsetY: CGFloat = 0
var i = shouldBeFirstVisible
// building list of visible items starting from the first one that should be visible
while i >= 0 && i < items.count {
let item = items[i]
let visibleIndex = oldVisible.firstIndex(where: { vis in vis.item.id == item.id })
let visible: VisibleItem?
if let visibleIndex {
let v = oldVisible.remove(at: visibleIndex)
if forceReloadVisible || v.view.bounds.width != bounds.width || v.item.hashValue != item.hashValue {
updateCell(v.view, i, items)
}
visible = v
} else {
visible = nil
}
if shouldBeFirstVisible == i {
if let vis = visible {
if // there is auto scroll in progress and the first item has a higher offset than bottom part
// of the screen. In order to make scrolling down & up equal in time, we treat this as a sign to
// re-make the first visible item
(listState.isAnimatedScrolling && vis.view.frame.origin.y + vis.view.bounds.height < contentOffsetY + bounds.height) ||
// the fist visible item previously is hidden now, remove it and move on
!isVisible(vis.view) {
let newIndex: Int
if listState.isAnimatedScrolling {
// skip many items to make the scrolling take less time
var indexDiff = !alreadyChangedIndexWhileScrolling ? Int(ceil(abs(offsetsDiff / averageItemHeight))) : 0
// if index was already changed, no need to change it again. Otherwise, the scroll will overscoll and return back animated. Because it means the whole screen was scrolled
alreadyChangedIndexWhileScrolling = true
indexDiff = offsetsDiff <= 0 ? indexDiff : -indexDiff
newIndex = max(0, min(items.count - 1, i + indexDiff))
// offset for the first visible item can now be 0 because the previous first visible item doesn't exist anymore
wasFirstVisibleItemOffset = 0
} else {
// don't skip multiple items if it's manual scrolling gesture
newIndex = i + (offsetsDiff <= 0 ? 1 : -1)
}
shouldBeFirstVisible = newIndex
i = newIndex
cellsToReuse.append(vis.view)
hideAndRemoveFromSuperviewIfNeeded(vis.view)
continue
}
}
let vis: VisibleItem
if let visible {
vis = VisibleItem(index: i, item: item, view: visible.view, offset: offsetToBottom(visible.view))
} else {
let cell = createCell(i, items, &cellsToReuse)!
cell.frame.origin.y = bottomY + wasFirstVisibleItemOffset - cell.frame.height
vis = VisibleItem(index: i, item: item, view: cell, offset: offsetToBottom(cell))
}
if vis.view.superview == nil {
addSubview(vis.view)
}
newVisible.append(vis)
nextOffsetY = vis.view.frame.origin.y
} else {
let vis: VisibleItem
if let visible {
vis = VisibleItem(index: i, item: item, view: visible.view, offset: offsetToBottom(visible.view))
nextOffsetY -= vis.view.frame.height
vis.view.frame.origin.y = nextOffsetY
} else {
let cell = createCell(i, items, &cellsToReuse)!
nextOffsetY -= cell.frame.height
cell.frame.origin.y = nextOffsetY
vis = VisibleItem(index: i, item: item, view: cell, offset: offsetToBottom(cell))
}
if vis.view.superview == nil {
addSubview(vis.view)
}
newVisible.append(vis)
}
if abs(nextOffsetY) < contentOffsetY && !allowOneMore {
break
} else if abs(nextOffsetY) < contentOffsetY {
allowOneMore = false
}
i += 1
}
if let firstVisible = newVisible.first, firstVisible.view.frame.origin.y + firstVisible.view.frame.height < contentOffsetY + bounds.height, firstVisible.index > 0 {
var offset: CGFloat = firstVisible.view.frame.origin.y + firstVisible.view.frame.height
let index = firstVisible.index
for i in stride(from: index - 1, through: 0, by: -1) {
let item = items[i]
let visibleIndex = oldVisible.firstIndex(where: { vis in vis.item.id == item.id })
let vis: VisibleItem
if let visibleIndex {
let visible = oldVisible.remove(at: visibleIndex)
visible.view.frame.origin.y = offset
vis = VisibleItem(index: i, item: item, view: visible.view, offset: offsetToBottom(visible.view))
} else {
let cell = createCell(i, items, &cellsToReuse)!
cell.frame.origin.y = offset
vis = VisibleItem(index: i, item: item, view: cell, offset: offsetToBottom(cell))
}
if vis.view.superview == nil {
addSubview(vis.view)
}
offset += vis.view.frame.height
newVisible.insert(vis, at: 0)
if offset >= contentOffsetY + bounds.height {
break
}
}
}
// removing already unneeded visible items
oldVisible.forEach { vis in
cellsToReuse.append(vis.view)
hideAndRemoveFromSuperviewIfNeeded(vis.view)
}
let itemsCountChanged = listState.items.count != items.count
prevProcessedOffset = contentOffsetY
listState.visibleItems = newVisible
listState.items = items
listState.firstVisibleItemId = listState.visibleItems.first?.item.id ?? EndlessScrollView<ScrollItem>.DEFAULT_ITEM_ID
listState.firstVisibleItemIndex = listState.visibleItems.first?.index ?? 0
listState.firstVisibleItemOffset = listState.visibleItems.first?.offset ?? -insetTop
estimatedContentHeight.update(contentOffset, listState, averageItemHeight, itemsCountChanged)
scrollBarView.contentSize = CGSizeMake(bounds.width, estimatedContentHeight.virtualOverscrolledHeight)
scrollBarView.contentOffset = CGPointMake(0, estimatedContentHeight.virtualScrollOffsetY)
scrollBarView.isHidden = listState.visibleItems.count == listState.items.count && (listState.visibleItems.isEmpty || -listState.firstVisibleItemOffset + (listState.visibleItems.last?.offset ?? 0) + insetTop < bounds.height)
if debug {
println("time spent \((-start.timeIntervalSinceNow).description.prefix(5).replacingOccurrences(of: "0.000", with: "<0").replacingOccurrences(of: "0.", with: ""))")
}
}
func setScrollPosition(_ index: Int, _ id: Int64, _ offset: CGFloat = 0) {
listState.firstVisibleItemIndex = index
listState.firstVisibleItemId = id
listState.firstVisibleItemOffset = offset == 0 ? -bounds.height + insetTop + insetBottom : offset
}
func scrollToItem(_ index: Int, top: Bool = true) {
if index >= listState.items.count || listState.isScrolling || listState.isAnimatedScrolling {
return
}
if bounds.height == 0 || contentSize.height == 0 {
scrollToItemIndexDelayed = index
return
}
listState.isScrolling = true
defer {
listState.isScrolling = false
}
// just a faster way to set top item as requested index
listState.firstVisibleItemIndex = index
listState.firstVisibleItemId = listState.items[index].id
listState.firstVisibleItemOffset = -bounds.height + insetTop + insetBottom
scrollBarView.flashScrollIndicators()
adaptItems(listState.items, false)
var adjustedOffset = self.contentOffset.y
var i = 0
var upPrev = index > listState.firstVisibleItemIndex
//let firstOrLastIndex = upPrev ? listState.visibleItems.last?.index ?? 0 : listState.firstVisibleItemIndex
//let step: CGFloat = max(0.1, CGFloat(abs(index - firstOrLastIndex)) * scrollStepMultiplier)
var stepSlowdownMultiplier: CGFloat = 1
while i < 200 {
let up = index > listState.firstVisibleItemIndex
if upPrev != up {
stepSlowdownMultiplier = stepSlowdownMultiplier * 0.5
upPrev = up
}
// these two lines makes scrolling's finish non-linear and NOT overscroll visually when reach target index
let firstOrLastIndex = up ? listState.visibleItems.last?.index ?? 0 : listState.firstVisibleItemIndex
let step: CGFloat = max(0.1, CGFloat(abs(index - firstOrLastIndex)) * scrollStepMultiplier) * stepSlowdownMultiplier
let offsetToScroll = (up ? -averageItemHeight : averageItemHeight) * step
adjustedOffset += offsetToScroll
if let item = listState.visibleItems.first(where: { $0.index == index }) {
let y = if top {
min(estimatedContentHeight.bottomOffsetY - bounds.height, item.view.frame.origin.y - insetTop)
} else {
max(estimatedContentHeight.topOffsetY - insetTop - insetBottom, item.view.frame.origin.y + item.view.bounds.height - bounds.height + insetBottom)
}
setContentOffset(CGPointMake(contentOffset.x, y), animated: false)
scrollBarView.flashScrollIndicators()
break
}
contentOffset = CGPointMake(contentOffset.x, adjustedOffset)
adaptItems(listState.items, false)
snapToContent(animated: false)
i += 1
}
adaptItems(listState.items, false)
snapToContent(animated: false)
estimatedContentHeight.update(contentOffset, listState, averageItemHeight, true)
}
func scrollToItemAnimated(_ index: Int, top: Bool = true) async {
if index >= listState.items.count || listState.isScrolling || listState.isAnimatedScrolling {
return
}
listState.isAnimatedScrolling = true
defer {
listState.isAnimatedScrolling = false
}
var adjustedOffset = self.contentOffset.y
var i = 0
var upPrev = index > listState.firstVisibleItemIndex
//let firstOrLastIndex = upPrev ? listState.visibleItems.last?.index ?? 0 : listState.firstVisibleItemIndex
//let step: CGFloat = max(0.1, CGFloat(abs(index - firstOrLastIndex)) * scrollStepMultiplier)
var stepSlowdownMultiplier: CGFloat = 1
while i < 200 {
let up = index > listState.firstVisibleItemIndex
if upPrev != up {
stepSlowdownMultiplier = stepSlowdownMultiplier * 0.5
upPrev = up
}
// these two lines makes scrolling's finish non-linear and NOT overscroll visually when reach target index
let firstOrLastIndex = up ? listState.visibleItems.last?.index ?? 0 : listState.firstVisibleItemIndex
let step: CGFloat = max(0.1, CGFloat(abs(index - firstOrLastIndex)) * scrollStepMultiplier) * stepSlowdownMultiplier
//println("Scrolling step \(step) \(stepSlowdownMultiplier) index \(index) \(firstOrLastIndex) \(index - firstOrLastIndex) \(adjustedOffset), up \(up), i \(i)")
let offsetToScroll = (up ? -averageItemHeight : averageItemHeight) * step
adjustedOffset += offsetToScroll
if let item = listState.visibleItems.first(where: { $0.index == index }) {
let y = if top {
min(estimatedContentHeight.bottomOffsetY - bounds.height, item.view.frame.origin.y - insetTop)
} else {
max(estimatedContentHeight.topOffsetY - insetTop - insetBottom, item.view.frame.origin.y + item.view.bounds.height - bounds.height + insetBottom)
}
setContentOffset(CGPointMake(contentOffset.x, y), animated: true)
scrollBarView.flashScrollIndicators()
break
}
contentOffset = CGPointMake(contentOffset.x, adjustedOffset)
// skipping unneded relayout if this offset is already processed
if prevProcessedOffset - contentOffset.y != 0 {
adaptItems(listState.items, false)
snapToContent(animated: false)
}
// let UI time to update to see the animated position change
await MainActor.run {}
i += 1
}
estimatedContentHeight.update(contentOffset, listState, averageItemHeight, true)
}
func scrollToBottom() {
scrollToItem(0, top: false)
}
func scrollToBottomAnimated() {
Task {
await scrollToItemAnimated(0, top: false)
}
}
func scroll(by: CGFloat, animated: Bool = true) {
setContentOffset(CGPointMake(contentOffset.x, contentOffset.y + by), animated: animated)
}
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
if !listState.items.isEmpty {
scrollToBottomAnimated()
}
return false
}
private func snapToContent(animated: Bool) {
let topBlankSpace = estimatedContentHeight.height < bounds.height ? bounds.height - estimatedContentHeight.height : 0
if topY < estimatedContentHeight.topOffsetY - topBlankSpace {
setContentOffset(CGPointMake(0, estimatedContentHeight.topOffsetY - topBlankSpace), animated: animated)
} else if bottomY > estimatedContentHeight.bottomOffsetY {
setContentOffset(CGPointMake(0, estimatedContentHeight.bottomOffsetY - bounds.height), animated: animated)
}
}
func offsetToBottom(_ view: UIView) -> CGFloat {
bottomY - (view.frame.origin.y + view.frame.height)
}
/// If I try to .removeFromSuperview() right when I need to remove the view, it is possible to crash the app when the view was hidden in result of
/// pressing Hide in menu on top of the revealed item within the group. So at that point the item should still be attached to the view
func hideAndRemoveFromSuperviewIfNeeded(_ view: UIView) {
if view.isHidden {
// already passed this function
return
}
(view as? ReusableView)?.prepareForReuse()
view.isHidden = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
if view.isHidden { view.removeFromSuperview() }
}
}
/// Synchronizing both scrollViews
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
true
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
snapToContent(animated: true)
}
}
override var contentOffset: CGPoint {
get { super.contentOffset }
set {
var newOffset = newValue
let topBlankSpace = estimatedContentHeight.height < bounds.height ? bounds.height - estimatedContentHeight.height : 0
if contentOffset.y > 0 && newOffset.y < estimatedContentHeight.topOffsetY - topBlankSpace && contentOffset.y > newOffset.y {
if !isDecelerating {
newOffset.y = min(contentOffset.y, newOffset.y + abs(newOffset.y - estimatedContentHeight.topOffsetY + topBlankSpace) / 1.8)
} else {
DispatchQueue.main.async {
self.setContentOffset(newValue, animated: false)
self.snapToContent(animated: true)
}
}
} else if contentOffset.y > 0 && newOffset.y + bounds.height > estimatedContentHeight.bottomOffsetY && contentOffset.y < newOffset.y {
if !isDecelerating {
newOffset.y = max(contentOffset.y, newOffset.y - abs(newOffset.y + bounds.height - estimatedContentHeight.bottomOffsetY) / 1.8)
} else {
DispatchQueue.main.async {
self.setContentOffset(newValue, animated: false)
self.snapToContent(animated: true)
}
}
}
super.contentOffset = newOffset
}
}
private func stopScrolling() {
let offsetYToStopAt = if abs(contentOffset.y - estimatedContentHeight.topOffsetY) < abs(bottomY - estimatedContentHeight.bottomOffsetY) {
estimatedContentHeight.topOffsetY
} else {
estimatedContentHeight.bottomOffsetY - bounds.height
}
setContentOffset(CGPointMake(contentOffset.x, offsetYToStopAt), animated: false)
}
func isVisible(_ view: UIView) -> Bool {
if view.superview == nil {
return false
}
return view.frame.intersects(CGRectMake(0, contentOffset.y, bounds.width, bounds.height))
}
}
private func println(_ text: String) {
print("\(Date.now.timeIntervalSince1970): \(text)")
}

View file

@ -681,12 +681,14 @@ struct GroupChatInfoView: View {
primaryButton: .destructive(Text("Remove")) {
Task {
do {
let updatedMember = try await apiRemoveMember(groupInfo.groupId, mem.groupMemberId)
let updatedMembers = try await apiRemoveMembers(groupInfo.groupId, [mem.groupMemberId])
await MainActor.run {
_ = chatModel.upsertGroupMember(groupInfo, updatedMember)
updatedMembers.forEach { updatedMember in
_ = chatModel.upsertGroupMember(groupInfo, updatedMember)
}
}
} catch let error {
logger.error("apiRemoveMember error: \(responseError(error))")
logger.error("apiRemoveMembers error: \(responseError(error))")
let a = getErrorAlert(error, "Error removing member")
alert = .error(title: a.title, error: a.message)
}

View file

@ -366,14 +366,8 @@ struct GroupMemberInfoView: View {
func newDirectChatButton(_ contactId: Int64, width: CGFloat) -> some View {
InfoViewButton(image: "message.fill", title: "message", width: width) {
Task {
do {
let chat = try await apiGetChat(type: .direct, id: contactId)
chatModel.addChat(chat)
ItemsModel.shared.loadOpenChat(chat.id) {
dismissAllSheets(animated: true)
}
} catch let error {
logger.error("openDirectChatButton apiGetChat error: \(responseError(error))")
ItemsModel.shared.loadOpenChat("@\(contactId)") {
dismissAllSheets(animated: true)
}
}
}
@ -616,13 +610,15 @@ struct GroupMemberInfoView: View {
primaryButton: .destructive(Text("Remove")) {
Task {
do {
let updatedMember = try await apiRemoveMember(groupInfo.groupId, mem.groupMemberId)
let updatedMembers = try await apiRemoveMembers(groupInfo.groupId, [mem.groupMemberId])
await MainActor.run {
_ = chatModel.upsertGroupMember(groupInfo, updatedMember)
updatedMembers.forEach { updatedMember in
_ = chatModel.upsertGroupMember(groupInfo, updatedMember)
}
dismiss()
}
} catch let error {
logger.error("apiRemoveMember error: \(responseError(error))")
logger.error("apiRemoveMembers error: \(responseError(error))")
let a = getErrorAlert(error, "Error removing member")
alert = .error(title: a.title, error: a.message)
}
@ -647,14 +643,16 @@ struct GroupMemberInfoView: View {
primaryButton: .default(Text("Change")) {
Task {
do {
let updatedMember = try await apiMemberRole(groupInfo.groupId, mem.groupMemberId, newRole)
let updatedMembers = try await apiMembersRole(groupInfo.groupId, [mem.groupMemberId], newRole)
await MainActor.run {
_ = chatModel.upsertGroupMember(groupInfo, updatedMember)
updatedMembers.forEach { updatedMember in
_ = chatModel.upsertGroupMember(groupInfo, updatedMember)
}
}
} catch let error {
newRole = mem.memberRole
logger.error("apiMemberRole error: \(responseError(error))")
logger.error("apiMembersRole error: \(responseError(error))")
let a = getErrorAlert(error, "Error changing role")
alert = .error(title: a.title, error: a.message)
}
@ -806,12 +804,14 @@ func unblockForAllAlert(_ gInfo: GroupInfo, _ mem: GroupMember) -> Alert {
func blockMemberForAll(_ gInfo: GroupInfo, _ member: GroupMember, _ blocked: Bool) {
Task {
do {
let updatedMember = try await apiBlockMemberForAll(gInfo.groupId, member.groupMemberId, blocked)
let updatedMembers = try await apiBlockMembersForAll(gInfo.groupId, [member.groupMemberId], blocked)
await MainActor.run {
_ = ChatModel.shared.upsertGroupMember(gInfo, updatedMember)
updatedMembers.forEach { updatedMember in
_ = ChatModel.shared.upsertGroupMember(gInfo, updatedMember)
}
}
} catch let error {
logger.error("apiBlockMemberForAll error: \(responseError(error))")
logger.error("apiBlockMembersForAll error: \(responseError(error))")
}
}
}

View file

@ -27,79 +27,78 @@ struct GroupMentionsView: View {
@State private var mentionName: String = ""
@State private var mentionRange: NSRange?
@State private var mentionMemberId: String?
@State private var sortedMembers: [GMember] = []
var body: some View {
ZStack {
ZStack(alignment: .bottom) {
if isVisible {
Color.white.opacity(0.01)
.edgesIgnoringSafeArea(.all)
.onTapGesture {
isVisible = false
}
}
VStack {
Spacer()
VStack {
Spacer()
VStack {
let filtered = filteredMembers()
if filtered.count > 0 {
Color.white.opacity(0.01)
.edgesIgnoringSafeArea(.all)
.onTapGesture {
isVisible = false
}
VStack(spacing: 0) {
Spacer()
Divider()
let list = List {
ForEach(filteredMembers, id: \.wrapped.groupMemberId) { member in
let mentioned = mentionMemberId == member.wrapped.memberId
let disabled = composeState.mentions.count >= MAX_NUMBER_OF_MENTIONS && !mentioned
memberRowView(member.wrapped, mentioned)
.contentShape(Rectangle())
.disabled(disabled)
.opacity(disabled ? 0.6 : 1)
.onTapGesture {
memberSelected(member)
let scroll = ScrollView {
LazyVStack(spacing: 0) {
ForEach(Array(filtered.enumerated()), id: \.element.wrapped.groupMemberId) { index, member in
let mentioned = mentionMemberId == member.wrapped.memberId
let disabled = composeState.mentions.count >= MAX_NUMBER_OF_MENTIONS && !mentioned
ZStack(alignment: .bottom) {
memberRowView(member.wrapped, mentioned)
.contentShape(Rectangle())
.disabled(disabled)
.opacity(disabled ? 0.6 : 1)
.onTapGesture {
memberSelected(member)
}
.padding(.horizontal)
.frame(height: MEMBER_ROW_SIZE)
Divider()
.padding(.leading)
.padding(.leading, 48)
}
}
}
}
.listStyle(PlainListStyle())
.frame(height: MEMBER_ROW_SIZE * min(MAX_VISIBLE_MEMBER_ROWS, CGFloat(filteredMembers.count)))
.frame(maxHeight: MEMBER_ROW_SIZE * min(MAX_VISIBLE_MEMBER_ROWS, CGFloat(filtered.count)))
.background(Color(UIColor.systemBackground))
if #available(iOS 16.0, *) {
list.scrollDismissesKeyboard(.never)
scroll.scrollDismissesKeyboard(.never)
} else {
list
scroll
}
}
.background(Color(UIColor.systemBackground))
}
.frame(maxWidth: .infinity, maxHeight: MEMBER_ROW_SIZE * MAX_VISIBLE_MEMBER_ROWS)
}
.offset(y: isVisible ? 0 : 300)
.animation(.spring(), value: isVisible)
.onChange(of: composeState.parsedMessage) { parsedMsg in
currentMessage = composeState.message
messageChanged(currentMessage, parsedMsg, selectedRange)
}
.onChange(of: selectedRange) { r in
// This condition is needed to prevent messageChanged called twice,
// because composeState.formattedText triggers later when message changes.
// The condition is only true if position changed without text change
if currentMessage == composeState.message {
messageChanged(currentMessage, composeState.parsedMessage, r)
}
}
.onAppear {
currentMessage = composeState.message
}
.onChange(of: composeState.parsedMessage) { parsedMsg in
currentMessage = composeState.message
messageChanged(currentMessage, parsedMsg, selectedRange)
}
.onChange(of: selectedRange) { r in
// This condition is needed to prevent messageChanged called twice,
// because composeState.formattedText triggers later when message changes.
// The condition is only true if position changed without text change
if currentMessage == composeState.message {
messageChanged(currentMessage, composeState.parsedMessage, r)
}
}
.onAppear {
currentMessage = composeState.message
}
}
private var filteredMembers: [GMember] {
let members = m.groupMembers
.filter { m in
let status = m.wrapped.memberStatus
return status != .memLeft && status != .memRemoved && status != .memInvited
}
.sorted { $0.wrapped.memberRole > $1.wrapped.memberRole }
private func filteredMembers() -> [GMember] {
let s = mentionName.lowercased()
return s.isEmpty
? members
: members.filter { $0.wrapped.localAliasAndFullName.localizedLowercase.contains(s) }
? sortedMembers
: sortedMembers.filter { $0.wrapped.localAliasAndFullName.localizedLowercase.contains(s) }
}
private func messageChanged(_ msg: String, _ parsedMsg: [FormattedText], _ range: NSRange) {
@ -112,7 +111,10 @@ struct GroupMentionsView: View {
mentionRange = r
mentionMemberId = composeState.mentions[name]?.memberId
if !m.membersLoaded {
Task { await m.loadGroupMembers(groupInfo) }
Task {
await m.loadGroupMembers(groupInfo)
sortMembers()
}
}
return
case .none: () //
@ -124,7 +126,10 @@ struct GroupMentionsView: View {
mentionName = ""
mentionRange = atRange
mentionMemberId = nil
Task { await m.loadGroupMembers(groupInfo) }
Task {
await m.loadGroupMembers(groupInfo)
sortMembers()
}
return
}
}
@ -134,6 +139,14 @@ struct GroupMentionsView: View {
closeMemberList()
}
private func sortMembers() {
sortedMembers = m.groupMembers.filter({ m in
let status = m.wrapped.memberStatus
return status != .memLeft && status != .memRemoved && status != .memInvited
})
.sorted { $0.wrapped.memberRole > $1.wrapped.memberRole }
}
private func removeUnusedMentions(_ parsedMsg: [FormattedText]) {
let usedMentions: Set<String> = Set(parsedMsg.compactMap { ft in
if case let .mention(name) = ft.format { name } else { nil }

View file

@ -37,6 +37,7 @@ struct GroupPreferencesView: View {
featureSection(.voice, $preferences.voice.enable, $preferences.voice.role)
featureSection(.files, $preferences.files.enable, $preferences.files.role)
featureSection(.simplexLinks, $preferences.simplexLinks.enable, $preferences.simplexLinks.role)
featureSection(.reports, $preferences.reports.enable)
featureSection(.history, $preferences.history.enable)
if groupInfo.isOwner {
@ -89,6 +90,7 @@ struct GroupPreferencesView: View {
settingsRow(icon, color: color) {
Toggle(feature.text, isOn: enable)
}
.disabled(feature == .reports) // remove in 6.4
if timedOn {
DropdownCustomTimePicker(
selection: $preferences.timedMessages.ttl,

View file

@ -1,371 +0,0 @@
//
// ReverseList.swift
// SimpleX (iOS)
//
// Created by Levitating Pineapple on 11/06/2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import Combine
import SimpleXChat
/// A List, which displays it's items in reverse order - from bottom to top
struct ReverseList<Content: View>: UIViewControllerRepresentable {
let items: Array<ChatItem>
@Binding var scrollState: ReverseListScrollModel.State
/// Closure, that returns user interface for a given item
let content: (ChatItem) -> Content
let loadPage: () -> Void
func makeUIViewController(context: Context) -> Controller {
Controller(representer: self)
}
func updateUIViewController(_ controller: Controller, context: Context) {
controller.representer = self
if case let .scrollingTo(destination) = scrollState, !items.isEmpty {
controller.view.layer.removeAllAnimations()
switch destination {
case .nextPage:
controller.scrollToNextPage()
case let .item(id):
controller.scroll(to: items.firstIndex(where: { $0.id == id }), position: .bottom)
case .bottom:
controller.scroll(to: 0, position: .top)
}
} else {
controller.update(items: items)
}
}
/// Controller, which hosts SwiftUI cells
class Controller: UITableViewController {
private enum Section { case main }
var representer: ReverseList
private var dataSource: UITableViewDiffableDataSource<Section, ChatItem>!
private var itemCount: Int = 0
private let updateFloatingButtons = PassthroughSubject<Void, Never>()
private var bag = Set<AnyCancellable>()
init(representer: ReverseList) {
self.representer = representer
super.init(style: .plain)
// 1. Style
tableView = InvertedTableView()
tableView.separatorStyle = .none
tableView.transform = .verticalFlip
tableView.backgroundColor = .clear
// 2. Register cells
if #available(iOS 16.0, *) {
tableView.register(
UITableViewCell.self,
forCellReuseIdentifier: cellReuseId
)
} else {
tableView.register(
HostingCell<Content>.self,
forCellReuseIdentifier: cellReuseId
)
}
// 3. Configure data source
self.dataSource = UITableViewDiffableDataSource<Section, ChatItem>(
tableView: tableView
) { (tableView, indexPath, item) -> UITableViewCell? in
if indexPath.item > self.itemCount - 8 {
self.representer.loadPage()
}
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseId, for: indexPath)
if #available(iOS 16.0, *) {
cell.contentConfiguration = UIHostingConfiguration { self.representer.content(item) }
.margins(.all, 0)
.minSize(height: 1) // Passing zero will result in system default of 44 points being used
} else {
if let cell = cell as? HostingCell<Content> {
cell.set(content: self.representer.content(item), parent: self)
} else {
fatalError("Unexpected Cell Type for: \(item)")
}
}
cell.transform = .verticalFlip
cell.selectionStyle = .none
cell.backgroundColor = .clear
return cell
}
// 4. External state changes will require manual layout updates
NotificationCenter.default
.addObserver(
self,
selector: #selector(updateLayout),
name: notificationName,
object: nil
)
updateFloatingButtons
.throttle(for: 0.2, scheduler: DispatchQueue.global(qos: .background), latest: true)
.sink {
if let listState = DispatchQueue.main.sync(execute: { [weak self] in self?.getListState() }) {
ChatView.FloatingButtonModel.shared.updateOnListChange(listState)
}
}
.store(in: &bag)
}
@available(*, unavailable)
required init?(coder: NSCoder) { fatalError() }
deinit { NotificationCenter.default.removeObserver(self) }
@objc private func updateLayout() {
if #available(iOS 16.0, *) {
tableView.setNeedsLayout()
tableView.layoutIfNeeded()
} else {
tableView.reloadData()
}
}
/// Hides keyboard, when user begins to scroll.
/// Equivalent to `.scrollDismissesKeyboard(.immediately)`
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
UIApplication.shared
.sendAction(
#selector(UIResponder.resignFirstResponder),
to: nil,
from: nil,
for: nil
)
NotificationCenter.default.post(name: .chatViewWillBeginScrolling, object: nil)
}
override func viewDidAppear(_ animated: Bool) {
tableView.clipsToBounds = false
parent?.viewIfLoaded?.clipsToBounds = false
}
/// Scrolls up
func scrollToNextPage() {
tableView.setContentOffset(
CGPoint(
x: tableView.contentOffset.x,
y: tableView.contentOffset.y + tableView.bounds.height
),
animated: true
)
Task { representer.scrollState = .atDestination }
}
/// Scrolls to Item at index path
/// - Parameter indexPath: Item to scroll to - will scroll to beginning of the list, if `nil`
func scroll(to index: Int?, position: UITableView.ScrollPosition) {
var animated = false
if #available(iOS 16.0, *) {
animated = true
}
if let index, tableView.numberOfRows(inSection: 0) != 0 {
tableView.scrollToRow(
at: IndexPath(row: index, section: 0),
at: position,
animated: animated
)
} else {
tableView.setContentOffset(
CGPoint(x: .zero, y: -InvertedTableView.inset),
animated: animated
)
}
Task { representer.scrollState = .atDestination }
}
func update(items: [ChatItem]) {
var snapshot = NSDiffableDataSourceSnapshot<Section, ChatItem>()
snapshot.appendSections([.main])
snapshot.appendItems(items)
dataSource.defaultRowAnimation = .none
dataSource.apply(
snapshot,
animatingDifferences: itemCount != 0 && abs(items.count - itemCount) == 1
)
// Sets content offset on initial load
if itemCount == 0 {
tableView.setContentOffset(
CGPoint(x: 0, y: -InvertedTableView.inset),
animated: false
)
}
itemCount = items.count
updateFloatingButtons.send()
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
updateFloatingButtons.send()
}
func getListState() -> ListState? {
if let visibleRows = tableView.indexPathsForVisibleRows,
visibleRows.last?.item ?? 0 < representer.items.count {
let scrollOffset: Double = tableView.contentOffset.y + InvertedTableView.inset
let topItemDate: Date? =
if let lastVisible = visibleRows.last(where: { isVisible(indexPath: $0) }) {
representer.items[lastVisible.item].meta.itemTs
} else {
nil
}
let bottomItemId: ChatItem.ID? =
if let firstVisible = visibleRows.first(where: { isVisible(indexPath: $0) }) {
representer.items[firstVisible.item].id
} else {
nil
}
return (scrollOffset: scrollOffset, topItemDate: topItemDate, bottomItemId: bottomItemId)
}
return nil
}
private func isVisible(indexPath: IndexPath) -> Bool {
if let relativeFrame = tableView.superview?.convert(
tableView.rectForRow(at: indexPath),
from: tableView
) {
relativeFrame.maxY > InvertedTableView.inset &&
relativeFrame.minY < tableView.frame.height - InvertedTableView.inset
} else { false }
}
}
/// `UIHostingConfiguration` back-port for iOS14 and iOS15
/// Implemented as a `UITableViewCell` that wraps and manages a generic `UIHostingController`
private final class HostingCell<Hosted: View>: UITableViewCell {
private let hostingController = UIHostingController<Hosted?>(rootView: nil)
/// Updates content of the cell
/// For reference: https://noahgilmore.com/blog/swiftui-self-sizing-cells/
func set(content: Hosted, parent: UIViewController) {
hostingController.view.backgroundColor = .clear
hostingController.rootView = content
if let hostingView = hostingController.view {
hostingView.invalidateIntrinsicContentSize()
if hostingController.parent != parent { parent.addChild(hostingController) }
if !contentView.subviews.contains(hostingController.view) {
contentView.addSubview(hostingController.view)
hostingView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingView.leadingAnchor
.constraint(equalTo: contentView.leadingAnchor),
hostingView.trailingAnchor
.constraint(equalTo: contentView.trailingAnchor),
hostingView.topAnchor
.constraint(equalTo: contentView.topAnchor),
hostingView.bottomAnchor
.constraint(equalTo: contentView.bottomAnchor)
])
}
if hostingController.parent != parent { hostingController.didMove(toParent: parent) }
} else {
fatalError("Hosting View not loaded \(hostingController)")
}
}
override func prepareForReuse() {
super.prepareForReuse()
hostingController.rootView = nil
}
}
}
typealias ListState = (
scrollOffset: Double,
topItemDate: Date?,
bottomItemId: ChatItem.ID?
)
/// Manages ``ReverseList`` scrolling
class ReverseListScrollModel: ObservableObject {
/// Represents Scroll State of ``ReverseList``
enum State: Equatable {
enum Destination: Equatable {
case nextPage
case item(ChatItem.ID)
case bottom
}
case scrollingTo(Destination)
case atDestination
}
@Published var state: State = .atDestination
func scrollToNextPage() {
state = .scrollingTo(.nextPage)
}
func scrollToBottom() {
state = .scrollingTo(.bottom)
}
func scrollToItem(id: ChatItem.ID) {
state = .scrollingTo(.item(id))
}
}
fileprivate let cellReuseId = "hostingCell"
fileprivate let notificationName = NSNotification.Name(rawValue: "reverseListNeedsLayout")
fileprivate extension CGAffineTransform {
/// Transform that vertically flips the view, preserving it's location
static let verticalFlip = CGAffineTransform(scaleX: 1, y: -1)
}
extension NotificationCenter {
static func postReverseListNeedsLayout() {
NotificationCenter.default.post(
name: notificationName,
object: nil
)
}
}
/// Disable animation on iOS 15
func withConditionalAnimation<Result>(
_ animation: Animation? = .default,
_ body: () throws -> Result
) rethrows -> Result {
if #available(iOS 16.0, *) {
try withAnimation(animation, body)
} else {
try body()
}
}
class InvertedTableView: UITableView {
static let inset = CGFloat(100)
static let insets = UIEdgeInsets(
top: inset,
left: .zero,
bottom: inset,
right: .zero
)
override var contentInsetAdjustmentBehavior: UIScrollView.ContentInsetAdjustmentBehavior {
get { .never }
set { }
}
override var contentInset: UIEdgeInsets {
get { Self.insets }
set { }
}
override var adjustedContentInset: UIEdgeInsets {
Self.insets
}
}

View file

@ -0,0 +1,52 @@
//
// ScrollViewCells.swift
// SimpleX (iOS)
//
// Created by Stanislav Dmitrenko on 27.01.2025.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
protocol ReusableView {
func prepareForReuse()
}
/// `UIHostingConfiguration` back-port for iOS14 and iOS15
/// Implemented as a `UIView` that wraps and manages a generic `UIHostingController`
final class HostingCell<Hosted: View>: UIView, ReusableView {
private let hostingController = UIHostingController<Hosted?>(rootView: nil)
/// Updates content of the cell
/// For reference: https://noahgilmore.com/blog/swiftui-self-sizing-cells/
func set(content: Hosted, parent: UIViewController) {
hostingController.view.backgroundColor = .clear
hostingController.rootView = content
if let hostingView = hostingController.view {
hostingView.invalidateIntrinsicContentSize()
if hostingController.parent != parent { parent.addChild(hostingController) }
if !subviews.contains(hostingController.view) {
addSubview(hostingController.view)
hostingView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingView.leadingAnchor
.constraint(equalTo: leadingAnchor),
hostingView.trailingAnchor
.constraint(equalTo: trailingAnchor),
hostingView.topAnchor
.constraint(equalTo: topAnchor),
hostingView.bottomAnchor
.constraint(equalTo: bottomAnchor)
])
}
if hostingController.parent != parent { hostingController.didMove(toParent: parent) }
} else {
fatalError("Hosting View not loaded \(hostingController)")
}
}
func prepareForReuse() {
//super.prepareForReuse()
hostingController.rootView = nil
}
}

View file

@ -30,12 +30,15 @@ struct SelectedItemsBottomToolbar: View {
var chatInfo: ChatInfo
// Bool - delete for everyone is possible
var deleteItems: (Bool) -> Void
var archiveItems: () -> Void
var moderateItems: () -> Void
//var shareItems: () -> Void
var forwardItems: () -> Void
@State var deleteEnabled: Bool = false
@State var deleteForEveryoneEnabled: Bool = false
@State var canArchiveReports: Bool = false
@State var canModerate: Bool = false
@State var moderateEnabled: Bool = false
@ -50,7 +53,11 @@ struct SelectedItemsBottomToolbar: View {
HStack(alignment: .center) {
Button {
deleteItems(deleteForEveryoneEnabled)
if canArchiveReports {
archiveItems()
} else {
deleteItems(deleteForEveryoneEnabled)
}
} label: {
Image(systemName: "trash")
.resizable()
@ -109,19 +116,25 @@ struct SelectedItemsBottomToolbar: View {
deleteCountProhibited = count == 0 || count > 200
forwardCountProhibited = count == 0 || count > 20
canModerate = possibleToModerate(chatInfo)
let groupInfo: GroupInfo? = if case let ChatInfo.group(groupInfo: info) = chatInfo {
info
} else {
nil
}
if let selected = selectedItems {
let me: Bool
let onlyOwnGroupItems: Bool
(deleteEnabled, deleteForEveryoneEnabled, me, onlyOwnGroupItems, forwardEnabled, selectedChatItems) = chatItems.reduce((true, true, true, true, true, [])) { (r, ci) in
(deleteEnabled, deleteForEveryoneEnabled, canArchiveReports, me, onlyOwnGroupItems, forwardEnabled, selectedChatItems) = chatItems.reduce((true, true, true, true, true, true, [])) { (r, ci) in
if selected.contains(ci.id) {
var (de, dee, me, onlyOwnGroupItems, fe, sel) = r
var (de, dee, ar, me, onlyOwnGroupItems, fe, sel) = r
de = de && ci.canBeDeletedForSelf
dee = dee && ci.meta.deletable && !ci.localNote && !ci.isReport
ar = ar && ci.isActiveReport && ci.chatDir != .groupSnd && groupInfo != nil && groupInfo!.membership.memberRole >= .moderator
onlyOwnGroupItems = onlyOwnGroupItems && ci.chatDir == .groupSnd && !ci.isReport
me = me && ci.content.msgContent != nil && ci.memberToModerate(chatInfo) != nil && !ci.isReport
fe = fe && ci.content.msgContent != nil && ci.meta.itemDeleted == nil && !ci.isLiveDummy && !ci.isReport
sel.insert(ci.id) // we are collecting new selected items here to account for any changes in chat items list
return (de, dee, me, onlyOwnGroupItems, fe, sel)
return (de, dee, ar, me, onlyOwnGroupItems, fe, sel)
} else {
return r
}

View file

@ -211,23 +211,32 @@ struct ChatListNavLink: View {
}
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
tagChatButton(chat)
let showReportsButton = chat.chatStats.reportsCount > 0 && groupInfo.membership.memberRole >= .moderator
let showClearButton = !chat.chatItems.isEmpty
let showDeleteGroup = groupInfo.canDelete
let showLeaveGroup = groupInfo.membership.memberCurrent
let totalNumberOfButtons = 1 + (showClearButton ? 1 : 0) + (showDeleteGroup ? 1 : 0) + (showLeaveGroup ? 1 : 0)
let totalNumberOfButtons = 1 + (showReportsButton ? 1 : 0) + (showClearButton ? 1 : 0) + (showDeleteGroup ? 1 : 0) + (showLeaveGroup ? 1 : 0)
if showClearButton, totalNumberOfButtons <= 3 {
if showClearButton && totalNumberOfButtons <= 3 {
clearChatButton()
}
if (showLeaveGroup) {
if showReportsButton && totalNumberOfButtons <= 3 {
archiveAllReportsButton()
}
if showLeaveGroup {
leaveGroupChatButton(groupInfo)
}
if showDeleteGroup {
if totalNumberOfButtons <= 3 {
if showDeleteGroup && totalNumberOfButtons <= 3 {
deleteGroupChatButton(groupInfo)
} else if totalNumberOfButtons > 3 {
if showDeleteGroup && !groupInfo.membership.memberActive {
deleteGroupChatButton(groupInfo)
moreOptionsButton(false, chat, groupInfo)
} else {
moreOptionsButton(chat, groupInfo)
moreOptionsButton(true, chat, groupInfo)
}
}
}
@ -313,6 +322,14 @@ struct ChatListNavLink: View {
}
}
private func archiveAllReportsButton() -> some View {
Button {
AlertManager.shared.showAlert(archiveAllReportsAlert())
} label: {
SwipeLabel(NSLocalizedString("Archive reports", comment: "swipe action"), systemImage: "archivebox", inverted: oneHandUI)
}
}
private func clearChatButton() -> some View {
Button {
AlertManager.shared.showAlert(clearChatAlert())
@ -354,15 +371,20 @@ struct ChatListNavLink: View {
)
}
private func moreOptionsButton(_ chat: Chat, _ groupInfo: GroupInfo?) -> some View {
private func moreOptionsButton(_ canShowGroupDelete: Bool, _ chat: Chat, _ groupInfo: GroupInfo?) -> some View {
Button {
var buttons: [Alert.Button] = [
.default(Text("Clear")) {
AlertManager.shared.showAlert(clearChatAlert())
}
]
if let gi = groupInfo, gi.canDelete {
var buttons: [Alert.Button] = []
buttons.append(.default(Text("Clear")) {
AlertManager.shared.showAlert(clearChatAlert())
})
if let groupInfo, chat.chatStats.reportsCount > 0 && groupInfo.membership.memberRole >= .moderator && groupInfo.ready {
buttons.append(.default(Text("Archive reports")) {
AlertManager.shared.showAlert(archiveAllReportsAlert())
})
}
if canShowGroupDelete, let gi = groupInfo, gi.canDelete {
buttons.append(.destructive(Text("Delete")) {
AlertManager.shared.showAlert(deleteGroupAlert(gi))
})
@ -372,7 +394,7 @@ struct ChatListNavLink: View {
actionSheet = SomeActionSheet(
actionSheet: ActionSheet(
title: Text("Clear or delete group?"),
title: canShowGroupDelete ? Text("Clear or delete group?") : Text("Clear group?"),
buttons: buttons
),
id: "other options"
@ -490,6 +512,27 @@ struct ChatListNavLink: View {
)
}
private func archiveAllReportsAlert() -> Alert {
Alert(
title: Text("Archive all reports?"),
message: Text("All reports will be archived for you."),
primaryButton: .destructive(Text("Archive")) {
Task { await archiveAllReportsForMe(chat.chatInfo.apiId) }
},
secondaryButton: .cancel()
)
}
private func archiveAllReportsForMe(_ apiId: Int64) async {
do {
if case let .groupChatItemsDeleted(user, groupInfo, chatItemIDs, _, member) = try await apiArchiveReceivedReports(groupId: apiId) {
await groupChatItemsDeleted(user, groupInfo, chatItemIDs, member)
}
} catch {
logger.error("archiveAllReportsForMe error: \(responseError(error))")
}
}
private func clearChatAlert() -> Alert {
Alert(
title: Text("Clear conversation?"),
@ -552,8 +595,9 @@ struct ChatListNavLink: View {
Task {
let ok = await connectContactViaAddress(contact.contactId, incognito, showAlert: { AlertManager.shared.showAlert($0) })
if ok {
ItemsModel.shared.loadOpenChat(contact.id)
AlertManager.shared.showAlert(connReqSentAlert(.contact))
ItemsModel.shared.loadOpenChat(contact.id) {
AlertManager.shared.showAlert(connReqSentAlert(.contact))
}
}
}
}

View file

@ -148,7 +148,10 @@ struct ChatListView: View {
@State private var userPickerShown: Bool = false
@State private var sheet: SomeSheet<AnyView>? = nil
@StateObject private var chatTagsModel = ChatTagsModel.shared
// iOS 15 is required it to show/hide toolbar while chat is hidden/visible
@State private var viewOnScreen = true
@AppStorage(GROUP_DEFAULT_ONE_HAND_UI, store: groupDefaults) private var oneHandUI = true
@AppStorage(DEFAULT_ONE_HAND_UI_CARD_SHOWN) private var oneHandUICardShown = false
@AppStorage(DEFAULT_ADDRESS_CREATION_CARD_SHOWN) private var addressCreationCardShown = false
@ -203,7 +206,17 @@ struct ChatListView: View {
.navigationBarHidden(searchMode || oneHandUI)
}
.scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center)
.onDisappear() { activeUserPickerSheet = nil }
.onAppear {
if #unavailable(iOS 16.0), !viewOnScreen {
viewOnScreen = true
}
}
.onDisappear {
activeUserPickerSheet = nil
if #unavailable(iOS 16.0) {
viewOnScreen = false
}
}
.refreshable {
AlertManager.shared.showAlert(Alert(
title: Text("Reconnect servers?"),
@ -258,7 +271,7 @@ struct ChatListView: View {
}
} else {
if oneHandUI {
content().toolbar { bottomToolbarGroup }
content().toolbar { bottomToolbarGroup() }
} else {
content().toolbar { topToolbar }
}
@ -286,9 +299,9 @@ struct ChatListView: View {
}
}
@ToolbarContentBuilder var bottomToolbarGroup: some ToolbarContent {
@ToolbarContentBuilder func bottomToolbarGroup() -> some ToolbarContent {
let padding: Double = Self.hasHomeIndicator ? 0 : 14
ToolbarItemGroup(placement: .bottomBar) {
ToolbarItemGroup(placement: viewOnScreen ? .bottomBar : .principal) {
leadingToolbarItem.padding(.bottom, padding)
Spacer()
SubsStatusIndicator().padding(.bottom, padding)

View file

@ -143,6 +143,7 @@ struct ChatPreviewView: View {
}
case let .group(groupInfo):
switch (groupInfo.membership.memberStatus) {
case .memRejected: inactiveIcon()
case .memLeft: inactiveIcon()
case .memRemoved: inactiveIcon()
case .memGroupDeleted: inactiveIcon()
@ -153,7 +154,7 @@ struct ChatPreviewView: View {
}
}
@ViewBuilder private func inactiveIcon() -> some View {
private func inactiveIcon() -> some View {
Image(systemName: "multiply.circle.fill")
.foregroundColor(.secondary.opacity(0.65))
.background(Circle().foregroundColor(Color(uiColor: .systemBackground)))
@ -168,7 +169,7 @@ struct ChatPreviewView: View {
let v = previewTitle(t)
switch (groupInfo.membership.memberStatus) {
case .memInvited: v.foregroundColor(deleting ? theme.colors.secondary : chat.chatInfo.incognito ? .indigo : theme.colors.primary)
case .memAccepted: v.foregroundColor(theme.colors.secondary)
case .memAccepted, .memRejected: v.foregroundColor(theme.colors.secondary)
default: if deleting { v.foregroundColor(theme.colors.secondary) } else { v }
}
default: previewTitle(t)
@ -336,6 +337,7 @@ struct ChatPreviewView: View {
}
case let .group(groupInfo):
switch (groupInfo.membership.memberStatus) {
case .memRejected: chatPreviewInfoText("rejected")
case .memInvited: groupInvitationPreviewText(groupInfo)
case .memAccepted: chatPreviewInfoText("connecting…")
default: EmptyView()
@ -384,12 +386,10 @@ struct ChatPreviewView: View {
case let .image(_, image):
smallContentPreview(size: dynamicMediaSize) {
CIImageView(chatItem: ci, preview: imageFromBase64(image), maxWidth: dynamicMediaSize, smallView: true, showFullScreenImage: $showFullscreenGallery)
.environmentObject(ReverseListScrollModel())
}
case let .video(_,image, duration):
smallContentPreview(size: dynamicMediaSize) {
CIVideoView(chatItem: ci, preview: imageFromBase64(image), duration: duration, maxWidth: dynamicMediaSize, videoWidth: nil, smallView: true, showFullscreenPlayer: $showFullscreenGallery)
.environmentObject(ReverseListScrollModel())
}
case let .voice(_, duration):
smallContentPreviewVoice(size: dynamicMediaSize) {

View file

@ -587,7 +587,7 @@ struct SMPStatsView: View {
} header: {
Text("Statistics")
} footer: {
Text("Starting from \(localTimestamp(statsStartedAt)).") + Text("\n") + Text("All data is kept private on your device.")
Text("Starting from \(localTimestamp(statsStartedAt)).") + textNewLine + Text("All data is kept private on your device.")
}
}
}
@ -703,7 +703,7 @@ struct XFTPStatsView: View {
} header: {
Text("Statistics")
} footer: {
Text("Starting from \(localTimestamp(statsStartedAt)).") + Text("\n") + Text("All data is kept private on your device.")
Text("Starting from \(localTimestamp(statsStartedAt)).") + textNewLine + Text("All data is kept private on your device.")
}
}
}

View file

@ -61,7 +61,7 @@ struct TagListView: View {
Button {
showAlert(
NSLocalizedString("Delete list?", comment: "alert title"),
message: NSLocalizedString("All chats will be removed from the list \(text), and the list deleted.", comment: "alert message"),
message: String.localizedStringWithFormat(NSLocalizedString("All chats will be removed from the list %@, and the list deleted.", comment: "alert message"), text),
actions: {[
UIAlertAction(
title: NSLocalizedString("Cancel", comment: "alert action"),

View file

@ -188,8 +188,7 @@ struct ContactListNavLink: View {
Task {
let ok = await connectContactViaAddress(contact.contactId, incognito, showAlert: { alert = SomeAlert(alert: $0, id: "ContactListNavLink connectContactViaAddress") })
if ok {
ItemsModel.shared.loadOpenChat(contact.id)
DispatchQueue.main.async {
ItemsModel.shared.loadOpenChat(contact.id) {
dismissAllSheets(animated: true) {
AlertManager.shared.showAlert(connReqSentAlert(.contact))
}

View file

@ -141,7 +141,7 @@ struct DatabaseErrorView: View {
}
private func migrationsText(_ ms: [String]) -> some View {
(Text("Migrations:").font(.subheadline) + Text(verbatim: "\n") + Text(ms.joined(separator: "\n")).font(.caption))
(Text("Migrations:").font(.subheadline) + textNewLine + Text(ms.joined(separator: "\n")).font(.caption))
.multilineTextAlignment(.center)
.padding(.horizontal, 25)
}

View file

@ -279,7 +279,7 @@ struct DatabaseView: View {
case let .archiveExportedWithErrors(archivePath, errs):
return Alert(
title: Text("Chat database exported"),
message: Text("You may save the exported archive.") + Text(verbatim: "\n") + Text("Some file(s) were not exported:") + Text(archiveErrorsText(errs)),
message: Text("You may save the exported archive.") + textNewLine + Text("Some file(s) were not exported:") + Text(archiveErrorsText(errs)),
dismissButton: .default(Text("Continue")) {
showShareSheet(items: [archivePath])
}

View file

@ -65,6 +65,7 @@ struct LocalAuthView: View {
// Clear sensitive data on screen just in case app fails to hide its views while new database is created
m.chatId = nil
ItemsModel.shared.reversedChatItems = []
ItemsModel.shared.chatItemsChangesListener.cleared()
m.updateChats([])
m.users = []
_ = kcAppPassword.set(password)

View file

@ -177,7 +177,7 @@ struct MigrateFromDevice: View {
case let .archiveExportedWithErrors(archivePath, errs):
return Alert(
title: Text("Chat database exported"),
message: Text("You may migrate the exported database.") + Text(verbatim: "\n") + Text("Some file(s) were not exported:") + Text(archiveErrorsText(errs)),
message: Text("You may migrate the exported database.") + textNewLine + Text("Some file(s) were not exported:") + Text(archiveErrorsText(errs)),
dismissButton: .default(Text("Continue")) {
Task { await uploadArchive(path: archivePath) }
}

View file

@ -539,7 +539,7 @@ struct MigrateToDevice: View {
chatInitControllerRemovingDatabases()
} else if ChatModel.shared.chatRunning == true {
// cannot delete storage if chat is running
try await apiStopChat()
try await stopChatAsync()
}
try await apiDeleteStorage()
try? FileManager.default.createDirectory(at: getWallpaperDirectory(), withIntermediateDirectories: true)
@ -623,7 +623,7 @@ struct MigrateToDevice: View {
AlertManager.shared.showAlert(
Alert(
title: Text("Error migrating settings"),
message: Text ("Some app settings were not migrated.") + Text("\n") + Text(responseError(error)))
message: Text ("Some app settings were not migrated.") + textNewLine + Text(responseError(error)))
)
}
hideView()
@ -632,6 +632,8 @@ struct MigrateToDevice: View {
private func hideView() {
onboardingStageDefault.set(.onboardingComplete)
m.onboardingStage = .onboardingComplete
m.migrationState = nil
MigrationToDeviceState.save(nil)
dismiss()
}

View file

@ -1205,12 +1205,14 @@ func openKnownContact(_ contact: Contact, dismiss: Bool, showAlreadyExistsAlert:
DispatchQueue.main.async {
if dismiss {
dismissAllSheets(animated: true) {
ItemsModel.shared.loadOpenChat(c.id)
showAlreadyExistsAlert?()
ItemsModel.shared.loadOpenChat(c.id) {
showAlreadyExistsAlert?()
}
}
} else {
ItemsModel.shared.loadOpenChat(c.id)
showAlreadyExistsAlert?()
ItemsModel.shared.loadOpenChat(c.id) {
showAlreadyExistsAlert?()
}
}
}
}
@ -1224,12 +1226,14 @@ func openKnownGroup(_ groupInfo: GroupInfo, dismiss: Bool, showAlreadyExistsAler
DispatchQueue.main.async {
if dismiss {
dismissAllSheets(animated: true) {
ItemsModel.shared.loadOpenChat(g.id)
showAlreadyExistsAlert?()
ItemsModel.shared.loadOpenChat(g.id) {
showAlreadyExistsAlert?()
}
}
} else {
ItemsModel.shared.loadOpenChat(g.id)
showAlreadyExistsAlert?()
ItemsModel.shared.loadOpenChat(g.id) {
showAlreadyExistsAlert?()
}
}
}
}

View file

@ -161,11 +161,8 @@ struct ChooseServerOperators: View {
case .showInfo:
ChooseServerOperatorsInfoView()
case .showConditions:
UsageConditionsView(
currUserServers: Binding.constant([]),
userServers: Binding.constant([])
)
.modifier(ThemedBackground(grouped: true))
SimpleConditionsView()
.modifier(ThemedBackground(grouped: true))
}
}
.frame(maxHeight: .infinity, alignment: .top)

View file

@ -145,6 +145,7 @@ struct CreateFirstProfile: View {
TextField("Enter your name…", text: $displayName)
.focused($focusDisplayName)
.padding(.horizontal)
.padding(.trailing, 20)
.padding(.vertical, 10)
.background(
RoundedRectangle(cornerRadius: 10, style: .continuous)

View file

@ -140,6 +140,8 @@ struct SimpleXInfo: View {
let textSpace = Text(verbatim: " ")
let textNewLine = Text(verbatim: "\n")
struct SimpleXInfo_Previews: PreviewProvider {
static var previews: some View {
SimpleXInfo(onboarding: true)

View file

@ -539,7 +539,46 @@ private let versionDescriptions: [VersionDescription] = [
description: "Delivered even when Apple drops them."
)),
]
)
),
VersionDescription(
version: "v6.3",
post: URL(string: "https://simplex.chat/blog/20250308-simplex-chat-v6-3-new-user-experience-safety-in-public-groups.html"),
features: [
.feature(Description(
icon: "at",
title: "Mention members 👋",
description: "Get notified when mentioned."
)),
.feature(Description(
icon: "flag",
title: "Send private reports",
description: "Help admins moderating their groups."
)),
.feature(Description(
icon: "list.bullet",
title: "Organize chats into lists",
description: "Don't miss important messages."
)),
.feature(Description(
icon: nil,
title: "Better privacy and security",
description: nil,
subfeatures: [
("eye.slash", "Private media file names."),
("trash", "Set message expiration in chats.")
]
)),
.feature(Description(
icon: nil,
title: "Better groups performance",
description: nil,
subfeatures: [
("bolt", "Faster sending messages."),
("person.2.slash", "Faster deletion of groups.")
]
)),
]
),
]
private let lastVersion = versionDescriptions.last!.version

View file

@ -20,6 +20,7 @@ struct TerminalView: View {
@State var composeState: ComposeState = ComposeState()
@State var selectedRange = NSRange()
@State private var keyboardVisible = false
@State private var keyboardHiddenDate = Date.now
@State var authorized = !UserDefaults.standard.bool(forKey: DEFAULT_PERFORM_LA)
@State private var terminalItem: TerminalItem?
@State private var scrolled = false
@ -101,7 +102,8 @@ struct TerminalView: View {
sendMessage: { _ in consoleSendMessage() },
showVoiceMessageButton: false,
onMediaAdded: { _ in },
keyboardVisible: $keyboardVisible
keyboardVisible: $keyboardVisible,
keyboardHiddenDate: $keyboardHiddenDate
)
.padding(.horizontal, 12)
}

View file

@ -367,13 +367,13 @@ struct ChatThemePreview: View {
let alice = ChatItem.getSample(1, CIDirection.directRcv, Date.now, NSLocalizedString("Good afternoon!", comment: "message preview"))
let bob = ChatItem.getSample(2, CIDirection.directSnd, Date.now, NSLocalizedString("Good morning!", comment: "message preview"), quotedItem: CIQuote.getSample(alice.id, alice.meta.itemTs, alice.content.text, chatDir: alice.chatDir))
HStack {
ChatItemView(chat: Chat.sampleData, chatItem: alice)
ChatItemView(chat: Chat.sampleData, chatItem: alice, scrollToItemId: { _ in })
.modifier(ChatItemClipped(alice, tailVisible: true))
Spacer()
}
HStack {
Spacer()
ChatItemView(chat: Chat.sampleData, chatItem: bob)
ChatItemView(chat: Chat.sampleData, chatItem: bob, scrollToItemId: { _ in })
.modifier(ChatItemClipped(bob, tailVisible: true))
.frame(alignment: .trailing)
}

View file

@ -19,7 +19,7 @@ struct MarkdownHelp: View {
mdFormat("_italic_", Text("italic").italic())
mdFormat("~strike~", Text("strike").strikethrough())
mdFormat("`a + b`", Text("`a + b`").font(.body.monospaced()))
mdFormat("!1 colored!", Text("colored").foregroundColor(.red) + Text(" (") + color("1", .red) + color("2", .green) + color("3", .blue) + color("4", .yellow) + color("5", .cyan) + Text("6").foregroundColor(.purple) + Text(")"))
mdFormat("!1 colored!", Text("colored").foregroundColor(.red) + Text(verbatim: " (") + color("1", .red) + color("2", .green) + color("3", .blue) + color("4", .yellow) + color("5", .cyan) + Text("6").foregroundColor(.purple) + Text(verbatim: ")"))
(
mdFormat("#secret#", Text("secret")
.foregroundColor(.clear)
@ -39,7 +39,7 @@ private func mdFormat(_ format: LocalizedStringKey, _ example: Text) -> some Vie
}
private func color(_ s: String, _ c: Color) -> Text {
Text(s).foregroundColor(c) + Text(", ")
Text(s).foregroundColor(c) + Text(verbatim: ", ")
}
struct MarkdownHelp_Previews: PreviewProvider {

View file

@ -368,8 +368,8 @@ struct AdvancedNetworkSettings: View {
let userMode = Text("A separate TCP connection will be used **for each chat profile you have in the app**.")
return switch mode {
case .user: userMode
case .session: userMode + Text("\n") + Text("New SOCKS credentials will be used every time you start the app.")
case .server: userMode + Text("\n") + Text("New SOCKS credentials will be used for each server.")
case .session: userMode + textNewLine + Text("New SOCKS credentials will be used every time you start the app.")
case .server: userMode + textNewLine + Text("New SOCKS credentials will be used for each server.")
case .entity: Text("A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail.")
}
}

View file

@ -238,22 +238,23 @@ struct UsageConditionsView: View {
var body: some View {
VStack(alignment: .leading, spacing: 20) {
HStack {
Text("Conditions of use").font(.largeTitle).bold()
Spacer()
conditionsLinkButton()
}
.padding(.top)
.padding(.top)
switch ChatModel.shared.conditions.conditionsAction {
case .none:
regularConditionsHeader()
.padding(.top)
.padding(.top)
ConditionsTextView()
.padding(.bottom)
.padding(.bottom)
case let .review(operators, deadline, _):
HStack {
Text("Updated conditions").font(.largeTitle).bold()
}
.padding(.top)
.padding(.top)
Text("Conditions will be accepted for the operator(s): **\(operators.map { $0.legalName_ }.joined(separator: ", "))**.")
ConditionsTextView()
VStack(spacing: 8) {
@ -265,6 +266,10 @@ struct UsageConditionsView: View {
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity, alignment: .center)
.padding(.horizontal, 32)
conditionsDiffButton(.footnote)
} else {
conditionsDiffButton()
.padding(.top)
}
}
.padding(.bottom)
@ -272,6 +277,9 @@ struct UsageConditionsView: View {
case let .accepted(operators):
regularConditionsHeader()
.padding(.top)
.padding(.top)
Text("Conditions are accepted for the operator(s): **\(operators.map { $0.legalName_ }.joined(separator: ", "))**.")
ConditionsTextView()
.padding(.bottom)
@ -312,6 +320,43 @@ struct UsageConditionsView: View {
}
}
}
@ViewBuilder private func conditionsDiffButton(_ font: Font? = nil) -> some View {
let commit = ChatModel.shared.conditions.currentConditions.conditionsCommit
if let commitUrl = URL(string: "https://github.com/simplex-chat/simplex-chat/commit/\(commit)") {
Link(destination: commitUrl) {
HStack {
Text("Open changes")
Image(systemName: "arrow.up.right.circle")
}
.font(font)
}
}
}
}
private func regularConditionsHeader() -> some View {
HStack {
Text("Conditions of use").font(.largeTitle).bold()
Spacer()
conditionsLinkButton()
}
}
struct SimpleConditionsView: View {
var body: some View {
VStack(alignment: .leading, spacing: 20) {
regularConditionsHeader()
.padding(.top)
.padding(.top)
ConditionsTextView()
.padding(.bottom)
.padding(.bottom)
}
.padding(.horizontal, 25)
.frame(maxHeight: .infinity)
}
}
func validateServers_(_ userServers: Binding<[UserOperatorServers]>, _ serverErrors: Binding<[UserServersError]>) {

View file

@ -13,7 +13,7 @@ struct NotificationsView: View {
@EnvironmentObject var m: ChatModel
@EnvironmentObject var theme: AppTheme
@State private var notificationMode: NotificationsMode = ChatModel.shared.notificationMode
@State private var showAlert: NotificationAlert?
@State private var ntfAlert: NotificationAlert?
@State private var legacyDatabase = dbContainerGroupDefault.get() == .documents
@State private var testing = false
@State private var testedSuccess: Bool? = nil
@ -25,7 +25,7 @@ struct NotificationsView: View {
ProgressView().scaleEffect(2)
}
}
.alert(item: $showAlert) { alert in
.alert(item: $ntfAlert) { alert in
if let token = m.deviceToken {
return notificationAlert(alert, token)
} else {
@ -41,7 +41,7 @@ struct NotificationsView: View {
List {
Section {
SelectionListView(list: NotificationsMode.values, selection: $notificationMode) { mode in
showAlert = .setMode(mode: mode)
ntfAlert = .setMode(mode: mode)
}
} footer: {
VStack(alignment: .leading) {
@ -95,7 +95,7 @@ struct NotificationsView: View {
if let server = m.notificationServer {
smpServers("Push server", [server], theme.colors.secondary)
testServerButton(server)
testTokenButton(server)
}
} header: {
Text("Push notifications")
@ -163,7 +163,7 @@ struct NotificationsView: View {
await MainActor.run {
let err = responseError(error)
logger.error("apiDeleteToken error: \(err)")
showAlert = .error(title: "Error deleting token", error: err)
ntfAlert = .error(title: "Error deleting token", error: err)
}
}
default:
@ -181,19 +181,19 @@ struct NotificationsView: View {
await MainActor.run {
let err = responseError(error)
logger.error("apiRegisterToken error: \(err)")
showAlert = .error(title: "Error enabling notifications", error: err)
ntfAlert = .error(title: "Error enabling notifications", error: err)
}
}
}
}
}
private func testServerButton(_ server: String) -> some View {
private func testTokenButton(_ server: String) -> some View {
HStack {
Button("Test server") {
Button("Test notifications") {
testing = true
Task {
await testServer(server)
await testServerAndToken(server)
await MainActor.run { testing = false }
}
}
@ -215,22 +215,61 @@ struct NotificationsView: View {
}
}
private func testServer(_ server: String) async {
private func testServerAndToken(_ server: String) async {
do {
let r = try await testProtoServer(server: server)
switch r {
case .success:
await MainActor.run {
testedSuccess = true
if let token = m.deviceToken {
do {
let status = try await apiCheckToken(token: token)
await MainActor.run {
m.tokenStatus = status
testedSuccess = status.workingToken
if status.workingToken {
showAlert(
NSLocalizedString("Notifications status", comment: "alert title"),
message: tokenStatusInfo(status, register: false)
)
} else {
showAlert(
title: NSLocalizedString("Notifications error", comment: "alert title"),
message: tokenStatusInfo(status, register: true),
buttonTitle: "Register",
buttonAction: {
reRegisterToken(token: token)
testedSuccess = nil
},
cancelButton: true
)
}
}
} catch let error {
await MainActor.run {
let err = responseError(error)
logger.error("apiCheckToken \(err)")
ntfAlert = .error(title: "Error checking token status", error: err)
}
}
} else {
await MainActor.run {
showAlert(
NSLocalizedString("No token!", comment: "alert title")
)
}
}
case let .failure(f):
await MainActor.run {
showAlert = .testFailure(testFailure: f)
ntfAlert = .testFailure(testFailure: f)
testedSuccess = false
}
}
} catch let error {
logger.error("testServerConnection \(responseError(error))")
await MainActor.run {
let err = responseError(error)
logger.error("testServerConnection \(err)")
ntfAlert = .error(title: "Error testing server connection", error: err)
}
}
}
}

View file

@ -477,7 +477,11 @@ struct SettingsView: View {
case .registered:
icon = "bolt.fill"
color = theme.colors.secondary
case .invalid:
case .invalid: fallthrough
case .invalidBad: fallthrough
case .invalidTopic: fallthrough
case .invalidExpired: fallthrough
case .invalidUnregistered:
icon = "bolt.slash"
color = theme.colors.secondary
case .confirmed:
@ -524,7 +528,7 @@ struct ProfilePreview: View {
func profileName(_ profileOf: NamedChat) -> Text {
var t = Text(profileOf.displayName).fontWeight(.semibold).font(.title2)
if profileOf.fullName != "" && profileOf.fullName != profileOf.displayName {
t = t + Text(" (" + profileOf.fullName + ")")
t = t + Text(verbatim: " (" + profileOf.fullName + ")")
// .font(.callout)
}
return t

View file

@ -33,7 +33,7 @@ struct StorageView: View {
private func directoryView(_ name: LocalizedStringKey, _ contents: [String: Int64]) -> some View {
Text(name).font(.headline)
ForEach(Array(contents), id: \.key) { (key, value) in
Text(key).bold() + Text(" ") + Text("\(ByteCountFormatter.string(fromByteCount: value, countStyle: .binary))")
Text(key).bold() + Text(verbatim: " ") + Text((ByteCountFormatter.string(fromByteCount: value, countStyle: .binary)))
}
}

View file

@ -5,22 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (може да се копира)</target>
@ -323,11 +307,6 @@
<target>%u пропуснати съобщения.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<target>(ново)</target>
@ -338,11 +317,6 @@
<target>(това устройство v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<target>**Добави контакт**: за създаване на нов линк.</target>
@ -407,11 +381,6 @@
<target>\*удебелен*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -448,11 +417,6 @@
- история на редактиране.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 сек</target>
@ -519,11 +483,6 @@
<target>30 секунди</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -631,6 +590,10 @@
<target>Грешки при потвърждението</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<target>Активни връзки</target>
@ -768,8 +731,8 @@
<target>Всички чатове и съобщения ще бъдат изтрити - това не може да бъде отменено!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -811,6 +774,10 @@
<target>Всички профили</target>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>Всички ваши контакти ще останат свързани.</target>
@ -886,6 +853,10 @@
<target>Позволи необратимо изтриване на изпратените съобщения. (24 часа)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<target>Разрешаване на изпращане на SimpleX линкове.</target>
@ -1048,6 +1019,14 @@
<source>Archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<target>Архивиране и качване</target>
@ -1066,6 +1045,10 @@
<source>Archive report?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<target>Архивирани контакти</target>
@ -1180,6 +1163,10 @@
<target>По-добри групи</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<target>По-добри дати на съобщението.</target>
@ -1200,6 +1187,10 @@
<target>Подобрени известия</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<target>По-добра сигурност ✅</target>
@ -1603,6 +1594,10 @@
<target>Изчисти разговора?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<note>No comment provided by engineer.</note>
@ -1732,6 +1727,10 @@
<target>Потвърди качването</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>Свързване</target>
@ -1993,31 +1992,32 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create" xml:space="preserve">
<source>Create</source>
<target>Създай</target>
<target>Създаване</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create 1-time link" xml:space="preserve">
<source>Create 1-time link</source>
<target>Създаване на еднократна препратка</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create SimpleX address" xml:space="preserve">
<source>Create SimpleX address</source>
<target>Създай SimpleX адрес</target>
<target>Създаване на адрес в SimpleX</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create a group using a random profile." xml:space="preserve">
<source>Create a group using a random profile.</source>
<target>Създай група с автоматично генериран профилл.</target>
<target>Създаване група с автоматично създаден профил.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create file" xml:space="preserve">
<source>Create file</source>
<target>Създай файл</target>
<target>Създаване на файл</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Create group" xml:space="preserve">
<source>Create group</source>
<target>Създай група</target>
<target>Създаване на група</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create group link" xml:space="preserve">
@ -2689,6 +2689,10 @@ This is your own one-time link!</source>
<target>Не активирай</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>Не показвай отново</target>
@ -3032,6 +3036,10 @@ This is your own one-time link!</source>
<source>Error changing to incognito!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<note>No comment provided by engineer.</note>
@ -3179,6 +3187,10 @@ This is your own one-time link!</source>
<source>Error reconnecting servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>Грешка при отстраняване на член</target>
@ -3279,6 +3291,10 @@ This is your own one-time link!</source>
<target>Грешка при синхронизиране на връзката</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>Грешка при актуализиране на груповия линк</target>
@ -3356,6 +3372,10 @@ This is your own one-time link!</source>
<target>Разшири</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>Експортирай база данни</target>
@ -3395,11 +3415,19 @@ This is your own one-time link!</source>
<target>Бързо и без чакане, докато подателят е онлайн!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<target>По-бързо присъединяване и по-надеждни съобщения.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Любим</target>
@ -3418,9 +3446,9 @@ This is your own one-time link!</source>
%@</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3543,6 +3571,10 @@ This is your own one-time link!</source>
<target>Поправката не се поддържа от члена на групата</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<note>servers error</note>
@ -3556,6 +3588,10 @@ This is your own one-time link!</source>
<source>For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<note>No comment provided by engineer.</note>
@ -3666,6 +3702,10 @@ Error: %2$@</source>
<target>GIF файлове и стикери</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<note>message preview</note>
@ -3778,6 +3818,10 @@ Error: %2$@</source>
<target>Помощ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>Скрит</target>
@ -4077,6 +4121,26 @@ More improvements are coming soon!</source>
<source>Interface colors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<target>Невалиден QR код</target>
@ -4444,6 +4508,10 @@ This is your link for group %@!</source>
<source>Member inactive</source>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<note>No comment provided by engineer.</note>
@ -4477,6 +4545,10 @@ This is your link for group %@!</source>
<target>Членовете на групата могат необратимо да изтриват изпратените съобщения. (24 часа)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<target>Членовете на групата могат да изпращат SimpleX линкове.</target>
@ -4502,6 +4574,10 @@ This is your link for group %@!</source>
<target>Членовете на групата могат да изпращат гласови съобщения.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<note>No comment provided by engineer.</note>
@ -4734,7 +4810,11 @@ This is your link for group %@!</source>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>Без звук</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -4783,6 +4863,10 @@ This is your link for group %@!</source>
<target>Състояние на мрежата</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>Нов kод за достъп</target>
@ -4926,6 +5010,10 @@ This is your link for group %@!</source>
<source>No media &amp; file servers.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<note>servers error</note>
@ -4974,6 +5062,10 @@ This is your link for group %@!</source>
<source>No servers to send files.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<note>No comment provided by engineer.</note>
@ -5010,10 +5102,18 @@ This is your link for group %@!</source>
<target>Известията са деактивирани!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -5244,6 +5344,10 @@ Requires compatible VPN.</source>
<source>Or to share privately</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<target>Други</target>
@ -5427,6 +5531,18 @@ Error: %@</source>
<target>Моля, съхранявайте паролата на сигурно място, НЯМА да можете да я промените, ако я загубите.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Полски интерфейс</target>
@ -5483,6 +5599,10 @@ Error: %@</source>
<target>Поверителни имена на файлове</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<note>No comment provided by engineer.</note>
@ -5553,6 +5673,10 @@ Error: %@</source>
<target>Забрани реакциите на съобщенията.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<target>Забранете изпращането на SimpleX линкове.</target>
@ -5794,6 +5918,18 @@ Enable in *Network &amp; servers* settings.</source>
<target>Намалена консумация на батерията</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>Отхвърляне</target>
@ -5921,6 +6057,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Report violation: only group moderators will see it.</source>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<note>No comment provided by engineer.</note>
@ -6321,6 +6465,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Изпращай известия</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>Изпращайте въпроси и идеи</target>
@ -6541,6 +6689,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Задайте го вместо системната идентификация.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>Задай kод за достъп</target>
@ -6972,6 +7124,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Времето на изчакване за установяване на TCP връзка</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -7044,6 +7200,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Тестът е неуспешен на стъпка %@.</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>Тествай сървър</target>
@ -7166,10 +7326,6 @@ It can happen because of some bug or when the connection is compromised.</source
<target>Профилът се споделя само с вашите контакти.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<note>No comment provided by engineer.</note>
@ -7291,6 +7447,10 @@ It can happen because of some bug or when the connection is compromised.</source
<source>This link was used with another mobile device, please create a new link on the desktop.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>Тази настройка се прилага за съобщения в текущия ви профил **%@**.</target>
@ -7394,6 +7554,10 @@ You will be prompted to complete authentication before this feature is enabled.<
<target>Избор на инкогнито при свързване.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<note>No comment provided by engineer.</note>
@ -7554,7 +7718,7 @@ To connect, please ask your contact to create another connection link and check
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>Уведомявай</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7585,6 +7749,10 @@ To connect, please ask your contact to create another connection link and check
<source>Update settings?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>Актуализирането на настройките ще свърже отново клиента към всички сървъри.</target>
@ -7640,6 +7808,10 @@ To connect, please ask your contact to create another connection link and check
<target>Използвай сървърите на SimpleX Chat?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>Използвай чата</target>
@ -7709,6 +7881,10 @@ To connect, please ask your contact to create another connection link and check
<source>Use the app with one hand.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<note>No comment provided by engineer.</note>
@ -8239,6 +8415,10 @@ Repeat connection request?</source>
<target>Изпратихте покана за групата</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>Ще бъдете свързани с групата, когато устройството на домакина на групата е онлайн, моля, изчакайте или проверете по-късно!</target>
@ -8310,7 +8490,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your SimpleX address" xml:space="preserve">
<source>Your SimpleX address</source>
<target>Вашият SimpleX адрес</target>
<target>Вашият адрес в SimpleX</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your calls" xml:space="preserve">
@ -9017,10 +9197,6 @@ Repeat connection request?</source>
<target>месеци</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>никога</target>
@ -9096,6 +9272,14 @@ Repeat connection request?</source>
<target>peer-to-peer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<target>квантово устойчиво e2e криптиране</target>
@ -9111,6 +9295,10 @@ Repeat connection request?</source>
<target>получено потвърждение…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>отхвърлено повикване</target>
@ -9239,10 +9427,6 @@ last received msg: %2$@</source>
<target>неизвестен статус</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<note>No comment provided by engineer.</note>

View file

@ -5,22 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (lze kopírovat)</target>
@ -321,11 +305,6 @@
<target>%u zpráv přeskočeno.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
@ -335,11 +314,6 @@
<target>(toto zařízení v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<note>No comment provided by engineer.</note>
@ -400,11 +374,6 @@
<target>\*tučně*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -438,11 +407,6 @@
- historie úprav.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<note>time to disappear</note>
@ -507,11 +471,6 @@
<target>30 vteřin</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -613,6 +572,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
@ -737,8 +700,8 @@
<target>Všechny chaty a zprávy budou smazány tuto akci nelze vrátit zpět!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -776,6 +739,10 @@
<source>All profiles</source>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>Všechny vaše kontakty zůstanou připojeny.</target>
@ -847,6 +814,10 @@
<target>Povolit nevratné smazání odeslaných zpráv. (24 hodin)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -1001,6 +972,14 @@
<source>Archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<note>No comment provided by engineer.</note>
@ -1017,6 +996,10 @@
<source>Archive report?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<note>No comment provided by engineer.</note>
@ -1124,6 +1107,10 @@
<source>Better groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
@ -1141,6 +1128,10 @@
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
@ -1519,6 +1510,10 @@
<target>Vyčistit konverzaci?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<note>No comment provided by engineer.</note>
@ -1644,6 +1639,10 @@
<source>Confirm upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>Připojit</target>
@ -2571,6 +2570,10 @@ This is your own one-time link!</source>
<target>Nepovolovat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>Znovu neukazuj</target>
@ -2900,6 +2903,10 @@ This is your own one-time link!</source>
<source>Error changing to incognito!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<note>No comment provided by engineer.</note>
@ -3044,6 +3051,10 @@ This is your own one-time link!</source>
<source>Error reconnecting servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>Chyba při odebrání člena</target>
@ -3142,6 +3153,10 @@ This is your own one-time link!</source>
<target>Chyba synchronizace připojení</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>Chyba aktualizace odkazu skupiny</target>
@ -3216,6 +3231,10 @@ This is your own one-time link!</source>
<source>Expand</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>Export databáze</target>
@ -3254,10 +3273,18 @@ This is your own one-time link!</source>
<target>Rychle a bez čekání, než bude odesílatel online!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Oblíbené</target>
@ -3276,9 +3303,9 @@ This is your own one-time link!</source>
%@</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3398,6 +3425,10 @@ This is your own one-time link!</source>
<target>Opravit nepodporované členem skupiny</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<note>servers error</note>
@ -3411,6 +3442,10 @@ This is your own one-time link!</source>
<source>For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<note>No comment provided by engineer.</note>
@ -3515,6 +3550,10 @@ Error: %2$@</source>
<target>GIFy a nálepky</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<note>message preview</note>
@ -3625,6 +3664,10 @@ Error: %2$@</source>
<target>Pomoc</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>Skryté</target>
@ -3915,6 +3958,26 @@ More improvements are coming soon!</source>
<source>Interface colors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<note>No comment provided by engineer.</note>
@ -4265,6 +4328,10 @@ This is your link for group %@!</source>
<source>Member inactive</source>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<note>No comment provided by engineer.</note>
@ -4298,6 +4365,10 @@ This is your link for group %@!</source>
<target>Členové skupiny mohou nevratně mazat odeslané zprávy. (24 hodin)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -4322,6 +4393,10 @@ This is your link for group %@!</source>
<target>Členové skupiny mohou posílat hlasové zprávy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<note>No comment provided by engineer.</note>
@ -4541,7 +4616,11 @@ This is your link for group %@!</source>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>Ztlumit</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -4588,6 +4667,10 @@ This is your link for group %@!</source>
<target>Stav sítě</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>Nové heslo</target>
@ -4730,6 +4813,10 @@ This is your link for group %@!</source>
<source>No media &amp; file servers.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<note>servers error</note>
@ -4777,6 +4864,10 @@ This is your link for group %@!</source>
<source>No servers to send files.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<note>No comment provided by engineer.</note>
@ -4812,10 +4903,18 @@ This is your link for group %@!</source>
<target>Oznámení jsou zakázána!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -5038,6 +5137,10 @@ Vyžaduje povolení sítě VPN.</target>
<source>Or to share privately</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
@ -5212,6 +5315,18 @@ Error: %@</source>
<target>Heslo uložte bezpečně, v případě jeho ztráty jej NEBUDE možné změnit.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Polské rozhraní</target>
@ -5268,6 +5383,10 @@ Error: %@</source>
<target>Soukromé názvy souborů</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<note>No comment provided by engineer.</note>
@ -5336,6 +5455,10 @@ Error: %@</source>
<target>Zakázat reakce na zprávy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -5571,6 +5694,18 @@ Enable in *Network &amp; servers* settings.</source>
<target>Snížení spotřeby baterie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>Odmítnout</target>
@ -5693,6 +5828,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Report violation: only group moderators will see it.</source>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<note>No comment provided by engineer.</note>
@ -6085,6 +6228,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Odeslat oznámení</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>Zasílání otázek a nápadů</target>
@ -6303,6 +6450,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Nastavte jej namísto ověřování systému.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>Nastavit heslo</target>
@ -6724,6 +6875,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Časový limit připojení TCP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -6793,6 +6948,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Test selhal v kroku %@.</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>Testovací server</target>
@ -6914,10 +7073,6 @@ Může se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitován
<target>Profil je sdílen pouze s vašimi kontakty.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<note>No comment provided by engineer.</note>
@ -7032,6 +7187,10 @@ Může se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitován
<source>This link was used with another mobile device, please create a new link on the desktop.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>Toto nastavení platí pro zprávy ve vašem aktuálním chat profilu **%@**.</target>
@ -7134,6 +7293,10 @@ Před zapnutím této funkce budete vyzváni k dokončení ověření.</target>
<target>Změnit inkognito režim při připojení.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<note>No comment provided by engineer.</note>
@ -7286,7 +7449,7 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>Zrušit ztlumení</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7316,6 +7479,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<source>Update settings?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>Aktualizací nastavení se klient znovu připojí ke všem serverům.</target>
@ -7369,6 +7536,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Používat servery SimpleX Chat?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>Použijte chat</target>
@ -7435,6 +7606,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<source>Use the app with one hand.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<note>No comment provided by engineer.</note>
@ -7933,6 +8108,10 @@ Repeat connection request?</source>
<target>Odeslali jste pozvánku do skupiny</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>Ke skupině budete připojeni, až bude zařízení hostitele skupiny online, vyčkejte prosím nebo se podívejte později!</target>
@ -8696,10 +8875,6 @@ Repeat connection request?</source>
<target>měsíců</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>nikdy</target>
@ -8774,6 +8949,14 @@ Repeat connection request?</source>
<target>peer-to-peer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<note>chat item text</note>
@ -8788,6 +8971,10 @@ Repeat connection request?</source>
<target>obdržel potvrzení…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>odmítnutý hovor</target>
@ -8907,10 +9094,6 @@ last received msg: %2$@</source>
<source>unknown status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<note>No comment provided by engineer.</note>

View file

@ -5,23 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<target> </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (can be copied)</target>
@ -332,11 +315,6 @@
<target>%u messages skipped.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<target>(new)</target>
@ -347,11 +325,6 @@
<target>(this device v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<target>**Create 1-time link**: to create and share a new invitation link.</target>
@ -417,11 +390,6 @@
<target>\*bold*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -458,11 +426,6 @@
- editing history.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 sec</target>
@ -531,11 +494,6 @@
<target>30 seconds</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -643,6 +601,11 @@
<target>Acknowledgement errors</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<target>Active</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<target>Active connections</target>
@ -783,9 +746,9 @@
<target>All chats and messages will be deleted - this cannot be undone!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<target>All chats will be removed from the list (text), and the list deleted.</target>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<target>All chats will be removed from the list %@, and the list deleted.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -828,6 +791,11 @@
<target>All profiles</target>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<target>All reports will be archived for you.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>All your contacts will remain connected.</target>
@ -903,6 +871,11 @@
<target>Allow to irreversibly delete sent messages. (24 hours)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<target>Allow to report messsages to moderators.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<target>Allow to send SimpleX links.</target>
@ -1068,6 +1041,16 @@
<target>Archive</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<target>Archive %lld reports?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<target>Archive all reports?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<target>Archive and upload</target>
@ -1088,6 +1071,11 @@
<target>Archive report?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<target>Archive reports</target>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<target>Archived contacts</target>
@ -1203,6 +1191,11 @@
<target>Better groups</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<target>Better groups performance</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<target>Better message dates.</target>
@ -1223,6 +1216,11 @@
<target>Better notifications</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<target>Better privacy and security</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<target>Better security ✅</target>
@ -1645,6 +1643,11 @@
<target>Clear conversation?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<target>Clear group?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<target>Clear or delete group?</target>
@ -1790,6 +1793,11 @@
<target>Confirm upload</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<target>Confirmed</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>Connect</target>
@ -2805,6 +2813,11 @@ This is your own one-time link!</target>
<target>Don't enable</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<target>Don't miss important messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>Don't show again</target>
@ -3161,6 +3174,11 @@ This is your own one-time link!</target>
<target>Error changing to incognito!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<target>Error checking token status</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<target>Error connecting to forwarding server %@. Please try later.</target>
@ -3316,6 +3334,11 @@ This is your own one-time link!</target>
<target>Error reconnecting servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<target>Error registering for notifications</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>Error removing member</target>
@ -3421,6 +3444,11 @@ This is your own one-time link!</target>
<target>Error synchronizing connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<target>Error testing server connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>Error updating group link</target>
@ -3501,6 +3529,11 @@ This is your own one-time link!</target>
<target>Expand</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<target>Expired</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>Export database</target>
@ -3541,11 +3574,21 @@ This is your own one-time link!</target>
<target>Fast and no wait until the sender is online!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<target>Faster deletion of groups.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<target>Faster joining and more reliable messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<target>Faster sending messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Favorite</target>
@ -3568,11 +3611,11 @@ This is your own one-time link!</target>
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<target>File is blocked by server operator:
(info.reason.text).</target>
%@.</target>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3700,6 +3743,11 @@ This is your own one-time link!</target>
<target>Fix not supported by group member</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<target>For all moderators</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<target>For chat profile %@:</target>
@ -3715,6 +3763,11 @@ This is your own one-time link!</target>
<target>For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<target>For me</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<target>For private routing</target>
@ -3839,6 +3892,11 @@ Error: %2$@</target>
<target>GIFs and stickers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<target>Get notified when mentioned.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<target>Good afternoon!</target>
@ -3954,6 +4012,11 @@ Error: %2$@</target>
<target>Help</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<target>Help admins moderating their groups.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>Hidden</target>
@ -4263,6 +4326,31 @@ More improvements are coming soon!</target>
<target>Interface colors</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<target>Invalid</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<target>Invalid (bad token)</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<target>Invalid (expired)</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<target>Invalid (unregistered)</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<target>Invalid (wrong topic)</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<target>Invalid QR code</target>
@ -4641,6 +4729,11 @@ This is your link for group %@!</target>
<target>Member inactive</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<target>Member reports</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<target>Member role will be changed to "%@". All chat members will be notified.</target>
@ -4676,6 +4769,11 @@ This is your link for group %@!</target>
<target>Members can irreversibly delete sent messages. (24 hours)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<target>Members can report messsages to moderators.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<target>Members can send SimpleX links.</target>
@ -4701,6 +4799,11 @@ This is your link for group %@!</target>
<target>Members can send voice messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<target>Mention members 👋</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<target>Menus</target>
@ -4949,7 +5052,12 @@ This is your link for group %@!</target>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>Mute</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<target>Mute all</target>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -5001,6 +5109,11 @@ This is your link for group %@!</target>
<target>Network status</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<target>New</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>New Passcode</target>
@ -5156,6 +5269,11 @@ This is your link for group %@!</target>
<target>No media &amp; file servers.</target>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<target>No message</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<target>No message servers.</target>
@ -5211,6 +5329,11 @@ This is your link for group %@!</target>
<target>No servers to send files.</target>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<target>No token!</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<target>No unread chats</target>
@ -5251,11 +5374,21 @@ This is your link for group %@!</target>
<target>Notifications are disabled!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<target>Notifications error</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<target>Notifications privacy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<target>Notifications status</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -5499,6 +5632,11 @@ Requires compatible VPN.</target>
<target>Or to share privately</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<target>Organize chats into lists</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<target>Other</target>
@ -5690,6 +5828,21 @@ Error: %@</target>
<target>Please store passphrase securely, you will NOT be able to change it if you lose it.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<target>Please try to disable and re-enable notfications.</target>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<target>Please wait for token activation to complete.</target>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<target>Please wait for token to be registered.</target>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Polish interface</target>
@ -5750,6 +5903,11 @@ Error: %@</target>
<target>Private filenames</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<target>Private media file names.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Private message routing</target>
@ -5825,6 +5983,11 @@ Error: %@</target>
<target>Prohibit messages reactions.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<target>Prohibit reporting messages to moderators.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<target>Prohibit sending SimpleX links.</target>
@ -6082,6 +6245,21 @@ Enable in *Network &amp; servers* settings.</target>
<target>Reduced battery usage</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<target>Register</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<target>Register notification token?</target>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<target>Registered</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>Reject</target>
@ -6218,6 +6396,16 @@ Enable in *Network &amp; servers* settings.</target>
<target>Report violation: only group moderators will see it.</target>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<target>Report: %@</target>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<target>Reporting messages to moderators is prohibited.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<target>Reports</target>
@ -6644,6 +6832,11 @@ Enable in *Network &amp; servers* settings.</target>
<target>Send notifications</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<target>Send private reports</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>Send questions and ideas</target>
@ -6884,6 +7077,11 @@ Enable in *Network &amp; servers* settings.</target>
<target>Set it instead of system authentication.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<target>Set message expiration in chats.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>Set passcode</target>
@ -7348,6 +7546,11 @@ Enable in *Network &amp; servers* settings.</target>
<target>TCP connection timeout</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<target>TCP port for messaging</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -7423,6 +7626,11 @@ Enable in *Network &amp; servers* settings.</target>
<target>Test failed at step %@.</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<target>Test notifications</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>Test server</target>
@ -7550,11 +7758,6 @@ It can happen because of some bug or when the connection is compromised.</target
<target>The profile is only shared with your contacts.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<target>The report will be archived for you.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<target>The same conditions will apply to operator **%@**.</target>
@ -7685,6 +7888,11 @@ It can happen because of some bug or when the connection is compromised.</target
<target>This link was used with another mobile device, please create a new link on the desktop.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<target>This message was deleted or not received yet.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>This setting applies to messages in your current chat profile **%@**.</target>
@ -7797,6 +8005,11 @@ You will be prompted to complete authentication before this feature is enabled.<
<target>Toggle incognito when connecting.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<target>Token status: %@.</target>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<target>Toolbar opacity</target>
@ -7962,7 +8175,7 @@ To connect, please ask your contact to create another connection link and check
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>Unmute</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7994,6 +8207,11 @@ To connect, please ask your contact to create another connection link and check
<target>Update settings?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<target>Updated conditions</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>Updating settings will re-connect the client to all servers.</target>
@ -8054,6 +8272,11 @@ To connect, please ask your contact to create another connection link and check
<target>Use SimpleX Chat servers?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<target>Use TCP port %@ when no port is specified.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>Use chat</target>
@ -8129,6 +8352,11 @@ To connect, please ask your contact to create another connection link and check
<target>Use the app with one hand.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<target>Use web port</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>User selection</target>
@ -8683,6 +8911,11 @@ Repeat connection request?</target>
<target>You sent group invitation</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<target>You should receive notifications.</target>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>You will be connected to group when the group host's device is online, please wait or check later!</target>
@ -9479,11 +9712,6 @@ Repeat connection request?</target>
<target>months</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<target>mute</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>never</target>
@ -9561,6 +9789,16 @@ Repeat connection request?</target>
<target>peer-to-peer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<target>pending</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<target>pending approval</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<target>quantum resistant e2e encryption</target>
@ -9576,6 +9814,11 @@ Repeat connection request?</target>
<target>received confirmation…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<target>rejected</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>rejected call</target>
@ -9710,11 +9953,6 @@ last received msg: %2$@</target>
<target>unknown status</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<target>unmute</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>unprotected</target>

View file

@ -5,22 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (voidaan kopioida)</target>
@ -312,11 +296,6 @@
<target>%u viestit ohitettu.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
@ -325,11 +304,6 @@
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<note>No comment provided by engineer.</note>
@ -390,11 +364,6 @@
<target>\*bold*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -425,11 +394,6 @@
- historian muokkaaminen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<note>time to disappear</note>
@ -494,11 +458,6 @@
<target>30 sekuntia</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -600,6 +559,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
@ -724,8 +687,8 @@
<target>Kaikki keskustelut ja viestit poistetaan - tätä ei voi kumota!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -763,6 +726,10 @@
<source>All profiles</source>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>Kaikki kontaktisi pysyvät yhteydessä.</target>
@ -834,6 +801,10 @@
<target>Salli lähetettyjen viestien peruuttamaton poistaminen. (24 tuntia)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -987,6 +958,14 @@
<source>Archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<note>No comment provided by engineer.</note>
@ -1003,6 +982,10 @@
<source>Archive report?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<note>No comment provided by engineer.</note>
@ -1110,6 +1093,10 @@
<source>Better groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
@ -1127,6 +1114,10 @@
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
@ -1504,6 +1495,10 @@
<target>Tyhjennä keskustelu?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<note>No comment provided by engineer.</note>
@ -1629,6 +1624,10 @@
<source>Confirm upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>Yhdistä</target>
@ -2556,6 +2555,10 @@ This is your own one-time link!</source>
<target>Älä salli</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>Älä näytä uudelleen</target>
@ -2884,6 +2887,10 @@ This is your own one-time link!</source>
<source>Error changing to incognito!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<note>No comment provided by engineer.</note>
@ -3027,6 +3034,10 @@ This is your own one-time link!</source>
<source>Error reconnecting servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>Virhe poistettaessa jäsentä</target>
@ -3124,6 +3135,10 @@ This is your own one-time link!</source>
<target>Virhe yhteyden synkronoinnissa</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>Virhe ryhmälinkin päivittämisessä</target>
@ -3198,6 +3213,10 @@ This is your own one-time link!</source>
<source>Expand</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>Vie tietokanta</target>
@ -3236,10 +3255,18 @@ This is your own one-time link!</source>
<target>Nopea ja ei odotusta, kunnes lähettäjä on online-tilassa!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Suosikki</target>
@ -3258,9 +3285,9 @@ This is your own one-time link!</source>
%@</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3380,6 +3407,10 @@ This is your own one-time link!</source>
<target>Ryhmän jäsen ei tue korjausta</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<note>servers error</note>
@ -3393,6 +3424,10 @@ This is your own one-time link!</source>
<source>For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<note>No comment provided by engineer.</note>
@ -3497,6 +3532,10 @@ Error: %2$@</source>
<target>GIFit ja tarrat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<note>message preview</note>
@ -3607,6 +3646,10 @@ Error: %2$@</source>
<target>Apua</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>Piilotettu</target>
@ -3897,6 +3940,26 @@ More improvements are coming soon!</source>
<source>Interface colors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<note>No comment provided by engineer.</note>
@ -4247,6 +4310,10 @@ This is your link for group %@!</source>
<source>Member inactive</source>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<note>No comment provided by engineer.</note>
@ -4280,6 +4347,10 @@ This is your link for group %@!</source>
<target>Ryhmän jäsenet voivat poistaa lähetetyt viestit peruuttamattomasti. (24 tuntia)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -4304,6 +4375,10 @@ This is your link for group %@!</source>
<target>Ryhmän jäsenet voivat lähettää ääniviestejä.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<note>No comment provided by engineer.</note>
@ -4523,7 +4598,11 @@ This is your link for group %@!</source>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>Mykistä</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -4570,6 +4649,10 @@ This is your link for group %@!</source>
<target>Verkon tila</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>Uusi pääsykoodi</target>
@ -4711,6 +4794,10 @@ This is your link for group %@!</source>
<source>No media &amp; file servers.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<note>servers error</note>
@ -4758,6 +4845,10 @@ This is your link for group %@!</source>
<source>No servers to send files.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<note>No comment provided by engineer.</note>
@ -4793,10 +4884,18 @@ This is your link for group %@!</source>
<target>Ilmoitukset on poistettu käytöstä!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -5018,6 +5117,10 @@ Edellyttää VPN:n sallimista.</target>
<source>Or to share privately</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
@ -5192,6 +5295,18 @@ Error: %@</source>
<target>Säilytä tunnuslause turvallisesti, ET voi muuttaa sitä, jos kadotat sen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Puolalainen käyttöliittymä</target>
@ -5248,6 +5363,10 @@ Error: %@</source>
<target>Yksityiset tiedostonimet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<note>No comment provided by engineer.</note>
@ -5316,6 +5435,10 @@ Error: %@</source>
<target>Estä viestireaktiot.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -5551,6 +5674,18 @@ Enable in *Network &amp; servers* settings.</source>
<target>Pienempi akun käyttö</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>Hylkää</target>
@ -5673,6 +5808,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Report violation: only group moderators will see it.</source>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<note>No comment provided by engineer.</note>
@ -6064,6 +6207,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Lähetys ilmoitukset</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>Lähetä kysymyksiä ja ideoita</target>
@ -6282,6 +6429,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Aseta se järjestelmän todennuksen sijaan.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>Aseta pääsykoodi</target>
@ -6702,6 +6853,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>TCP-yhteyden aikakatkaisu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -6771,6 +6926,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Testi epäonnistui vaiheessa %@.</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>Testipalvelin</target>
@ -6892,10 +7051,6 @@ Tämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut.</t
<target>Profiili jaetaan vain kontaktiesi kanssa.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<note>No comment provided by engineer.</note>
@ -7010,6 +7165,10 @@ Tämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut.</t
<source>This link was used with another mobile device, please create a new link on the desktop.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>Tämä asetus koskee nykyisen keskusteluprofiilisi viestejä *%@**.</target>
@ -7111,6 +7270,10 @@ Sinua kehotetaan suorittamaan todennus loppuun, ennen kuin tämä ominaisuus ote
<source>Toggle incognito when connecting.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<note>No comment provided by engineer.</note>
@ -7263,7 +7426,7 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>Poista mykistys</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7293,6 +7456,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<source>Update settings?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>Asetusten päivittäminen yhdistää asiakkaan uudelleen kaikkiin palvelimiin.</target>
@ -7346,6 +7513,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Käytä SimpleX Chat palvelimia?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>Käytä chattia</target>
@ -7412,6 +7583,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<source>Use the app with one hand.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<note>No comment provided by engineer.</note>
@ -7910,6 +8085,10 @@ Repeat connection request?</source>
<target>Lähetit ryhmäkutsun</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>Sinut yhdistetään ryhmään, kun ryhmän isännän laite on online-tilassa, odota tai tarkista myöhemmin!</target>
@ -8673,10 +8852,6 @@ Repeat connection request?</source>
<target>kuukautta</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>ei koskaan</target>
@ -8751,6 +8926,14 @@ Repeat connection request?</source>
<target>vertais</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<note>chat item text</note>
@ -8765,6 +8948,10 @@ Repeat connection request?</source>
<target>vahvistus saatu…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>hylätty puhelu</target>
@ -8883,10 +9070,6 @@ last received msg: %2$@</source>
<source>unknown status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<note>No comment provided by engineer.</note>

View file

@ -5,22 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (peut être copié)</target>
@ -330,11 +314,6 @@
<target>%u messages sautés.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<target>(nouveau)</target>
@ -345,11 +324,6 @@
<target>(cet appareil v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<target>**Ajouter un contact**: pour créer un nouveau lien d'invitation.</target>
@ -415,11 +389,6 @@
<target>\*gras*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -456,11 +425,6 @@
- l'historique de modification.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 sec</target>
@ -528,11 +492,6 @@
<target>30 secondes</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -640,6 +599,10 @@
<target>Erreur d'accusé de réception</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<target>Connections actives</target>
@ -777,8 +740,8 @@
<target>Toutes les discussions et tous les messages seront supprimés - il est impossible de revenir en arrière !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -821,6 +784,10 @@
<target>Tous les profiles</target>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>Tous vos contacts resteront connectés.</target>
@ -896,6 +863,10 @@
<target>Autoriser la suppression irréversible de messages envoyés. (24 heures)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<target>Autorise l'envoi de liens SimpleX.</target>
@ -1058,6 +1029,14 @@
<source>Archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<target>Archiver et téléverser</target>
@ -1076,6 +1055,10 @@
<source>Archive report?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<target>Contacts archivés</target>
@ -1190,6 +1173,10 @@
<target>Des groupes plus performants</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<target>Meilleures dates de messages.</target>
@ -1210,6 +1197,10 @@
<target>Notifications améliorées</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<target>Sécurité accrue ✅</target>
@ -1630,6 +1621,10 @@
<target>Effacer la conversation?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<note>No comment provided by engineer.</note>
@ -1773,6 +1768,10 @@
<target>Confirmer la transmission</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>Se connecter</target>
@ -2775,6 +2774,10 @@ Il s'agit de votre propre lien unique !</target>
<target>Ne pas activer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>Ne plus afficher</target>
@ -3129,6 +3132,10 @@ Il s'agit de votre propre lien unique !</target>
<target>Erreur lors du passage en mode incognito!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<target>Erreur de connexion au serveur de redirection %@. Veuillez réessayer plus tard.</target>
@ -3282,6 +3289,10 @@ Il s'agit de votre propre lien unique !</target>
<target>Erreur de reconnexion des serveurs</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>Erreur lors de la suppression d'un membre</target>
@ -3385,6 +3396,10 @@ Il s'agit de votre propre lien unique !</target>
<target>Erreur de synchronisation de connexion</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>Erreur lors de la mise à jour du lien de groupe</target>
@ -3465,6 +3480,10 @@ Il s'agit de votre propre lien unique !</target>
<target>Étendre</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>Exporter la base de données</target>
@ -3505,11 +3524,19 @@ Il s'agit de votre propre lien unique !</target>
<target>Rapide et ne nécessitant pas d'attendre que l'expéditeur soit en ligne !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<target>Connexion plus rapide et messages plus fiables.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Favoris</target>
@ -3531,9 +3558,9 @@ Il s'agit de votre propre lien unique !</target>
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3661,6 +3688,10 @@ Il s'agit de votre propre lien unique !</target>
<target>Correction non prise en charge par un membre du groupe</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<target>Pour le profil de discussion %@ :</target>
@ -3676,6 +3707,10 @@ Il s'agit de votre propre lien unique !</target>
<target>Par exemple, si votre contact reçoit des messages via un serveur SimpleX Chat, votre application les transmettra via un serveur Flux.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<target>Pour le routage privé</target>
@ -3800,6 +3835,10 @@ Erreur: %2$@</target>
<target>GIFs et stickers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<target>Bonjour!</target>
@ -3914,6 +3953,10 @@ Erreur: %2$@</target>
<target>Aide</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>Caché</target>
@ -4220,6 +4263,26 @@ D'autres améliorations sont à venir!</target>
<target>Couleurs d'interface</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<target>Code QR invalide</target>
@ -4595,6 +4658,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Membre inactif</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<target>Le rôle du membre sera modifié pour « %@ ». Tous les membres du chat seront notifiés.</target>
@ -4630,6 +4697,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Les membres du groupe peuvent supprimer de manière irréversible les messages envoyés. (24 heures)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<target>Les membres du groupe peuvent envoyer des liens SimpleX.</target>
@ -4655,6 +4726,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Les membres du groupe peuvent envoyer des messages vocaux.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<target>Menus</target>
@ -4901,7 +4976,11 @@ Voici votre lien pour le groupe %@ !</target>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>Muet</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -4953,6 +5032,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>État du réseau</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>Nouveau code d'accès</target>
@ -5105,6 +5188,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Pas de serveurs de médias et de fichiers.</target>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<target>Pas de serveurs de messages.</target>
@ -5160,6 +5247,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Pas de serveurs pour envoyer des fichiers.</target>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<note>No comment provided by engineer.</note>
@ -5198,11 +5289,19 @@ Voici votre lien pour le groupe %@ !</target>
<target>Les notifications sont désactivées!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<target>Notifications sécurisées</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -5441,6 +5540,10 @@ Nécessite l'activation d'un VPN.</target>
<target>Ou à partager en privé</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<target>Autres</target>
@ -5632,6 +5735,18 @@ Erreur: %@</target>
<target>Veuillez conserver votre phrase secrète en lieu sûr, vous NE pourrez PAS la changer si vous la perdez.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Interface en polonais</target>
@ -5692,6 +5807,10 @@ Erreur: %@</target>
<target>Noms de fichiers privés</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Routage privé des messages</target>
@ -5767,6 +5886,10 @@ Erreur: %@</target>
<target>Interdire les réactions aux messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<target>Interdire l'envoi de liens SimpleX.</target>
@ -6024,6 +6147,18 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>Réduction de la consommation de batterie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>Rejeter</target>
@ -6153,6 +6288,14 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<source>Report violation: only group moderators will see it.</source>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<note>No comment provided by engineer.</note>
@ -6577,6 +6720,10 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>Envoi de notifications</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>Envoyez vos questions et idées</target>
@ -6816,6 +6963,10 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>Il permet de remplacer l'authentification du système.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>Définir le code d'accès</target>
@ -7278,6 +7429,10 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>Délai de connexion TCP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -7353,6 +7508,10 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>Échec du test à l'étape %@.</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>Tester le serveur</target>
@ -7480,10 +7639,6 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise.
<target>Le profil n'est partagé qu'avec vos contacts.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<target>Les mêmes conditions s'appliquent à l'opérateur **%@**.</target>
@ -7613,6 +7768,10 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise.
<target>Ce lien a été utilisé avec un autre appareil mobile, veuillez créer un nouveau lien sur le bureau.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>Ce paramètre s'applique aux messages de votre profil de chat actuel **%@**.</target>
@ -7725,6 +7884,10 @@ Vous serez invité à confirmer l'authentification avant que cette fonction ne s
<target>Basculer en mode incognito lors de la connexion.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<target>Opacité de la barre d'outils</target>
@ -7890,7 +8053,7 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>Démute</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7922,6 +8085,10 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Mettre à jour les paramètres?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>La mise à jour des ces paramètres reconnectera le client à tous les serveurs.</target>
@ -7982,6 +8149,10 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Utiliser les serveurs SimpleX Chat?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>Utiliser le chat</target>
@ -8057,6 +8228,10 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Utiliser l'application d'une main.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Sélection de l'utilisateur</target>
@ -8610,6 +8785,10 @@ Répéter la demande de connexion ?</target>
<target>Vous avez envoyé une invitation de groupe</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>Vous serez connecté·e au groupe lorsque l'appareil de l'hôte sera en ligne, veuillez attendre ou vérifier plus tard !</target>
@ -9404,11 +9583,6 @@ Répéter la demande de connexion ?</target>
<target>mois</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<target>muet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>jamais</target>
@ -9486,6 +9660,14 @@ Répéter la demande de connexion ?</target>
<target>pair-à-pair</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<target>chiffrement e2e résistant post-quantique</target>
@ -9501,6 +9683,10 @@ Répéter la demande de connexion ?</target>
<target>confimation reçu…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>appel rejeté</target>
@ -9635,11 +9821,6 @@ dernier message reçu: %2$@</target>
<target>statut inconnu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<target>démuter</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>non protégé</target>

View file

@ -1693,12 +1693,14 @@ We will be adding server redundancy to prevent lost messages.</source>
<source>Live message!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live messages" xml:space="preserve">
<trans-unit id="Live messages" xml:space="preserve" approved="no">
<source>Live messages</source>
<target state="translated">Žive poruke</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Local name" xml:space="preserve">
<trans-unit id="Local name" xml:space="preserve" approved="no">
<source>Local name</source>
<target state="translated">Lokalno ime</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Local profile data only" xml:space="preserve">
@ -3715,6 +3717,14 @@ SimpleX servers cannot see your profile.</source>
<source>Immediately</source>
<target state="translated">Odmah</target>
</trans-unit>
<trans-unit id="Address settings" xml:space="preserve" approved="no">
<source>Address settings</source>
<target state="translated">Podešavanje adrese</target>
</trans-unit>
<trans-unit id="Admins can block a member for all." xml:space="preserve" approved="no">
<source>Admins can block a member for all.</source>
<target state="needs-translation">Administratori mogu da blokiraju</target>
</trans-unit>
</body>
</file>
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="hr" datatype="plaintext">

View file

@ -5,22 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (コピー可能)</target>
@ -330,11 +314,6 @@
<target>%u 件のメッセージがスキップされました。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<target>(新規)</target>
@ -345,11 +324,6 @@
<target>(このデバイス v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<target>**コンタクトの追加**: 新しい招待リンクを作成するか、受け取ったリンクから接続します。</target>
@ -415,11 +389,6 @@
<target>\*太字*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -456,11 +425,6 @@
- 編集履歴。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 秒</target>
@ -528,11 +492,6 @@
<target>30秒</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -634,6 +593,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
@ -761,8 +724,8 @@
<target>全チャットとメッセージが削除されます(※元に戻せません※)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -801,6 +764,10 @@
<target>すべてのプロフィール</target>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>あなたの連絡先が繋がったまま継続します。</target>
@ -874,6 +841,10 @@
<target>送信済みメッセージの永久削除を許可する。(24時間)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<target>SimpleXリンクの送信を許可。</target>
@ -1035,6 +1006,14 @@
<source>Archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<target>アーカイブとアップロード</target>
@ -1052,6 +1031,10 @@
<source>Archive report?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<note>No comment provided by engineer.</note>
@ -1159,6 +1142,10 @@
<source>Better groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
@ -1176,6 +1163,10 @@
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
@ -1557,6 +1548,10 @@
<target>ダイアログのクリアしますか?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<note>No comment provided by engineer.</note>
@ -1685,6 +1680,10 @@
<source>Confirm upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>接続</target>
@ -2628,6 +2627,10 @@ This is your own one-time link!</source>
<target>有効にしない</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>次から表示しない</target>
@ -2957,6 +2960,10 @@ This is your own one-time link!</source>
<source>Error changing to incognito!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<note>No comment provided by engineer.</note>
@ -3100,6 +3107,10 @@ This is your own one-time link!</source>
<source>Error reconnecting servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>メンバー除名にエラー発生</target>
@ -3197,6 +3208,10 @@ This is your own one-time link!</source>
<target>接続の同期エラー</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>グループのリンクのアップデートにエラー発生</target>
@ -3271,6 +3286,10 @@ This is your own one-time link!</source>
<source>Expand</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>データベースをエキスポート</target>
@ -3309,10 +3328,18 @@ This is your own one-time link!</source>
<target>送信者がオンラインになるまでの待ち時間がなく、速い!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>お気に入り</target>
@ -3331,9 +3358,9 @@ This is your own one-time link!</source>
%@</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3453,6 +3480,10 @@ This is your own one-time link!</source>
<target>グループメンバーによる修正はサポートされていません</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<note>servers error</note>
@ -3466,6 +3497,10 @@ This is your own one-time link!</source>
<source>For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<note>No comment provided by engineer.</note>
@ -3570,6 +3605,10 @@ Error: %2$@</source>
<target>GIFとステッカー</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<note>message preview</note>
@ -3680,6 +3719,10 @@ Error: %2$@</source>
<target>ヘルプ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>プライベート</target>
@ -3970,6 +4013,26 @@ More improvements are coming soon!</source>
<source>Interface colors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<note>No comment provided by engineer.</note>
@ -4320,6 +4383,10 @@ This is your link for group %@!</source>
<source>Member inactive</source>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<note>No comment provided by engineer.</note>
@ -4353,6 +4420,10 @@ This is your link for group %@!</source>
<target>グループのメンバーがメッセージを完全削除することができます。(24時間)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -4377,6 +4448,10 @@ This is your link for group %@!</source>
<target>グループのメンバーが音声メッセージを送信できます。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<note>No comment provided by engineer.</note>
@ -4598,7 +4673,11 @@ This is your link for group %@!</source>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>ミュート</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -4645,6 +4724,10 @@ This is your link for group %@!</source>
<target>ネットワーク状況</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>新しいパスコード</target>
@ -4787,6 +4870,10 @@ This is your link for group %@!</source>
<source>No media &amp; file servers.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<note>servers error</note>
@ -4834,6 +4921,10 @@ This is your link for group %@!</source>
<source>No servers to send files.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<note>No comment provided by engineer.</note>
@ -4869,10 +4960,18 @@ This is your link for group %@!</source>
<target>通知が無効になっています!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -5095,6 +5194,10 @@ VPN を有効にする必要があります。</target>
<source>Or to share privately</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
@ -5269,6 +5372,18 @@ Error: %@</source>
<target>パスフレーズを失くさないように保管してください。失くすと変更できなくなります。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>ポーランド語UI</target>
@ -5325,6 +5440,10 @@ Error: %@</source>
<target>プライベートなファイル名</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<note>No comment provided by engineer.</note>
@ -5394,6 +5513,10 @@ Error: %@</source>
<target>メッセージへのリアクションは禁止されています。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -5628,6 +5751,18 @@ Enable in *Network &amp; servers* settings.</source>
<target>電池使用量低減</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>拒否</target>
@ -5750,6 +5885,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Report violation: only group moderators will see it.</source>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<note>No comment provided by engineer.</note>
@ -6141,6 +6284,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>通知を送信する</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>質問やアイデアを送る</target>
@ -6352,6 +6499,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>システム認証の代わりに設定します。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>パスコードを設定する</target>
@ -6773,6 +6924,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>TCP接続タイムアウト</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -6842,6 +6997,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>テストはステップ %@ で失敗しました。</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>テストサーバ</target>
@ -6963,10 +7122,6 @@ It can happen because of some bug or when the connection is compromised.</source
<target>プロフィールは連絡先にしか共有されません。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<note>No comment provided by engineer.</note>
@ -7080,6 +7235,10 @@ It can happen because of some bug or when the connection is compromised.</source
<source>This link was used with another mobile device, please create a new link on the desktop.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>この設定は現在のチャットプロフィール **%@** のメッセージに適用されます。</target>
@ -7181,6 +7340,10 @@ You will be prompted to complete authentication before this feature is enabled.<
<source>Toggle incognito when connecting.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<note>No comment provided by engineer.</note>
@ -7333,7 +7496,7 @@ To connect, please ask your contact to create another connection link and check
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>ミュート解除</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7363,6 +7526,10 @@ To connect, please ask your contact to create another connection link and check
<source>Update settings?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>設定を更新すると、全サーバにクライントの再接続が行われます。</target>
@ -7416,6 +7583,10 @@ To connect, please ask your contact to create another connection link and check
<target>SimpleX チャット サーバーを使用しますか?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>チャット</target>
@ -7482,6 +7653,10 @@ To connect, please ask your contact to create another connection link and check
<source>Use the app with one hand.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<note>No comment provided by engineer.</note>
@ -7981,6 +8156,10 @@ Repeat connection request?</source>
<target>グループの招待を送りました</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>グループのホスト端末がオンラインになったら、接続されます。後でチェックするか、しばらくお待ちください!</target>
@ -8744,10 +8923,6 @@ Repeat connection request?</source>
<target>月</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>一度も</target>
@ -8822,6 +8997,14 @@ Repeat connection request?</source>
<target>P2P</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<note>chat item text</note>
@ -8836,6 +9019,10 @@ Repeat connection request?</source>
<target>確認を受け取りました…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>拒否した通話</target>
@ -8954,10 +9141,6 @@ last received msg: %2$@</source>
<source>unknown status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<note>No comment provided by engineer.</note>

View file

@ -5,22 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (można skopiować)</target>
@ -208,6 +192,7 @@
</trans-unit>
<trans-unit id="%d seconds(s)" xml:space="preserve">
<source>%d seconds(s)</source>
<target>%d sekundach</target>
<note>delete after time</note>
</trans-unit>
<trans-unit id="%d skipped message(s)" xml:space="preserve">
@ -330,11 +315,6 @@
<target>%u pominiętych wiadomości.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<target>(nowy)</target>
@ -345,11 +325,6 @@
<target>(to urządzenie v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<target>**Dodaj kontakt**: aby utworzyć nowy link z zaproszeniem lub połączyć się za pomocą otrzymanego linku.</target>
@ -415,11 +390,6 @@
<target>\*pogrubiony*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -456,11 +426,6 @@
- historia edycji.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 sek</target>
@ -501,6 +466,7 @@
</trans-unit>
<trans-unit id="1 year" xml:space="preserve">
<source>1 year</source>
<target>1 roku</target>
<note>delete after time</note>
</trans-unit>
<trans-unit id="1-time link" xml:space="preserve">
@ -528,11 +494,6 @@
<target>30 sekund</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -640,6 +601,11 @@
<target>Błędy potwierdzenia</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<target>Aktywne</target>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<target>Aktywne połączenia</target>
@ -657,6 +623,7 @@
</trans-unit>
<trans-unit id="Add list" xml:space="preserve">
<source>Add list</source>
<target>Dodaj listę</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add profile" xml:space="preserve">
@ -686,6 +653,7 @@
</trans-unit>
<trans-unit id="Add to list" xml:space="preserve">
<source>Add to list</source>
<target>Dodaj do listy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add welcome message" xml:space="preserve">
@ -765,6 +733,7 @@
</trans-unit>
<trans-unit id="All" xml:space="preserve">
<source>All</source>
<target>Wszystko</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All app data is deleted." xml:space="preserve">
@ -777,8 +746,9 @@
<target>Wszystkie czaty i wiadomości zostaną usunięte - nie można tego cofnąć!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<target>Wszystkie rozmowy zostaną usunięte z listy %@, a lista usunięta.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -798,6 +768,7 @@
</trans-unit>
<trans-unit id="All messages and files are sent **end-to-end encrypted**, with post-quantum security in direct messages." xml:space="preserve">
<source>All messages and files are sent **end-to-end encrypted**, with post-quantum security in direct messages.</source>
<target>Wszystkie wiadomości i pliki są wysyłane **z szyfrowaniem end-to-end**, z bezpieczeństwem postkwantowym w wiadomościach bezpośrednich.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All messages will be deleted - this cannot be undone!" xml:space="preserve">
@ -820,6 +791,11 @@
<target>Wszystkie profile</target>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<target>Wszystkie raporty zostaną dla Ciebie zarchiwizowane.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>Wszystkie Twoje kontakty pozostaną połączone.</target>
@ -895,6 +871,11 @@
<target>Zezwól na nieodwracalne usunięcie wysłanych wiadomości. (24 godziny)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<target>Zezwól na zgłaszanie wiadomości moderatorom.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<target>Zezwól na wysyłanie linków SimpleX.</target>
@ -977,6 +958,7 @@
</trans-unit>
<trans-unit id="Another reason" xml:space="preserve">
<source>Another reason</source>
<target>Inny powód</target>
<note>report reason</note>
</trans-unit>
<trans-unit id="Answer call" xml:space="preserve">
@ -1006,6 +988,7 @@
</trans-unit>
<trans-unit id="App group:" xml:space="preserve">
<source>App group:</source>
<target>Grupa aplikacji:</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App icon" xml:space="preserve">
@ -1055,6 +1038,17 @@
</trans-unit>
<trans-unit id="Archive" xml:space="preserve">
<source>Archive</source>
<target>Archiwizuj</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<target>Archiwizować %lld reports?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<target>Archiwizować wszystkie zgłoszenia?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
@ -1069,12 +1063,19 @@
</trans-unit>
<trans-unit id="Archive report" xml:space="preserve">
<source>Archive report</source>
<target>Archiwizuj zgłoszenie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive report?" xml:space="preserve">
<source>Archive report?</source>
<target>Archiwizować zgłoszenie?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<target>Archiwizuj zgłoszenia</target>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<target>Zarchiwizowane kontakty</target>
@ -1087,6 +1088,7 @@
</trans-unit>
<trans-unit id="Ask" xml:space="preserve">
<source>Ask</source>
<target>Zapytaj</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Attach" xml:space="preserve">
@ -1189,6 +1191,10 @@
<target>Lepsze grupy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<target>Lepsze daty wiadomości.</target>
@ -1209,6 +1215,10 @@
<target>Lepsze powiadomienia</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<target>Lepsze zabezpieczenia ✅</target>
@ -1311,6 +1321,7 @@
</trans-unit>
<trans-unit id="Businesses" xml:space="preserve">
<source>Businesses</source>
<target>Firmy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="By chat profile (default) or [by connection](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA)." xml:space="preserve">
@ -1629,6 +1640,10 @@
<target>Wyczyścić rozmowę?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<note>No comment provided by engineer.</note>
@ -1768,6 +1783,10 @@
<target>Potwierdź wgranie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>Połącz</target>
@ -2761,6 +2780,10 @@ To jest twój jednorazowy link!</target>
<target>Nie włączaj</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>Nie pokazuj ponownie</target>
@ -3111,6 +3134,10 @@ To jest twój jednorazowy link!</target>
<target>Błąd zmiany na incognito!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<target>Błąd połączenia z serwerem przekierowania %@. Spróbuj ponownie później.</target>
@ -3263,6 +3290,10 @@ To jest twój jednorazowy link!</target>
<target>Błąd ponownego łączenia serwerów</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>Błąd usuwania członka</target>
@ -3365,6 +3396,10 @@ To jest twój jednorazowy link!</target>
<target>Błąd synchronizacji połączenia</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>Błąd aktualizacji linku grupy</target>
@ -3443,6 +3478,10 @@ To jest twój jednorazowy link!</target>
<target>Rozszerz</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>Eksportuj bazę danych</target>
@ -3483,11 +3522,19 @@ To jest twój jednorazowy link!</target>
<target>Szybko i bez czekania aż nadawca będzie online!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<target>Szybsze dołączenie i bardziej niezawodne wiadomości.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Ulubione</target>
@ -3509,9 +3556,9 @@ To jest twój jednorazowy link!</target>
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3639,6 +3686,10 @@ To jest twój jednorazowy link!</target>
<target>Naprawa nie jest obsługiwana przez członka grupy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<note>servers error</note>
@ -3652,6 +3703,10 @@ To jest twój jednorazowy link!</target>
<source>For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<note>No comment provided by engineer.</note>
@ -3773,6 +3828,10 @@ Błąd: %2$@</target>
<target>GIF-y i naklejki</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<target>Dzień dobry!</target>
@ -3887,6 +3946,10 @@ Błąd: %2$@</target>
<target>Pomoc</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>Ukryte</target>
@ -4189,6 +4252,26 @@ More improvements are coming soon!</source>
<target>Kolory interfejsu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<target>Nieprawidłowy kod QR</target>
@ -4561,6 +4644,10 @@ To jest twój link do grupy %@!</target>
<target>Członek nieaktywny</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<note>No comment provided by engineer.</note>
@ -4594,6 +4681,10 @@ To jest twój link do grupy %@!</target>
<target>Członkowie grupy mogą nieodwracalnie usuwać wysłane wiadomości. (24 godziny)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<target>Członkowie grupy mogą wysyłać linki SimpleX.</target>
@ -4619,6 +4710,10 @@ To jest twój link do grupy %@!</target>
<target>Członkowie grupy mogą wysyłać wiadomości głosowe.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<target>Menu</target>
@ -4864,7 +4959,11 @@ To jest twój link do grupy %@!</target>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>Wycisz</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -4914,6 +5013,10 @@ To jest twój link do grupy %@!</target>
<target>Status sieci</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>Nowy Pin</target>
@ -5063,6 +5166,10 @@ To jest twój link do grupy %@!</target>
<source>No media &amp; file servers.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<note>servers error</note>
@ -5113,6 +5220,10 @@ To jest twój link do grupy %@!</target>
<source>No servers to send files.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<note>No comment provided by engineer.</note>
@ -5151,10 +5262,18 @@ To jest twój link do grupy %@!</target>
<target>Powiadomienia są wyłączone!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -5386,6 +5505,10 @@ Wymaga włączenia VPN.</target>
<source>Or to share privately</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<target>Inne</target>
@ -5577,6 +5700,18 @@ Błąd: %@</target>
<target>Przechowuj kod dostępu w bezpieczny sposób, w przypadku jego utraty NIE będzie można go zmienić.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Polski interfejs</target>
@ -5635,6 +5770,10 @@ Błąd: %@</target>
<target>Prywatne nazwy plików</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Trasowanie prywatnych wiadomości</target>
@ -5710,6 +5849,10 @@ Błąd: %@</target>
<target>Zabroń reakcje wiadomości.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<target>Zabroń wysyłania linków SimpleX.</target>
@ -5967,6 +6110,18 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Zmniejszone zużycie baterii</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>Odrzuć</target>
@ -6096,6 +6251,14 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<source>Report violation: only group moderators will see it.</source>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<note>No comment provided by engineer.</note>
@ -6518,6 +6681,10 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Wyślij powiadomienia</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>Wyślij pytania i pomysły</target>
@ -6753,6 +6920,10 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Ustaw go zamiast uwierzytelniania systemowego.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>Ustaw pin</target>
@ -7204,6 +7375,10 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Limit czasu połączenia TCP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -7278,6 +7453,10 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Test nie powiódł się na etapie %@.</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>Przetestuj serwer</target>
@ -7403,10 +7582,6 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom
<target>Profil jest udostępniany tylko Twoim kontaktom.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<note>No comment provided by engineer.</note>
@ -7531,6 +7706,10 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom
<target>Ten link dostał użyty z innym urządzeniem mobilnym, proszę stworzyć nowy link na komputerze.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>To ustawienie dotyczy wiadomości Twojego bieżącego profilu czatu **%@**.</target>
@ -7639,6 +7818,10 @@ Przed włączeniem tej funkcji zostanie wyświetlony monit uwierzytelniania.</ta
<target>Przełącz incognito przy połączeniu.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<target>Nieprzezroczystość paska narzędzi</target>
@ -7803,7 +7986,7 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>Wyłącz wyciszenie</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7835,6 +8018,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
<target>Zaktualizować ustawienia?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>Aktualizacja ustawień spowoduje ponowne połączenie klienta ze wszystkimi serwerami.</target>
@ -7894,6 +8081,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
<target>Użyć serwerów SimpleX Chat?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>Użyj czatu</target>
@ -7966,6 +8157,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
<target>Korzystaj z aplikacji jedną ręką.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Wybór użytkownika</target>
@ -8512,6 +8707,10 @@ Powtórzyć prośbę połączenia?</target>
<target>Wysłałeś zaproszenie do grupy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>Zostaniesz połączony do grupy, gdy urządzenie gospodarza grupy będzie online, proszę czekać lub sprawdzić później!</target>
@ -8693,6 +8892,7 @@ Powtórzyć prośbę połączenia?</target>
</trans-unit>
<trans-unit id="Your servers" xml:space="preserve">
<source>Your servers</source>
<target>Twoje serwery</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your settings" xml:space="preserve">
@ -9302,11 +9502,6 @@ Powtórzyć prośbę połączenia?</target>
<target>miesiące</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<target>wycisz</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>nigdy</target>
@ -9384,6 +9579,14 @@ Powtórzyć prośbę połączenia?</target>
<target>peer-to-peer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<target>kwantowo odporne szyfrowanie e2e</target>
@ -9399,6 +9602,10 @@ Powtórzyć prośbę połączenia?</target>
<target>otrzymano potwierdzenie…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>odrzucone połączenie</target>
@ -9532,11 +9739,6 @@ ostatnia otrzymana wiadomość: %2$@</target>
<target>nieznany status</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<target>wyłącz wyciszenie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>niezabezpieczony</target>
@ -9781,6 +9983,7 @@ ostatnia otrzymana wiadomość: %2$@</target>
</trans-unit>
<trans-unit id="New messages in %d chats" xml:space="preserve">
<source>New messages in %d chats</source>
<target>Nowe wiadomości w %d czatach</target>
<note>notification body</note>
</trans-unit>
</body>

View file

@ -5,22 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (สามารถคัดลอกได้)</target>
@ -306,11 +290,6 @@
<target>%u ข้อความที่ถูกข้าม</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
@ -319,11 +298,6 @@
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<note>No comment provided by engineer.</note>
@ -384,11 +358,6 @@
<target>\*ตัวหนา*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -419,11 +388,6 @@
- ประวัติการแก้ไข</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<note>time to disappear</note>
@ -488,11 +452,6 @@
<target>30 วินาที</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -592,6 +551,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
@ -716,8 +679,8 @@
<target>แชทและข้อความทั้งหมดจะถูกลบ - การดำเนินการนี้ไม่สามารถยกเลิกได้!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -755,6 +718,10 @@
<source>All profiles</source>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>ผู้ติดต่อทั้งหมดของคุณจะยังคงเชื่อมต่ออยู่.</target>
@ -826,6 +793,10 @@
<target>อนุญาตให้ลบข้อความที่ส่งไปแล้วอย่างถาวร</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -979,6 +950,14 @@
<source>Archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<note>No comment provided by engineer.</note>
@ -995,6 +974,10 @@
<source>Archive report?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<note>No comment provided by engineer.</note>
@ -1102,6 +1085,10 @@
<source>Better groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
@ -1119,6 +1106,10 @@
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
@ -1496,6 +1487,10 @@
<target>ลบการสนทนา?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<note>No comment provided by engineer.</note>
@ -1621,6 +1616,10 @@
<source>Confirm upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>เชื่อมต่อ</target>
@ -2543,6 +2542,10 @@ This is your own one-time link!</source>
<target>อย่าเปิดใช้งาน</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>ไม่ต้องแสดงอีก</target>
@ -2870,6 +2873,10 @@ This is your own one-time link!</source>
<source>Error changing to incognito!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<note>No comment provided by engineer.</note>
@ -3012,6 +3019,10 @@ This is your own one-time link!</source>
<source>Error reconnecting servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>เกิดข้อผิดพลาดในการลบสมาชิก</target>
@ -3109,6 +3120,10 @@ This is your own one-time link!</source>
<target>เกิดข้อผิดพลาดในการซิงโครไนซ์การเชื่อมต่อ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>เกิดข้อผิดพลาดในการอัปเดตลิงก์กลุ่ม</target>
@ -3183,6 +3198,10 @@ This is your own one-time link!</source>
<source>Expand</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>ส่งออกฐานข้อมูล</target>
@ -3221,10 +3240,18 @@ This is your own one-time link!</source>
<target>รวดเร็วและไม่ต้องรอจนกว่าผู้ส่งจะออนไลน์!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>ที่ชอบ</target>
@ -3243,9 +3270,9 @@ This is your own one-time link!</source>
%@</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3365,6 +3392,10 @@ This is your own one-time link!</source>
<target>การแก้ไขไม่สนับสนุนโดยสมาชิกกลุ่ม</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<note>servers error</note>
@ -3378,6 +3409,10 @@ This is your own one-time link!</source>
<source>For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<note>No comment provided by engineer.</note>
@ -3482,6 +3517,10 @@ Error: %2$@</source>
<target>GIFs และสติกเกอร์</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<note>message preview</note>
@ -3592,6 +3631,10 @@ Error: %2$@</source>
<target>ความช่วยเหลือ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>ซ่อนอยู่</target>
@ -3881,6 +3924,26 @@ More improvements are coming soon!</source>
<source>Interface colors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<note>No comment provided by engineer.</note>
@ -4230,6 +4293,10 @@ This is your link for group %@!</source>
<source>Member inactive</source>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<note>No comment provided by engineer.</note>
@ -4263,6 +4330,10 @@ This is your link for group %@!</source>
<target>สมาชิกกลุ่มสามารถลบข้อความที่ส่งแล้วอย่างถาวร</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -4287,6 +4358,10 @@ This is your link for group %@!</source>
<target>สมาชิกกลุ่มสามารถส่งข้อความเสียง</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<note>No comment provided by engineer.</note>
@ -4505,7 +4580,11 @@ This is your link for group %@!</source>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>ปิดเสียง</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -4552,6 +4631,10 @@ This is your link for group %@!</source>
<target>สถานะเครือข่าย</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>รหัสผ่านใหม่</target>
@ -4692,6 +4775,10 @@ This is your link for group %@!</source>
<source>No media &amp; file servers.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<note>servers error</note>
@ -4739,6 +4826,10 @@ This is your link for group %@!</source>
<source>No servers to send files.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<note>No comment provided by engineer.</note>
@ -4774,10 +4865,18 @@ This is your link for group %@!</source>
<target>ปิดการแจ้งเตือน!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -4997,6 +5096,10 @@ Requires compatible VPN.</source>
<source>Or to share privately</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
@ -5171,6 +5274,18 @@ Error: %@</source>
<target>โปรดจัดเก็บรหัสผ่านอย่างปลอดภัย คุณจะไม่สามารถเปลี่ยนรหัสผ่านได้หากคุณทำรหัสผ่านหาย</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>อินเตอร์เฟซภาษาโปแลนด์</target>
@ -5227,6 +5342,10 @@ Error: %@</source>
<target>ชื่อไฟล์ส่วนตัว</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<note>No comment provided by engineer.</note>
@ -5295,6 +5414,10 @@ Error: %@</source>
<target>ห้ามแสดงปฏิกิริยาต่อข้อความ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
@ -5529,6 +5652,18 @@ Enable in *Network &amp; servers* settings.</source>
<target>ลดการใช้แบตเตอรี่</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>ปฏิเสธ</target>
@ -5650,6 +5785,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Report violation: only group moderators will see it.</source>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<note>No comment provided by engineer.</note>
@ -6041,6 +6184,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>ส่งการแจ้งเตือน</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>ส่งคําถามและความคิด</target>
@ -6257,6 +6404,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>ตั้งแทนการรับรองความถูกต้องของระบบ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>ตั้งรหัสผ่าน</target>
@ -6675,6 +6826,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>หมดเวลาการเชื่อมต่อ TCP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -6744,6 +6899,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>การทดสอบล้มเหลวในขั้นตอน %@</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>เซิร์ฟเวอร์ทดสอบ</target>
@ -6866,10 +7025,6 @@ It can happen because of some bug or when the connection is compromised.</source
<target>โปรไฟล์นี้แชร์กับผู้ติดต่อของคุณเท่านั้น</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<note>No comment provided by engineer.</note>
@ -6982,6 +7137,10 @@ It can happen because of some bug or when the connection is compromised.</source
<source>This link was used with another mobile device, please create a new link on the desktop.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>การตั้งค่านี้ใช้กับข้อความในโปรไฟล์แชทปัจจุบันของคุณ **%@**</target>
@ -7083,6 +7242,10 @@ You will be prompted to complete authentication before this feature is enabled.<
<source>Toggle incognito when connecting.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<note>No comment provided by engineer.</note>
@ -7235,7 +7398,7 @@ To connect, please ask your contact to create another connection link and check
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>เปิดเสียง</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7265,6 +7428,10 @@ To connect, please ask your contact to create another connection link and check
<source>Update settings?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>การอัปเดตการตั้งค่าจะเชื่อมต่อไคลเอนต์กับเซิร์ฟเวอร์ทั้งหมดอีกครั้ง</target>
@ -7318,6 +7485,10 @@ To connect, please ask your contact to create another connection link and check
<target>ใช้เซิร์ฟเวอร์ SimpleX Chat ไหม?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>ใช้แชท</target>
@ -7382,6 +7553,10 @@ To connect, please ask your contact to create another connection link and check
<source>Use the app with one hand.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<note>No comment provided by engineer.</note>
@ -7879,6 +8054,10 @@ Repeat connection request?</source>
<target>คุณส่งคำเชิญเข้าร่วมกลุ่มแล้ว</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>คุณจะเชื่อมต่อกับกลุ่มเมื่ออุปกรณ์โฮสต์ของกลุ่มออนไลน์อยู่ โปรดรอหรือตรวจสอบภายหลัง!</target>
@ -8639,10 +8818,6 @@ Repeat connection request?</source>
<target>เดือน</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>ไม่เคย</target>
@ -8717,6 +8892,14 @@ Repeat connection request?</source>
<target>เพื่อนต่อเพื่อน</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<note>chat item text</note>
@ -8731,6 +8914,10 @@ Repeat connection request?</source>
<target>ได้รับการยืนยัน…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>สายถูกปฏิเสธ</target>
@ -8849,10 +9036,6 @@ last received msg: %2$@</source>
<source>unknown status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<note>No comment provided by engineer.</note>

View file

@ -5,22 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (kopyalanabilir)</target>
@ -330,11 +314,6 @@
<target>%u mesajlar atlandı.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<target>(yeni)</target>
@ -345,11 +324,6 @@
<target>(bu cihaz v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<target>**Kişi ekle**: yeni bir davet bağlantısı oluşturmak için, ya da aldığın bağlantıyla bağlan.</target>
@ -415,11 +389,6 @@
<target>\*kalın*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -456,11 +425,6 @@
- düzenleme geçmişi.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 saniye</target>
@ -528,11 +492,6 @@
<target>30 saniye</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -640,6 +599,10 @@
<target>Onay hataları</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<target>Aktif bağlantılar</target>
@ -777,8 +740,8 @@
<target>Tüm konuşmalar ve mesajlar silinecektir. Bu, geri alınamaz!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -821,6 +784,10 @@
<target>Tüm Profiller</target>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>Konuştuğun kişilerin tümü bağlı kalacaktır.</target>
@ -896,6 +863,10 @@
<target>Gönderilen mesajların kalıcı olarak silinmesine izin ver. (24 saat içinde)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<target>SimpleX bağlantıları göndilmesine izin ver.</target>
@ -1058,6 +1029,14 @@
<source>Archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<target>Arşivle ve yükle</target>
@ -1076,6 +1055,10 @@
<source>Archive report?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<target>Arşivli kişiler</target>
@ -1190,6 +1173,10 @@
<target>Daha iyi gruplar</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<target>Daha iyi mesaj tarihleri.</target>
@ -1210,6 +1197,10 @@
<target>Daha iyi bildirimler</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<target>Daha iyi güvenlik ✅</target>
@ -1630,6 +1621,10 @@
<target>Sohbet temizlensin mi?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<note>No comment provided by engineer.</note>
@ -1773,6 +1768,10 @@
<target>Yüklemeyi onayla</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>Bağlan</target>
@ -2774,6 +2773,10 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Etkinleştirme</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>Yeniden gösterme</target>
@ -3128,6 +3131,10 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Gizli moduna geçerken hata oluştu!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<target>Yönlendirme sunucusu %@'ya bağlanırken hata oluştu. Lütfen daha sonra deneyin.</target>
@ -3281,6 +3288,10 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Hata sunuculara yeniden bağlanılıyor</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>Kişiyi silerken sorun oluştu</target>
@ -3384,6 +3395,10 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Bağlantı senkronizasyonunda hata oluştu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>Grup bağlantısı güncellenirken hata oluştu</target>
@ -3464,6 +3479,10 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Genişlet</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>Veritabanını dışarı aktar</target>
@ -3504,11 +3523,19 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Hızlı ve gönderici çevrimiçi olana kadar beklemek yok!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<target>Daha hızlı katılma ve daha güvenilir mesajlar.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Favori</target>
@ -3530,9 +3557,9 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3660,6 +3687,10 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Düzeltme grup üyesi tarafından desteklenmiyor</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<target>Sohbet profili için %@:</target>
@ -3675,6 +3706,10 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Örneğin, eğer kişiniz SimpleX Sohbet sunucusundan mesajları alıyorsa, uygulamanız bu mesajları Flux sunucusundan iletecektir.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<target>Gizli yönlendirme için</target>
@ -3799,6 +3834,10 @@ Hata: %2$@</target>
<target>GİFler ve çıkartmalar</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<target>İyi öğlenler!</target>
@ -3913,6 +3952,10 @@ Hata: %2$@</target>
<target>Yardım</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>Gizlenmiş</target>
@ -4219,6 +4262,26 @@ Daha fazla iyileştirme yakında geliyor!</target>
<target>Arayüz renkleri</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<target>Geçersiz QR kodu</target>
@ -4594,6 +4657,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Üye inaktif</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<target>Üye rolü "%@" olarak değiştirilecektir. Tüm sohbet üyeleri bilgilendirilecektir.</target>
@ -4628,6 +4695,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Grup üyeleri, gönderilen mesajları kalıcı olarak silebilir. (24 saat içinde)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<target>Grup üyeleri SimpleX bağlantıları gönderebilir.</target>
@ -4653,6 +4724,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Grup üyeleri sesli mesajlar gönderebilir.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<target>Menüler</target>
@ -4898,7 +4973,11 @@ Bu senin grup için bağlantın %@!</target>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>Sustur</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -4948,6 +5027,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Ağ durumu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>Yeni şifre</target>
@ -5097,6 +5180,10 @@ Bu senin grup için bağlantın %@!</target>
<source>No media &amp; file servers.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<note>servers error</note>
@ -5147,6 +5234,10 @@ Bu senin grup için bağlantın %@!</target>
<source>No servers to send files.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<note>No comment provided by engineer.</note>
@ -5185,10 +5276,18 @@ Bu senin grup için bağlantın %@!</target>
<target>Bildirimler devre dışı!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -5420,6 +5519,10 @@ VPN'nin etkinleştirilmesi gerekir.</target>
<source>Or to share privately</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<target>Diğer</target>
@ -5611,6 +5714,18 @@ Hata: %@</target>
<target>Lütfen parolayı güvenli bir şekilde saklayın, kaybederseniz parolayı DEĞİŞTİREMEZSİNİZ.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Lehçe arayüz</target>
@ -5669,6 +5784,10 @@ Hata: %@</target>
<target>Gizli dosya adları</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Gizli mesaj yönlendirme</target>
@ -5744,6 +5863,10 @@ Hata: %@</target>
<target>Mesajlarda tepkileri yasakla.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<target>SimpleX bağlantısı gönderimini yasakla.</target>
@ -6001,6 +6124,18 @@ Enable in *Network &amp; servers* settings.</source>
<target>Azaltılmış pil kullanımı</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>Reddet</target>
@ -6130,6 +6265,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Report violation: only group moderators will see it.</source>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<note>No comment provided by engineer.</note>
@ -6552,6 +6695,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Bildirimler gönder</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>Fikirler ve sorular gönderin</target>
@ -6787,6 +6934,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Sistem kimlik doğrulaması yerine ayarla.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>Şifre ayarla</target>
@ -7241,6 +7392,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>TCP bağlantı zaman aşımı</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -7315,6 +7470,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Test %@ adımında başarısız oldu.</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>Sunucuyu test et</target>
@ -7440,10 +7599,6 @@ Bazı hatalar nedeniyle veya bağlantı tehlikeye girdiğinde meydana gelebilir.
<target>Profil sadece kişilerinle paylaşılacak.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<note>No comment provided by engineer.</note>
@ -7568,6 +7723,10 @@ Bazı hatalar nedeniyle veya bağlantı tehlikeye girdiğinde meydana gelebilir.
<target>Bu bağlantı başka bir mobil cihazda kullanıldı, lütfen masaüstünde yeni bir bağlantı oluşturun.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>Bu ayar, geçerli sohbet profiliniz **%@** deki mesajlara uygulanır.</target>
@ -7676,6 +7835,10 @@ Bu özellik etkinleştirilmeden önce kimlik doğrulamayı tamamlamanız istenec
<target>Bağlanırken gizli moda geçiş yap.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<target>Araç çubuğu opaklığı</target>
@ -7840,7 +8003,7 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>Susturmayı kaldır</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7872,6 +8035,10 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste
<target>Ayarları güncelleyelim mi?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>Ayarların güncellenmesi, istemciyi tüm sunuculara yeniden bağlayacaktır.</target>
@ -7931,6 +8098,10 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste
<target>SimpleX Chat sunucuları kullanılsın mı?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>Sohbeti kullan</target>
@ -8003,6 +8174,10 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste
<target>Uygulamayı tek elle kullan.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Kullanıcı seçimi</target>
@ -8549,6 +8724,10 @@ Bağlantı isteği tekrarlansın mı?</target>
<target>Grup daveti gönderdiniz</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>Grup sahibinin cihazı çevrimiçi olduğunda gruba bağlanacaksınız, lütfen bekleyin veya daha sonra kontrol edin!</target>
@ -9339,11 +9518,6 @@ Bağlantı isteği tekrarlansın mı?</target>
<target>aylar</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<target>Sessiz</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>asla</target>
@ -9421,6 +9595,14 @@ Bağlantı isteği tekrarlansın mı?</target>
<target>eşler arası</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<target>kuantuma dayanıklı e2e şifreleme</target>
@ -9436,6 +9618,10 @@ Bağlantı isteği tekrarlansın mı?</target>
<target>onaylama alındı…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>geri çevrilmiş çağrı</target>
@ -9569,11 +9755,6 @@ son alınan msj: %2$@</target>
<target>bilinmeyen durum</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<target>susturmayı kaldır</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>korumasız</target>

View file

@ -5,22 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (можна скопіювати)</target>
@ -330,11 +314,6 @@
<target>%u повідомлень пропущено.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<target>(новий)</target>
@ -345,11 +324,6 @@
<target>(цей пристрій v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<target>**Додати контакт**: створити нове посилання-запрошення.</target>
@ -415,11 +389,6 @@
<target>\*жирний*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -456,11 +425,6 @@
- історія редагування.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 сек</target>
@ -528,11 +492,6 @@
<target>30 секунд</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -640,6 +599,10 @@
<target>Помилки підтвердження</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<target>Активні з'єднання</target>
@ -777,8 +740,8 @@
<target>Всі чати та повідомлення будуть видалені - це неможливо скасувати!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -821,6 +784,10 @@
<target>Всі профілі</target>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>Всі ваші контакти залишаться на зв'язку.</target>
@ -896,6 +863,10 @@
<target>Дозволяє безповоротно видаляти надіслані повідомлення. (24 години)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<target>Дозволити надсилати посилання SimpleX.</target>
@ -1058,6 +1029,14 @@
<source>Archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<target>Архівування та завантаження</target>
@ -1076,6 +1055,10 @@
<source>Archive report?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<target>Архівні контакти</target>
@ -1190,6 +1173,10 @@
<target>Кращі групи</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<target>Кращі дати повідомлень.</target>
@ -1210,6 +1197,10 @@
<target>Кращі сповіщення</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<target>Краща безпека ✅</target>
@ -1630,6 +1621,10 @@
<target>Відверта розмова?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<note>No comment provided by engineer.</note>
@ -1773,6 +1768,10 @@
<target>Підтвердити завантаження</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>Підключіться</target>
@ -2775,6 +2774,10 @@ This is your own one-time link!</source>
<target>Не вмикати</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>Більше не показувати</target>
@ -3129,6 +3132,10 @@ This is your own one-time link!</source>
<target>Помилка переходу на інкогніто!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<target>Помилка підключення до сервера переадресації %@. Спробуйте пізніше.</target>
@ -3282,6 +3289,10 @@ This is your own one-time link!</source>
<target>Помилка перепідключення серверів</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>Помилка видалення учасника</target>
@ -3385,6 +3396,10 @@ This is your own one-time link!</source>
<target>Помилка синхронізації з'єднання</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>Помилка оновлення посилання на групу</target>
@ -3465,6 +3480,10 @@ This is your own one-time link!</source>
<target>Розгорнути</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>Експорт бази даних</target>
@ -3505,11 +3524,19 @@ This is your own one-time link!</source>
<target>Швидко і без очікування, поки відправник буде онлайн!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<target>Швидше приєднання та надійніші повідомлення.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Улюблений</target>
@ -3531,9 +3558,9 @@ This is your own one-time link!</source>
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3661,6 +3688,10 @@ This is your own one-time link!</source>
<target>Виправлення не підтримується учасником групи</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<target>Для профілю чату %@:</target>
@ -3676,6 +3707,10 @@ This is your own one-time link!</source>
<target>Наприклад, якщо ваш контакт отримує повідомлення через сервер SimpleX Chat, ваш додаток доставлятиме їх через сервер Flux.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<target>Для приватної маршрутизації</target>
@ -3800,6 +3835,10 @@ Error: %2$@</source>
<target>GIF-файли та наклейки</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<target>Доброго дня!</target>
@ -3914,6 +3953,10 @@ Error: %2$@</source>
<target>Довідка</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>Приховано</target>
@ -4220,6 +4263,26 @@ More improvements are coming soon!</source>
<target>Кольори інтерфейсу</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<target>Неправильний QR-код</target>
@ -4595,6 +4658,10 @@ This is your link for group %@!</source>
<target>Користувач неактивний</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<target>Роль учасника буде змінено на "%@". Усі учасники чату отримають сповіщення.</target>
@ -4630,6 +4697,10 @@ This is your link for group %@!</source>
<target>Учасники групи можуть безповоротно видаляти надіслані повідомлення. (24 години)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<target>Учасники групи можуть надсилати посилання SimpleX.</target>
@ -4655,6 +4726,10 @@ This is your link for group %@!</source>
<target>Учасники групи можуть надсилати голосові повідомлення.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<target>Меню</target>
@ -4901,7 +4976,11 @@ This is your link for group %@!</source>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>Вимкнути звук</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -4953,6 +5032,10 @@ This is your link for group %@!</source>
<target>Стан мережі</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>Новий пароль</target>
@ -5105,6 +5188,10 @@ This is your link for group %@!</source>
<target>Ніяких медіа та файлових серверів.</target>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<target>Ніяких серверів повідомлень.</target>
@ -5160,6 +5247,10 @@ This is your link for group %@!</source>
<target>Немає серверів для надсилання файлів.</target>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<note>No comment provided by engineer.</note>
@ -5198,11 +5289,19 @@ This is your link for group %@!</source>
<target>Сповіщення вимкнено!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<target>Сповіщення про приватність</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -5441,6 +5540,10 @@ Requires compatible VPN.</source>
<target>Або поділитися приватно</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<target>Інше</target>
@ -5632,6 +5735,18 @@ Error: %@</source>
<target>Будь ласка, зберігайте пароль надійно, ви НЕ зможете змінити його, якщо втратите.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Польський інтерфейс</target>
@ -5692,6 +5807,10 @@ Error: %@</source>
<target>Приватні імена файлів</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Маршрутизація приватних повідомлень</target>
@ -5767,6 +5886,10 @@ Error: %@</source>
<target>Заборонити реакції на повідомлення.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<target>Заборонити надсилання посилань SimpleX.</target>
@ -6024,6 +6147,18 @@ Enable in *Network &amp; servers* settings.</source>
<target>Зменшення використання акумулятора</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>Відхилити</target>
@ -6153,6 +6288,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Report violation: only group moderators will see it.</source>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<note>No comment provided by engineer.</note>
@ -6577,6 +6720,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Надсилати сповіщення</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>Надсилайте запитання та ідеї</target>
@ -6816,6 +6963,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Встановіть його замість аутентифікації системи.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>Встановити пароль</target>
@ -7278,6 +7429,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Тайм-аут TCP-з'єднання</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -7353,6 +7508,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Тест завершився невдало на кроці %@.</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>Тестовий сервер</target>
@ -7480,10 +7639,6 @@ It can happen because of some bug or when the connection is compromised.</source
<target>Профіль доступний лише вашим контактам.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<target>Такі ж умови діятимуть і для оператора **%@**.</target>
@ -7613,6 +7768,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>Це посилання було використано з іншого мобільного пристрою, будь ласка, створіть нове посилання на робочому столі.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>Це налаштування застосовується до повідомлень у вашому поточному профілі чату **%@**.</target>
@ -7725,6 +7884,10 @@ You will be prompted to complete authentication before this feature is enabled.<
<target>Увімкніть інкогніто при підключенні.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<target>Непрозорість панелі інструментів</target>
@ -7890,7 +8053,7 @@ To connect, please ask your contact to create another connection link and check
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>Увімкнути звук</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7922,6 +8085,10 @@ To connect, please ask your contact to create another connection link and check
<target>Оновити налаштування?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>Оновлення налаштувань призведе до перепідключення клієнта до всіх серверів.</target>
@ -7982,6 +8149,10 @@ To connect, please ask your contact to create another connection link and check
<target>Використовувати сервери SimpleX Chat?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>Використовуйте чат</target>
@ -8057,6 +8228,10 @@ To connect, please ask your contact to create another connection link and check
<target>Використовуйте додаток однією рукою.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Вибір користувача</target>
@ -8610,6 +8785,10 @@ Repeat connection request?</source>
<target>Ви надіслали запрошення до групи</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>Ви будете підключені до групи, коли пристрій господаря групи буде в мережі, будь ласка, зачекайте або перевірте пізніше!</target>
@ -9404,11 +9583,6 @@ Repeat connection request?</source>
<target>місяців</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<target>приглушити</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>ніколи</target>
@ -9486,6 +9660,14 @@ Repeat connection request?</source>
<target>одноранговий</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<target>квантово-стійке шифрування e2e</target>
@ -9501,6 +9683,10 @@ Repeat connection request?</source>
<target>отримали підтвердження…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>відхилений виклик</target>
@ -9635,11 +9821,6 @@ last received msg: %2$@</source>
<target>невідомий статус</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<target>увімкнути звук</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>незахищені</target>

View file

@ -5,22 +5,6 @@
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.4" build-num="15F31d"/>
</header>
<body>
<trans-unit id="&#10;" xml:space="preserve">
<source>
</source>
<target>
</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" " xml:space="preserve">
<source> </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (" xml:space="preserve">
<source> (</source>
<target> (</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve">
<source> (can be copied)</source>
<target> (可复制)</target>
@ -322,11 +306,6 @@
<target>已跳过 %u 条消息。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(" xml:space="preserve">
<source>(</source>
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<target>(新)</target>
@ -337,11 +316,6 @@
<target>(此设备 v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create 1-time link**: to create and share a new invitation link." xml:space="preserve">
<source>**Create 1-time link**: to create and share a new invitation link.</source>
<target>**添加联系人**: 创建新的邀请链接,或通过您收到的链接进行连接.</target>
@ -406,11 +380,6 @@
<target>\*加粗*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<target>, </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!&#10;- delivery receipts (up to 20 members).&#10;- faster and more stable." xml:space="preserve">
<source>- connect to [directory service](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)!
- delivery receipts (up to 20 members).
@ -447,11 +416,6 @@
- 编辑消息历史。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<source>.</source>
<target>.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 秒</target>
@ -517,11 +481,6 @@
<target>30秒</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<source>: </source>
<target>: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="&lt;p&gt;Hi!&lt;/p&gt;&#10;&lt;p&gt;&lt;a href=&quot;%@&quot;&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;" xml:space="preserve">
<source>&lt;p&gt;Hi!&lt;/p&gt;
&lt;p&gt;&lt;a href="%@"&gt;Connect to me via SimpleX Chat&lt;/a&gt;&lt;/p&gt;</source>
@ -626,6 +585,10 @@
<target>确认错误</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active" xml:space="preserve">
<source>Active</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<target>活动连接</target>
@ -756,8 +719,8 @@
<target>所有聊天记录和消息将被删除——这一行为无法撤销!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All chats will be removed from the list (text), and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list (text), and the list deleted.</source>
<trans-unit id="All chats will be removed from the list %@, and the list deleted." xml:space="preserve">
<source>All chats will be removed from the list %@, and the list deleted.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve">
@ -799,6 +762,10 @@
<target>所有配置文件</target>
<note>profile dropdown</note>
</trans-unit>
<trans-unit id="All reports will be archived for you." xml:space="preserve">
<source>All reports will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
<target>所有联系人会保持连接。</target>
@ -874,6 +841,10 @@
<target>允许不可撤回地删除已发送消息</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to report messsages to moderators." xml:space="preserve">
<source>Allow to report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<target>允许发送 SimpleX 链接。</target>
@ -1035,6 +1006,14 @@
<source>Archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive %lld reports?" xml:space="preserve">
<source>Archive %lld reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive all reports?" xml:space="preserve">
<source>Archive all reports?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<target>存档和上传</target>
@ -1053,6 +1032,10 @@
<source>Archive report?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive reports" xml:space="preserve">
<source>Archive reports</source>
<note>swipe action</note>
</trans-unit>
<trans-unit id="Archived contacts" xml:space="preserve">
<source>Archived contacts</source>
<target>已存档的联系人</target>
@ -1165,6 +1148,10 @@
<target>更佳的群组</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups performance" xml:space="preserve">
<source>Better groups performance</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
@ -1183,6 +1170,10 @@
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better privacy and security" xml:space="preserve">
<source>Better privacy and security</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
@ -1590,6 +1581,10 @@
<target>清除对话吗?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear group?" xml:space="preserve">
<source>Clear group?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear or delete group?" xml:space="preserve">
<source>Clear or delete group?</source>
<note>No comment provided by engineer.</note>
@ -1724,6 +1719,10 @@
<target>确认上传</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirmed" xml:space="preserve">
<source>Confirmed</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>连接</target>
@ -2715,6 +2714,10 @@ This is your own one-time link!</source>
<target>不要启用</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't miss important messages." xml:space="preserve">
<source>Don't miss important messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>不再显示</target>
@ -3062,6 +3065,10 @@ This is your own one-time link!</source>
<source>Error changing to incognito!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error checking token status" xml:space="preserve">
<source>Error checking token status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
<source>Error connecting to forwarding server %@. Please try later.</source>
<target>连接到转发服务器 %@ 时出错。请稍后尝试。</target>
@ -3213,6 +3220,10 @@ This is your own one-time link!</source>
<target>重新连接服务器时出错</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error registering for notifications" xml:space="preserve">
<source>Error registering for notifications</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>删除成员错误</target>
@ -3314,6 +3325,10 @@ This is your own one-time link!</source>
<target>同步连接错误</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error testing server connection" xml:space="preserve">
<source>Error testing server connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error updating group link" xml:space="preserve">
<source>Error updating group link</source>
<target>更新群组链接错误</target>
@ -3392,6 +3407,10 @@ This is your own one-time link!</source>
<target>展开</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Expired" xml:space="preserve">
<source>Expired</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
<source>Export database</source>
<target>导出数据库</target>
@ -3432,11 +3451,19 @@ This is your own one-time link!</source>
<target>快速且无需等待发件人在线!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster deletion of groups." xml:space="preserve">
<source>Faster deletion of groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster joining and more reliable messages." xml:space="preserve">
<source>Faster joining and more reliable messages.</source>
<target>加入速度更快、信息更可靠。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Faster sending messages." xml:space="preserve">
<source>Faster sending messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>最喜欢</target>
@ -3456,9 +3483,9 @@ This is your own one-time link!</source>
%@</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="File is blocked by server operator:&#10;(info.reason.text)." xml:space="preserve">
<trans-unit id="File is blocked by server operator:&#10;%@." xml:space="preserve">
<source>File is blocked by server operator:
(info.reason.text).</source>
%@.</source>
<note>file error text</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@ -3586,6 +3613,10 @@ This is your own one-time link!</source>
<target>修复群组成员不支持的问题</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For all moderators" xml:space="preserve">
<source>For all moderators</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For chat profile %@:" xml:space="preserve">
<source>For chat profile %@:</source>
<note>servers error</note>
@ -3599,6 +3630,10 @@ This is your own one-time link!</source>
<source>For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For me" xml:space="preserve">
<source>For me</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="For private routing" xml:space="preserve">
<source>For private routing</source>
<note>No comment provided by engineer.</note>
@ -3716,6 +3751,10 @@ Error: %2$@</source>
<target>GIF 和贴纸</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Get notified when mentioned." xml:space="preserve">
<source>Get notified when mentioned.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<target>下午好!</target>
@ -3830,6 +3869,10 @@ Error: %2$@</source>
<target>帮助</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Help admins moderating their groups." xml:space="preserve">
<source>Help admins moderating their groups.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hidden" xml:space="preserve">
<source>Hidden</source>
<target>隐藏</target>
@ -4131,6 +4174,26 @@ More improvements are coming soon!</source>
<target>界面颜色</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid" xml:space="preserve">
<source>Invalid</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (bad token)" xml:space="preserve">
<source>Invalid (bad token)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (expired)" xml:space="preserve">
<source>Invalid (expired)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (unregistered)" xml:space="preserve">
<source>Invalid (unregistered)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid (wrong topic)" xml:space="preserve">
<source>Invalid (wrong topic)</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
<source>Invalid QR code</source>
<target>无效的二维码</target>
@ -4503,6 +4566,10 @@ This is your link for group %@!</source>
<target>成员不活跃</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member reports" xml:space="preserve">
<source>Member reports</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All chat members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All chat members will be notified.</source>
<note>No comment provided by engineer.</note>
@ -4536,6 +4603,10 @@ This is your link for group %@!</source>
<target>群组成员可以不可撤回地删除已发送的消息</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can report messsages to moderators." xml:space="preserve">
<source>Members can report messsages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Members can send SimpleX links." xml:space="preserve">
<source>Members can send SimpleX links.</source>
<target>群成员可发送 SimpleX 链接。</target>
@ -4561,6 +4632,10 @@ This is your link for group %@!</source>
<target>群组成员可以发送语音消息。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mention members 👋" xml:space="preserve">
<source>Mention members 👋</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<target>菜单</target>
@ -4804,7 +4879,11 @@ This is your link for group %@!</source>
<trans-unit id="Mute" xml:space="preserve">
<source>Mute</source>
<target>静音</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Mute all" xml:space="preserve">
<source>Mute all</source>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Muted when inactive!" xml:space="preserve">
<source>Muted when inactive!</source>
@ -4854,6 +4933,10 @@ This is your link for group %@!</source>
<target>网络状态</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New" xml:space="preserve">
<source>New</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="New Passcode" xml:space="preserve">
<source>New Passcode</source>
<target>新密码</target>
@ -5001,6 +5084,10 @@ This is your link for group %@!</source>
<source>No media &amp; file servers.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No message" xml:space="preserve">
<source>No message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No message servers." xml:space="preserve">
<source>No message servers.</source>
<note>servers error</note>
@ -5049,6 +5136,10 @@ This is your link for group %@!</source>
<source>No servers to send files.</source>
<note>servers error</note>
</trans-unit>
<trans-unit id="No token!" xml:space="preserve">
<source>No token!</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="No unread chats" xml:space="preserve">
<source>No unread chats</source>
<note>No comment provided by engineer.</note>
@ -5086,10 +5177,18 @@ This is your link for group %@!</source>
<target>通知被禁用!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications error" xml:space="preserve">
<source>Notifications error</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications privacy" xml:space="preserve">
<source>Notifications privacy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Notifications status" xml:space="preserve">
<source>Notifications status</source>
<note>alert title</note>
</trans-unit>
<trans-unit id="Now admins can:&#10;- delete members' messages.&#10;- disable members (&quot;observer&quot; role)" xml:space="preserve">
<source>Now admins can:
- delete members' messages.
@ -5321,6 +5420,10 @@ Requires compatible VPN.</source>
<source>Or to share privately</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Organize chats into lists" xml:space="preserve">
<source>Organize chats into lists</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<target>其他</target>
@ -5509,6 +5612,18 @@ Error: %@</source>
<target>请安全地保存密码,如果您丢失了密码,您将无法更改它。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try to disable and re-enable notfications." xml:space="preserve">
<source>Please try to disable and re-enable notfications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token activation to complete." xml:space="preserve">
<source>Please wait for token activation to complete.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Please wait for token to be registered." xml:space="preserve">
<source>Please wait for token to be registered.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>波兰语界面</target>
@ -5566,6 +5681,10 @@ Error: %@</source>
<target>私密文件名</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private media file names." xml:space="preserve">
<source>Private media file names.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>私有消息路由</target>
@ -5641,6 +5760,10 @@ Error: %@</source>
<target>禁止消息回应。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit reporting messages to moderators." xml:space="preserve">
<source>Prohibit reporting messages to moderators.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<target>禁止发送 SimpleX 链接。</target>
@ -5897,6 +6020,18 @@ Enable in *Network &amp; servers* settings.</source>
<target>减少电池使用量</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register" xml:space="preserve">
<source>Register</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Register notification token?" xml:space="preserve">
<source>Register notification token?</source>
<note>token info</note>
</trans-unit>
<trans-unit id="Registered" xml:space="preserve">
<source>Registered</source>
<note>token status text</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>拒绝</target>
@ -6025,6 +6160,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Report violation: only group moderators will see it.</source>
<note>report reason</note>
</trans-unit>
<trans-unit id="Report: %@" xml:space="preserve">
<source>Report: %@</source>
<note>report in notification</note>
</trans-unit>
<trans-unit id="Reporting messages to moderators is prohibited." xml:space="preserve">
<source>Reporting messages to moderators is prohibited.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reports" xml:space="preserve">
<source>Reports</source>
<note>No comment provided by engineer.</note>
@ -6443,6 +6586,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>发送通知</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send private reports" xml:space="preserve">
<source>Send private reports</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send questions and ideas" xml:space="preserve">
<source>Send questions and ideas</source>
<target>发送问题和想法</target>
@ -6677,6 +6824,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>设置它以代替系统身份验证。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set message expiration in chats." xml:space="preserve">
<source>Set message expiration in chats.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passcode" xml:space="preserve">
<source>Set passcode</source>
<target>设置密码</target>
@ -7125,6 +7276,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>TCP 连接超时</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP port for messaging" xml:space="preserve">
<source>TCP port for messaging</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="TCP_KEEPCNT" xml:space="preserve">
<source>TCP_KEEPCNT</source>
<target>TCP_KEEPCNT</target>
@ -7198,6 +7353,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>在步骤 %@ 上测试失败。</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test notifications" xml:space="preserve">
<source>Test notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
<source>Test server</source>
<target>测试服务器</target>
@ -7323,10 +7482,6 @@ It can happen because of some bug or when the connection is compromised.</source
<target>该资料仅与您的联系人共享。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The report will be archived for you." xml:space="preserve">
<source>The report will be archived for you.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The same conditions will apply to operator **%@**." xml:space="preserve">
<source>The same conditions will apply to operator **%@**.</source>
<note>No comment provided by engineer.</note>
@ -7450,6 +7605,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>此链接已在其他移动设备上使用,请在桌面上创建新链接。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This message was deleted or not received yet." xml:space="preserve">
<source>This message was deleted or not received yet.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
<source>This setting applies to messages in your current chat profile **%@**.</source>
<target>此设置适用于您当前聊天资料 **%@** 中的消息。</target>
@ -7556,6 +7715,10 @@ You will be prompted to complete authentication before this feature is enabled.<
<target>在连接时切换隐身模式。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Token status: %@." xml:space="preserve">
<source>Token status: %@.</source>
<note>token status</note>
</trans-unit>
<trans-unit id="Toolbar opacity" xml:space="preserve">
<source>Toolbar opacity</source>
<target>工具栏不透明度</target>
@ -7720,7 +7883,7 @@ To connect, please ask your contact to create another connection link and check
<trans-unit id="Unmute" xml:space="preserve">
<source>Unmute</source>
<target>取消静音</target>
<note>swipe action</note>
<note>notification label action</note>
</trans-unit>
<trans-unit id="Unread" xml:space="preserve">
<source>Unread</source>
@ -7752,6 +7915,10 @@ To connect, please ask your contact to create another connection link and check
<target>更新设置?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updated conditions" xml:space="preserve">
<source>Updated conditions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>更新设置会将客户端重新连接到所有服务器。</target>
@ -7810,6 +7977,10 @@ To connect, please ask your contact to create another connection link and check
<target>使用 SimpleX Chat 服务器?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use TCP port %@ when no port is specified." xml:space="preserve">
<source>Use TCP port %@ when no port is specified.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use chat" xml:space="preserve">
<source>Use chat</source>
<target>使用聊天</target>
@ -7882,6 +8053,10 @@ To connect, please ask your contact to create another connection link and check
<target>用一只手使用应用程序。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use web port" xml:space="preserve">
<source>Use web port</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>用户选择</target>
@ -8427,6 +8602,10 @@ Repeat connection request?</source>
<target>您发送了群组邀请</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You should receive notifications." xml:space="preserve">
<source>You should receive notifications.</source>
<note>token info</note>
</trans-unit>
<trans-unit id="You will be connected to group when the group host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected to group when the group host's device is online, please wait or check later!</source>
<target>您将在组主设备上线时连接到该群组,请稍等或稍后再检查!</target>
@ -9213,11 +9392,6 @@ Repeat connection request?</source>
<target>月</target>
<note>time unit</note>
</trans-unit>
<trans-unit id="mute" xml:space="preserve">
<source>mute</source>
<target>静音</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="never" xml:space="preserve">
<source>never</source>
<target>从不</target>
@ -9295,6 +9469,14 @@ Repeat connection request?</source>
<target>点对点</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending" xml:space="preserve">
<source>pending</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="pending approval" xml:space="preserve">
<source>pending approval</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<target>抗量子端到端加密</target>
@ -9310,6 +9492,10 @@ Repeat connection request?</source>
<target>已受到确认……</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected" xml:space="preserve">
<source>rejected</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="rejected call" xml:space="preserve">
<source>rejected call</source>
<target>拒接来电</target>
@ -9443,11 +9629,6 @@ last received msg: %2$@</source>
<target>未知状态</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unmute" xml:space="preserve">
<source>unmute</source>
<target>取消静音</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>未受保护</target>

View file

@ -790,7 +790,12 @@ func receivedMsgNtf(_ res: ChatResponse) async -> (String, NSENotificationData)?
cItem = autoReceiveFile(file) ?? cItem
}
let ntf: NSENotificationData = (cInfo.ntfsEnabled(chatItem: cItem) && cItem.showNotification) ? .messageReceived(user, cInfo, cItem) : .noNtf
return (chatItem.chatId, ntf)
let chatIdOrMemberId = if case let .groupRcv(groupMember) = chatItem.chatItem.chatDir {
groupMember.id
} else {
chatItem.chatInfo.id
}
return (chatIdOrMemberId, ntf)
} else {
return nil
}

View file

@ -1,7 +1,3 @@
/*
Localizable.strings
SimpleX
/* notification body */
"New messages in %d chats" = "Nowe wiadomości w %d czatach";
Created by EP on 30/07/2024.
Copyright © 2024 SimpleX Chat. All rights reserved.
*/

View file

@ -17,7 +17,7 @@
"Comment" = "Hozzászólás";
/* No comment provided by engineer. */
"Currently maximum supported file size is %@." = "Jelenleg a maximálisan támogatott fájlméret: %@.";
"Currently maximum supported file size is %@." = "Jelenleg támogatott legnagyobb fájl méret: %@.";
/* No comment provided by engineer. */
"Database downgrade required" = "Adatbázis visszafejlesztése szükséges";
@ -92,7 +92,7 @@
"Share" = "Megosztás";
/* No comment provided by engineer. */
"Slow network?" = "Lassú internetkapcsolat?";
"Slow network?" = "Lassú a hálózata?";
/* No comment provided by engineer. */
"Unknown database error: %@" = "Ismeretlen adatbázishiba: %@";

View file

@ -166,17 +166,17 @@
647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; };
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; };
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */; };
649B28DD2CFE07CF00536B68 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28D82CFE07CF00536B68 /* libffi.a */; };
649B28DE2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28D92CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a */; };
649B28DF2CFE07CF00536B68 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28DA2CFE07CF00536B68 /* libgmpxx.a */; };
649B28E02CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28DB2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a */; };
649B28E12CFE07CF00536B68 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28DC2CFE07CF00536B68 /* libgmp.a */; };
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; };
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; };
64AA1C6C27F3537400AC7277 /* DeletedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */; };
64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */; };
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; };
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; };
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; };
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H-ghc9.6.3.a */; };
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H.a */; };
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; };
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; };
64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; };
64D0C2C629FAC1EC00B38D5F /* AddContactLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C529FAC1EC00B38D5F /* AddContactLearnMore.swift */; };
@ -198,9 +198,14 @@
8C8118722C220B5B00E6FC94 /* Yams in Frameworks */ = {isa = PBXBuildFile; productRef = 8C8118712C220B5B00E6FC94 /* Yams */; };
8C81482C2BD91CD4002CBEC3 /* AudioDevicePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C81482B2BD91CD4002CBEC3 /* AudioDevicePicker.swift */; };
8C9BC2652C240D5200875A27 /* ThemeModeEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C9BC2642C240D5100875A27 /* ThemeModeEditor.swift */; };
8CAD466F2D15A8100078D18F /* ChatScrollHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CAD466E2D15A8100078D18F /* ChatScrollHelpers.swift */; };
8CAEF1502D11A6A000240F00 /* ChatItemsLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CAEF14F2D11A6A000240F00 /* ChatItemsLoader.swift */; };
8CB15EA02CFDA30600C28209 /* ChatItemsMerger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CB15E9F2CFDA30600C28209 /* ChatItemsMerger.swift */; };
8CB3476C2CF5CFFA006787A5 /* Ink in Frameworks */ = {isa = PBXBuildFile; productRef = 8CB3476B2CF5CFFA006787A5 /* Ink */; };
8CB3476E2CF5F58B006787A5 /* ConditionsWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CB3476D2CF5F58B006787A5 /* ConditionsWebView.swift */; };
8CBC14862D357CDB00BBD901 /* StorageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CBC14852D357CDB00BBD901 /* StorageView.swift */; };
8CC317442D4FEB9B00292A20 /* EndlessScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC317432D4FEB9B00292A20 /* EndlessScrollView.swift */; };
8CC317462D4FEBA800292A20 /* ScrollViewCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC317452D4FEBA800292A20 /* ScrollViewCells.swift */; };
8CC4ED902BD7B8530078AEE8 /* CallAudioDeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */; };
8CC956EE2BC0041000412A11 /* NetworkObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC956ED2BC0041000412A11 /* NetworkObserver.swift */; };
8CE848A32C5A0FA000D5C7C8 /* SelectableChatItemToolbars.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CE848A22C5A0FA000D5C7C8 /* SelectableChatItemToolbars.swift */; };
@ -225,7 +230,6 @@
CEE723B12C3BD3D70009AE93 /* SimpleX SE.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = CEE723A72C3BD3D70009AE93 /* SimpleX SE.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
CEE723F02C3D25C70009AE93 /* ShareView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEE723EF2C3D25C70009AE93 /* ShareView.swift */; };
CEE723F22C3D25ED0009AE93 /* ShareModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEE723F12C3D25ED0009AE93 /* ShareModel.swift */; };
CEEA861D2C2ABCB50084E1EA /* ReverseList.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEA861C2C2ABCB50084E1EA /* ReverseList.swift */; };
CEFB2EDF2CA1BCC7004B1ECE /* SheetRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFB2EDE2CA1BCC7004B1ECE /* SheetRepresentable.swift */; };
D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; };
D72A9088294BD7A70047C86D /* NativeTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A9087294BD7A70047C86D /* NativeTextEditor.swift */; };
@ -519,17 +523,17 @@
648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = "<group>"; };
648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemForwardingView.swift; sourceTree = "<group>"; };
6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
649B28D82CFE07CF00536B68 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
649B28D92CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a"; sourceTree = "<group>"; };
649B28DA2CFE07CF00536B68 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
649B28DB2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a"; sourceTree = "<group>"; };
649B28DC2CFE07CF00536B68 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = "<group>"; };
649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; };
64AA1C6827EE10C800AC7277 /* ContextItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextItemView.swift; sourceTree = "<group>"; };
64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedItemView.swift; sourceTree = "<group>"; };
64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemInfoView.swift; sourceTree = "<group>"; };
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H-ghc9.6.3.a"; sourceTree = "<group>"; };
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H.a"; sourceTree = "<group>"; };
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = "<group>"; };
64D0C2C529FAC1EC00B38D5F /* AddContactLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContactLearnMore.swift; sourceTree = "<group>"; };
@ -551,8 +555,13 @@
8C852B072C1086D100BA61E8 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = "<group>"; };
8C86EBE42C0DAE4F00E12243 /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
8C9BC2642C240D5100875A27 /* ThemeModeEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeModeEditor.swift; sourceTree = "<group>"; };
8CAD466E2D15A8100078D18F /* ChatScrollHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatScrollHelpers.swift; sourceTree = "<group>"; };
8CAEF14F2D11A6A000240F00 /* ChatItemsLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemsLoader.swift; sourceTree = "<group>"; };
8CB15E9F2CFDA30600C28209 /* ChatItemsMerger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemsMerger.swift; sourceTree = "<group>"; };
8CB3476D2CF5F58B006787A5 /* ConditionsWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConditionsWebView.swift; sourceTree = "<group>"; };
8CBC14852D357CDB00BBD901 /* StorageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageView.swift; sourceTree = "<group>"; };
8CC317432D4FEB9B00292A20 /* EndlessScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EndlessScrollView.swift; sourceTree = "<group>"; };
8CC317452D4FEBA800292A20 /* ScrollViewCells.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollViewCells.swift; sourceTree = "<group>"; };
8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallAudioDeviceManager.swift; sourceTree = "<group>"; };
8CC956ED2BC0041000412A11 /* NetworkObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkObserver.swift; sourceTree = "<group>"; };
8CE848A22C5A0FA000D5C7C8 /* SelectableChatItemToolbars.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectableChatItemToolbars.swift; sourceTree = "<group>"; };
@ -576,7 +585,6 @@
CEE723D42C3C21F50009AE93 /* SimpleX SE.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX SE.entitlements"; sourceTree = "<group>"; };
CEE723EF2C3D25C70009AE93 /* ShareView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareView.swift; sourceTree = "<group>"; };
CEE723F12C3D25ED0009AE93 /* ShareModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareModel.swift; sourceTree = "<group>"; };
CEEA861C2C2ABCB50084E1EA /* ReverseList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseList.swift; sourceTree = "<group>"; };
CEFB2EDE2CA1BCC7004B1ECE /* SheetRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetRepresentable.swift; sourceTree = "<group>"; };
D72A9087294BD7A70047C86D /* NativeTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTextEditor.swift; sourceTree = "<group>"; };
D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
@ -675,14 +683,14 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
649B28DF2CFE07CF00536B68 /* libgmpxx.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
649B28E12CFE07CF00536B68 /* libgmp.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
649B28E02CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a in Frameworks */,
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */,
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */,
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */,
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H-ghc9.6.3.a in Frameworks */,
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H.a in Frameworks */,
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
649B28DE2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a in Frameworks */,
649B28DD2CFE07CF00536B68 /* libffi.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -737,6 +745,8 @@
5C5F4AC227A5E9AF00B51EF1 /* Chat */ = {
isa = PBXGroup;
children = (
8CC317452D4FEBA800292A20 /* ScrollViewCells.swift */,
8CC317432D4FEB9B00292A20 /* EndlessScrollView.swift */,
6440CA01288AEC770062C672 /* Group */,
5CE4407427ADB657007B033A /* ChatItem */,
5CEACCE527DE977C000BD591 /* ComposeMessage */,
@ -747,11 +757,13 @@
5CE4407127ADB1D0007B033A /* Emoji.swift */,
5CADE79B292131E900072E13 /* ContactPreferencesView.swift */,
5CBE6C11294487F7002D9531 /* VerifyCodeView.swift */,
CEEA861C2C2ABCB50084E1EA /* ReverseList.swift */,
5CBE6C132944CC12002D9531 /* ScanCodeView.swift */,
64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */,
648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */,
8CE848A22C5A0FA000D5C7C8 /* SelectableChatItemToolbars.swift */,
8CB15E9F2CFDA30600C28209 /* ChatItemsMerger.swift */,
8CAEF14F2D11A6A000240F00 /* ChatItemsLoader.swift */,
8CAD466E2D15A8100078D18F /* ChatScrollHelpers.swift */,
);
path = Chat;
sourceTree = "<group>";
@ -759,11 +771,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
649B28D82CFE07CF00536B68 /* libffi.a */,
649B28DC2CFE07CF00536B68 /* libgmp.a */,
649B28DA2CFE07CF00536B68 /* libgmpxx.a */,
649B28D92CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a */,
649B28DB2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a */,
64C829992D54AEEE006B9E89 /* libffi.a */,
64C829982D54AEED006B9E89 /* libgmp.a */,
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */,
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H-ghc9.6.3.a */,
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.0.8-3RDt4h0Fq4hJV00CU7V8H.a */,
);
path = Libraries;
sourceTree = "<group>";
@ -1408,8 +1420,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CEEA861D2C2ABCB50084E1EA /* ReverseList.swift in Sources */,
64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */,
8CC317442D4FEB9B00292A20 /* EndlessScrollView.swift in Sources */,
640417CE2B29B8C200CCB412 /* NewChatView.swift in Sources */,
6440CA03288AECA70062C672 /* AddGroupMembersView.swift in Sources */,
640743612CD360E600158442 /* ChooseServerOperators.swift in Sources */,
@ -1427,6 +1439,7 @@
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */,
644EFFE0292CFD7F00525D5B /* CIVoiceView.swift in Sources */,
6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */,
8CC317462D4FEBA800292A20 /* ScrollViewCells.swift in Sources */,
5C93293129239BED0090FFF9 /* ProtocolServerView.swift in Sources */,
5C9CC7AD28C55D7800BEF955 /* DatabaseEncryptionView.swift in Sources */,
8C74C3EC2C1B92A900039E77 /* Theme.swift in Sources */,
@ -1516,6 +1529,7 @@
5C6BA667289BD954009B8ECC /* DismissSheets.swift in Sources */,
5C577F7D27C83AA10006112D /* MarkdownHelp.swift in Sources */,
6407BA83295DA85D0082BA18 /* CIInvalidJSONView.swift in Sources */,
8CAD466F2D15A8100078D18F /* ChatScrollHelpers.swift in Sources */,
644EFFDE292BCD9D00525D5B /* ComposeVoiceView.swift in Sources */,
5CA059EB279559F40002BEB4 /* SimpleXApp.swift in Sources */,
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */,
@ -1527,6 +1541,7 @@
5CADE79C292131E900072E13 /* ContactPreferencesView.swift in Sources */,
CEA6E91C2CBD21B0002B5DB4 /* UserDefault.swift in Sources */,
5CB346E52868AA7F001FD2EF /* SuspendChat.swift in Sources */,
8CAEF1502D11A6A000240F00 /* ChatItemsLoader.swift in Sources */,
5C9C2DA52894777E00CC63B1 /* GroupProfileView.swift in Sources */,
5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */,
8C81482C2BD91CD4002CBEC3 /* AudioDevicePicker.swift in Sources */,
@ -1566,6 +1581,7 @@
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */,
8CC4ED902BD7B8530078AEE8 /* CallAudioDeviceManager.swift in Sources */,
18415C6C56DBCEC2CBBD2F11 /* WebRTCClient.swift in Sources */,
8CB15EA02CFDA30600C28209 /* ChatItemsMerger.swift in Sources */,
184152CEF68D2336FC2EBCB0 /* CallViewRenderers.swift in Sources */,
5CB634AD29E46CF70066AD6B /* LocalAuthView.swift in Sources */,
18415FEFE153C5920BFB7828 /* GroupWelcomeView.swift in Sources */,
@ -1947,7 +1963,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 261;
CURRENT_PROJECT_VERSION = 269;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@ -1973,6 +1989,7 @@
);
LLVM_LTO = YES_THIN;
MARKETING_VERSION = 6.3;
OTHER_LDFLAGS = "-Wl,-stack_size,0x1000000";
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@ -1996,7 +2013,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 261;
CURRENT_PROJECT_VERSION = 269;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@ -2022,6 +2039,7 @@
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.3;
OTHER_LDFLAGS = "-Wl,-stack_size,0x1000000";
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@ -2037,7 +2055,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 261;
CURRENT_PROJECT_VERSION = 269;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@ -2057,7 +2075,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 261;
CURRENT_PROJECT_VERSION = 269;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@ -2082,7 +2100,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 261;
CURRENT_PROJECT_VERSION = 269;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
@ -2119,7 +2137,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 261;
CURRENT_PROJECT_VERSION = 269;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
@ -2156,7 +2174,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 261;
CURRENT_PROJECT_VERSION = 269;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@ -2207,7 +2225,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 261;
CURRENT_PROJECT_VERSION = 269;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@ -2258,7 +2276,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 261;
CURRENT_PROJECT_VERSION = 269;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@ -2292,7 +2310,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 261;
CURRENT_PROJECT_VERSION = 269;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;

View file

@ -203,7 +203,7 @@ public func chatResponse(_ s: String) -> ChatResponse {
let jChats = jApiChats["chats"] as? NSArray {
let chats = jChats.map { jChat in
if let chatData = try? parseChatData(jChat) {
return chatData
return chatData.0
}
return ChatData.invalidJSON(serializeJSON(jChat, options: .prettyPrinted) ?? "")
}
@ -213,8 +213,8 @@ public func chatResponse(_ s: String) -> ChatResponse {
if let jApiChat = jResp["apiChat"] as? NSDictionary,
let user: UserRef = try? decodeObject(jApiChat["user"] as Any),
let jChat = jApiChat["chat"] as? NSDictionary,
let chat = try? parseChatData(jChat) {
return .apiChat(user: user, chat: chat)
let (chat, navInfo) = try? parseChatData(jChat, jApiChat["navInfo"] as? NSDictionary) {
return .apiChat(user: user, chat: chat, navInfo: navInfo)
}
} else if type == "chatCmdError" {
if let jError = jResp["chatCmdError"] as? NSDictionary {
@ -247,10 +247,11 @@ private func errorJson(_ jDict: NSDictionary) -> String? {
}
}
func parseChatData(_ jChat: Any) throws -> ChatData {
func parseChatData(_ jChat: Any, _ jNavInfo: Any? = nil) throws -> (ChatData, NavigationInfo) {
let jChatDict = jChat as! NSDictionary
let chatInfo: ChatInfo = try decodeObject(jChatDict["chatInfo"]!)
let chatStats: ChatStats = try decodeObject(jChatDict["chatStats"]!)
let navInfo: NavigationInfo = jNavInfo == nil ? NavigationInfo() : try decodeObject((jNavInfo as! NSDictionary)["navInfo"]!)
let jChatItems = jChatDict["chatItems"] as! NSArray
let chatItems = jChatItems.map { jCI in
if let ci: ChatItem = try? decodeObject(jCI) {
@ -262,7 +263,7 @@ func parseChatData(_ jChat: Any) throws -> ChatData {
json: serializeJSON(jCI, options: .prettyPrinted) ?? ""
)
}
return ChatData(chatInfo: chatInfo, chatItems: chatItems, chatStats: chatStats)
return (ChatData(chatInfo: chatInfo, chatItems: chatItems, chatStats: chatStats), navInfo)
}
func decodeObject<T: Decodable>(_ obj: Any) throws -> T {

View file

@ -42,7 +42,7 @@ public enum ChatCommand {
case apiGetSettings(settings: AppSettings)
case apiGetChatTags(userId: Int64)
case apiGetChats(userId: Int64)
case apiGetChat(type: ChatType, id: Int64, pagination: ChatPagination, search: String)
case apiGetChat(chatId: ChatId, pagination: ChatPagination, search: String)
case apiGetChatItemInfo(type: ChatType, id: Int64, itemId: Int64)
case apiSendMessages(type: ChatType, id: Int64, live: Bool, ttl: Int?, composedMessages: [ComposedMessage])
case apiCreateChatTag(tag: ChatTagData)
@ -55,6 +55,8 @@ public enum ChatCommand {
case apiUpdateChatItem(type: ChatType, id: Int64, itemId: Int64, updatedMessage: UpdatedMessage, live: Bool)
case apiDeleteChatItem(type: ChatType, id: Int64, itemIds: [Int64], mode: CIDeleteMode)
case apiDeleteMemberChatItem(groupId: Int64, itemIds: [Int64])
case apiArchiveReceivedReports(groupId: Int64)
case apiDeleteReceivedReports(groupId: Int64, itemIds: [Int64], mode: CIDeleteMode)
case apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, add: Bool, reaction: MsgReaction)
case apiGetReactionMembers(userId: Int64, groupId: Int64, itemId: Int64, reaction: MsgReaction)
case apiPlanForwardChatItems(toChatType: ChatType, toChatId: Int64, itemIds: [Int64])
@ -62,15 +64,16 @@ public enum ChatCommand {
case apiGetNtfToken
case apiRegisterToken(token: DeviceToken, notificationMode: NotificationsMode)
case apiVerifyToken(token: DeviceToken, nonce: String, code: String)
case apiCheckToken(token: DeviceToken)
case apiDeleteToken(token: DeviceToken)
case apiGetNtfConns(nonce: String, encNtfInfo: String)
case apiGetConnNtfMessages(connIds: [String])
case apiNewGroup(userId: Int64, incognito: Bool, groupProfile: GroupProfile)
case apiAddMember(groupId: Int64, contactId: Int64, memberRole: GroupMemberRole)
case apiJoinGroup(groupId: Int64)
case apiMemberRole(groupId: Int64, memberId: Int64, memberRole: GroupMemberRole)
case apiBlockMemberForAll(groupId: Int64, memberId: Int64, blocked: Bool)
case apiRemoveMember(groupId: Int64, memberId: Int64)
case apiMembersRole(groupId: Int64, memberIds: [Int64], memberRole: GroupMemberRole)
case apiBlockMembersForAll(groupId: Int64, memberIds: [Int64], blocked: Bool)
case apiRemoveMembers(groupId: Int64, memberIds: [Int64], withMessages: Bool)
case apiLeaveGroup(groupId: Int64)
case apiListMembers(groupId: Int64)
case apiUpdateGroupProfile(groupId: Int64, groupProfile: GroupProfile)
@ -209,7 +212,7 @@ public enum ChatCommand {
case let .apiGetSettings(settings): return "/_get app settings \(encodeJSON(settings))"
case let .apiGetChatTags(userId): return "/_get tags \(userId)"
case let .apiGetChats(userId): return "/_get chats \(userId) pcc=on"
case let .apiGetChat(type, id, pagination, search): return "/_get chat \(ref(type, id)) \(pagination.cmdString)" +
case let .apiGetChat(chatId, pagination, search): return "/_get chat \(chatId) \(pagination.cmdString)" +
(search == "" ? "" : " search=\(search)")
case let .apiGetChatItemInfo(type, id, itemId): return "/_get item info \(ref(type, id)) \(itemId)"
case let .apiSendMessages(type, id, live, ttl, composedMessages):
@ -229,6 +232,8 @@ public enum ChatCommand {
case let .apiUpdateChatItem(type, id, itemId, um, live): return "/_update item \(ref(type, id)) \(itemId) live=\(onOff(live)) \(um.cmdString)"
case let .apiDeleteChatItem(type, id, itemIds, mode): return "/_delete item \(ref(type, id)) \(itemIds.map({ "\($0)" }).joined(separator: ",")) \(mode.rawValue)"
case let .apiDeleteMemberChatItem(groupId, itemIds): return "/_delete member item #\(groupId) \(itemIds.map({ "\($0)" }).joined(separator: ","))"
case let .apiArchiveReceivedReports(groupId): return "/_archive reports #\(groupId)"
case let .apiDeleteReceivedReports(groupId, itemIds, mode): return "/_delete reports #\(groupId) \(itemIds.map({ "\($0)" }).joined(separator: ",")) \(mode.rawValue)"
case let .apiChatItemReaction(type, id, itemId, add, reaction): return "/_reaction \(ref(type, id)) \(itemId) \(onOff(add)) \(encodeJSON(reaction))"
case let .apiGetReactionMembers(userId, groupId, itemId, reaction): return "/_reaction members \(userId) #\(groupId) \(itemId) \(encodeJSON(reaction))"
case let .apiPlanForwardChatItems(type, id, itemIds): return "/_forward plan \(ref(type, id)) \(itemIds.map({ "\($0)" }).joined(separator: ","))"
@ -238,15 +243,16 @@ public enum ChatCommand {
case .apiGetNtfToken: return "/_ntf get "
case let .apiRegisterToken(token, notificationMode): return "/_ntf register \(token.cmdString) \(notificationMode.rawValue)"
case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)"
case let .apiCheckToken(token): return "/_ntf check \(token.cmdString)"
case let .apiDeleteToken(token): return "/_ntf delete \(token.cmdString)"
case let .apiGetNtfConns(nonce, encNtfInfo): return "/_ntf conns \(nonce) \(encNtfInfo)"
case let .apiGetConnNtfMessages(connIds): return "/_ntf conn messages \(connIds.joined(separator: ","))"
case let .apiNewGroup(userId, incognito, groupProfile): return "/_group \(userId) incognito=\(onOff(incognito)) \(encodeJSON(groupProfile))"
case let .apiAddMember(groupId, contactId, memberRole): return "/_add #\(groupId) \(contactId) \(memberRole)"
case let .apiJoinGroup(groupId): return "/_join #\(groupId)"
case let .apiMemberRole(groupId, memberId, memberRole): return "/_member role #\(groupId) \(memberId) \(memberRole.rawValue)"
case let .apiBlockMemberForAll(groupId, memberId, blocked): return "/_block #\(groupId) \(memberId) blocked=\(onOff(blocked))"
case let .apiRemoveMember(groupId, memberId): return "/_remove #\(groupId) \(memberId)"
case let .apiMembersRole(groupId, memberIds, memberRole): return "/_member role #\(groupId) \(memberIds.map({ "\($0)" }).joined(separator: ",")) \(memberRole.rawValue)"
case let .apiBlockMembersForAll(groupId, memberIds, blocked): return "/_block #\(groupId) \(memberIds.map({ "\($0)" }).joined(separator: ",")) blocked=\(onOff(blocked))"
case let .apiRemoveMembers(groupId, memberIds, withMessages): return "/_remove #\(groupId) \(memberIds.map({ "\($0)" }).joined(separator: ",")) messages=\(onOff(withMessages))"
case let .apiLeaveGroup(groupId): return "/_leave #\(groupId)"
case let .apiListMembers(groupId): return "/_members #\(groupId)"
case let .apiUpdateGroupProfile(groupId, groupProfile): return "/_group_profile #\(groupId) \(encodeJSON(groupProfile))"
@ -402,6 +408,8 @@ public enum ChatCommand {
case .apiDeleteChatItem: return "apiDeleteChatItem"
case .apiConnectContactViaAddress: return "apiConnectContactViaAddress"
case .apiDeleteMemberChatItem: return "apiDeleteMemberChatItem"
case .apiArchiveReceivedReports: return "apiArchiveReceivedReports"
case .apiDeleteReceivedReports: return "apiDeleteReceivedReports"
case .apiChatItemReaction: return "apiChatItemReaction"
case .apiGetReactionMembers: return "apiGetReactionMembers"
case .apiPlanForwardChatItems: return "apiPlanForwardChatItems"
@ -409,15 +417,16 @@ public enum ChatCommand {
case .apiGetNtfToken: return "apiGetNtfToken"
case .apiRegisterToken: return "apiRegisterToken"
case .apiVerifyToken: return "apiVerifyToken"
case .apiCheckToken: return "apiCheckToken"
case .apiDeleteToken: return "apiDeleteToken"
case .apiGetNtfConns: return "apiGetNtfConns"
case .apiGetConnNtfMessages: return "apiGetConnNtfMessages"
case .apiNewGroup: return "apiNewGroup"
case .apiAddMember: return "apiAddMember"
case .apiJoinGroup: return "apiJoinGroup"
case .apiMemberRole: return "apiMemberRole"
case .apiBlockMemberForAll: return "apiBlockMemberForAll"
case .apiRemoveMember: return "apiRemoveMember"
case .apiMembersRole: return "apiMembersRole"
case .apiBlockMembersForAll: return "apiBlockMembersForAll"
case .apiRemoveMembers: return "apiRemoveMembers"
case .apiLeaveGroup: return "apiLeaveGroup"
case .apiListMembers: return "apiListMembers"
case .apiUpdateGroupProfile: return "apiUpdateGroupProfile"
@ -591,7 +600,7 @@ public enum ChatResponse: Decodable, Error {
case chatStopped
case chatSuspended
case apiChats(user: UserRef, chats: [ChatData])
case apiChat(user: UserRef, chat: ChatData)
case apiChat(user: UserRef, chat: ChatData, navInfo: NavigationInfo?)
case chatTags(user: UserRef, userTags: [ChatTag])
case chatItemInfo(user: UserRef, chatItem: AChatItem, chatItemInfo: ChatItemInfo)
case serverTestResult(user: UserRef, testServer: String, testFailure: ProtocolTestFailure?)
@ -672,18 +681,18 @@ public enum ChatResponse: Decodable, Error {
case userAcceptedGroupSent(user: UserRef, groupInfo: GroupInfo, hostContact: Contact?)
case groupLinkConnecting(user: UserRef, groupInfo: GroupInfo, hostMember: GroupMember)
case businessLinkConnecting(user: UserRef, groupInfo: GroupInfo, hostMember: GroupMember, fromContact: Contact)
case userDeletedMember(user: UserRef, groupInfo: GroupInfo, member: GroupMember)
case userDeletedMembers(user: UserRef, groupInfo: GroupInfo, members: [GroupMember], withMessages: Bool)
case leftMemberUser(user: UserRef, groupInfo: GroupInfo)
case groupMembers(user: UserRef, group: Group)
case receivedGroupInvitation(user: UserRef, groupInfo: GroupInfo, contact: Contact, memberRole: GroupMemberRole)
case groupDeletedUser(user: UserRef, groupInfo: GroupInfo)
case joinedGroupMemberConnecting(user: UserRef, groupInfo: GroupInfo, hostMember: GroupMember, member: GroupMember)
case memberRole(user: UserRef, groupInfo: GroupInfo, byMember: GroupMember, member: GroupMember, fromRole: GroupMemberRole, toRole: GroupMemberRole)
case memberRoleUser(user: UserRef, groupInfo: GroupInfo, member: GroupMember, fromRole: GroupMemberRole, toRole: GroupMemberRole)
case membersRoleUser(user: UserRef, groupInfo: GroupInfo, members: [GroupMember], toRole: GroupMemberRole)
case memberBlockedForAll(user: UserRef, groupInfo: GroupInfo, byMember: GroupMember, member: GroupMember, blocked: Bool)
case memberBlockedForAllUser(user: UserRef, groupInfo: GroupInfo, member: GroupMember, blocked: Bool)
case deletedMemberUser(user: UserRef, groupInfo: GroupInfo, member: GroupMember)
case deletedMember(user: UserRef, groupInfo: GroupInfo, byMember: GroupMember, deletedMember: GroupMember)
case membersBlockedForAllUser(user: UserRef, groupInfo: GroupInfo, members: [GroupMember], blocked: Bool)
case deletedMemberUser(user: UserRef, groupInfo: GroupInfo, member: GroupMember, withMessages: Bool)
case deletedMember(user: UserRef, groupInfo: GroupInfo, byMember: GroupMember, deletedMember: GroupMember, withMessages: Bool)
case leftMember(user: UserRef, groupInfo: GroupInfo, member: GroupMember)
case groupDeleted(user: UserRef, groupInfo: GroupInfo, member: GroupMember)
case contactsMerged(user: UserRef, intoContact: Contact, mergedContact: Contact)
@ -852,16 +861,16 @@ public enum ChatResponse: Decodable, Error {
case .userAcceptedGroupSent: return "userAcceptedGroupSent"
case .groupLinkConnecting: return "groupLinkConnecting"
case .businessLinkConnecting: return "businessLinkConnecting"
case .userDeletedMember: return "userDeletedMember"
case .userDeletedMembers: return "userDeletedMembers"
case .leftMemberUser: return "leftMemberUser"
case .groupMembers: return "groupMembers"
case .receivedGroupInvitation: return "receivedGroupInvitation"
case .groupDeletedUser: return "groupDeletedUser"
case .joinedGroupMemberConnecting: return "joinedGroupMemberConnecting"
case .memberRole: return "memberRole"
case .memberRoleUser: return "memberRoleUser"
case .membersRoleUser: return "membersRoleUser"
case .memberBlockedForAll: return "memberBlockedForAll"
case .memberBlockedForAllUser: return "memberBlockedForAllUser"
case .membersBlockedForAllUser: return "membersBlockedForAllUser"
case .deletedMemberUser: return "deletedMemberUser"
case .deletedMember: return "deletedMember"
case .leftMember: return "leftMember"
@ -949,7 +958,7 @@ public enum ChatResponse: Decodable, Error {
case .chatStopped: return noDetails
case .chatSuspended: return noDetails
case let .apiChats(u, chats): return withUser(u, String(describing: chats))
case let .apiChat(u, chat): return withUser(u, String(describing: chat))
case let .apiChat(u, chat, navInfo): return withUser(u, "chat: \(String(describing: chat))\nnavInfo: \(String(describing: navInfo))")
case let .chatTags(u, userTags): return withUser(u, "userTags: \(String(describing: userTags))")
case let .chatItemInfo(u, chatItem, chatItemInfo): return withUser(u, "chatItem: \(String(describing: chatItem))\nchatItemInfo: \(String(describing: chatItemInfo))")
case let .serverTestResult(u, server, testFailure): return withUser(u, "server: \(server)\nresult: \(String(describing: testFailure))")
@ -1039,18 +1048,18 @@ public enum ChatResponse: Decodable, Error {
case let .userAcceptedGroupSent(u, groupInfo, hostContact): return withUser(u, "groupInfo: \(groupInfo)\nhostContact: \(String(describing: hostContact))")
case let .groupLinkConnecting(u, groupInfo, hostMember): return withUser(u, "groupInfo: \(groupInfo)\nhostMember: \(String(describing: hostMember))")
case let .businessLinkConnecting(u, groupInfo, hostMember, fromContact): return withUser(u, "groupInfo: \(groupInfo)\nhostMember: \(String(describing: hostMember))\nfromContact: \(String(describing: fromContact))")
case let .userDeletedMember(u, groupInfo, member): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)")
case let .userDeletedMembers(u, groupInfo, members, withMessages): return withUser(u, "groupInfo: \(groupInfo)\nmembers: \(members)\nwithMessages: \(withMessages)")
case let .leftMemberUser(u, groupInfo): return withUser(u, String(describing: groupInfo))
case let .groupMembers(u, group): return withUser(u, String(describing: group))
case let .receivedGroupInvitation(u, groupInfo, contact, memberRole): return withUser(u, "groupInfo: \(groupInfo)\ncontact: \(contact)\nmemberRole: \(memberRole)")
case let .groupDeletedUser(u, groupInfo): return withUser(u, String(describing: groupInfo))
case let .joinedGroupMemberConnecting(u, groupInfo, hostMember, member): return withUser(u, "groupInfo: \(groupInfo)\nhostMember: \(hostMember)\nmember: \(member)")
case let .memberRole(u, groupInfo, byMember, member, fromRole, toRole): return withUser(u, "groupInfo: \(groupInfo)\nbyMember: \(byMember)\nmember: \(member)\nfromRole: \(fromRole)\ntoRole: \(toRole)")
case let .memberRoleUser(u, groupInfo, member, fromRole, toRole): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)\nfromRole: \(fromRole)\ntoRole: \(toRole)")
case let .membersRoleUser(u, groupInfo, members, toRole): return withUser(u, "groupInfo: \(groupInfo)\nmembers: \(members)\ntoRole: \(toRole)")
case let .memberBlockedForAll(u, groupInfo, byMember, member, blocked): return withUser(u, "groupInfo: \(groupInfo)\nbyMember: \(byMember)\nmember: \(member)\nblocked: \(blocked)")
case let .memberBlockedForAllUser(u, groupInfo, member, blocked): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)\nblocked: \(blocked)")
case let .deletedMemberUser(u, groupInfo, member): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)")
case let .deletedMember(u, groupInfo, byMember, deletedMember): return withUser(u, "groupInfo: \(groupInfo)\nbyMember: \(byMember)\ndeletedMember: \(deletedMember)")
case let .membersBlockedForAllUser(u, groupInfo, members, blocked): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(members)\nblocked: \(blocked)")
case let .deletedMemberUser(u, groupInfo, member, withMessages): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)\nwithMessages: \(withMessages)")
case let .deletedMember(u, groupInfo, byMember, deletedMember, withMessages): return withUser(u, "groupInfo: \(groupInfo)\nbyMember: \(byMember)\ndeletedMember: \(deletedMember)\nwithMessages: \(withMessages)")
case let .leftMember(u, groupInfo, member): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)")
case let .groupDeleted(u, groupInfo, member): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)")
case let .contactsMerged(u, intoContact, mergedContact): return withUser(u, "intoContact: \(intoContact)\nmergedContact: \(mergedContact)")
@ -1200,10 +1209,15 @@ struct NewUser: Encodable {
}
public enum ChatPagination {
public static let INITIAL_COUNT = 75
public static let PRELOAD_COUNT = 100
public static let UNTIL_PRELOAD_COUNT = 50
case last(count: Int)
case after(chatItemId: Int64, count: Int)
case before(chatItemId: Int64, count: Int)
case around(chatItemId: Int64, count: Int)
case initial(count: Int)
var cmdString: String {
switch self {
@ -1211,6 +1225,7 @@ public enum ChatPagination {
case let .after(chatItemId, count): return "after=\(chatItemId) count=\(count)"
case let .before(chatItemId, count): return "before=\(chatItemId) count=\(count)"
case let .around(chatItemId, count): return "around=\(chatItemId) count=\(count)"
case let .initial(count): return "initial=\(count)"
}
}
}
@ -1218,7 +1233,7 @@ public enum ChatPagination {
public struct ChatTagData: Encodable {
public var emoji: String?
public var text: String
public init(emoji: String?, text: String) {
self.emoji = emoji
self.text = text
@ -1474,7 +1489,7 @@ public struct UserOperatorServers: Identifiable, Equatable, Codable {
}
set { `operator` = newValue }
}
public static var sampleData1 = UserOperatorServers(
operator: ServerOperator.sampleData1,
smpServers: [UserServer.sampleData.preset],
@ -1785,7 +1800,7 @@ public struct NetCfg: Codable, Equatable {
rcvConcurrency: 8,
smpPingInterval: 1200_000_000
)
public var withProxyTimeouts: NetCfg {
var cfg = self
cfg.tcpConnectTimeout = NetCfg.proxyDefaults.tcpConnectTimeout
@ -1795,7 +1810,7 @@ public struct NetCfg: Codable, Equatable {
cfg.smpPingInterval = NetCfg.proxyDefaults.smpPingInterval
return cfg
}
public var hasProxyTimeouts: Bool {
tcpConnectTimeout == NetCfg.proxyDefaults.tcpConnectTimeout &&
tcpTimeout == NetCfg.proxyDefaults.tcpTimeout &&
@ -1928,7 +1943,7 @@ public struct NetworkProxy: Equatable, Codable {
public static var def: NetworkProxy {
NetworkProxy()
}
public var valid: Bool {
let hostOk = switch NWEndpoint.Host(host) {
case .ipv4: true
@ -1939,7 +1954,7 @@ public struct NetworkProxy: Equatable, Codable {
port > 0 && port <= 65535 &&
NetworkProxy.validCredential(username) && NetworkProxy.validCredential(password)
}
public static func validCredential(_ s: String) -> Bool {
!s.contains(":") && !s.contains("@")
}
@ -2039,6 +2054,16 @@ public struct ChatSettings: Codable, Hashable {
public static let defaults: ChatSettings = ChatSettings(enableNtfs: .all, sendRcpts: nil, favorite: false)
}
public struct NavigationInfo: Decodable {
public var afterUnread: Int = 0
public var afterTotal: Int = 0
public init(afterUnread: Int = 0, afterTotal: Int = 0) {
self.afterUnread = afterUnread
self.afterTotal = afterTotal
}
}
public enum MsgFilter: String, Codable, Hashable {
case none
case all
@ -2245,7 +2270,7 @@ public enum NotificationsMode: String, Decodable, SelectableItem {
case .instant: "Instant"
}
}
public var icon: String {
switch self {
case .off: return "arrow.clockwise"
@ -2760,7 +2785,7 @@ public struct AppSettings: Codable, Equatable {
public var uiThemes: [ThemeOverrides]? = nil
public var oneHandUI: Bool? = nil
public var chatBottomBar: Bool? = nil
public func prepareForExport() -> AppSettings {
var empty = AppSettings()
let def = AppSettings.defaults

View file

@ -711,6 +711,7 @@ public enum GroupFeature: String, Decodable, Feature, Hashable {
case voice
case files
case simplexLinks
case reports
case history
public var id: Self { self }
@ -731,6 +732,7 @@ public enum GroupFeature: String, Decodable, Feature, Hashable {
case .voice: true
case .files: true
case .simplexLinks: true
case .reports: false
case .history: false
}
}
@ -744,6 +746,7 @@ public enum GroupFeature: String, Decodable, Feature, Hashable {
case .voice: return NSLocalizedString("Voice messages", comment: "chat feature")
case .files: return NSLocalizedString("Files and media", comment: "chat feature")
case .simplexLinks: return NSLocalizedString("SimpleX links", comment: "chat feature")
case .reports: return NSLocalizedString("Member reports", comment: "chat feature")
case .history: return NSLocalizedString("Visible history", comment: "chat feature")
}
}
@ -757,6 +760,7 @@ public enum GroupFeature: String, Decodable, Feature, Hashable {
case .voice: return "mic"
case .files: return "doc"
case .simplexLinks: return "link.circle"
case .reports: return "flag"
case .history: return "clock"
}
}
@ -770,6 +774,7 @@ public enum GroupFeature: String, Decodable, Feature, Hashable {
case .voice: return "mic.fill"
case .files: return "doc.fill"
case .simplexLinks: return "link.circle.fill"
case .reports: return "flag.fill"
case .history: return "clock.fill"
}
}
@ -819,6 +824,11 @@ public enum GroupFeature: String, Decodable, Feature, Hashable {
case .on: return "Allow to send SimpleX links."
case .off: return "Prohibit sending SimpleX links."
}
case .reports:
switch enabled {
case .on: return "Allow to report messsages to moderators."
case .off: return "Prohibit reporting messages to moderators."
}
case .history:
switch enabled {
case .on: return "Send up to 100 last messages to new members."
@ -862,6 +872,11 @@ public enum GroupFeature: String, Decodable, Feature, Hashable {
case .on: return "Members can send SimpleX links."
case .off: return "SimpleX links are prohibited."
}
case .reports:
switch enabled {
case .on: return "Members can report messsages to moderators."
case .off: return "Reporting messages to moderators is prohibited."
}
case .history:
switch enabled {
case .on: return "Up to 100 last messages are sent to new members."
@ -1007,6 +1022,7 @@ public struct FullGroupPreferences: Decodable, Equatable, Hashable {
public var voice: RoleGroupPreference
public var files: RoleGroupPreference
public var simplexLinks: RoleGroupPreference
public var reports: GroupPreference
public var history: GroupPreference
public init(
@ -1017,6 +1033,7 @@ public struct FullGroupPreferences: Decodable, Equatable, Hashable {
voice: RoleGroupPreference,
files: RoleGroupPreference,
simplexLinks: RoleGroupPreference,
reports: GroupPreference,
history: GroupPreference
) {
self.timedMessages = timedMessages
@ -1026,6 +1043,7 @@ public struct FullGroupPreferences: Decodable, Equatable, Hashable {
self.voice = voice
self.files = files
self.simplexLinks = simplexLinks
self.reports = reports
self.history = history
}
@ -1037,6 +1055,7 @@ public struct FullGroupPreferences: Decodable, Equatable, Hashable {
voice: RoleGroupPreference(enable: .on, role: nil),
files: RoleGroupPreference(enable: .on, role: nil),
simplexLinks: RoleGroupPreference(enable: .on, role: nil),
reports: GroupPreference(enable: .on),
history: GroupPreference(enable: .on)
)
}
@ -1049,6 +1068,7 @@ public struct GroupPreferences: Codable, Hashable {
public var voice: RoleGroupPreference?
public var files: RoleGroupPreference?
public var simplexLinks: RoleGroupPreference?
public var reports: GroupPreference?
public var history: GroupPreference?
public init(
@ -1059,6 +1079,7 @@ public struct GroupPreferences: Codable, Hashable {
voice: RoleGroupPreference? = nil,
files: RoleGroupPreference? = nil,
simplexLinks: RoleGroupPreference? = nil,
reports: GroupPreference? = nil,
history: GroupPreference? = nil
) {
self.timedMessages = timedMessages
@ -1068,6 +1089,7 @@ public struct GroupPreferences: Codable, Hashable {
self.voice = voice
self.files = files
self.simplexLinks = simplexLinks
self.reports = reports
self.history = history
}
@ -1079,6 +1101,7 @@ public struct GroupPreferences: Codable, Hashable {
voice: RoleGroupPreference(enable: .on, role: nil),
files: RoleGroupPreference(enable: .on, role: nil),
simplexLinks: RoleGroupPreference(enable: .on, role: nil),
reports: GroupPreference(enable: .on),
history: GroupPreference(enable: .on)
)
}
@ -1092,6 +1115,7 @@ public func toGroupPreferences(_ fullPreferences: FullGroupPreferences) -> Group
voice: fullPreferences.voice,
files: fullPreferences.files,
simplexLinks: fullPreferences.simplexLinks,
reports: fullPreferences.reports,
history: fullPreferences.history
)
}
@ -1588,6 +1612,7 @@ public struct ChatStats: Decodable, Hashable {
// actual only via getChats() and getChat(.initial), otherwise, zero
public var reportsCount: Int = 0
public var minUnreadItemId: Int64 = 0
// actual only via getChats(), otherwise, false
public var unreadChat: Bool = false
}
@ -2116,11 +2141,13 @@ public struct GroupMember: Identifiable, Decodable, Hashable {
public var memberActive: Bool {
switch memberStatus {
case .memRejected: return false
case .memRemoved: return false
case .memLeft: return false
case .memGroupDeleted: return false
case .memUnknown: return false
case .memInvited: return false
case .memPendingApproval: return true
case .memIntroduced: return false
case .memIntroInvited: return false
case .memAccepted: return false
@ -2133,11 +2160,13 @@ public struct GroupMember: Identifiable, Decodable, Hashable {
public var memberCurrent: Bool {
switch memberStatus {
case .memRejected: return false
case .memRemoved: return false
case .memLeft: return false
case .memGroupDeleted: return false
case .memUnknown: return false
case .memInvited: return false
case .memPendingApproval: return false
case .memIntroduced: return true
case .memIntroInvited: return true
case .memAccepted: return true
@ -2263,11 +2292,13 @@ public enum GroupMemberCategory: String, Decodable, Hashable {
}
public enum GroupMemberStatus: String, Decodable, Hashable {
case memRejected = "rejected"
case memRemoved = "removed"
case memLeft = "left"
case memGroupDeleted = "deleted"
case memUnknown = "unknown"
case memInvited = "invited"
case memPendingApproval = "pending_approval"
case memIntroduced = "introduced"
case memIntroInvited = "intro-inv"
case memAccepted = "accepted"
@ -2278,11 +2309,13 @@ public enum GroupMemberStatus: String, Decodable, Hashable {
public var text: LocalizedStringKey {
switch self {
case .memRejected: return "rejected"
case .memRemoved: return "removed"
case .memLeft: return "left"
case .memGroupDeleted: return "group deleted"
case .memUnknown: return "unknown status"
case .memInvited: return "invited"
case .memPendingApproval: return "pending approval"
case .memIntroduced: return "connecting (introduced)"
case .memIntroInvited: return "connecting (introduction invitation)"
case .memAccepted: return "connecting (accepted)"
@ -2295,11 +2328,13 @@ public enum GroupMemberStatus: String, Decodable, Hashable {
public var shortText: LocalizedStringKey {
switch self {
case .memRejected: return "rejected"
case .memRemoved: return "removed"
case .memLeft: return "left"
case .memGroupDeleted: return "group deleted"
case .memUnknown: return "unknown"
case .memInvited: return "invited"
case .memPendingApproval: return "pending"
case .memIntroduced: return "connecting"
case .memIntroInvited: return "connecting"
case .memAccepted: return "connecting"
@ -2411,13 +2446,6 @@ public struct ChatItemDeletion: Decodable, Hashable {
public struct AChatItem: Decodable, Hashable {
public var chatInfo: ChatInfo
public var chatItem: ChatItem
public var chatId: String {
if case let .groupRcv(groupMember) = chatItem.chatDir {
return groupMember.id
}
return chatInfo.id
}
}
public struct CIMentionMember: Decodable, Hashable {
@ -3238,6 +3266,20 @@ public enum CIForwardedFrom: Decodable, Hashable {
}
}
public var chatTypeApiIdMsgId: (ChatType, Int64, ChatItem.ID?)? {
switch self {
case .unknown: nil
case let .contact(_, _, contactId, msgId):
if let contactId {
(ChatType.direct, contactId, msgId)
} else { nil }
case let .group(_, _, groupId, msgId):
if let groupId {
(ChatType.group, groupId, msgId)
} else { nil }
}
}
public func text(_ chatType: ChatType) -> LocalizedStringKey {
chatType == .local
? (chatName == "" ? "saved" : "saved from \(chatName)")
@ -3506,8 +3548,12 @@ extension MsgReaction: Decodable {
let type = try container.decode(String.self, forKey: CodingKeys.type)
switch type {
case "emoji":
let emoji = try container.decode(MREmojiChar.self, forKey: CodingKeys.emoji)
self = .emoji(emoji: emoji)
do {
let emoji = try container.decode(MREmojiChar.self, forKey: CodingKeys.emoji)
self = .emoji(emoji: emoji)
} catch {
self = .unknown(type: "emoji")
}
default:
self = .unknown(type: type)
}
@ -3781,7 +3827,7 @@ public enum FileError: Decodable, Equatable, Hashable {
public var errorInfo: String {
switch self {
case .auth: NSLocalizedString("Wrong key or unknown file chunk address - most likely file is deleted.", comment: "file error text")
case let .blocked(_, info): NSLocalizedString("File is blocked by server operator:\n\(info.reason.text).", comment: "file error text")
case let .blocked(_, info): String.localizedStringWithFormat(NSLocalizedString("File is blocked by server operator:\n%@.", comment: "file error text"), info.reason.text)
case .noFile: NSLocalizedString("File not found - most likely file was deleted or cancelled.", comment: "file error text")
case let .relay(srvError): String.localizedStringWithFormat(NSLocalizedString("File server error: %@", comment: "file error text"), srvError.errorInfo)
case let .other(fileError): String.localizedStringWithFormat(NSLocalizedString("Error: %@", comment: "file error text"), fileError)
@ -4124,9 +4170,61 @@ public enum NtfTknStatus: String, Decodable, Hashable {
case new = "NEW"
case registered = "REGISTERED"
case invalid = "INVALID"
case invalidBad = "INVALID,BAD"
case invalidTopic = "INVALID,TOPIC"
case invalidExpired = "INVALID,EXPIRED"
case invalidUnregistered = "INVALID,UNREGISTERED"
case confirmed = "CONFIRMED"
case active = "ACTIVE"
case expired = "EXPIRED"
public var workingToken: Bool {
switch self {
case .new: true
case .registered: true
case .invalid: false
case .invalidBad: false
case .invalidTopic: false
case .invalidExpired: false
case .invalidUnregistered: false
case .confirmed: true
case .active: true
case .expired: false
}
}
public var text: String {
switch self {
case .new: NSLocalizedString("New", comment: "token status text")
case .registered: NSLocalizedString("Registered", comment: "token status text")
case .invalid: NSLocalizedString("Invalid", comment: "token status text")
case .invalidBad: NSLocalizedString("Invalid (bad token)", comment: "token status text")
case .invalidTopic: NSLocalizedString("Invalid (wrong topic)", comment: "token status text")
case .invalidExpired: NSLocalizedString("Invalid (expired)", comment: "token status text")
case .invalidUnregistered: NSLocalizedString("Invalid (unregistered)", comment: "token status text")
case .confirmed: NSLocalizedString("Confirmed", comment: "token status text")
case .active: NSLocalizedString("Active", comment: "token status text")
case .expired: NSLocalizedString("Expired", comment: "token status text")
}
}
public func info(register: Bool) -> String {
switch self {
case .new: return NSLocalizedString("Please wait for token to be registered.", comment: "token info")
case .registered: fallthrough
case .confirmed: return NSLocalizedString("Please wait for token activation to complete.", comment: "token info")
case .active: return NSLocalizedString("You should receive notifications.", comment: "token info")
case .invalid: fallthrough
case .invalidBad: fallthrough
case .invalidTopic: fallthrough
case .invalidExpired: fallthrough
case .invalidUnregistered: fallthrough
case .expired:
return register
? NSLocalizedString("Register notification token?", comment: "token info")
: NSLocalizedString("Please try to disable and re-enable notfications.", comment: "token info")
}
}
}
public struct SndFileTransfer: Decodable, Hashable {

View file

@ -27,6 +27,7 @@ extension ChatLike {
case .files: p.files.on(for: groupInfo.membership)
case .simplexLinks: p.simplexLinks.on(for: groupInfo.membership)
case .history: p.history.on
case .reports: p.reports.on
}
} else {
return true

View file

@ -203,6 +203,11 @@ func hideSecrets(_ cItem: ChatItem) -> String {
}
return res
} else {
return cItem.text
let mc = cItem.content.msgContent
if case let .report(text, reason) = mc {
return String.localizedStringWithFormat(NSLocalizedString("Report: %@", comment: "report in notification"), text.isEmpty ? reason.text : text)
} else {
return cItem.text
}
}
}

View file

@ -21,4 +21,13 @@ DIR *opendir$INODE64(const char *name) {
return opendir(name);
}
int readdir$INODE64(DIR *restrict dirp, struct dirent *restrict entry,
struct dirent **restrict result) {
return readdir_r(dirp, entry, result);
}
DIR *fdopendir$INODE64(const char *name) {
return opendir(name);
}
#endif

View file

@ -1,9 +1,3 @@
/* No comment provided by engineer. */
"\n" = "\n";
/* No comment provided by engineer. */
" (" = " (";
/* No comment provided by engineer. */
" (can be copied)" = " (може да се копира)";
@ -22,30 +16,15 @@
/* No comment provided by engineer. */
"- voice messages up to 5 minutes.\n- custom time to disappear.\n- editing history." = "- гласови съобщения до 5 минути.\n- персонализирано време за изчезване.\n- история на редактиране.";
/* No comment provided by engineer. */
", " = ", ";
/* No comment provided by engineer. */
": " = ": ";
/* No comment provided by engineer. */
"!1 colored!" = "!1 цветно!";
/* No comment provided by engineer. */
"." = ".";
/* No comment provided by engineer. */
"(" = "(";
/* No comment provided by engineer. */
"(new)" = "(ново)";
/* No comment provided by engineer. */
"(this device v%@)" = "(това устройство v%@)";
/* No comment provided by engineer. */
")" = ")";
/* No comment provided by engineer. */
"[Contribute](https://github.com/simplex-chat/simplex-chat#contribute)" = "[Допринеси](https://github.com/simplex-chat/simplex-chat#contribute)";
@ -1135,16 +1114,19 @@
"Correct name to %@?" = "Поправи име на %@?";
/* No comment provided by engineer. */
"Create" = "Създай";
"Create" = "Създаване";
/* No comment provided by engineer. */
"Create a group using a random profile." = "Създай група с автоматично генериран профилл.";
"Create 1-time link" = "Създаване на еднократна препратка";
/* No comment provided by engineer. */
"Create a group using a random profile." = "Създаване група с автоматично създаден профил.";
/* server test step */
"Create file" = "Създай файл";
"Create file" = "Създаване на файл";
/* No comment provided by engineer. */
"Create group" = "Създай група";
"Create group" = "Създаване на група";
/* No comment provided by engineer. */
"Create group link" = "Създай групов линк";
@ -1165,7 +1147,7 @@
"Create secret group" = "Създай тайна група";
/* No comment provided by engineer. */
"Create SimpleX address" = "Създай SimpleX адрес";
"Create SimpleX address" = "Създаване на адрес в SimpleX";
/* No comment provided by engineer. */
"Create your profile" = "Създай своя профил";
@ -2637,7 +2619,7 @@
/* No comment provided by engineer. */
"Multiple chat profiles" = "Множество профили за чат";
/* swipe action */
/* notification label action */
"Mute" = "Без звук";
/* No comment provided by engineer. */
@ -3980,7 +3962,7 @@
/* authentication reason */
"Unlock app" = "Отключи приложението";
/* swipe action */
/* notification label action */
"Unmute" = "Уведомявай";
/* swipe action */
@ -4479,7 +4461,7 @@
"Your settings" = "Вашите настройки";
/* No comment provided by engineer. */
"Your SimpleX address" = "Вашият SimpleX адрес";
"Your SimpleX address" = "Вашият адрес в SimpleX";
/* No comment provided by engineer. */
"Your SMP servers" = "Вашите SMP сървъри";

View file

@ -1,9 +1,3 @@
/* No comment provided by engineer. */
"\n" = "\n";
/* No comment provided by engineer. */
" (" = " (";
/* No comment provided by engineer. */
" (can be copied)" = " (lze kopírovat)";
@ -19,27 +13,12 @@
/* No comment provided by engineer. */
"- voice messages up to 5 minutes.\n- custom time to disappear.\n- editing history." = "- 5 minutové hlasové zprávy.\n- vlastní čas mizení.\n- historie úprav.";
/* No comment provided by engineer. */
", " = ", ";
/* No comment provided by engineer. */
": " = ": ";
/* No comment provided by engineer. */
"!1 colored!" = "!1 barevný!";
/* No comment provided by engineer. */
"." = ".";
/* No comment provided by engineer. */
"(" = "(";
/* No comment provided by engineer. */
"(this device v%@)" = "(toto zařízení v%@)";
/* No comment provided by engineer. */
")" = ")";
/* No comment provided by engineer. */
"[Contribute](https://github.com/simplex-chat/simplex-chat#contribute)" = "[Přispějte](https://github.com/simplex-chat/simplex-chat#contribute)";
@ -2036,7 +2015,7 @@
/* No comment provided by engineer. */
"Multiple chat profiles" = "Více chatovacích profilů";
/* swipe action */
/* notification label action */
"Mute" = "Ztlumit";
/* No comment provided by engineer. */
@ -3124,7 +3103,7 @@
/* authentication reason */
"Unlock app" = "Odemknout aplikaci";
/* swipe action */
/* notification label action */
"Unmute" = "Zrušit ztlumení";
/* swipe action */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,3 @@
/* No comment provided by engineer. */
"\n" = "\n";
/* No comment provided by engineer. */
" (" = " (";
/* No comment provided by engineer. */
" (can be copied)" = " (voidaan kopioida)";
@ -16,24 +10,9 @@
/* No comment provided by engineer. */
"- voice messages up to 5 minutes.\n- custom time to disappear.\n- editing history." = "- ääniviestit enintään 5 minuuttia.\n- mukautettu katoamisaika.\n- historian muokkaaminen.";
/* No comment provided by engineer. */
", " = ", ";
/* No comment provided by engineer. */
": " = ": ";
/* No comment provided by engineer. */
"!1 colored!" = "!1 värillinen!";
/* No comment provided by engineer. */
"." = ".";
/* No comment provided by engineer. */
"(" = "(";
/* No comment provided by engineer. */
")" = ")";
/* No comment provided by engineer. */
"[Contribute](https://github.com/simplex-chat/simplex-chat#contribute)" = "[Osallistu](https://github.com/simplex-chat/simplex-chat#contribute)";
@ -1988,7 +1967,7 @@
/* No comment provided by engineer. */
"Multiple chat profiles" = "Useita keskusteluprofiileja";
/* swipe action */
/* notification label action */
"Mute" = "Mykistä";
/* No comment provided by engineer. */
@ -3058,7 +3037,7 @@
/* authentication reason */
"Unlock app" = "Avaa sovellus";
/* swipe action */
/* notification label action */
"Unmute" = "Poista mykistys";
/* swipe action */

View file

@ -1,9 +1,3 @@
/* No comment provided by engineer. */
"\n" = "\n";
/* No comment provided by engineer. */
" (" = " (";
/* No comment provided by engineer. */
" (can be copied)" = " (peut être copié)";
@ -22,30 +16,15 @@
/* No comment provided by engineer. */
"- voice messages up to 5 minutes.\n- custom time to disappear.\n- editing history." = "- messages vocaux pouvant durer jusqu'à 5 minutes.\n- délai personnalisé de disparition.\n- l'historique de modification.";
/* No comment provided by engineer. */
", " = ", ";
/* No comment provided by engineer. */
": " = ": ";
/* No comment provided by engineer. */
"!1 colored!" = "!1 coloré!";
/* No comment provided by engineer. */
"." = ".";
/* No comment provided by engineer. */
"(" = "(";
/* No comment provided by engineer. */
"(new)" = "(nouveau)";
/* No comment provided by engineer. */
"(this device v%@)" = "(cet appareil v%@)";
/* No comment provided by engineer. */
")" = ")";
/* No comment provided by engineer. */
"[Contribute](https://github.com/simplex-chat/simplex-chat#contribute)" = "[Contribuer](https://github.com/simplex-chat/simplex-chat#contribute)";
@ -3156,10 +3135,7 @@
/* No comment provided by engineer. */
"Multiple chat profiles" = "Différents profils de chat";
/* No comment provided by engineer. */
"mute" = "muet";
/* swipe action */
/* notification label action */
"Mute" = "Muet";
/* No comment provided by engineer. */
@ -5015,10 +4991,7 @@
/* authentication reason */
"Unlock app" = "Déverrouiller l'app";
/* No comment provided by engineer. */
"unmute" = "démuter";
/* swipe action */
/* notification label action */
"Unmute" = "Démute";
/* No comment provided by engineer. */

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@
"NSFaceIDUsageDescription" = "A SimpleX Face ID-t használ a helyi hitelesítéshez";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "A SimpleX helyi hálózati hozzáférést használ, hogy lehetővé tegye a felhasználói csevegőprofil használatát számítógépen keresztül ugyanazon a hálózaton.";
"NSLocalNetworkUsageDescription" = "A SimpleX helyi hálózati hozzáférést használ, hogy lehetővé tegye a felhasználói csevegési profil használatát számítógépen keresztül ugyanazon a hálózaton.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "A SimpleXnek mikrofon-hozzáférésre van szüksége hang- és videohívásokhoz, valamint hangüzenetek rögzítéséhez.";

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,3 @@
/* No comment provided by engineer. */
"\n" = "\n";
/* No comment provided by engineer. */
" (" = " (";
/* No comment provided by engineer. */
" (can be copied)" = " (コピー可能)";
@ -22,30 +16,15 @@
/* No comment provided by engineer. */
"- voice messages up to 5 minutes.\n- custom time to disappear.\n- editing history." = "- 最長 5 分間の音声メッセージ。\n- 消えるまでのカスタム時間。\n- 編集履歴。";
/* No comment provided by engineer. */
", " = ", ";
/* No comment provided by engineer. */
": " = ": ";
/* No comment provided by engineer. */
"!1 colored!" = "!1 色付き!";
/* No comment provided by engineer. */
"." = ".";
/* No comment provided by engineer. */
"(" = "(";
/* No comment provided by engineer. */
"(new)" = "(新規)";
/* No comment provided by engineer. */
"(this device v%@)" = "(このデバイス v%@)";
/* No comment provided by engineer. */
")" = ")";
/* No comment provided by engineer. */
"[Contribute](https://github.com/simplex-chat/simplex-chat#contribute)" = "[貢献する](https://github.com/simplex-chat/simplex-chat#contribute)";
@ -2201,7 +2180,7 @@
/* No comment provided by engineer. */
"Multiple chat profiles" = "複数チャットのプロフィール";
/* swipe action */
/* notification label action */
"Mute" = "ミュート";
/* No comment provided by engineer. */
@ -3256,7 +3235,7 @@
/* authentication reason */
"Unlock app" = "アプリのロック解除";
/* swipe action */
/* notification label action */
"Unmute" = "ミュート解除";
/* swipe action */

View file

@ -1,9 +1,3 @@
/* No comment provided by engineer. */
"\n" = "\n";
/* No comment provided by engineer. */
" (" = " (";
/* No comment provided by engineer. */
" (can be copied)" = " (kan gekopieerd worden)";
@ -22,30 +16,15 @@
/* No comment provided by engineer. */
"- voice messages up to 5 minutes.\n- custom time to disappear.\n- editing history." = "- spraakberichten tot 5 minuten.\n- aangepaste tijd om te verdwijnen.\n- bewerkingsgeschiedenis.";
/* No comment provided by engineer. */
", " = ", ";
/* No comment provided by engineer. */
": " = ": ";
/* No comment provided by engineer. */
"!1 colored!" = "!1 gekleurd!";
/* No comment provided by engineer. */
"." = ".";
/* No comment provided by engineer. */
"(" = "(";
/* No comment provided by engineer. */
"(new)" = "(nieuw)";
/* No comment provided by engineer. */
"(this device v%@)" = "(dit apparaat v%@)";
/* No comment provided by engineer. */
")" = ")";
/* No comment provided by engineer. */
"[Contribute](https://github.com/simplex-chat/simplex-chat#contribute)" = "[Bijdragen](https://github.com/simplex-chat/simplex-chat#contribute)";
@ -199,6 +178,9 @@
/* time interval */
"%d sec" = "%d sec";
/* delete after time */
"%d seconds(s)" = "%d seconden";
/* integrity error chat item */
"%d skipped message(s)" = "%d overgeslagen bericht(en)";
@ -304,6 +286,9 @@
time interval */
"1 week" = "1 week";
/* delete after time */
"1 year" = "1 jaar";
/* No comment provided by engineer. */
"1-time link" = "Eenmalige link";
@ -388,6 +373,9 @@
/* No comment provided by engineer. */
"Acknowledgement errors" = "Bevestigingsfouten";
/* token status text */
"Active" = "actief";
/* No comment provided by engineer. */
"Active connections" = "Actieve verbindingen";
@ -397,6 +385,9 @@
/* No comment provided by engineer. */
"Add friends" = "Vrienden toevoegen";
/* No comment provided by engineer. */
"Add list" = "Lijst toevoegen";
/* No comment provided by engineer. */
"Add profile" = "Profiel toevoegen";
@ -412,6 +403,9 @@
/* No comment provided by engineer. */
"Add to another device" = "Toevoegen aan een ander apparaat";
/* No comment provided by engineer. */
"Add to list" = "Toevoegen aan lijst";
/* No comment provided by engineer. */
"Add welcome message" = "Welkom bericht toevoegen";
@ -469,12 +463,18 @@
/* chat item text */
"agreeing encryption…" = "versleuteling overeenkomen…";
/* No comment provided by engineer. */
"All" = "alle";
/* No comment provided by engineer. */
"All app data is deleted." = "Alle app-gegevens worden verwijderd.";
/* No comment provided by engineer. */
"All chats and messages will be deleted - this cannot be undone!" = "Alle chats en berichten worden verwijderd, dit kan niet ongedaan worden gemaakt!";
/* alert message */
"All chats will be removed from the list %@, and the list deleted." = "Alle chats worden uit de lijst %@ verwijderd en de lijst wordt verwijderd.";
/* No comment provided by engineer. */
"All data is erased when it is entered." = "Alle gegevens worden bij het invoeren gewist.";
@ -502,6 +502,9 @@
/* profile dropdown */
"All profiles" = "Alle profielen";
/* No comment provided by engineer. */
"All reports will be archived for you." = "Alle rapporten worden voor u gearchiveerd.";
/* No comment provided by engineer. */
"All your contacts will remain connected." = "Al uw contacten blijven verbonden.";
@ -547,6 +550,9 @@
/* No comment provided by engineer. */
"Allow to irreversibly delete sent messages. (24 hours)" = "Sta toe om verzonden berichten definitief te verwijderen. (24 uur)";
/* No comment provided by engineer. */
"Allow to report messsages to moderators." = "Hiermee kunt u berichten rapporteren aan moderators.";
/* No comment provided by engineer. */
"Allow to send files and media." = "Sta toe om bestanden en media te verzenden.";
@ -601,6 +607,9 @@
/* No comment provided by engineer. */
"and %lld other events" = "en %lld andere gebeurtenissen";
/* report reason */
"Another reason" = "Een andere reden";
/* No comment provided by engineer. */
"Answer call" = "Beantwoord oproep";
@ -616,6 +625,9 @@
/* No comment provided by engineer. */
"App encrypts new local files (except videos)." = "App versleutelt nieuwe lokale bestanden (behalve video's).";
/* No comment provided by engineer. */
"App group:" = "App-groep:";
/* No comment provided by engineer. */
"App icon" = "App icon";
@ -643,18 +655,42 @@
/* No comment provided by engineer. */
"Apply to" = "Toepassen op";
/* No comment provided by engineer. */
"Archive" = "Archief";
/* No comment provided by engineer. */
"Archive %lld reports?" = "%lld rapporten archiveren?";
/* No comment provided by engineer. */
"Archive all reports?" = "Alle rapporten archiveren?";
/* No comment provided by engineer. */
"Archive and upload" = "Archiveren en uploaden";
/* No comment provided by engineer. */
"Archive contacts to chat later." = "Archiveer contacten om later te chatten.";
/* No comment provided by engineer. */
"Archive report" = "Rapport archiveren";
/* No comment provided by engineer. */
"Archive report?" = "Rapport archiveren?";
/* swipe action */
"Archive reports" = "Rapporten archiveren";
/* No comment provided by engineer. */
"Archived contacts" = "Gearchiveerde contacten";
/* No comment provided by engineer. */
"archived report" = "gearchiveerd rapport";
/* No comment provided by engineer. */
"Archiving database" = "Database archiveren";
/* No comment provided by engineer. */
"Ask" = "Vragen";
/* No comment provided by engineer. */
"Attach" = "Bijvoegen";
@ -730,6 +766,9 @@
/* No comment provided by engineer. */
"Better groups" = "Betere groepen";
/* No comment provided by engineer. */
"Better groups performance" = "Betere prestaties van groepen";
/* No comment provided by engineer. */
"Better message dates." = "Betere datums voor berichten.";
@ -742,6 +781,9 @@
/* No comment provided by engineer. */
"Better notifications" = "Betere meldingen";
/* No comment provided by engineer. */
"Better privacy and security" = "Betere privacy en veiligheid";
/* No comment provided by engineer. */
"Better security ✅" = "Betere beveiliging ✅";
@ -814,6 +856,9 @@
/* No comment provided by engineer. */
"Business chats" = "Zakelijke chats";
/* No comment provided by engineer. */
"Businesses" = "bedrijven";
/* No comment provided by engineer. */
"By chat profile (default) or [by connection](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA)." = "Via chatprofiel (standaard) of [via verbinding](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA).";
@ -884,6 +929,9 @@
/* No comment provided by engineer. */
"Change" = "Veranderen";
/* alert title */
"Change automatic message deletion?" = "Automatisch verwijderen van berichten wijzigen?";
/* authentication reason */
"Change chat profiles" = "Gebruikersprofielen wijzigen";
@ -1032,6 +1080,12 @@
/* No comment provided by engineer. */
"Clear conversation?" = "Gesprek wissen?";
/* No comment provided by engineer. */
"Clear group?" = "Groep wissen?";
/* No comment provided by engineer. */
"Clear or delete group?" = "Groep wissen of verwijderen?";
/* No comment provided by engineer. */
"Clear private notes?" = "Privénotities verwijderen?";
@ -1047,6 +1101,9 @@
/* No comment provided by engineer. */
"colored" = "gekleurd";
/* report reason */
"Community guidelines violation" = "Schending van de communityrichtlijnen";
/* server test step */
"Compare file" = "Bestand vergelijken";
@ -1119,6 +1176,9 @@
/* No comment provided by engineer. */
"Confirm upload" = "Bevestig het uploaden";
/* token status text */
"Confirmed" = "Bevestigd";
/* server test step */
"Connect" = "Verbind";
@ -1218,6 +1278,9 @@
/* No comment provided by engineer. */
"Connection and servers status." = "Verbindings- en serverstatus.";
/* No comment provided by engineer. */
"Connection blocked" = "Verbinding geblokkeerd";
/* No comment provided by engineer. */
"Connection error" = "Verbindingsfout";
@ -1227,12 +1290,21 @@
/* chat list item title (it should not be shown */
"connection established" = "verbinding gemaakt";
/* No comment provided by engineer. */
"Connection is blocked by server operator:\n%@" = "Verbinding is geblokkeerd door serveroperator:\n%@";
/* No comment provided by engineer. */
"Connection not ready." = "Verbinding nog niet klaar.";
/* No comment provided by engineer. */
"Connection notifications" = "Verbindingsmeldingen";
/* No comment provided by engineer. */
"Connection request sent!" = "Verbindingsverzoek verzonden!";
/* No comment provided by engineer. */
"Connection requires encryption renegotiation." = "Verbinding vereist heronderhandeling over encryptie.";
/* No comment provided by engineer. */
"Connection security" = "Beveiliging van de verbinding";
@ -1293,6 +1365,9 @@
/* No comment provided by engineer. */
"Contacts can mark messages for deletion; you will be able to view them." = "Contact personen kunnen berichten markeren voor verwijdering; u kunt ze wel bekijken.";
/* blocking reason */
"Content violates conditions of use" = "Inhoud schendt de gebruiksvoorwaarden";
/* No comment provided by engineer. */
"Continue" = "Doorgaan";
@ -1335,6 +1410,9 @@
/* No comment provided by engineer. */
"Create link" = "Maak link";
/* No comment provided by engineer. */
"Create list" = "Maak een lijst";
/* No comment provided by engineer. */
"Create new profile in [desktop app](https://simplex.chat/downloads/). 💻" = "Maak een nieuw profiel aan in [desktop-app](https://simplex.chat/downloads/). 💻";
@ -1514,6 +1592,9 @@
/* No comment provided by engineer. */
"Delete chat" = "Chat verwijderen";
/* No comment provided by engineer. */
"Delete chat messages from your device." = "Verwijder chatberichten van uw apparaat.";
/* No comment provided by engineer. */
"Delete chat profile" = "Chatprofiel verwijderen";
@ -1568,6 +1649,9 @@
/* No comment provided by engineer. */
"Delete link?" = "Link verwijderen?";
/* alert title */
"Delete list?" = "Lijst verwijderen?";
/* No comment provided by engineer. */
"Delete member message?" = "Bericht van lid verwijderen?";
@ -1598,6 +1682,9 @@
/* server test step */
"Delete queue" = "Wachtrij verwijderen";
/* No comment provided by engineer. */
"Delete report" = "Rapport verwijderen";
/* No comment provided by engineer. */
"Delete up to 20 messages at once." = "Verwijder maximaal 20 berichten tegelijk.";
@ -1706,6 +1793,12 @@
/* No comment provided by engineer. */
"Disable (keep overrides)" = "Uitschakelen (overschrijvingen behouden)";
/* alert title */
"Disable automatic message deletion?" = "Automatisch verwijderen van berichten uitschakelen?";
/* alert button */
"Disable delete messages" = "Berichten verwijderen uitschakelen";
/* No comment provided by engineer. */
"Disable for all" = "Uitschakelen voor iedereen";
@ -1766,15 +1859,24 @@
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "Gebruik SimpleX NIET voor noodoproepen.";
/* No comment provided by engineer. */
"Documents:" = "Documenten:";
/* No comment provided by engineer. */
"Don't create address" = "Maak geen adres aan";
/* No comment provided by engineer. */
"Don't enable" = "Niet inschakelen";
/* No comment provided by engineer. */
"Don't miss important messages." = "Mis geen belangrijke berichten.";
/* No comment provided by engineer. */
"Don't show again" = "Niet meer weergeven";
/* No comment provided by engineer. */
"Done" = "Klaar";
/* No comment provided by engineer. */
"Downgrade and open chat" = "Downgraden en chat openen";
@ -1956,6 +2058,9 @@
/* chat item text */
"encryption re-negotiation required for %@" = "heronderhandeling van versleuteling vereist voor % @";
/* No comment provided by engineer. */
"Encryption renegotiation in progress." = "Er wordt opnieuw onderhandeld over de encryptie.";
/* No comment provided by engineer. */
"ended" = "geëindigd";
@ -2031,6 +2136,9 @@
/* No comment provided by engineer. */
"Error changing to incognito!" = "Fout bij het overschakelen naar incognito!";
/* No comment provided by engineer. */
"Error checking token status" = "Fout bij het controleren van de tokenstatus";
/* No comment provided by engineer. */
"Error connecting to forwarding server %@. Please try later." = "Fout bij het verbinden met doorstuurserver %@. Probeer het later opnieuw.";
@ -2043,6 +2151,9 @@
/* No comment provided by engineer. */
"Error creating group link" = "Fout bij maken van groep link";
/* alert title */
"Error creating list" = "Fout bij het aanmaken van de lijst";
/* No comment provided by engineer. */
"Error creating member contact" = "Fout bij aanmaken contact";
@ -2052,6 +2163,9 @@
/* No comment provided by engineer. */
"Error creating profile!" = "Fout bij aanmaken van profiel!";
/* No comment provided by engineer. */
"Error creating report" = "Fout bij maken van rapport";
/* No comment provided by engineer. */
"Error decrypting file" = "Fout bij het ontsleutelen van bestand";
@ -2118,12 +2232,21 @@
/* No comment provided by engineer. */
"Error reconnecting servers" = "Fout bij opnieuw verbinden van servers";
/* alert title */
"Error registering for notifications" = "Fout bij registreren voor meldingen";
/* No comment provided by engineer. */
"Error removing member" = "Fout bij verwijderen van lid";
/* alert title */
"Error reordering lists" = "Fout bij het opnieuw ordenen van lijsten";
/* No comment provided by engineer. */
"Error resetting statistics" = "Fout bij het resetten van statistieken";
/* alert title */
"Error saving chat list" = "Fout bij het opslaan van chatlijst";
/* No comment provided by engineer. */
"Error saving group profile" = "Fout bij opslaan van groep profiel";
@ -2175,6 +2298,9 @@
/* No comment provided by engineer. */
"Error synchronizing connection" = "Fout bij het synchroniseren van de verbinding";
/* No comment provided by engineer. */
"Error testing server connection" = "Fout bij het testen van de serververbinding";
/* No comment provided by engineer. */
"Error updating group link" = "Fout bij bijwerken van groep link";
@ -2229,6 +2355,9 @@
/* No comment provided by engineer. */
"expired" = "verlopen";
/* token status text */
"Expired" = "Verlopen";
/* No comment provided by engineer. */
"Export database" = "Database exporteren";
@ -2253,18 +2382,30 @@
/* No comment provided by engineer. */
"Fast and no wait until the sender is online!" = "Snel en niet wachten tot de afzender online is!";
/* No comment provided by engineer. */
"Faster deletion of groups." = "Sneller verwijderen van groepen.";
/* No comment provided by engineer. */
"Faster joining and more reliable messages." = "Snellere deelname en betrouwbaardere berichten.";
/* No comment provided by engineer. */
"Faster sending messages." = "Sneller verzenden van berichten.";
/* swipe action */
"Favorite" = "Favoriet";
/* No comment provided by engineer. */
"Favorites" = "Favorieten";
/* file error alert title */
"File error" = "Bestandsfout";
/* alert message */
"File errors:\n%@" = "Bestandsfouten:\n%@";
/* file error text */
"File is blocked by server operator:\n%@." = "Bestand is geblokkeerd door serveroperator:\n%@.";
/* file error text */
"File not found - most likely file was deleted or cancelled." = "Bestand niet gevonden - hoogstwaarschijnlijk is het bestand verwijderd of geannuleerd.";
@ -2340,6 +2481,9 @@
/* No comment provided by engineer. */
"Fix not supported by group member" = "Herstel wordt niet ondersteund door groepslid";
/* No comment provided by engineer. */
"For all moderators" = "Voor alle moderators";
/* No comment provided by engineer. */
"for better metadata privacy." = "voor betere privacy van metagegevens.";
@ -2352,6 +2496,9 @@
/* No comment provided by engineer. */
"For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server." = "Als uw contactpersoon bijvoorbeeld berichten ontvangt via een SimpleX Chat-server, worden deze door uw app via een Flux-server verzonden.";
/* No comment provided by engineer. */
"For me" = "Voor mij";
/* No comment provided by engineer. */
"For private routing" = "Voor privé-routering";
@ -2424,6 +2571,9 @@
/* No comment provided by engineer. */
"Further reduced battery usage" = "Verder verminderd batterij verbruik";
/* No comment provided by engineer. */
"Get notified when mentioned." = "Ontvang een melding als u vermeld wordt.";
/* No comment provided by engineer. */
"GIFs and stickers" = "GIF's en stickers";
@ -2496,9 +2646,15 @@
/* No comment provided by engineer. */
"Group will be deleted for you - this cannot be undone!" = "De groep wordt voor u verwijderd, dit kan niet ongedaan worden gemaakt!";
/* No comment provided by engineer. */
"Groups" = "Groepen";
/* No comment provided by engineer. */
"Help" = "Help";
/* No comment provided by engineer. */
"Help admins moderating their groups." = "Help beheerders bij het modereren van hun groepen.";
/* No comment provided by engineer. */
"Hidden" = "Verborgen";
@ -2535,6 +2691,9 @@
/* No comment provided by engineer. */
"How it helps privacy" = "Hoe het de privacy helpt";
/* alert button */
"How it works" = "Hoe het werkt";
/* No comment provided by engineer. */
"How SimpleX works" = "Hoe SimpleX werkt";
@ -2622,6 +2781,12 @@
/* No comment provided by engineer. */
"inactive" = "inactief";
/* report reason */
"Inappropriate content" = "Ongepaste inhoud";
/* report reason */
"Inappropriate profile" = "Ongepast profiel";
/* No comment provided by engineer. */
"Incognito" = "Incognito";
@ -2688,6 +2853,21 @@
/* No comment provided by engineer. */
"Interface colors" = "Interface kleuren";
/* token status text */
"Invalid" = "Ongeldig";
/* token status text */
"Invalid (bad token)" = "Ongeldig (ongeldig token)";
/* token status text */
"Invalid (expired)" = "Ongeldig (verlopen)";
/* token status text */
"Invalid (unregistered)" = "Ongeldig (niet geregistreerd)";
/* token status text */
"Invalid (wrong topic)" = "Ongeldig (verkeerd onderwerp)";
/* invalid chat data */
"invalid chat" = "ongeldige gesprek";
@ -2889,6 +3069,15 @@
/* No comment provided by engineer. */
"Linked desktops" = "Gelinkte desktops";
/* swipe action */
"List" = "Lijst";
/* No comment provided by engineer. */
"List name and emoji should be different for all lists." = "De naam en emoji van de lijst moeten voor alle lijsten verschillend zijn.";
/* No comment provided by engineer. */
"List name..." = "Naam van lijst...";
/* No comment provided by engineer. */
"LIVE" = "LIVE";
@ -2958,6 +3147,9 @@
/* item status text */
"Member inactive" = "Lid inactief";
/* chat feature */
"Member reports" = "Ledenrapporten";
/* No comment provided by engineer. */
"Member role will be changed to \"%@\". All chat members will be notified." = "De rol van het lid wordt gewijzigd naar \"%@\". Alle chatleden worden op de hoogte gebracht.";
@ -2979,6 +3171,9 @@
/* No comment provided by engineer. */
"Members can irreversibly delete sent messages. (24 hours)" = "Groepsleden kunnen verzonden berichten onherroepelijk verwijderen. (24 uur)";
/* No comment provided by engineer. */
"Members can report messsages to moderators." = "Leden kunnen berichten melden bij moderators.";
/* No comment provided by engineer. */
"Members can send direct messages." = "Groepsleden kunnen directe berichten sturen.";
@ -2994,6 +3189,9 @@
/* No comment provided by engineer. */
"Members can send voice messages." = "Groepsleden kunnen spraak berichten verzenden.";
/* No comment provided by engineer. */
"Mention members 👋" = "Vermeld leden 👋";
/* No comment provided by engineer. */
"Menus" = "Menu's";
@ -3066,6 +3264,9 @@
/* No comment provided by engineer. */
"Messages from %@ will be shown!" = "Berichten van %@ worden getoond!";
/* alert message */
"Messages in this chat will never be deleted." = "Berichten in deze chat zullen nooit worden verwijderd.";
/* No comment provided by engineer. */
"Messages received" = "Berichten ontvangen";
@ -3138,9 +3339,15 @@
/* marked deleted chat item preview text */
"moderated by %@" = "gemodereerd door %@";
/* member role */
"moderator" = "moderator";
/* time unit */
"months" = "maanden";
/* swipe action */
"More" = "Meer";
/* No comment provided by engineer. */
"More improvements are coming soon!" = "Meer verbeteringen volgen snel!";
@ -3156,12 +3363,12 @@
/* No comment provided by engineer. */
"Multiple chat profiles" = "Meerdere chatprofielen";
/* No comment provided by engineer. */
"mute" = "dempen";
/* swipe action */
/* notification label action */
"Mute" = "Dempen";
/* notification label action */
"Mute all" = "Alles dempen";
/* No comment provided by engineer. */
"Muted when inactive!" = "Gedempt wanneer inactief!";
@ -3195,6 +3402,9 @@
/* delete after time */
"never" = "nooit";
/* token status text */
"New" = "Nieuw";
/* No comment provided by engineer. */
"New chat" = "Nieuw gesprek";
@ -3255,6 +3465,15 @@
/* Authentication unavailable */
"No app password" = "Geen app wachtwoord";
/* No comment provided by engineer. */
"No chats" = "Geen chats";
/* No comment provided by engineer. */
"No chats found" = "Geen chats gevonden";
/* No comment provided by engineer. */
"No chats in list %@" = "Geen chats in lijst %@";
/* No comment provided by engineer. */
"No contacts selected" = "Geen contacten geselecteerd";
@ -3288,6 +3507,9 @@
/* servers error */
"No media & file servers." = "Geen media- en bestandsservers.";
/* No comment provided by engineer. */
"No message" = "Geen bericht";
/* servers error */
"No message servers." = "Geen berichtenservers.";
@ -3324,12 +3546,21 @@
/* copied message info in history */
"no text" = "geen tekst";
/* alert title */
"No token!" = "Geen token!";
/* No comment provided by engineer. */
"No unread chats" = "Geen ongelezen chats";
/* No comment provided by engineer. */
"No user identifiers." = "Geen gebruikers-ID's.";
/* No comment provided by engineer. */
"Not compatible!" = "Niet compatibel!";
/* No comment provided by engineer. */
"Notes" = "Notities";
/* No comment provided by engineer. */
"Nothing selected" = "Niets geselecteerd";
@ -3342,9 +3573,15 @@
/* No comment provided by engineer. */
"Notifications are disabled!" = "Meldingen zijn uitgeschakeld!";
/* alert title */
"Notifications error" = "Meldingsfout";
/* No comment provided by engineer. */
"Notifications privacy" = "Privacy van meldingen";
/* alert title */
"Notifications status" = "Meldingsstatus";
/* No comment provided by engineer. */
"Now admins can:\n- delete members' messages.\n- disable members (\"observer\" role)" = "Nu kunnen beheerders: \n- berichten van leden verwijderen.\n- schakel leden uit (\"waarnemer\" rol)";
@ -3407,6 +3644,12 @@
/* No comment provided by engineer. */
"Only group owners can enable voice messages." = "Alleen groep eigenaren kunnen spraak berichten inschakelen.";
/* No comment provided by engineer. */
"Only sender and moderators see it" = "Alleen de verzender en moderators zien het";
/* No comment provided by engineer. */
"Only you and moderators see it" = "Alleen jij en moderators zien het";
/* No comment provided by engineer. */
"Only you can add message reactions." = "Alleen jij kunt bericht reacties toevoegen.";
@ -3455,12 +3698,21 @@
/* No comment provided by engineer. */
"Open group" = "Open groep";
/* No comment provided by engineer. */
"Open link" = "Link openen";
/* No comment provided by engineer. */
"Open links from chat list" = "Open links van chatlijst";
/* authentication reason */
"Open migration to another device" = "Open de migratie naar een ander apparaat";
/* No comment provided by engineer. */
"Open Settings" = "Open instellingen";
/* No comment provided by engineer. */
"Open web link?" = "Weblink openen?";
/* No comment provided by engineer. */
"Opening app…" = "App openen…";
@ -3488,6 +3740,9 @@
/* No comment provided by engineer. */
"Or to share privately" = "Of om privé te delen";
/* No comment provided by engineer. */
"Organize chats into lists" = "Organiseer chats in lijsten";
/* No comment provided by engineer. */
"other" = "overig";
@ -3614,6 +3869,15 @@
/* No comment provided by engineer. */
"Please store passphrase securely, you will NOT be able to change it if you lose it." = "Bewaar het wachtwoord veilig, u kunt deze NIET wijzigen als u het kwijtraakt.";
/* token info */
"Please try to disable and re-enable notfications." = "Probeer meldingen uit en weer in te schakelen.";
/* token info */
"Please wait for token activation to complete." = "Wacht tot de tokenactivering voltooid is.";
/* token info */
"Please wait for token to be registered." = "Wacht tot het token is geregistreerd.";
/* No comment provided by engineer. */
"Polish interface" = "Poolse interface";
@ -3650,6 +3914,9 @@
/* No comment provided by engineer. */
"Private filenames" = "Privé bestandsnamen";
/* No comment provided by engineer. */
"Private media file names." = "Namen van persoonlijke mediabestanden.";
/* No comment provided by engineer. */
"Private message routing" = "Routering van privéberichten";
@ -3695,6 +3962,9 @@
/* No comment provided by engineer. */
"Prohibit messages reactions." = "Berichten reacties verbieden.";
/* No comment provided by engineer. */
"Prohibit reporting messages to moderators." = "Het melden van berichten aan moderators is niet toegestaan.";
/* No comment provided by engineer. */
"Prohibit sending direct messages to members." = "Verbied het sturen van directe berichten naar leden.";
@ -3857,6 +4127,15 @@
/* No comment provided by engineer. */
"Reduced battery usage" = "Verminderd batterijgebruik";
/* No comment provided by engineer. */
"Register" = "Register";
/* token info */
"Register notification token?" = "Meldingstoken registreren?";
/* token status text */
"Registered" = "Geregistreerd";
/* reject incoming call via notification
swipe action */
"Reject" = "Afwijzen";
@ -3936,6 +4215,36 @@
/* chat item action */
"Reply" = "Antwoord";
/* chat item action */
"Report" = "Rapport";
/* report reason */
"Report content: only group moderators will see it." = "Inhoud melden: alleen groepsmoderators kunnen dit zien.";
/* report reason */
"Report member profile: only group moderators will see it." = "Rapporteer ledenprofiel: alleen groepsmoderators kunnen dit zien.";
/* report reason */
"Report other: only group moderators will see it." = "Anders melden: alleen groepsmoderators kunnen het zien.";
/* No comment provided by engineer. */
"Report reason?" = "Reden melding?";
/* report reason */
"Report spam: only group moderators will see it." = "Spam melden: alleen groepsmoderators kunnen het zien.";
/* report reason */
"Report violation: only group moderators will see it." = "Rapporteer overtreding: alleen groepsmoderators kunnen dit zien.";
/* report in notification */
"Report: %@" = "Rapport: %@";
/* No comment provided by engineer. */
"Reporting messages to moderators is prohibited." = "Het is niet toegestaan om berichten aan moderators te melden.";
/* No comment provided by engineer. */
"Reports" = "Rapporten";
/* chat list item title */
"requested to connect" = "verzocht om verbinding te maken";
@ -4039,6 +4348,9 @@
/* No comment provided by engineer. */
"Save group profile" = "Groep profiel opslaan";
/* No comment provided by engineer. */
"Save list" = "Lijst opslaan";
/* No comment provided by engineer. */
"Save passphrase and open chat" = "Wachtwoord opslaan en open je chats";
@ -4207,6 +4519,9 @@
/* No comment provided by engineer. */
"Send notifications" = "Meldingen verzenden";
/* No comment provided by engineer. */
"Send private reports" = "Verstuur rapporten privé";
/* No comment provided by engineer. */
"Send questions and ideas" = "Stuur vragen en ideeën";
@ -4339,6 +4654,9 @@
/* No comment provided by engineer. */
"Set 1 day" = "Stel 1 dag in";
/* No comment provided by engineer. */
"Set chat name…" = "Stel chatnaam in…";
/* No comment provided by engineer. */
"Set contact name…" = "Contactnaam instellen…";
@ -4351,11 +4669,14 @@
/* No comment provided by engineer. */
"Set it instead of system authentication." = "Stel het in in plaats van systeemverificatie.";
/* No comment provided by engineer. */
"Set message expiration in chats." = "Stel de berichtvervaldatum in chats in.";
/* profile update event chat item */
"set new contact address" = "nieuw contactadres instellen";
/* profile update event chat item */
"set new profile picture" = "nieuwe profielfoto instellen";
"set new profile picture" = "nieuwe profielfoto";
/* No comment provided by engineer. */
"Set passcode" = "Toegangscode instellen";
@ -4547,6 +4868,10 @@
/* notification title */
"Somebody" = "Iemand";
/* blocking reason
report reason */
"Spam" = "Spam";
/* No comment provided by engineer. */
"Square, circle, or anything in between." = "Vierkant, cirkel of iets daartussenin.";
@ -4604,6 +4929,9 @@
/* No comment provided by engineer. */
"Stopping chat" = "Chat stoppen";
/* No comment provided by engineer. */
"Storage" = "Opslag";
/* No comment provided by engineer. */
"strike" = "staking";
@ -4673,6 +5001,9 @@
/* No comment provided by engineer. */
"TCP connection timeout" = "Timeout van TCP-verbinding";
/* No comment provided by engineer. */
"TCP port for messaging" = "TCP-poort voor berichtenuitwisseling";
/* No comment provided by engineer. */
"TCP_KEEPCNT" = "TCP_KEEPCNT";
@ -4688,6 +5019,9 @@
/* server test failure */
"Test failed at step %@." = "Test mislukt bij stap %@.";
/* No comment provided by engineer. */
"Test notifications" = "Testmeldingen";
/* No comment provided by engineer. */
"Test server" = "Server test";
@ -4808,6 +5142,9 @@
/* No comment provided by engineer. */
"This action cannot be undone - the messages sent and received earlier than selected will be deleted. It may take several minutes." = "Deze actie kan niet ongedaan worden gemaakt, de berichten die eerder zijn verzonden en ontvangen dan geselecteerd, worden verwijderd. Het kan enkele minuten duren.";
/* alert message */
"This action cannot be undone - the messages sent and received in this chat earlier than selected will be deleted." = "Deze actie kan niet ongedaan worden gemaakt. De berichten die eerder in deze chat zijn verzonden en ontvangen dan geselecteerd, worden verwijderd.";
/* No comment provided by engineer. */
"This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost." = "Deze actie kan niet ongedaan worden gemaakt. Uw profiel, contacten, berichten en bestanden gaan definitief verloren.";
@ -4841,6 +5178,9 @@
/* No comment provided by engineer. */
"This link was used with another mobile device, please create a new link on the desktop." = "Deze link is gebruikt met een ander mobiel apparaat. Maak een nieuwe link op de desktop.";
/* No comment provided by engineer. */
"This message was deleted or not received yet." = "Dit bericht is verwijderd of nog niet ontvangen.";
/* No comment provided by engineer. */
"This setting applies to messages in your current chat profile **%@**." = "Deze instelling is van toepassing op berichten in je huidige chatprofiel **%@**.";
@ -4907,6 +5247,9 @@
/* No comment provided by engineer. */
"Toggle incognito when connecting." = "Schakel incognito in tijdens het verbinden.";
/* token status */
"Token status: %@." = "Tokenstatus: %@.";
/* No comment provided by engineer. */
"Toolbar opacity" = "De transparantie van de werkbalk";
@ -5015,10 +5358,7 @@
/* authentication reason */
"Unlock app" = "Ontgrendel app";
/* No comment provided by engineer. */
"unmute" = "dempen opheffen";
/* swipe action */
/* notification label action */
"Unmute" = "Dempen opheffen";
/* No comment provided by engineer. */
@ -5123,12 +5463,18 @@
/* No comment provided by engineer. */
"Use SOCKS proxy" = "Gebruik SOCKS proxy";
/* No comment provided by engineer. */
"Use TCP port %@ when no port is specified." = "Gebruik TCP-poort %@ als er geen poort is opgegeven.";
/* No comment provided by engineer. */
"Use the app while in the call." = "Gebruik de app tijdens het gesprek.";
/* No comment provided by engineer. */
"Use the app with one hand." = "Gebruik de app met één hand.";
/* No comment provided by engineer. */
"Use web port" = "Gebruik een webpoort";
/* No comment provided by engineer. */
"User selection" = "Gebruikersselectie";
@ -5339,6 +5685,9 @@
/* pref value */
"yes" = "Ja";
/* No comment provided by engineer. */
"Yes" = "Ja";
/* No comment provided by engineer. */
"you" = "jij";
@ -5534,6 +5883,9 @@
/* chat list item description */
"you shared one-time link incognito" = "je hebt een eenmalige link incognito gedeeld";
/* token info */
"You should receive notifications." = "U zou meldingen moeten ontvangen.";
/* snd group event chat item */
"you unblocked %@" = "je hebt %@ gedeblokkeerd";

View file

@ -1,9 +1,3 @@
/* No comment provided by engineer. */
"\n" = "\n";
/* No comment provided by engineer. */
" (" = " (";
/* No comment provided by engineer. */
" (can be copied)" = " (można skopiować)";
@ -22,30 +16,15 @@
/* No comment provided by engineer. */
"- voice messages up to 5 minutes.\n- custom time to disappear.\n- editing history." = "- wiadomości głosowe do 5 minut.\n- niestandardowy czas zniknięcia.\n- historia edycji.";
/* No comment provided by engineer. */
", " = ", ";
/* No comment provided by engineer. */
": " = ": ";
/* No comment provided by engineer. */
"!1 colored!" = "!1 pokolorowany!";
/* No comment provided by engineer. */
"." = ".";
/* No comment provided by engineer. */
"(" = "(";
/* No comment provided by engineer. */
"(new)" = "(nowy)";
/* No comment provided by engineer. */
"(this device v%@)" = "(to urządzenie v%@)";
/* No comment provided by engineer. */
")" = ")";
/* No comment provided by engineer. */
"[Contribute](https://github.com/simplex-chat/simplex-chat#contribute)" = "[Przyczyń się](https://github.com/simplex-chat/simplex-chat#contribute)";
@ -199,6 +178,9 @@
/* time interval */
"%d sec" = "%d sek";
/* delete after time */
"%d seconds(s)" = "%d sekundach";
/* integrity error chat item */
"%d skipped message(s)" = "%d pominięte wiadomość(i)";
@ -304,6 +286,9 @@
time interval */
"1 week" = "1 tydzień";
/* delete after time */
"1 year" = "1 roku";
/* No comment provided by engineer. */
"1-time link" = "link jednorazowy";
@ -385,6 +370,9 @@
/* No comment provided by engineer. */
"Acknowledgement errors" = "Błędy potwierdzenia";
/* token status text */
"Active" = "Aktywne";
/* No comment provided by engineer. */
"Active connections" = "Aktywne połączenia";
@ -394,6 +382,9 @@
/* No comment provided by engineer. */
"Add friends" = "Dodaj znajomych";
/* No comment provided by engineer. */
"Add list" = "Dodaj listę";
/* No comment provided by engineer. */
"Add profile" = "Dodaj profil";
@ -409,6 +400,9 @@
/* No comment provided by engineer. */
"Add to another device" = "Dodaj do innego urządzenia";
/* No comment provided by engineer. */
"Add to list" = "Dodaj do listy";
/* No comment provided by engineer. */
"Add welcome message" = "Dodaj wiadomość powitalną";
@ -466,12 +460,18 @@
/* chat item text */
"agreeing encryption…" = "uzgadnianie szyfrowania…";
/* No comment provided by engineer. */
"All" = "Wszystko";
/* No comment provided by engineer. */
"All app data is deleted." = "Wszystkie dane aplikacji są usunięte.";
/* No comment provided by engineer. */
"All chats and messages will be deleted - this cannot be undone!" = "Wszystkie czaty i wiadomości zostaną usunięte - nie można tego cofnąć!";
/* alert message */
"All chats will be removed from the list %@, and the list deleted." = "Wszystkie rozmowy zostaną usunięte z listy %@, a lista usunięta.";
/* No comment provided by engineer. */
"All data is erased when it is entered." = "Wszystkie dane są usuwane po jego wprowadzeniu.";
@ -484,6 +484,9 @@
/* feature role */
"all members" = "wszyscy członkowie";
/* No comment provided by engineer. */
"All messages and files are sent **end-to-end encrypted**, with post-quantum security in direct messages." = "Wszystkie wiadomości i pliki są wysyłane **z szyfrowaniem end-to-end**, z bezpieczeństwem postkwantowym w wiadomościach bezpośrednich.";
/* No comment provided by engineer. */
"All messages will be deleted - this cannot be undone!" = "Wszystkie wiadomości zostaną usunięte nie można tego cofnąć!";
@ -496,6 +499,9 @@
/* profile dropdown */
"All profiles" = "Wszystkie profile";
/* No comment provided by engineer. */
"All reports will be archived for you." = "Wszystkie raporty zostaną dla Ciebie zarchiwizowane.";
/* No comment provided by engineer. */
"All your contacts will remain connected." = "Wszystkie Twoje kontakty pozostaną połączone.";
@ -541,6 +547,9 @@
/* No comment provided by engineer. */
"Allow to irreversibly delete sent messages. (24 hours)" = "Zezwól na nieodwracalne usunięcie wysłanych wiadomości. (24 godziny)";
/* No comment provided by engineer. */
"Allow to report messsages to moderators." = "Zezwól na zgłaszanie wiadomości moderatorom.";
/* No comment provided by engineer. */
"Allow to send files and media." = "Pozwól na wysyłanie plików i mediów.";
@ -595,6 +604,9 @@
/* No comment provided by engineer. */
"and %lld other events" = "i %lld innych wydarzeń";
/* report reason */
"Another reason" = "Inny powód";
/* No comment provided by engineer. */
"Answer call" = "Odbierz połączenie";
@ -610,6 +622,9 @@
/* No comment provided by engineer. */
"App encrypts new local files (except videos)." = "Aplikacja szyfruje nowe lokalne pliki (bez filmów).";
/* No comment provided by engineer. */
"App group:" = "Grupa aplikacji:";
/* No comment provided by engineer. */
"App icon" = "Ikona aplikacji";
@ -637,18 +652,39 @@
/* No comment provided by engineer. */
"Apply to" = "Zastosuj dla";
/* No comment provided by engineer. */
"Archive" = "Archiwizuj";
/* No comment provided by engineer. */
"Archive %lld reports?" = "Archiwizować %lld reports?";
/* No comment provided by engineer. */
"Archive all reports?" = "Archiwizować wszystkie zgłoszenia?";
/* No comment provided by engineer. */
"Archive and upload" = "Archiwizuj i prześlij";
/* No comment provided by engineer. */
"Archive contacts to chat later." = "Archiwizuj kontakty aby porozmawiać później.";
/* No comment provided by engineer. */
"Archive report" = "Archiwizuj zgłoszenie";
/* No comment provided by engineer. */
"Archive report?" = "Archiwizować zgłoszenie?";
/* swipe action */
"Archive reports" = "Archiwizuj zgłoszenia";
/* No comment provided by engineer. */
"Archived contacts" = "Zarchiwizowane kontakty";
/* No comment provided by engineer. */
"Archiving database" = "Archiwizowanie bazy danych";
/* No comment provided by engineer. */
"Ask" = "Zapytaj";
/* No comment provided by engineer. */
"Attach" = "Dołącz";
@ -808,6 +844,9 @@
/* No comment provided by engineer. */
"Business chats" = "Czaty biznesowe";
/* No comment provided by engineer. */
"Businesses" = "Firmy";
/* No comment provided by engineer. */
"By chat profile (default) or [by connection](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA)." = "Według profilu czatu (domyślnie) lub [według połączenia](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA).";
@ -3042,10 +3081,7 @@
/* No comment provided by engineer. */
"Multiple chat profiles" = "Wiele profili czatu";
/* No comment provided by engineer. */
"mute" = "wycisz";
/* swipe action */
/* notification label action */
"Mute" = "Wycisz";
/* No comment provided by engineer. */
@ -4751,10 +4787,7 @@
/* authentication reason */
"Unlock app" = "Odblokuj aplikację";
/* No comment provided by engineer. */
"unmute" = "wyłącz wyciszenie";
/* swipe action */
/* notification label action */
"Unmute" = "Wyłącz wyciszenie";
/* No comment provided by engineer. */
@ -5342,6 +5375,9 @@
/* No comment provided by engineer. */
"Your server address" = "Twój adres serwera";
/* No comment provided by engineer. */
"Your servers" = "Twoje serwery";
/* No comment provided by engineer. */
"Your settings" = "Twoje ustawienia";

File diff suppressed because it is too large Load diff

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