Compare commits

...

1636 Commits

Author SHA1 Message Date
Arturs Krumins 3a0921c093 ios: asychronous subscription updates (#4707)
* ios: asychronous subscription updates

* cleanup
2024-08-17 13:26:56 +01:00
Evgeny 3740805125 core: batch connection subscription transactions (#4701)
* core: batch connection subscription transactions

* simplexmq
2024-08-16 11:55:22 +01:00
Arturs Krumins b0e0b0beb8 remove text slection context menu from chat item (#4699) 2024-08-15 20:08:51 +01:00
Arturs Krumins c823a4fa6c extend chat view material behind keyboard (#4698)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-15 18:43:30 +01:00
Arturs Krumins 3c694e2841 upgrade code scanner (#4650)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-15 18:21:22 +01:00
Arturs Krumins c159c2ede3 ios: fix pending connection sheet styling when opened via icon; fix tappable area of pending connections and contact requests (#4694)
* fix new contact sheet styling

* fix contact request tappable area

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-08-15 14:15:24 +04:00
spaced4ndy 1d0d7bbd01 core: batch send file descriptions (#4684)
* core: batch send file descriptions

* fix useMember

* fix result interpretation

* remove comment

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-15 13:43:57 +04:00
Evgeny Poberezkin 82c4d77c73 6.0.1: ios 233, android 232, desktop 62 2024-08-14 23:10:06 +01:00
Evgeny 25938af62f ui: translations (#4654)
* Translated using Weblate (Dutch)

Currently translated at 100.0% (2030 of 2030 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 28.5% (580 of 2030 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 5.2% (106 of 2030 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2030 of 2030 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 28.5% (580 of 2030 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 5.2% (106 of 2030 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1785 of 1785 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% (2030 of 2030 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% (1785 of 1785 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 29.3% (595 of 2030 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% (2030 of 2030 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% (1785 of 1785 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% (2030 of 2030 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% (1785 of 1785 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 29.9% (607 of 2030 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 30.5% (621 of 2030 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% (2032 of 2032 strings)

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

* Translated using Weblate (French)

Currently translated at 97.4% (1981 of 2032 strings)

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

* Translated using Weblate (French)

Currently translated at 97.8% (1989 of 2032 strings)

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

* Translated using Weblate (French)

Currently translated at 98.7% (2007 of 2032 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (2032 of 2032 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1785 of 1785 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2032 of 2032 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (2032 of 2032 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (2032 of 2032 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1785 of 1785 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2032 of 2032 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (2032 of 2032 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% (2032 of 2032 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% (1785 of 1785 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (2032 of 2032 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 31.3% (638 of 2032 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 5.2% (107 of 2032 strings)

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

* process localizations

* update ru

---------

Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: billy appetie <billy_appetie@users.noreply.hosted.weblate.org>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
2024-08-14 21:12:50 +01:00
Evgeny edfcced1fa website: translation (#4692)
* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (257 of 257 strings)

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

* space

---------

Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
2024-08-14 21:01:28 +01:00
Evgeny Poberezkin 5bff5a855e core: 6.0.1.0 2024-08-14 20:30:11 +01:00
Arturs Krumins 46a60d979b ios: fix messages reseting position, when app is brought from background to foreground (#4686)
* ios: fix messages reseting position, when app is brought back to foreground

* minor
2024-08-14 20:14:40 +01:00
Arturs Krumins f6ef57534f ios: add text to share extension link preview (#4683)
* ios: add text to share extension link preview

* remove maxHeight contraint
2024-08-14 19:29:13 +01:00
Stanislav Dmitrenko 1e4479f736 android, desktop: fix loading more items when fast switching chats (#4685)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-14 19:08:08 +01:00
Stanislav Dmitrenko 789c762c81 android: hide keyboard when not needed (#4689)
* android: hide keyboard when not needed

* revert some parts

* more places

* unused

* delay

* comment
2024-08-14 18:59:53 +01:00
Evgeny e9baeba31f blog: v6 announcement (#4598)
* blog: v6 announcement

* update
2024-08-14 14:10:14 +01:00
Arturs Krumins 2d5bbcdd61 ios: fix merged item order (#4682) 2024-08-14 07:59:58 +01:00
Arturs Krumins c3f67aff69 ios: speed up network status handling (#4678)
* move network status into a separate model

* reduce network model observation scope (#4679)

* dont pass chat

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-13 21:08:04 +01:00
Arturs Krumins 7cb3a499b2 ios: optimise chat switching (#4663)
* ios: shooth chat switching

* debug button

* navigation timeout

* fix scroll crash

* fix merge

* whitespace

* wip

* add spinner; extract load and nav logic

* cleanup

* direct chat button

* cleanup

* showLoadingProgress

* reverse rename

* rename

* spinner layout

* move all programmatic navigation to `openLoadChat`

* remove access restriction

* fix scroll on item added regression

* print

* fix page load regression

* fix member sheet disappearing

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-13 19:37:48 +01:00
Stanislav Dmitrenko 32e7fd72d3 android, desktop: searching in different screens using the same data (#4673)
* android, desktop: searching in different screens using the same data

* don't filter if not needed
2024-08-13 19:15:54 +01:00
Stanislav Dmitrenko 915bbed400 android, desktop: fix chatView state propagation (#4676) 2024-08-13 19:11:04 +01:00
Stanislav Dmitrenko 2ae5a8bffd android, desktop: padding for RTL layout and remembering prefered layout (#4675)
* android, desktop: padding for RTL layout and remembering prefered layout

* refactor

* changes
2024-08-13 19:07:03 +01:00
Stanislav Dmitrenko cd1550a14d android, desktop: fix crash on marking chat read (#4671) 2024-08-13 18:56:47 +01:00
Stanislav Dmitrenko c72c461306 android: replacing a crash with an alert when opening broken Uri (#4674)
* android: replacing a crash with an alert when opening broken Uri

* strings

---------

Co-authored-by: Evgeny <evgeny@poberezkin.com>
2024-08-13 18:42:33 +01:00
spaced4ndy 38fa4c231f ui: improve remote controller stop reason (#4670) 2024-08-13 15:05:13 +04:00
spaced4ndy cb683d0706 ui: disable subs indicator when chat is stopped (#4672) 2024-08-13 13:14:27 +04:00
Diogo 84ae39b012 android: fix group creation chat redirection showing attachments view (#4669) 2024-08-13 12:18:06 +04:00
Stanislav Dmitrenko 6a12f2dec8 ios: fix updating chat wallpaper while app is in background (#4661) 2024-08-12 21:57:04 +01:00
Diogo d1f704d160 multiplatform: mark chat non deleted only on send/receive (keep chatDeleted flag on open) (#4664) 2024-08-12 19:50:36 +04:00
Diogo 9871ebb3b1 ios: mark chat non deleted only on send/receive (keep chatDeleted flag on open) (#4659)
* ios: navigation to delete chat working for group members

* modify

* Revert "modify"

This reverts commit fc811bbb84.

* don't mark non deleted on open, mark on send

* simplify

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-08-12 18:49:34 +04:00
Evgeny 02c404593c cli: do not log events for hidden user profiles (#4658)
* cli: do not log events for hidden user profiles

* fix
2024-08-12 08:45:11 +01:00
sh 1d9c5b7a0b flatpak: update metainfo (#4660) 2024-08-12 11:42:48 +04:00
Evgeny Poberezkin e20a4e54c3 6.0: ios 232, android 230, desktop 61 2024-08-11 14:31:00 +01:00
Stanislav Dmitrenko 1f8c69ec23 ios: fix applying chat theme (#4656) 2024-08-11 13:11:11 +01:00
Arturs Krumins 35c37263b8 ios: fix group replaced in the list of chats with direct chat (#4655)
* add viewbuilder

* fix

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-11 12:06:25 +01:00
Arturs Krumins 9b70599cc5 ios: scroll chat list to bottom, when items are added (#4651)
* scroll chat list to bottom

* simpler

* is really near bottom

* reduce thresholds

* comment

* itemAdded

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-11 10:07:45 +01:00
Evgeny a4a11f99d2 ios: fix switching to another chat prevents marking items as unread (#4652) 2024-08-11 07:18:01 +01:00
Evgeny Poberezkin 7c8955fcdb ios: core library 6.0.0.7 2024-08-10 22:49:47 +01:00
Arturs Krumins f922064f5c iOS: fix chat list temporarily navigating to an empty view (#4647)
* add two way binding for chatList navigation

* style

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-10 22:23:56 +01:00
Evgeny 110839627f ios: new message sheet detents (#4639)
* ios: new message sheet detents

* animation

* use isActive

* fix sheet rendering

* minor

* increase onTap area

* cleanup

* cleanup

* refactor, dont allow reducing sheet once opened

---------

Co-authored-by: Levitating Pineapple <noreply@levitatingpineapple.com>
2024-08-10 22:18:49 +01:00
Evgeny Poberezkin c90b71120f core: 6.0.0.7 2024-08-10 21:53:21 +01:00
Evgeny 3ec029e489 core: fix auto-reply to the previous version clients (#4649)
* core: fix auto-reply to the previous version clients

* add condition, refactor
2024-08-10 21:52:21 +01:00
Evgeny f4c799aced ui: translations (#4648)
* Translated using Weblate (German)

Currently translated at 100.0% (2030 of 2030 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% (2030 of 2030 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% (1785 of 1785 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% (2030 of 2030 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (2030 of 2030 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% (2030 of 2030 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% (1785 of 1785 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2030 of 2030 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% (1785 of 1785 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 28.0% (569 of 2030 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% (2030 of 2030 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% (1785 of 1785 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% (1785 of 1785 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% (2030 of 2030 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% (1785 of 1785 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2030 of 2030 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% (2030 of 2030 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% (1785 of 1785 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2030 of 2030 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (2030 of 2030 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% (1785 of 1785 strings)

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

* process localizations, update RU

* remove quotes

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
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: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
2024-08-10 15:51:29 +01:00
Evgeny d970470702 ui: fix throttled chat ordering (#4645)
* ios: fix throttled chat ordering

* optimize

* account for added chats

* revert kotlin change

* dont pop chat that is already on top, unify with addChat

* android, desktop: fix chat ordering

* update

* clear

* fix ios

* refactor sorting
2024-08-10 14:04:37 +01:00
Evgeny Poberezkin 9ee74bd36e core: 6.0.0.6 (simplexmq 6.0.0.8) 2024-08-09 23:16:39 +01:00
Evgeny 0a4ff2e35f core: reduce usage of STM transactions for better performance and memory usage (#4636)
* core: reduce usage of STM transactions for better performance and memory usage

* simplexmq

* fix test crash

* enable all tests

* simplexmq
2024-08-09 22:30:30 +01:00
Stanislav Dmitrenko a3550df893 android, desktop: small layout changes (#4643)
* android, desktop: small layout changes

* padding

* blue theme handling

* themedBackground on onboarding

* status bar in call

* disabled elevation on attachments sheet to prevent seeing shadow from the bottom

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-09 21:51:40 +01:00
Evgeny Poberezkin 3778698a6e ios: set default toolbar opacity to regular, show dropdown 2024-08-09 17:26:57 +01:00
Arturs Krumins cf7a16e857 ios: translucent bars in chat view (#4641)
* extend reverse list; disable clipping

* wallpaper - ignore safe area

* minor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-08-09 17:23:57 +01:00
Evgeny bef1597fa1 ui: fix when moderation for multiple items is enabled (#4642)
* ios: fix when moderation for multiple items is enabled

* same on Android

* same

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-08-09 19:56:19 +04:00
spaced4ndy f06118835d android: don't show local authentication notice on first start (#4640) 2024-08-09 18:29:14 +04:00
Evgeny Poberezkin fa9e50a904 desktop: correct ru translation 2024-08-09 13:28:39 +01:00
Evgeny Poberezkin 932a65630c desktop, android: remove duplicate localization string 2024-08-09 13:17:14 +01:00
Evgeny b649b64999 ui: translations (#4638)
* Translated using Weblate (German)

Currently translated at 97.8% (1986 of 2029 strings)

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

* Translated using Weblate (Russian)

Currently translated at 99.2% (2014 of 2029 strings)

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

* Translated using Weblate (French)

Currently translated at 97.4% (1978 of 2029 strings)

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

* Translated using Weblate (Italian)

Currently translated at 99.1% (2012 of 2029 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.1% (2012 of 2029 strings)

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

* Translated using Weblate (Chinese (Traditional))

Currently translated at 59.0% (1198 of 2029 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 99.0% (2010 of 2029 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 99.1% (2012 of 2029 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 88.6% (1799 of 2029 strings)

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

* Translated using Weblate (Czech)

Currently translated at 88.7% (1801 of 2029 strings)

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

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 79.7% (1618 of 2029 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 99.0% (2009 of 2029 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 89.1% (1809 of 2029 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 86.0% (1745 of 2029 strings)

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

* Translated using Weblate (Finnish)

Currently translated at 72.6% (1474 of 2029 strings)

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

* Translated using Weblate (Korean)

Currently translated at 45.7% (929 of 2029 strings)

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

* Translated using Weblate (Polish)

Currently translated at 95.7% (1943 of 2029 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 45.5% (925 of 2029 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 92.8% (1883 of 2029 strings)

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

* Translated using Weblate (Thai)

Currently translated at 63.7% (1293 of 2029 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 85.0% (1726 of 2029 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 89.1% (1809 of 2029 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 99.1% (2012 of 2029 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 89.7% (1821 of 2029 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 33.0% (670 of 2029 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 27.4% (556 of 2029 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 99.2% (2013 of 2029 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2029 of 2029 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (2029 of 2029 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% (1786 of 1786 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% (2029 of 2029 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% (1786 of 1786 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2029 of 2029 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% (2029 of 2029 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% (1786 of 1786 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% (2029 of 2029 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 99.7% (1781 of 1786 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2029 of 2029 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% (1786 of 1786 strings)

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

* process localizations

* ru: translate New message

---------

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: summoner001 <summoner@vivaldi.net>
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: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
2024-08-09 13:07:19 +01:00
Evgeny e94ead3a4f ui: rename sheet to "New message" (#4637)
* ui: rename sheet to "New message"

* export localizations
2024-08-09 12:40:39 +01:00
spaced4ndy 42d7c20a47 ios: fix appSheet screen protection for ios 16 (#4635)
* ios: fix app sheet screen protection for ios 16

* comment
2024-08-09 11:43:42 +01:00
Evgeny Poberezkin cf8fd2ea11 6.0-beta.4: ios 231, android 229, desktop 60 2024-08-08 21:43:23 +01:00
Evgeny 5006742577 android: move reachable toolbar card above Private notes for the new users (#4633) 2024-08-08 20:49:00 +01:00
Stanislav Dmitrenko 38d46891a1 android, desktop: onboarding design changes (#4631)
* android, desktop: onboarding design changes

* changes

* onboardingState + status bar color

* paddings, update texts

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-08 20:25:56 +01:00
Evgeny 6a7e573b42 ios: rename group default for SimpleX Lock to protect share extension without unnecessarily locking the app (#4632) 2024-08-08 18:27:46 +01:00
Stanislav Dmitrenko b31a74567d ios: fix appSheet (#4627)
* ios: fix appSheet

* old method

* refactor

* refactor

* Revert "refactor"

This reverts commit 32333a13d3.

* Revert "refactor"

This reverts commit da42bd9ecf.

* Revert "old method"

This reverts commit a9cd219479.

* refactor

* remove

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-08-08 21:12:55 +04:00
Evgeny b3f0e71ded ios: toolbar opacity (#4630)
* ios: toolbar material

* top toolbar too
2024-08-08 17:25:45 +01:00
Evgeny ed50623ef5 ui: translations (#4626)
* Translated using Weblate (Russian)

Currently translated at 100.0% (2020 of 2020 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 86.3% (1537 of 1780 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (2020 of 2020 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% (1780 of 1780 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% (2020 of 2020 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% (1780 of 1780 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 89.5% (1808 of 2020 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (2020 of 2020 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% (1780 of 1780 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2020 of 2020 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 98.8% (1997 of 2020 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 98.8% (1997 of 2020 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 98.9% (1998 of 2020 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 98.9% (1998 of 2020 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 99.0% (2000 of 2020 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 99.0% (2000 of 2020 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 99.2% (2004 of 2020 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 99.2% (2004 of 2020 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% (2020 of 2020 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% (2020 of 2020 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% (1780 of 1780 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% (2020 of 2020 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% (1780 of 1780 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% (2021 of 2021 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 98.9% (1999 of 2021 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 93.6% (1667 of 1780 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% (2021 of 2021 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 99.5% (2011 of 2021 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.7% (2015 of 2021 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% (2021 of 2021 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 94.8% (1689 of 1780 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (2023 of 2023 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2023 of 2023 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% (2021 of 2021 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% (1780 of 1780 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% (2023 of 2023 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 93.4% (1890 of 2023 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2023 of 2023 strings)

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

* import/export localizations

* ru: corrections

* export localizations

---------

Co-authored-by: J R <jr@simplex.chat>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: הצל השחור וואהה!!!! <ty79k9+5pm8c50cjgpm4@sharklasers.com>
2024-08-08 15:27:36 +01:00
Evgeny 53368713a0 Translated using Weblate (Russian) (#4629)
Currently translated at 100.0% (257 of 257 strings)

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

Co-authored-by: J R <jr@simplex.chat>
2024-08-08 15:26:00 +01:00
Evgeny Poberezkin 5739b94808 core: 6.0.0.5 (simplexmq 6.0.0.7) 2024-08-08 13:18:49 +01:00
spaced4ndy 0782408682 multiplatform: improve info views actions buttons design (#4622)
* multiplatform: improve info views actions buttons design

* spaces

* rework

* fix width
2024-08-08 13:10:13 +01:00
Evgeny 41576f80e7 ui: update whats new in 6.0 (#4625)
* ui: update whats new in 6.0

* update

* export localization

* android whats new
2024-08-08 13:07:55 +01:00
Arturs Krumins 2503a86f07 ios: tapping chat list bottom bar scrolls to search input (#4623)
* ios: tapping bottom bar scrolls to search input

* disable for iOS15
2024-08-07 23:00:16 +01:00
spaced4ndy dc713268e8 ios: fix search color in simplex dark theme (#4611)
* ios: fix search color in simplex dark theme

* paddings, colors, group icon

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-07 22:39:05 +01:00
Stanislav Dmitrenko d0c52e43a2 android, desktop: throttle items moving around in chat list too often (#4617)
* android, desktop: throttle items moving around in chat list too often

* test

* Revert "test"

This reverts commit 82db198ed9.

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-07 20:34:51 +01:00
Diogo 2e8e6cef7e android: reachable toolbar card on start (#4608)
* android: reachable toolbar card on start

* same padding for all elements

* show alert with instruction when dismissed

* reset tip, fix for variable font size

* layout, rename

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-08-07 20:20:12 +01:00
Arturs Krumins 239c815f3e ios: fix chat list bottom bar background appearance (#4612)
* ios: fix chat list bottom bar background appearance

* push up bottom bar, when no home indicator is present; tapable chats

* smaller toolbar

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-07 16:24:15 +01:00
Stanislav Dmitrenko 1a6245fe51 android, desktop: prevent migration when network conf wasn't applied (#4615)
* android, desktop: prevent migration when network conf wasn't applied

* name of param
2024-08-07 15:42:31 +01:00
Evgeny b3d15f97f0 core: stop stats when chat is stopped (#4616)
* core: stop stats when chat is stopped

* rename field

* simplexmq
2024-08-07 14:49:58 +01:00
Evgeny c0b8cfb3e2 ui: reset hints in dev tools (#4613)
* ui: reset hints in dev tools

* fix disabled, icon, remove damage

* icon
2024-08-07 11:01:23 +01:00
Arturs Krumins 818161c6ed ios: fix chat list swipe action localisation regression (#4610) 2024-08-07 08:36:52 +01:00
Evgeny Poberezkin 4c53620dfa 6.0-beta.3: ios 230, android 228, desktop 59 2024-08-06 23:33:59 +01:00
spaced4ndy ea5afb28d3 ios: one hand UI (#4589)
* ios: fix bottom toolbar for one hand ui (#4585)

* fix chat list toolbars forhandUI

* add TODO

* cleanup

* fix safe top safe area

* format

---------

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

* fix sheet layout; move user picker (#4592)

* ios: invert swipe actions in oneHandUI mode (#4596)

* add swipe label

* minor

* adjust font

* dynamic type

* limit use to oneHandUI

* icon size

* fix offset

* change font style

---------

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

* ios: reachable toolbar card on start (#4594)

* ios: reachable toolbar card on start

* rename toggle

* move to one-hand UI default to app group

* clean up

* remove tap gesture on toolbar

* "fix" iOS 15

---------

Co-authored-by: Arturs Krumins <auth@levitatingpineapple.com>
Co-authored-by: Evgeny <evgeny@poberezkin.com>
Co-authored-by: Levitating Pineapple <noreply@levitatingpineapple.com>
2024-08-06 22:33:48 +01:00
spaced4ndy 060760675d ios: fix local authentication becoming enabled by default on app update and for new installations (#4595) 2024-08-06 22:06:07 +01:00
Diogo 75101ac885 desktop: dismiss chat sheet when contact connects while qrcode is open (#4607) 2024-08-06 21:58:31 +01:00
Evgeny Poberezkin 159f66e812 ios: update library 2024-08-06 21:24:41 +01:00
Evgeny Poberezkin 6d19b48979 core: 6.0.0.4 (simplexmq 6.0.0.6) 2024-08-06 19:39:09 +01:00
Evgeny ce73a15787 ui: translations (#4600)
* Translated using Weblate (Dutch)

Currently translated at 98.2% (1969 of 2004 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 99.4% (1992 of 2004 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 99.6% (1996 of 2004 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 99.8% (2001 of 2004 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 99.9% (2002 of 2004 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% (2004 of 2004 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% (1746 of 1746 strings)

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

* Translated using Weblate (Russian)

Currently translated at 91.9% (1842 of 2004 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2004 of 2004 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 99.7% (1741 of 1746 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% (2004 of 2004 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% (1746 of 1746 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% (2004 of 2004 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% (1746 of 1746 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% (2004 of 2004 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% (1746 of 1746 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2004 of 2004 strings)

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

* export/import localizations

* ru: typos

* export localizations

---------

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: GameBoyNoob <game.boy.new26@gmail.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
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: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
2024-08-06 19:35:04 +01:00
Evgeny e6545a1747 ui: whats new in v6.0, rename "Deleted chats" to "Archived contacts" (#4599)
* ios: whats new in v6.0

* android, rename Deleted chats to Archive contacts
2024-08-06 19:20:54 +01:00
Diogo 601b081cab android: one hand UI fixes and improvements (#4597)
* fix bottom toolbar in share one hand ui

* rename one hand ui label to reachable chat toolbar

* one hand ui to be android default

* dumb if remove

* make one hand ui always false when outside android

* override set of one hand ui for imports on desktop

* no need to override current

* always default one hand to true

* one hand ui without using mirrors

* remove unused vars

* added space on multiplication

* clean subscription to prop and param spread

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-08-06 18:27:57 +01:00
spaced4ndy d31dedf132 ui: revert to always show subscriptions indicator, but make it light blue instead of gray for new users (fresh installation with no chats) (#4604) 2024-08-06 20:31:45 +04:00
Evgeny 7441ed9892 core: choose random servers for the first user profile, use the same servers for other profiles (#4584)
* core: choose random servers for the first user profile, use the same servers for other profiles

* update ui clients
2024-08-06 16:13:36 +01:00
Stanislav Dmitrenko f6ee6338c4 android: status bar color fix in non-oneHandUI (#4603) 2024-08-06 16:12:30 +01:00
Stanislav Dmitrenko 5a42c0c1d2 android, desktop: show database import/export errors (#4601)
* android, desktop: show database import/export errors

* no line
2024-08-06 15:37:55 +01:00
Stanislav Dmitrenko 240131a023 android, desktop: move some network settings to advanced network settings (#4583)
* android, desktop: move some network settings to advanced network settings

* strings

* icon

* string

* fix

* change

* icon and footer

* paddings

* revert debug lines
2024-08-06 15:08:47 +01:00
spaced4ndy 37e275c3ca core: change simplex contact cards order (#4593) 2024-08-06 12:58:05 +04:00
spaced4ndy f893ad15de ui: only show subsription summary indicator after any chat is created; ios: fix servers summary sheet dismissal, screen protection (#4590) 2024-08-06 12:03:25 +04:00
Evgeny a0763b3a43 ios: same size of action buttons in chat info sheets (#4587) 2024-08-06 08:12:42 +01:00
Arturs Krumins e6ba82c8ff ios: improve performance, when receiving many messages in a single chat (#4586)
* use UnreadCollector for new messages

* less confusing

* collect removed items to reduce unread counts

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-05 23:36:33 +01:00
spaced4ndy a8bdf1555f ios: new chat sheet & info views action buttons improvements (#4582) 2024-08-05 21:22:09 +04:00
Evgeny d278b3dbcd core: resume message subscriptions as soon as client is moved to foreground (iOS) or network connection appears (iOS and Android) (#4577)
* core: resume subscriptions as soon as iOS client is moved to foreground

* simplexmq

* simplexmq
2024-08-05 16:42:29 +01:00
spaced4ndy ac4b1e9406 multiplatform: improve deleted chats design (#4581) 2024-08-05 19:39:16 +04:00
Stanislav Dmitrenko b04f159970 android, desktop: blur images of blocked group members (#4579)
* android, desktop: blur images of blocked group members

* simplify

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-05 15:01:50 +01:00
Diogo 55331289d3 ios: improve new and existing chat interactions - new chat sheet, one hand ui, info views action buttons; new modes of contact deletion (keep conversation, only delete conversation) (#4427)
* ios: added delete contacts, one hand ui, and contact action buttons

* remove unused, rework info buttons wip

* ios: moved existing buttons to new chat sheet

* ios: add basic list of contacts to new chat sheet

* ios: add deleted chats section to new chat sheet

* group chat info navigation

* fix spacing of group info buttons

* remove comment

* unify spacing logic across info views

* info button alerts wip

* calls alerts wip

* call buttons alerts

* fix call button to correctly update on preference change while in view

* refactor

* fix alert ids

* contact list wip

* more contact list actions

* open chat wip

* fix contact list elements clickability

* ios: search functionality on new chat sheet

* ios: white bg for search box on new chat sheet

* ios: don't show empty list when pasted contact is not known

* ios: add search and nav title to deleted chats

* navigation links wip

* fix refreshable

* ios: empty states for lists

* ios: hide contact cards from chat list

* ios: make search bar icon sizes consistent

* ios: fix deleted conversation dissapearing from chat list on back

* fix pending invitation cleanup in chat sheet

* rename search label from open to search

* make cleanup alert work on sheet and on dismiss

* dismiss all sheets after creation of groups

* fix double toolbar on group invite members

* fix double toolbar on group link invitation screen

* dismiss all on group creation error

* comment

* show alert in dismissAllSheets completion

* fix sheet dismissal on known group

* rework contact list with buttons (fixes dark mode)

* fix dark mode on new chat view

* fix search dark mode

* increase search padding

* improve new chat title and info button placing

* info view background

* improve create group title placement

* refactor

* fix delete dialogue in light mode

* change icon

* archivebox on contact list

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-05 15:58:24 +04:00
Stanislav Dmitrenko b2b1519aea android, desktop: multiple messages deletion (#4559)
* android, desktop: multiple messages deletion

* icons

* icon
2024-08-05 10:26:27 +01:00
Evgeny e769abf14a ui: translations (#4575)
* Deleted translation using Weblate (Hindi)

* Deleted translation using Weblate (Malayalam)

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1963 of 1963 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 97.1% (1695 of 1745 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1963 of 1963 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% (1963 of 1963 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 99.6% (1739 of 1745 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1963 of 1963 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1745 of 1745 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 99.0% (1728 of 1745 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 2.5% (44 of 1745 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 91.8% (1803 of 1963 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1963 of 1963 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% (1745 of 1745 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% (1745 of 1745 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 2.8% (50 of 1745 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 96.5% (1895 of 1963 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 38.9% (680 of 1745 strings)

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

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

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

* Translated using Weblate (Arabic)

Currently translated at 3.4% (61 of 1745 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 3.8% (67 of 1745 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 99.5% (1987 of 1996 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 4.5% (80 of 1745 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% (1996 of 1996 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% (1996 of 1996 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 100.0% (1996 of 1996 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1996 of 1996 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1996 of 1996 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 46.8% (935 of 1996 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1996 of 1996 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% (1745 of 1745 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 5.5% (96 of 1745 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 46.9% (937 of 1996 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1996 of 1996 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1996 of 1996 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 99.9% (1744 of 1745 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 28.0% (559 of 1996 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% (1996 of 1996 strings)

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

* import/export localizations

* update strings

---------

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Muhammad AbdelMajeed <Muhammad.offic@proton.me>
Co-authored-by: shit face <shitface@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: הצל השחור וואהה!!!! <ty79k9+5pm8c50cjgpm4@sharklasers.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Fábio Ferreira <ffcfpten@gmail.com>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: Pixelcode <pixelcode@dismail.de>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: mlanp <github@lang.xyz>
2024-08-05 10:19:32 +01:00
Evgeny 9ca7031f82 Translated using Weblate (German) (#4574)
Currently translated at 100.0% (257 of 257 strings)

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

Co-authored-by: Pixelcode <pixelcode@dismail.de>
2024-08-05 09:36:49 +01:00
Evgeny 7a418918d6 ios: blur images of blocked group members (#4573)
* ios: blur images of blocked group members

* refactor
2024-08-04 22:24:08 +01:00
Stanislav Dmitrenko 8f1302e1c6 android, desktop: chat preview, compose message, new chat button (#4576)
* android, desktop: chat preview, compose message, new chat button

* padding on desktop

* multiplier

* no placeholder in console

* sheet elevation zero when hidden

* divider

* padding

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-04 21:57:23 +01:00
Evgeny ee7c5d2aac android: smaller new chat button in 1-hand UI mode, line on the correct side of the bar (#4569)
* android: smaller new chat button in 1-hand UI mode, line on the correct side of the bar (wrong color in 1-hand UI mode)

* remove comment

* desktop: open new chat information buttons on start modal

* remove no longer applicable comment

* desktop, android: move to chat when accepting from chat list and snsReady

* android: keep search visible if keyboard is open on new chat sheet

* android: keep search visibile if keyboard is open on chat list

* android: scroll modal header on new chat sheet

* android: added divider between search and toolbar in one hand ui

* make one hand ui toolbar more extensible by using scafold

* android: remove tiny paddings around one hand ui toolbars

* android: hide toolbar when searching on one hand ui

* avoid passing one hand ui as param everywhere

* make paddings match in new chat sheet action buttons

* flip animation

* refactor and divider fix

* fix padding

* bigger padding

* appPrefs

---------

Co-authored-by: Diogo Cunha <diogofncunha@gmail.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-08-04 21:37:20 +01:00
Evgeny bf697c722a ios: update messages in share extension alert when message sending is slow (#4578) 2024-08-04 20:48:54 +01:00
Evgeny f30dfa0be7 ios: move onion and private routing to advanced network settings, enable private routing by default (#4571)
* ios: move onion and private routing to advanced network settings, enable private routing by default

* update

* update labels

* update localizations
2024-08-04 12:01:09 +01:00
Evgeny Poberezkin 9c73ef9769 android, desktop: search placeholder color and size 2024-08-03 10:21:54 +01:00
Stanislav Dmitrenko e38db7fb44 android: status bar and navigation bar colors from theme (#4568)
* android: status bar and navigation bar colors from theme

* padding

* background on desktop

* useless code

* colors

* removed unused param

* one more place
2024-08-02 23:48:41 +01:00
Evgeny Poberezkin cb76c8079c core: fix archive export when some filename is not compatible with zip (#4561)
* core: fix archive export when some filename is not compatible with zip

* update

* core, ios

* update kotlin apis, ios: add alert to migrate from device
2024-08-02 20:23:54 +01:00
Stanislav Dmitrenko 8fbba16f53 android, desktop: enhancements to chat switching (#4567) 2024-08-02 16:01:21 +01:00
Arturs Krumins 5384e2826d ios: throttle items moving around in chat list too often (#4564)
* ios: add throttling for incoming messages

* cleanup

* throttle, update unread

* dont pop the first chat

* move chats every 3 seconds

* fix

* optimize

* better updateChats

* remove file

* diff

* restore special case for the current chat

* ios: simpler item throttler

* minor

* minor

* refactor

* sort by key

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-02 14:08:10 +01:00
Diogo 0975079a93 multiplatform: improve new and existing chat interactions - new chat sheet, one hand ui, info views action buttons; new modes of contact deletion (keep conversation, only delete conversation) (#4435)
* android, desktop: added action buttons and delete to contact card, added toolbar

* android, desktop: added setting for one hand ui

* android: implemented one hand ui for chat list screen (#4448)

* android: implemented one hand ui for chat list screen

* android, desktop: remove extra toolbar

* android: fixed user picker positioning

* android, desktop: new chat sheet (#4479)

* (early draft) android, desktop: new chat sheet

* first draft

* android, desktop: new chat UI improvements

* android, desktop: removed group connections

not needed, missunderstanding in requirements

* android, desktop: deleted contacts and requests

* android, desktop: showing only actionable contacts

* android, desktop: made full new chat sheet scrollable

* android, desktop: handled empty lists

* refactor: fixed fn access scopes

* android, desktop: made sure contacts list refreshes on changes

* android: removed one hand ui for new chat sheet

* android, desktop: removed no longer used code

* android: moved new chat button to toolbar for one hand ui

* removed unused imports

* android, desktop: remove favorite contact set functionality from new chat sheet

* android, desktop: improved chat redirect

* android, desktop: removed padding from contact rows

* android, desktop: improved paddings

* android, desktop: started to use accent color for contact cards and requests

* android, desktop: fixed modals and improved contact stage tracking

* android, desktop: made deleted contacts contactable

* android, desktop: allowed for simplex links to be pasted in new chat sheet

* android, desktop: added interaction for contact cards

* close modal

* android, desktop: started to hide cards from chat list

* android, desktop: translations cleanup

* android, desktop: started to mark deleted chat as non deleted when open from new chat sheet

* android, desktop: fixed link pastes for existing connections

* android, desktop: redirect to groups when group links are pasted in new chat sheet

* move one hand ui toggle

* refactor

* on contact card interaction only close new chat sheet on connect

* android, desktop: removed usages of connection stage enum

* android, desktop: stopped preloading active chats on new chat sheet

* android: fixed invitation cleanup

* desktop: fixed invitation cleanup

* desktop: improved consistency on modals to close

* desktop: added small delay to focus re-position logic to avoid focus change cancelling click events

* android, desktop: made add contact learn more smaller to avoid header becoming bigger than expected

* android, desktop: redirect to chat on accept if send is ready

---------

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

* android, desktop: hide new chat sheet action buttons when search text is not empty instead of when search is focused (#4529)

* android, desktop: contacts, groups and group member action buttons (#4523)

* android, desktop: made action buttons round

* android, desktop: updated action buttons for contacts

* android, desktop: added action buttons for groups

* android, desktop: removed context menu items

* android, desktop: cleaned up visuals and paddings for contact and group card action buttons

* android, desktop: improved modal close logic

* android, desktop: improved search

* adjust color, fix paddings

* android, desktop: avoided async calls to open chats and simplified search as result

* android, desktop: moved mute button to the end on group view to match chat view

* android, desktop: made filling of icons consistent

* android, desktop: fixed contacts sheet close and dismiss actions on contact connection

* order

---------

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

* android, desktop: streamlined delete actions based on contact type (#4538)

* android, desktop: streamlined delete actions based on contact type

* removed unused translations

* refactor, adjust texts

* move toggle closer to buttons

* fix text

* fix accept request

* android, desktop: made sure deleted contacts update on deletes

---------

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

* restore deleted file

* desktop: stop closing modal on message search

* android, desktop: remove scroll preservation on new chat sheet unmount

* android, desktop: add functionality to search inside deleted conversation on main new chat sheet screen

* android, desktop: fixed attachment bug when clicking contact with keyboard open inside new chat sheet

* desktop, android: set incognito contacts color to Indigo in contact list

* remove unused code

* remove openedFromChatView

* android, desktop: change icon for contact requests and added icon for contact cards

* refactor

* fix paddings

* fix padding

* refactor

* android, desktop: fix attachment issue for deleted contacts

* remove unused

* android: invert new chat sheet on one hand ui

* info buttons alerts

* info buttons paddings

* android: one hand ui for new chat sheet and deleted chats

* fix build after latest master changes on chat model and mutations in chat

* android,desktop: add menu items back

* add scrollbars to new chat sheet

* desktop: inactivate and rephrase scan since it is not supported

* android: one hand ui for forward chat list

* android, desktop: fix for no chats in one hand ui

* desktop: use left side of screen for new chat actions

* desktop: close end modal when new chat sheet is clicked

* android: fix no filtered contacts on delete contacts view

* fix scrollbar not showing

* android: few adjustmnets in one hand ui

* change icon

* increase icon size

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-08-02 14:09:57 +04:00
Stanislav Dmitrenko 74e2b7582e scripts (linux): fix building appimage with missing runtime file (#4565) 2024-08-02 09:34:04 +01:00
spaced4ndy 413a8f6b76 core: correctly update chat item deletable state on deletions (#4558) 2024-08-01 18:56:41 +04:00
Evgeny Poberezkin 619cff91b2 ios: export localized strings for translation 2024-08-01 14:58:39 +01:00
Evgeny Poberezkin 2ee16f9398 website: translations (#4556)
* Translated using Weblate (Czech)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Czech)

Currently translated at 100.0% (257 of 257 strings)

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

---------

Co-authored-by: zenobit <zen@osowoso.xyz>
2024-08-01 14:14:50 +01:00
Arturs Krumins bfab2d9fb6 ios: fix alert reseting list position (#4554)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-01 10:21:31 +01:00
Evgeny Poberezkin 229ea80499 ios: fix sharing links with previews (#4552)
* desktop: fix app without user crashing when trying to get subscription data (#4551)

* use newline

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-08-01 09:51:22 +01:00
spaced4ndy 95de471754 desktop: fix app without user crashing when trying to get subscription data (#4551) 2024-08-01 08:05:35 +01:00
Arturs Krumins cbc86cd81e ios: disable chats in share-sheet based on preferences (#4549)
* claenup

* cleanup

* remove groupFeatureEnabled from Chat

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-08-01 07:48:17 +01:00
Stanislav Dmitrenko 19cab39ee8 android, desktop: refactoring to use mutex when updating chats (#4541)
* moving to mutablestate + snapshotstatelist from snapshotstatelist

* android, desktop: refactoring to use mutex when updating chats

* wrapped into class instead of object

* fix

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-31 18:43:31 +01:00
Arturs Krumins 6fa3695ad6 ios: add database password prompt to share-sheet, fix sharing screenshot (#4546)
* ios: add password prompt to share-sheet

* fix sharing screenshots

* s/Password/Passphrase/

* alert title

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-31 18:07:11 +01:00
Stanislav Dmitrenko 6e6afdbd25 ios: multiple messages deletion (#4535)
* ios: multiple messages deletion

* changes

* layout

* fix

* changes in design and UX

* fixes

* padding

* paddings

* refactor

* changes

* gray circles, separator, optimize

* titles

* disable moderation for own single message

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-31 15:00:14 +01:00
Evgeny Poberezkin 93e88c3953 ios: optionally lock share extension when SimpleX Lock is enabled (default is to lock), allow link previews if enabled in the app, use the same shape of avatars (#4547) 2024-07-31 13:54:47 +01:00
Evgeny Poberezkin 676b533393 ui: translations (#4540)
* Translated using Weblate (Hungarian)

Currently translated at 99.7% (1948 of 1953 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 99.7% (1948 of 1953 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% (1953 of 1953 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% (1687 of 1687 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% (1953 of 1953 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% (1687 of 1687 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1953 of 1953 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% (1953 of 1953 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% (1687 of 1687 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 3.8% (75 of 1953 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 99.6% (1947 of 1953 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1953 of 1953 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1953 of 1953 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% (1687 of 1687 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1953 of 1953 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 94.2% (1590 of 1687 strings)

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

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 83.5% (1631 of 1953 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 4.4% (86 of 1953 strings)

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

* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

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

* Translated using Weblate (French)

Currently translated at 99.7% (1948 of 1953 strings)

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

* Translated using Weblate (French)

Currently translated at 99.5% (1679 of 1687 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 96.0% (1875 of 1953 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 94.1% (1589 of 1687 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% (1953 of 1953 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% (1687 of 1687 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1953 of 1953 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 25.4% (498 of 1953 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% (1687 of 1687 strings)

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

* Translated using Weblate (French)

Currently translated at 99.5% (1680 of 1687 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 99.5% (1945 of 1953 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.3% (1659 of 1687 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 98.3% (1659 of 1687 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 4.6% (90 of 1953 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 99.5% (1944 of 1952 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% (1685 of 1687 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1958 of 1958 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% (1952 of 1952 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% (1687 of 1687 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 26.0% (509 of 1952 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% (1958 of 1958 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1958 of 1958 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% (1952 of 1952 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% (1687 of 1687 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1958 of 1958 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% (1952 of 1952 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% (1687 of 1687 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 26.6% (521 of 1952 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% (1952 of 1952 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% (1687 of 1687 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1952 of 1952 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1687 of 1687 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1952 of 1952 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% (1687 of 1687 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 5.2% (103 of 1952 strings)

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

* Translated using Weblate (Polish)

Currently translated at 96.6% (1893 of 1958 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1952 of 1952 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% (1687 of 1687 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 27.8% (543 of 1952 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 5.2% (103 of 1952 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1963 of 1963 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1963 of 1963 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 99.9% (1957 of 1958 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 100.0% (1687 of 1687 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 5.3% (104 of 1952 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1963 of 1963 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1963 of 1963 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1963 of 1963 strings)

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

* update multiplatform strings

* ios: import localizations

* export localizations, add localized strings to extensions

---------

Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: billy appetie <billy_appetie@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Diego Luiz <diegoluizfps@gmail.com>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Mqlx <vncrlecgubhp@rel.eliott.cc>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
2024-07-31 08:54:03 +01:00
Stanislav Dmitrenko e1fb0ac0b1 ui: delete multiple messages (#4532)
* ui: delete multiple messages

* ios

* simplify, rename

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-30 23:56:56 +01:00
Evgeny Poberezkin 8bda64a5c1 core: api to delete multiple messages (#4452)
* core: api proposal (not implemeted) to delete multiple messages

* core: batch delete multiple messages; allow to moderate self (#4513)

* allow to moderate self, remove saving item-message record on mark delete

* direct batched

* local batched

* group batched

* moderate batched

* refactor

* fix

* fix test

* remove unused event

* direct message batching wip

* direct test

* more tests

* trunk

* batch compressed

* remove unused function

* new agent api

* sendGroupMessages

* forward batched

* refactor

* remove comment

* rename, comment

* refactor

* many chat batches test (doesn't pass)

* refactor

* comment

* rename

* comment

* linearize

* fix

* fix

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* core: check item deletable with margin (#4533)

* simplexmq

* remove L.singleton (ghc 8.10.7)

* test delay

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-07-30 22:59:47 +01:00
spaced4ndy ab058d7222 core: add SimpleX-Status preset contact card; create contact cards for each new user (#4544) 2024-07-30 20:00:51 +04:00
Evgeny Poberezkin 4f9c53f561 6.0-beta.2: ios 229, android 227, desktop 58 2024-07-30 08:14:22 +01:00
Stanislav Dmitrenko 5257c6f9ca android, desktop: fix crash on fast clicking every chat in list (#4536)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-30 07:33:15 +01:00
Evgeny Poberezkin 6729b1fb4f ios: update core library 2024-07-29 23:00:54 +01:00
Evgeny Poberezkin ac5351a752 core: 6.0.0.3 (simplexmq 6.0.0.5) 2024-07-29 22:14:23 +01:00
Evgeny Poberezkin 2ff4619ca4 ios: improve chat list layout (#4537) 2024-07-29 22:11:02 +01:00
spaced4ndy 493ad14b39 core: make user db actions high priority, faster chat start with async db operations (#4531)
* core: move db actions out of synchronous execution on chat start

* revert some

* multiplatform: load chat data before starting chat

* use priority database access

* simplexmq

* fix race in the tests

* check chat is running

* core: allow getting call invitations and notificationn token when chat is stopped

* ios: load chats and refresh call invitations before chat is started

* simplexmq

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-29 21:52:45 +01:00
Arturs Krumins 7f08f87ee4 ios: improve conversation scrolling (fixes hangs when messages are updated). (#4534)
* ios: fix hang while updating chat item state

* throttle item update

* fix

* remove buttons, switch back to Debug

* remove items getter/setter from ChatModel

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-29 21:17:14 +01:00
Evgeny Poberezkin ce1b66cef2 ios: optimize marking messages read (#4530)
* ios: optimize marking messages read

* remove view ifs
2024-07-29 09:49:43 +01:00
Evgeny Poberezkin 3e18fdc34d ios: link framework into share extension without embedding 2024-07-28 23:28:53 +01:00
Evgeny Poberezkin c09075d71e ios: update core library 2024-07-28 23:05:41 +01:00
Evgeny Poberezkin 41b4d7851a ios: improve chat list layout (#4528) 2024-07-28 21:53:21 +01:00
Evgeny Poberezkin 92bec5eabb core: 6.0.0.2 (simplexmq 6.0.0.4) 2024-07-28 18:11:38 +01:00
Stanislav Dmitrenko 24587ecc92 scripts (windows): add follow redirects to curl (#4526) 2024-07-28 17:55:58 +01:00
Evgeny Poberezkin 6865515f43 ios: share extension (#4466)
* ios: share extension (#4414)

* ios: add share extension target

* ios: Add UI

* ios: send file from share-sheet

* image utils

* ShareError

* error handling; ui-cleanup

* progress bar; completion for direct chat

* cleanup

* cleanup

* ios: unify filter and sort between forward and share sheets

* ios: match share sheet styling with the main app

* ios: fix text input stroke width

* ios: align compose views

* more of the same...

* ShareAPI

* remove combine

* minor

* Better error descriptions

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* ios: enable file sending workers in share extension (#4474)

* ios: align compose background, row height and fallback images for share-sheet (#4467)

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* ios: coordinate database access between share extension, the app and notifications extension (#4472)

* ios: database management proposal

* Add SEState

* Global event loop

* minor

* reset state

* use apiCreateItem for local chats

* simplify waiting for suspension

* loading bar

* Dismiss share sheet with error

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* send image message (#4481)

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* ios: improve share extension completion handling (#4486)

* improve completion handling

* minor

* show only spinner for group send

* rework event loop, errorAlert

* group chat timeout loading bar

* state machine WIP

* event loop actor

* alert

* errors text

* default

* file error

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* ios: add remaining share types; process attachment in background on launch (#4510)

* add remaining share types; process attachment in background on launch

* cleanup diff

* revert `makeVideoQualityLower`

* reduce diff

* reduce diff

* iOS15 support

* process events when sharing link and text

* cleanup

* remove video file on failure

* cleanup CompletionHandler

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* ios: share extension - additional alerts and media previews (#4521)

* add remaining share types; process attachment in background on launch

* cleanup diff

* revert `makeVideoQualityLower`

* reduce diff

* reduce diff

* iOS15 support

* process events when sharing link and text

* cleanup

* remove video file on failure

* cleanup CompletionHandler

* media previews

* network timeout alert

* revert framework compiler optimisation flag

* suspend chat after sheet dismiss

* activate chat

* update

* fix search

* sendMessageColor, file preview, chat deselect, simplify error action

* cleanup

* interupt database closing when sheet is reopened quickly

* cleanup redundant alert check

* restore package

* refactor previews, remove link preview

* show link preview when becomes available

* comment

* dont fail on invalid image

* suspend

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* ios: descriptive database errors (#4527)

* ios: set share extension as inactive when suspending chat

---------

Co-authored-by: Arturs Krumins <auth@levitatingpineapple.com>
2024-07-28 17:54:58 +01:00
Evgeny Poberezkin 5ee6f40e75 cli: allow passing ChatOpts parameter (#4525) 2024-07-28 12:06:07 +01:00
Evgeny Poberezkin 637189cc2d core: multiline output (#4520) 2024-07-26 15:21:06 +01:00
Evgeny Poberezkin 13bfc9e92b core: update app settings for migration (#4518) 2024-07-26 10:30:49 +01:00
Stanislav Dmitrenko 032c5d3a5b android, desktop: blur for media (#4508)
* android, desktop: blur for media

* change

* new option and applied blur to other elements

* new line

* added to migration

* long click handling

* hover on desktop

* changes

* change

* showDownloadButton function

* file rename

* don't blur when menu is visible

* rename
2024-07-26 09:29:13 +01:00
Evgeny Poberezkin a53333be20 ios: increase wallpaper scale (#4517) 2024-07-26 09:11:42 +01:00
Stanislav Dmitrenko a966f6b19d ios: blur for media (#4512)
* ios: blur for media

* line

* one more place

* changes for video

* using notification center

* change

* unused code

* string

* simplify

* refactor ifs

* fix

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-26 08:38:22 +01:00
Arturs Krumins 70d577260b ios: fix crash when changing screen orientation with tiled wallpaper (#4511)
* ios: fix crash, when displaying wallpaper

* simpler

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-25 20:19:44 +01:00
Stanislav Dmitrenko ea12982788 ios: fix two-line preview on IOS 17+ (#4514) 2024-07-25 14:53:10 +01:00
Stanislav Dmitrenko 6fca6c22c5 ios: interactive media and link previews in the list of chats (#4487)
* ios: interactive media and link previews in the list of chats

* commented out voice preview

* voice message support and various fixes

* changes to video

* changes

* playing voice in chat list with scrolling

* revert

This reverts commit 60f57403d1.

* prevent feedback loop

* version of dependency

* voice

* fix param

* working voice

* reacting on messages and chat deletion

* fix two videos in a row

* video item layout

* fix

---------

Co-authored-by: Levitating Pineapple <noreply@levitatingpineapple.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-23 18:11:42 +01:00
Evgeny Poberezkin e343dd017b core: fix nix build for iOS build with tagged JSON (e.g., Flutter apps) (#4484) 2024-07-22 19:35:36 +01:00
spaced4ndy 70a94d772a multiplatform: optimize subscription indicator (#4503) 2024-07-22 20:40:22 +04:00
spaced4ndy 2689d1e27b ios: optimize subscription indicator (#4501) 2024-07-22 19:32:54 +04:00
spaced4ndy 4a9b54fbaf core: get subs total api (#4500) 2024-07-22 19:06:53 +04:00
Evgeny Poberezkin f10a0ce58e core: receive only one notification message on push notification (#4504)
* core: receive only one notification message on push notification

* ios: receive only one notification message on push

* update stats to include notification server stats

* Codable

* update simplexmq
2024-07-22 15:48:57 +01:00
spaced4ndy 6d488ba489 android: improve proxy errors (#4489) 2024-07-19 20:10:31 +04:00
spaced4ndy 95776e0951 ios: improve proxy errors (#4485) 2024-07-19 18:39:12 +04:00
spaced4ndy bf9cdf3053 android: allow sending messages immediately on joinConnection, acceptContact (#4483) 2024-07-19 12:50:27 +04:00
spaced4ndy fa73e63a79 ios: allow sending messages immediately on joinConnection, acceptContact (#4478) 2024-07-19 11:31:43 +04:00
spaced4ndy bfab76ed90 core: allow sending messages immediately on joinConnection, acceptContact (#4465) 2024-07-18 20:33:51 +04:00
Stanislav Dmitrenko 905295ee5f android, desktop: interactive media and link previews in the list of chats (#4460)
* android, desktop: chat item content preview in chat list

* better

* moved code

* layout

* multiplier for files

* small

* changes

* changes

* changes

* no padding

* changes

* color

* multiplier

* changes

* fix state inconsistency in gallery

* voice messages improvements

* showing draft

* re-layout preview

* rename and padding

* fix

* padding

* link icon

* without offset

* image

* hand on hover

* color

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-18 16:26:06 +01:00
Evgeny Poberezkin a1e707ac1b ui: translations (#4469)
* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1934 of 1934 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 99.6% (1928 of 1934 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 100.0% (1934 of 1934 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% (1681 of 1681 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 99.6% (1928 of 1934 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% (1934 of 1934 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% (1934 of 1934 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% (1681 of 1681 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 2.8% (55 of 1934 strings)

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

* Translated using Weblate (German)

Currently translated at 97.7% (1908 of 1952 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1934 of 1934 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 99.6% (1928 of 1934 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 100.0% (1934 of 1934 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% (1681 of 1681 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 99.6% (1928 of 1934 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% (1934 of 1934 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% (1934 of 1934 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% (1681 of 1681 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 2.8% (55 of 1934 strings)

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

* Translated using Weblate (German)

Currently translated at 97.7% (1908 of 1952 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 98.7% (1927 of 1952 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1952 of 1952 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% (1952 of 1952 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1952 of 1952 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% (1681 of 1681 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% (1952 of 1952 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 92.8% (1813 of 1952 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1952 of 1952 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% (1952 of 1952 strings)

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

* process localizations

---------

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: MM <mecymyse@gmail.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
2024-07-17 19:00:47 +01:00
Evgeny Poberezkin fea51b75e9 ios: fix start chat api 2024-07-17 14:20:58 +01:00
Evgeny Poberezkin ff8bbf11e7 core: allow start in extension without subscriptions but with enabled files (#4464)
* core: allow start in extension without subscriptions but with enabled files

* only start sending files

* update

* update

* update simplexmq
2024-07-17 14:14:19 +01:00
Evgeny Poberezkin 391e9d57f2 docs: update transparency 2024-07-16 21:31:15 +01:00
Evgeny Poberezkin dae9f8575d ui: change labels in server stats, move percentage toggle (#4468)
* ui: change labels in server stats, move percentage toggle

* localizations
2024-07-16 20:41:00 +01:00
spaced4ndy 065d9be614 multiplatform: better errors (#4463) 2024-07-16 17:19:58 +04:00
spaced4ndy 4251762553 ios: better errors (#4462) 2024-07-16 17:19:37 +04:00
Evgeny Poberezkin c7017b3efc 6.0-beta.1: ios 228, android 226, desktop 57 2024-07-16 09:52:55 +01:00
Evgeny Poberezkin b4ae3b9431 ui: enable private message routing by default for all unknown servers (#4461) 2024-07-15 23:13:33 +01:00
Evgeny Poberezkin 7138b09bae core: 6.0.0.1 (simplexmq 6.0.0.2) 2024-07-15 23:06:11 +01:00
Evgeny Poberezkin bf59402856 cli: option to only use SOCKS5 proxy with onion-only relays (#4459)
* cli: option to only use SOCKS5 proxy with onion-only relays

* simplexmq

* show socks mode in CLI, fix to use correct network config
2024-07-15 23:04:09 +01:00
Stanislav Dmitrenko c6e5d6e2b8 android, desktop: chat list item layout (#4458)
* android, desktop: chat list item layout

* changes

* changes

* removed background

* paddings

* returned aligning
2024-07-15 14:21:18 +01:00
Evgeny Poberezkin 0847b725b3 ios: toolbar and message entry area background color (#4449)
* ios: toolbar and message entry area background color

* remove VStack, opacity

* ios: adjust compose view background color to match top bar (#4456)

* search

* replace BlurView with .thinMaterial

* context item background with shadow

* search

* Revert "context item background with shadow"

This reverts commit fc4ad32417.

* rework shadow

* shadow on both sides

* Revert "shadow on both sides"

This reverts commit a07920af91.

* Revert "rework shadow"

This reverts commit 78728263fb.

* dividers

* remove paddings

* height

* search

* focus search

* color

* search background

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-07-15 13:14:14 +01:00
Evgeny Poberezkin 0d6f43a5ac ui: different label for subscribed connections: Message push, Active connections (#4453)
* ui: different label for subscribed connections: Message push, Active connections

* update

* localizations
2024-07-15 08:54:31 +01:00
spaced4ndy 5a014ba410 multiplatform: show admin and owner roles in the conversation (#4455) 2024-07-15 08:35:48 +01:00
Evgeny Poberezkin 99888f9d5f ios: show admin and owner roles in the conversation (#4451) 2024-07-15 08:35:37 +01:00
Stanislav Dmitrenko 670bf34ff5 desktop: in-app update functionality (#4443)
* desktop: in-app update functionality

* without Android

* refactor

* working windows

* tabs vs spaces

* better working mac

* changes

* repo

* undo manifest changes

* changes

* changes

* unneeded changes

* revert

* new line

* fix update notice

* different way

* changes to mac logic

* changes to mac logic

* more

* update strings

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-13 20:06:04 +01:00
Evgeny Poberezkin 3e873fcb32 core: faster tracking of active subscriptions; ui: only track in foreground (#4446)
* core: faster tracking of active subscriptions

* combine db transaction

* optimizations of queries from UI

* ios: track when active

* ios: disable log

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-07-13 08:44:51 +01:00
Evgeny Poberezkin 23f24b1677 website: translations (#4436)
* Translated using Weblate (French)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (257 of 257 strings)

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

* blog: future of privacy (#4396)

* blog: future of privacy

* update

* Translated using Weblate (French)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Czech)

Currently translated at 98.8% (254 of 257 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% (257 of 257 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% (257 of 257 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% (257 of 257 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (257 of 257 strings)

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

---------

Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: WebTrans <WebTrans@users.noreply.hosted.weblate.org>
2024-07-12 20:35:58 +01:00
Evgeny Poberezkin 17526fa385 ui: translations (#4433)
* blog: future of privacy (#4396)

* blog: future of privacy

* update

* Translated using Weblate (French)

Currently translated at 100.0% (1552 of 1552 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1552 of 1552 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1552 of 1552 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1552 of 1552 strings)

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (1552 of 1552 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% (1823 of 1823 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 18.7% (341 of 1823 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% (1552 of 1552 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 11.6% (213 of 1823 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% (1552 of 1552 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1823 of 1823 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% (1552 of 1552 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 100.0% (1552 of 1552 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1823 of 1823 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% (1823 of 1823 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% (1552 of 1552 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% (1552 of 1552 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 12.2% (223 of 1823 strings)

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

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 89.1% (1625 of 1823 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 19.4% (354 of 1823 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% (1552 of 1552 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 20.3% (371 of 1823 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 20.6% (376 of 1823 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 12.3% (225 of 1823 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 12.5% (228 of 1823 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 12.6% (230 of 1823 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 12.6% (232 of 1832 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1832 of 1832 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% (1832 of 1832 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% (1832 of 1832 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% (1552 of 1552 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% (1832 of 1832 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% (1552 of 1552 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1832 of 1832 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% (1832 of 1832 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% (1552 of 1552 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 13.2% (243 of 1832 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1832 of 1832 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1832 of 1832 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% (1832 of 1832 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% (1832 of 1832 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 13.8% (254 of 1832 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% (1835 of 1835 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% (1835 of 1835 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% (1835 of 1835 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 14.4% (266 of 1835 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1835 of 1835 strings)

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

* Translated using Weblate (Italian)

Currently translated at 99.9% (1834 of 1835 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1835 of 1835 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% (1835 of 1835 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% (1835 of 1835 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1835 of 1835 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1835 of 1835 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 15.0% (277 of 1835 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1834 of 1835 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 15.8% (291 of 1835 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 16.6% (305 of 1835 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% (1835 of 1835 strings)

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

* Translated using Weblate (Czech)

Currently translated at 93.9% (1724 of 1835 strings)

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

* Translated using Weblate (Korean)

Currently translated at 0.8% (13 of 1552 strings)

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

* Translated using Weblate (Persian)

Currently translated at 100.0% (1835 of 1835 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 18.0% (332 of 1835 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 18.7% (344 of 1835 strings)

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

* Translated using Weblate (Korean)

Currently translated at 1.2% (20 of 1552 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 96.7% (1775 of 1835 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1835 of 1835 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% (1552 of 1552 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% (1835 of 1835 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% (1552 of 1552 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 19.2% (354 of 1835 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 95.8% (1758 of 1835 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1835 of 1835 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1837 of 1837 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% (1835 of 1837 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% (1552 of 1552 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1837 of 1837 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% (1837 of 1837 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 100.0% (1837 of 1837 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1837 of 1837 strings)

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

* Translated using Weblate (Korean)

Currently translated at 51.1% (940 of 1837 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1836 of 1837 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1837 of 1837 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% (1552 of 1552 strings)

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

* Added translation using Weblate (Indonesian)

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1837 of 1837 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 98.1% (1803 of 1837 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1837 of 1837 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% (1552 of 1552 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% (1837 of 1837 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% (1552 of 1552 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 98.2% (1804 of 1837 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 10.3% (160 of 1552 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 98.2% (1805 of 1837 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1837 of 1837 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 33.5% (616 of 1837 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 33.5% (616 of 1837 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% (1552 of 1552 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 19.9% (367 of 1837 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 21.6% (398 of 1837 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 98.1% (1803 of 1837 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 36.5% (672 of 1837 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 22.8% (419 of 1837 strings)

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

* Translated using Weblate (Finnish)

Currently translated at 80.9% (1487 of 1837 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 24.4% (449 of 1837 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 1.1% (22 of 1837 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 1.2% (23 of 1837 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 25.1% (462 of 1837 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1837 of 1837 strings)

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

* Translated using Weblate (Czech)

Currently translated at 95.9% (1763 of 1837 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 26.2% (483 of 1837 strings)

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

* Translated using Weblate (Czech)

Currently translated at 96.6% (1775 of 1837 strings)

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

* Translated using Weblate (Indonesian)

Currently translated at 2.8% (52 of 1837 strings)

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

* process localizations

---------

Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Flavian <3zorro.1@gmail.com>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: jorge2000x <xjwrccr9@duck.com>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: Songun Lee <leesongun@users.noreply.hosted.weblate.org>
Co-authored-by: sor sor <agentvolca47@gmail.com>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: Anonimas <Anonimas3@users.noreply.hosted.weblate.org>
Co-authored-by: robbie.med <161779148+robbie-med@users.noreply.github.com>
Co-authored-by: Antonio Oliveira <antoniovini47@gmail.com>
Co-authored-by: PaulDotSH <84643540+PaulDotSH@users.noreply.github.com>
Co-authored-by: WebTrans <WebTrans@users.noreply.hosted.weblate.org>
Co-authored-by: Jiri Grönroos <jiri.gronroos@iki.fi>
Co-authored-by: billy appetie <billy_appetie@users.noreply.hosted.weblate.org>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
2024-07-12 20:31:41 +01:00
spaced4ndy 70204e071d ui: split servers into lists; allow to enable only tested servers (#4445) 2024-07-12 21:03:30 +04:00
Evgeny Poberezkin b348979b32 core: use disabled servers as known for private message routing (#4444)
* core: use disabled servers as known for private message routing

* send all servers to agent, add all preset servers

* update nix hashes

* refactor

* check that some servers are enabled, refactor

* update simplexmq

* remove functions
2024-07-12 14:12:20 +01:00
spaced4ndy 71ad8f2fd1 multiplatform: check temporary proxy error (#4442)
* android: check temporary proxy error

* version error

* errors
2024-07-11 21:44:31 +04:00
spaced4ndy 2dff94cbb4 ios: check temporary proxy error (#4440)
* ios: check temporary proxy error

* update

* more errs

* more errs

* refactor

* update

* refactor
2024-07-11 19:49:28 +04:00
spaced4ndy a73abfe642 core: update simplexmq (proxy err encoding) (#4441) 2024-07-11 19:29:56 +04:00
Arturs Krumins 859fa0bc22 ios: make image utilities accessible from extensions (#4438)
* ios: move image utils in to framework

* Rename UIImage convenience init
2024-07-11 13:56:55 +01:00
Arturs Krumins 41c4f13939 ios: optimise mark-as-read performance (#4434)
* ios: optimise mark-as-read rendering performance

* merge master

* minor

* make chat observable

* make model EnvironmentObject

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-11 08:57:56 +01:00
spaced4ndy f84ac713d7 android: lookup group members via map (#4432) 2024-07-10 18:50:23 +04:00
spaced4ndy f41c04735b ios: lookup group members via map (#4431) 2024-07-10 16:15:14 +04:00
spaced4ndy a8da9b9cd9 core: fix invitee sending redundant pending messages whey they should be forwarded (#4430) 2024-07-10 13:52:04 +04:00
Evgeny Poberezkin 64a0f509f7 6.0-beta.0: ios 227, android 225, desktop 56 2024-07-09 22:38:08 +01:00
spaced4ndy c4f8a50f0d ios: show inactive and forwarded group message status; show inactive members (#4423)
* ios: differentiate inactive and forwarded group snd statuses; show member connection disabled/inactive

* lazy

* simplify

* Update apps/ios/SimpleXChat/ChatTypes.swift

* export localizations, update strings

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-09 21:52:33 +01:00
spaced4ndy 93a4c0854e desktop, android: show inactive and forwarded group message status; show inactive members (#4426)
* multiplatform: differentiate inactive and forwarded group snd statuses; show member connection disabled/inactive

* forward icon

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-09 21:28:01 +01:00
Evgeny Poberezkin 49c29c74df core: 6.0.0.0 2024-07-09 19:41:42 +01:00
Evgeny Poberezkin e6ee5df158 core: update simplexmq 6.0.0.0 2024-07-09 19:07:44 +01:00
Stanislav Dmitrenko f4be0278b6 desktop: zoom and font size (#4421)
* desktop: font scale

* new line

* moved to slider

* default value highlighting

* clickable

* more places with adapted scale

* attachment and edit icons

* verified

* icons in chat view

* zoom

* new chat button size

* preview icons

* android support

* preview

* text scale in chat view's text field

* paddings

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-09 18:41:23 +01:00
spaced4ndy a9d2535292 core: differentiate inactive and forwarded group snd statuses (#4420)
* core: GroupSndStatus

* rfc

* encoding, db apis

* pending, forwarded statuses

* encoding
2024-07-09 18:29:36 +01:00
spaced4ndy 3e623684bc android, desktop: servers summary (#4398)
* multiplatform: subscription icon (#4397)

* multiplatform: added network setting to control display of subscription percentage

* multiplatform: moved filter to search bar and scan to button

* multiplatform: added types and calls for new apis

* Update apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt

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

* chore: minor changes in API connections and usage

* fix: removed show sub setting from net cfg

* multiplatform: added subscription status to chats screen

* multiplatform: added reconnect all servers api

* multiplatform: added basic view for single user messages

* multiplatform: added basic xftp server info view

* multiplatform: added detailed stats view for SMP server

* multiplatform: added detailed stats view for XFTP server

* multiplatform: added individual server view for XFTP servers

* multiplatform: added individual server view for SMP servers

* multiplatform: added custom coloring for connections

* multiplatform: added all translation strings

* multiplatform: added support for multi user in serve summary

* multiplatform: added missing translations

* multiplatform: added share button to servers info

* better type safety for server summaries

* multiplatform: fixed action arrow paddings in server summary views

* multiplatform: serverSummaryView padding and icon fixes

* multiplatform: reused shared section divider

* move and rename

* remove tab icons, text

* colors

* filter button

* paddings

* fix translation keys

* text

* fix buttons clickable area, alerts

* stats view

* remove chevrons

* colors

* remove id, fix open server button

* don't log terminal items

* desktop left modal

* single timer, pass state variable

* remove unused

* fix no summary view

* net cfg

* ability to hide servers screen by clicking outside servers screen

* addressed review feedback

* move user/all users selector under tabs

* disable horizontal scroll on desktop

---------

Co-authored-by: Diogo Cunha <diogofncunha@gmail.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-09 12:45:09 +01:00
Evgeny Poberezkin fd90b47194 Merge branch 'stable' 2024-07-09 11:23:54 +01:00
Stanislav Dmitrenko acd3467d10 desktop: change libffi dependency (#4416) 2024-07-08 21:23:25 +01:00
Evgeny Poberezkin 71ce598355 ios: make message corners rounded in theme preview (#4410)
Co-authored-by: Levitating Pineapple <noreply@levitatingpineapple.com>
2024-07-05 14:43:36 +01:00
Arturs Krumins 63393eaf0b ios: make theme wallpaper visible on iOS15, further improve scrolling (#4408) 2024-07-05 13:34:03 +01:00
Evgeny Poberezkin f90de83215 ios: corrections, localizations (#4406) 2024-07-05 08:23:29 +01:00
Evgeny Poberezkin 1c10209a31 blog: future of privacy (#4396)
* blog: future of privacy

* update
2024-07-04 21:13:48 +01:00
Arturs Krumins 5d7abf31ce ios: make message corners rounded when selecting context menus (#4401)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-04 18:37:03 +01:00
spaced4ndy 44c0861fe4 ios: apply theming to servers summary view (#4404) 2024-07-04 21:11:20 +04:00
sh 1e6dc8002c flatpak: update metainfo (#4400) 2024-07-04 17:39:16 +04:00
Narasimha-sc 0509ff9a1b docs: Flatpak download (#4393)
* docs: Flathub

* correction

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-07-04 08:00:12 +01:00
Evgeny Poberezkin f12e504828 core: update simplexmq (fast connection handshake) (#4369)
* core: update simplexmq (fast connection handshake)

* core: update simplexmq (fast connection handshake)

* fix encoding tests

* fix tests
2024-07-04 07:58:13 +01:00
Evgeny Poberezkin 6a273677f1 docs: contributing (#4392)
* docs: contributing

* corrections
2024-07-03 22:51:21 +01:00
Evgeny Poberezkin f5eea018d9 ios: chat themes and wallpapers (#4376)
* ios: wallpapers (#4304)

* ios: wallpapers

* theme selection

* applied theme colors and preset wallpaper

* more places with background

* one more

* accent color

* defaults

* rename

* background

* no change to cell color

* unneeded

* changes

* no global tint

* defaults

* removed unneeded class

* for merging

* ios: wallpapers types (#4325)

* types and api

* divided types per target

* creating directory for wallpapers

* creating wallpaper dir at launch

* ios: wallpapers appearance (#4335)

* appearance

* changes

* refactor

* scale

* lambda to function

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>

* ios: wallpapers user/chat overrides (#4345)

* ios: wallpapers user/chat overrides

* chat overrides

* color picker updates colors correctly

* fix state update

* labels

* background for light theme

* small optimization

* removed commented code

* ios: enhancements to wallpapers (#4361)

* ios: enhancements to wallpapers

* colors for background

* ios: wallpapers import/export (#4362)

* ios: wallpapers import/export

* comment

* ios: wallpapers theme updates (#4365)

* ios: wallpapers theme updates

* group member background

* colors

* profile picture colors

* unneeded

* optimizations, images, state fixes

* fixes

* no editing of title color

* rename Menus and alerts, refactor

* tint applying fix

* fixes

* migration of accent and themes

* fix updating system theme

* migration changes

* limiting color range

* ios: wallpapers rename enum (#4384)

* ios: wallpapers rename enum2 (#4385)

* ios: wallpapers rename enum2

* change

* colors were commented

* fix build and look

---------

Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2024-07-03 22:42:13 +01:00
Evgeny Poberezkin 5f96f6c117 core: extending queue information to debug delivery (#4395)
* core: extending queue information to debug delivery

* simplexmq
2024-07-03 19:34:58 +01:00
spaced4ndy e963ef53e7 ios: test ntf server (#4394)
* ios: test ntf server

* reset on change

* fix formatting
2024-07-03 18:31:09 +01:00
spaced4ndy 1180edf80e ios: servers summary (#4321)
* types

* chat list buttons

* update

* wip

* xftp summary

* sub status view

* reconnect server button

* reset stats button

* refactor

* subscription icon in server view

* getAgentSubsSummary api

* view

* subs indicator with timer

* rename

* variableValueAsPercentage

* encodePrettyPrinted

* totals, timer

* reduce interval

* show more/less stats

* refactor

* sort

* rework indicator wip

* change offline icon

* rework indicator

* show percent

* file progress

* fix

* onion

* user servers, icons

* dashes

* Revert "user servers, icons"

This reverts commit 805e7e9bd6.

* remove icon, remove total, remove session %

* exclude sessions

* move starting from

* file stats

* fix

* open server settings

* file in progress

* update

* wpi

* wip

* rework stats

* arrow for sessions

* texts

* reconnect all

* single user

* rework file stats

* update

* dont log terminal items

* center

* update

* _connSubIgnored

* rename

* update

* large titles

* refactor

* update

* text

* upd

* single dash
2024-07-03 13:59:46 +01:00
spaced4ndy 4bd6517d19 core: servers stats improvements, fixes (#4358) 2024-07-03 15:58:37 +04:00
Evgeny Poberezkin 2585f4ecfd ios: ChatView performance improvements (#4353)
* feat: Add synthesized hashable conformance to chat and API types (#4348)

* UIKit ReverseList

* ReverseList - manual layout updates for external state

* Propagate ScrollModel; Disable async media width

* Filter chat items

* Remove UIKit menu wrapper

* Make chat item width calculation synchronous (#4371)

* Fix floating button regression

* Improve filter performance

* Fix page load the merged items exceed full page

* Resolve iOS15 compabibility

* Restore build config

* Add page-up scroll; Fix same item decrementing unread counter multiple times

* Fix: Chat not loading additional pages, if newest items are all merged and exceed page size

* Minor

* Fix item loading regression

* Fix item loading regression 2

* Fix unread regression

* refactor

---------

Co-authored-by: Arturs Krumins <auth@levitatingpineapple.com>
Co-authored-by: Levitating Pineapple <noreply@levitatingpineapple.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-07-03 10:24:26 +01:00
Evgeny Poberezkin e22e01acd2 5.8.2: ios 226, android 223, desktop 55 2024-07-02 21:28:34 +01:00
Stanislav Dmitrenko 8e4299afb6 android, desktop: close modals only for desktop (#4390) 2024-07-02 18:26:23 +01:00
Stanislav Dmitrenko ecff3c6ee5 android, desktop: notifications improvement (missed call, hidden user) (#4389)
* android, desktop: notifications improvement (missed call, hidden user)

* change

* change
2024-07-02 18:19:43 +01:00
Evgeny Poberezkin 85af368371 core: 5.8.2.0, simplexmq: 5.8.2.0 2024-07-02 15:07:46 +01:00
Stanislav Dmitrenko 0d3928bd51 android, desktop: handle situation when not all databases created before shut down (#4294)
* android, desktop: handle situation when not all databases created before shut down

* more logic of choosing whether to delete databases or not

* comment

* rename

* refactoring
2024-07-02 15:02:36 +01:00
Evgeny Poberezkin ddeaa1c7c3 core: servers 2024-07-02 14:50:25 +01:00
Evgeny Poberezkin 00ba468898 core: update simplexmq (disable fast handshake) (#4388)
* core: update simplexmq (disable fast handshake)

* fix encoding tests

* fix

* update simplexmq
2024-07-02 14:35:47 +01:00
spaced4ndy 593c7d247c ui: add ServerEnabled type (#4381) 2024-07-01 17:10:22 +04:00
Evgeny Poberezkin 5907d8bd0c core: remove legacy agent stats (#4375) 2024-07-01 11:25:27 +01:00
sh 231082860e flatpak: verify app (#4379) 2024-07-01 09:34:38 +01:00
Evgeny Poberezkin c6366cb269 Merge branch 'stable' 2024-06-29 16:53:30 +01:00
sergeyshadok d066c66282 Update XFTP-SERVER.md (#4184)
Systemd itself uses %<something> tokens so %% needs to be used for specifiers

(https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html)
2024-06-29 16:50:28 +01:00
Evgeny Poberezkin fab3827697 core: fix markdown for trailing / and ) characters in the links (#4357) 2024-06-29 08:41:21 +01:00
Evgeny Poberezkin d8126e0cd0 website: update join team 2024-06-28 19:09:01 +01:00
sh 5baf8789d6 flatpak: add desktop and metainfo (#4366)
* flatpak: add desktop and metainfo

* metainfo: update

* corrections

* ampersand

* shorter

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-06-28 10:09:34 +01:00
Evgeny Poberezkin dd5454f390 Merge branch 'stable' 2024-06-28 00:12:10 +01:00
Evgeny Poberezkin fca098f535 docs: update donation addresses 2024-06-28 00:10:51 +01:00
spaced4ndy fba0478e50 docs: more additions to chat protocol (#4355)
* docs: more additions to chat protocol

* schema wip

* schema

* update diagram

* remove comments

* punctuation

* diagram text

* update threat model

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-06-25 08:37:54 +01:00
spaced4ndy d951003191 core: servers summary api (#4319)
* core: servers summary api

* rework

* server known types

* set stats file path

* rename

* local simplexmq

* update

* rfc

* update

* update

* get servers

* compile summary

* remove sort

* rename

* rename, refactor

* refactor attempt

* refactor attempt 2

* refactor

* fix

* fix2

* remove space

* refactor xftp

* update

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-06-25 09:51:55 +04:00
spaced4ndy 1af513c548 docs: update chat protocol (#4344) 2024-06-23 20:36:25 +01:00
Evgeny Poberezkin 85dc467f74 5.8.1: ios 225, android 221, desktop 54 2024-06-19 23:41:23 +01:00
spaced4ndy 89e65c2fc1 multiplatform: check preferences before share/forward (#4338) 2024-06-19 18:53:45 +04:00
Evgeny Poberezkin 0fa8d77214 ios: fix search disappearing in forward view (#4337)
* ios: fix search disappearing in forward view

* update

* diff

* refactor

* use List
2024-06-19 12:51:56 +01:00
spaced4ndy 6ba82c8c39 ios: check preferences before forward (#4336)
* ios: check preferences before forward

* rework

* clean up

* shorter message

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-06-19 13:49:44 +04:00
Evgeny Poberezkin e19c14b249 ios: update core library to 5.8.1 2024-06-19 10:12:22 +01:00
Evgeny Poberezkin d993381d31 Revert "web: glossary fix (#4298)"
This reverts commit d3274b28ba.
2024-06-18 23:44:58 +01:00
Evgeny Poberezkin 0198c1f110 core: 5.8.1.0 2024-06-18 23:12:27 +01:00
spaced4ndy 6c4c9b172c core: fix markdown check (#4334)
* core: fix markdown

* more tests

* enable tests

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-06-18 12:44:33 -07:00
spaced4ndy d9a61af401 core: fix preference application (#4330) 2024-06-18 10:37:45 +04:00
spaced4ndy a58522ef15 core: api to reconnect single server (#4317) 2024-06-17 11:52:55 +04:00
Evgeny Poberezkin bcd510c913 cli: option to confirm up migrations (#4150)
* cli: option to confirm up migrations

* fix test
2024-06-16 20:24:37 -07:00
M. Sarmad Qadeer c4083e00c5 web: update feed (#4255)
* web: update feed

* change date filter in feed.rss
2024-06-16 14:31:36 -07:00
M. Sarmad Qadeer 7cd35b9068 web: design fixes eg: blog titles & link wrap (#4305)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-06-16 14:22:53 -07:00
M. Sarmad Qadeer d3274b28ba web: glossary fix (#4298) 2024-06-16 08:23:40 -07:00
Narasimha-sc 40bd5dc2da web: update copyright year 2023->2024 (#4297)
* Update copyright year

* Update ar.json

* Update bg.json

* Update cs.json

* Update de.json

* Update es.json

* Update fr.json

* Update hu.json

* Update it.json

* Update ja.json

* Update nl.json

* Update pl.json

* Update pt_BR.json

* Update ru.json
2024-06-16 08:19:43 -07:00
Diogo 1573b7af13 ios: prevented error on desktop in lack of camera permissions (#4306)
* refactor: 💡 moved ScannerInView to separate module

made it more extensible and ready to be reused

* fix: 🐛 prevented error on desktop in lack of camera permissions

right now, connect to desktop functionality was failing if you didn't
accept permissions before jumping to this screen for the first time. In
here I did pick from other sections where cases of no permissions or
unknown permissions were correctly handled and did reuse the same
mechanism

* chore: 🤖 reverted file move

* chore: 🤖 reverted class change

* chore: 🤖 reverted uncessary change

* chore: 🤖 removed leftover
2024-06-11 09:29:53 +04:00
Narasimha-sc a5bf3cbca8 v5.6 -> v5.8 (#4308) 2024-06-10 18:33:27 +01:00
Stanislav Dmitrenko d5529031ee android, desktop: socks proxy toggle enhancements (#4312) 2024-06-10 18:33:10 +01:00
spaced4ndy d244338b13 ui: differentiate remote ctrl errors, better error texts (#4302) 2024-06-10 18:18:05 +04:00
spaced4ndy ce55c84b96 core: differentiate RCP error in view, test (#4310) 2024-06-10 17:58:53 +04:00
spaced4ndy c52f9baefa desktop: close chat view when chat is stopped (#4313) 2024-06-10 13:11:35 +01:00
Stanislav Dmitrenko ea1c5da65d desktop: change thread who responsible for writting settings (#4311) 2024-06-10 13:05:53 +01:00
sh 5695bb9d46 docs: change smp webpage path (#4307) 2024-06-08 15:42:12 +01:00
spaced4ndy 13751d5705 core: update simplexmq (upload chunks after preparation) (#4299) 2024-06-06 16:09:56 +04:00
spaced4ndy 02803b1491 core: fix testXFTPRcvError test 2024-06-05 21:16:04 +04:00
spaced4ndy 222af69a71 multiplatform: file errors (#4289) 2024-06-05 21:03:59 +04:00
spaced4ndy 5e96e1ea2b ios: file errors (#4281) 2024-06-05 21:03:05 +04:00
spaced4ndy 490e8cead8 core: file errors (#4261) 2024-06-05 21:02:13 +04:00
Evgeny Poberezkin f578ee843b core: update simplexmq (remove protocol encodings) (#4272)
* core: update simplexmq (remove protocol encodings)

* nix

* update simplexmq

* update simplexmq
2024-06-05 20:49:01 +04:00
Evgeny Poberezkin cf2eb76cb7 website: update MoneroKon group link 2024-06-05 17:33:52 +01:00
Evgeny Poberezkin 48f9dcab9a blog: update image 2024-06-04 20:03:42 +01:00
Evgeny Poberezkin ac2ef54838 blog: v5.8 announcement (#4275)
* blog: v5.8 announcement

* update

* update

* update readme

* images, preview

* simplify

* spaces
2024-06-04 19:44:29 +01:00
Evgeny Poberezkin 7e269c6b8c android, desktop: enter app logic (#4288)
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-06-04 15:59:23 +01:00
Stanislav Dmitrenko 3e739924bb android, desktop: prevent duplication of group in UI when creating one (#4284) 2024-06-04 15:59:02 +01:00
Stanislav Dmitrenko 83706b19da android, desktop: removed additional background under chat bubbles (#4287) 2024-06-04 15:58:29 +01:00
Stanislav Dmitrenko 6f19a7a20f android, desktop: fixes swipe to reply when animations were disabled in the OS (#4286) 2024-06-04 15:57:48 +01:00
spaced4ndy a8740cee4b core: fix cancellation of snd files without description (e.g. while being prepared for upload) (#4285) 2024-06-04 16:17:12 +04:00
sh 4000fe383d docs/smp-server: web server pages configuration and statistics update (#4279)
* docs/smp-server: web server pages configuration and statistics update

* update table

* update

* typo

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-06-03 20:29:12 +01:00
Evgeny Poberezkin 75445e604e 5.8: ios 224, android 219, desktop 53 2024-06-03 14:05:59 +01:00
spaced4ndy 0596278e50 docs: flexible user records rfc (#4205) 2024-06-03 14:15:41 +04:00
Stanislav Dmitrenko 7a77775a42 android, desktop: fix member search in group (#4277) 2024-06-03 08:25:08 +01:00
Evgeny Poberezkin dc8d08ec04 website: translations (#4274)
* Added translation using Weblate (Hungarian)

* Added translation using Weblate (Hungarian)

* Translated using Weblate (Dutch)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (257 of 257 strings)

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

---------

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
2024-06-02 19:43:59 +01:00
Evgeny Poberezkin 4ad0e0f65e ui: translations (#4273)
* Translated using Weblate (Italian)

Currently translated at 100.0% (1819 of 1819 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% (1549 of 1549 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1819 of 1819 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1819 of 1819 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 99.8% (1547 of 1549 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1819 of 1819 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1819 of 1819 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% (1819 of 1819 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% (1549 of 1549 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1819 of 1819 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% (1819 of 1819 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1819 of 1819 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% (1549 of 1549 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% (1819 of 1819 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% (1549 of 1549 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1823 of 1823 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% (1823 of 1823 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% (1549 of 1549 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1823 of 1823 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% (1549 of 1549 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (Persian)

Currently translated at 99.9% (1822 of 1823 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1819 of 1819 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% (1549 of 1549 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1819 of 1819 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1819 of 1819 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 99.8% (1547 of 1549 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1819 of 1819 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1819 of 1819 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% (1819 of 1819 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% (1549 of 1549 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1819 of 1819 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% (1819 of 1819 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1819 of 1819 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% (1549 of 1549 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% (1819 of 1819 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% (1549 of 1549 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1823 of 1823 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% (1823 of 1823 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% (1549 of 1549 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1549 of 1549 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1823 of 1823 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% (1549 of 1549 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (Persian)

Currently translated at 99.9% (1822 of 1823 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 13.0% (237 of 1823 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1823 of 1823 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% (1549 of 1549 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1823 of 1823 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% (1549 of 1549 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% (1823 of 1823 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% (1549 of 1549 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1822 of 1823 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 100.0% (1549 of 1549 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% (1823 of 1823 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 100.0% (1823 of 1823 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 17.6% (322 of 1823 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% (1549 of 1549 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% (1549 of 1549 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 96.9% (1767 of 1823 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1549 of 1549 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 100.0% (1549 of 1549 strings)

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

* import/export localizations

---------

Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: J R <jr@simplex.chat>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: Siavash <ciavash@proton.me>
Co-authored-by: Flavian <3zorro.1@gmail.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Ninja Left <s1lntlwd@proton.me>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
2024-06-02 19:20:46 +01:00
Evgeny Poberezkin d01515e755 blog: Protecting Children's Safety Requires End-to-End Encryption 2024-06-01 21:47:38 +01:00
Evgeny Poberezkin 3fa70ba217 5.8-beta.5: ios 223, android 218, desktop 52 2024-06-01 11:03:22 +01:00
Evgeny Poberezkin 6ae4cddc2e Merge branch 'stable' 2024-06-01 09:33:36 +01:00
Evgeny Poberezkin ac8ee971f5 5.7.5: ios 222, android 216, desktop 51 2024-06-01 09:15:41 +01:00
Evgeny Poberezkin 11d4872186 core: 5.8.0.5 (simplexmq 5.8.0.10) 2024-06-01 00:22:26 +01:00
Evgeny Poberezkin 370e2e87ad Merge branch 'stable' 2024-05-31 23:50:00 +01:00
Evgeny Poberezkin ef30fcf5e2 cli: options for private message routing and fallback mode (#4256)
* cli: options for private message routing and fallback mode

* remove short options

* fix tests

* encoding

* fix
2024-05-31 23:41:20 +01:00
Evgeny Poberezkin 6ad1423f29 core: 5.7.5.0 (simplexmq: 5.7.6.0, file download fix) 2024-05-31 23:35:00 +01:00
Stanislav Dmitrenko c52e5349db ios: more sheets will become hidden while protect screen on (#4259)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-31 22:47:57 +01:00
Stanislav Dmitrenko 3c98c6acc0 android, desktop: selectable cards for proxy options (#4263)
* android, desktop: selectable cards for proxy options

* title
2024-05-31 22:25:15 +01:00
Stanislav Dmitrenko c251f5e2bd android, desktop: debug subscribed SMP queues (#4262)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-31 18:54:12 +01:00
Evgeny Poberezkin b165603136 ios: log file error to console 2024-05-31 18:33:57 +01:00
spaced4ndy 184a24b70e ui: fix filtering of contacts that can be invited to group (#4265) 2024-05-31 18:30:59 +01:00
spaced4ndy d46bae6498 ios: allow to save sent file on tap (#4264) 2024-05-31 20:20:49 +04:00
Evgeny Poberezkin 5ac521f6d8 core: commands to debug subscribed SMP queues (#4253)
* core: commands to debug subscribed SMP queues

* getLastRcvMsgInfo

* DESC

* update

* update commands, ui compiles

* update

* ios: fix type

* swap

* simplexmq

* group member queue info

* copy button in the alert
2024-05-31 12:45:58 +01:00
Stanislav Dmitrenko 7b5b747b19 desktop: performant drawing of wallpaper (#4249)
* desktop: low quality drawing of wallpaper

* fast drawing

* clean up

* unused
2024-05-30 17:07:58 +01:00
Stanislav Dmitrenko 037655e30f android, desktop: creating wallpapers dir in some situations (#4254) 2024-05-30 17:04:00 +01:00
spaced4ndy 54088c6d5a core: "/get queues" api to debug agent queues (#4252) 2024-05-30 14:24:33 +04:00
Stanislav Dmitrenko 78f7fcc89f android, desktop: wallpaper fixes (#4251) 2024-05-30 07:03:23 +01:00
Evgeny Poberezkin b402caeb89 5.8-beta.4: ios 221, android 215, desktop 50 2024-05-29 18:49:35 +01:00
Evgeny Poberezkin ff8a8de3c8 Revert "android, desktop: change wallpaper file type from PNG to WebP (#4250)"
This reverts commit d22c0c2614.
2024-05-29 17:35:57 +01:00
Stanislav Dmitrenko d22c0c2614 android, desktop: change wallpaper file type from PNG to WebP (#4250) 2024-05-29 13:31:31 +01:00
Evgeny Poberezkin 73c8d3c2e3 android, desktop: add Persian interface language 2024-05-29 10:06:54 +01:00
Evgeny Poberezkin 0110385e65 ui: v5.8 whats new (#4244)
* ios: v5.8 whats new

* blog post stub

* update

* android

* ios: export localizations
2024-05-29 09:59:41 +01:00
Evgeny Poberezkin ad0a678c5f core: 5.8.0.4 (simplexmq 5.8.0.7) 2024-05-29 08:20:51 +01:00
sh 0495a4cd78 docs/smp-server: expand tor configuration, add security practices (#4228)
* docs/smp-server: expand tor configuration, add security practices

* docs/smp-server: add TOC

* update

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-28 22:26:15 +01:00
Stanislav Dmitrenko 02267c5263 android: show alert of exception while initializing WebView (#4245)
* android: show alert of exception while initializing WebView

* Update apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-28 22:01:45 +01:00
Stanislav Dmitrenko cad3bc048f desktop: prevent corruption of settings file (#4243)
* desktop: prevent corruption of settings file

* check for existence

* unneeded

* simplify

* unused
2024-05-28 21:41:22 +01:00
Stanislav Dmitrenko 1b04423745 android, desktop: close notes tab on switching between chats (#4246) 2024-05-28 16:35:43 +01:00
spaced4ndy 2143eb2d7a core: batch send pending group messages (#4242) 2024-05-28 18:32:29 +04:00
spaced4ndy 3d395b0e45 core: inactive connections/members (#4009) 2024-05-28 16:42:07 +04:00
Stanislav Dmitrenko d79b4dfb5a android: replace new line in Uri before transforming it to URI (#4240) 2024-05-28 11:24:57 +01:00
Evgeny Poberezkin 0ae9f5ebba website: translations (#4241)
* Translated using Weblate (German)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (257 of 257 strings)

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

---------

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: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
2024-05-28 11:23:58 +01:00
Evgeny Poberezkin 57c80786dc ui: translations, remove translations for wallpaper names used in exported themes (#4239)
* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 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 54.1% (943 of 1741 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

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

* Translated using Weblate (Persian)

Currently translated at 65.5% (1141 of 1741 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 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% (1515 of 1515 strings)

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

* Translated using Weblate (Persian)

Currently translated at 76.3% (1330 of 1741 strings)

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

* Translated using Weblate (Persian)

Currently translated at 83.0% (1446 of 1741 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1751 of 1751 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1751 of 1751 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% (1751 of 1751 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 100.0% (1772 of 1772 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1772 of 1772 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 99.3% (1760 of 1772 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 88.3% (1566 of 1772 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1772 of 1772 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 100.0% (1772 of 1772 strings)

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

* Translated using Weblate (Polish)

Currently translated at 98.3% (1743 of 1772 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1772 of 1772 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1772 of 1772 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% (1772 of 1772 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1772 of 1772 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 98.8% (1751 of 1772 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1771 of 1772 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1772 of 1772 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% (1515 of 1515 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% (1772 of 1772 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% (1772 of 1772 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% (1515 of 1515 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 95.6% (1449 of 1515 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1772 of 1772 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% (1772 of 1772 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 9.8% (175 of 1772 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% (1515 of 1515 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 10.6% (189 of 1772 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% (1778 of 1778 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% (1515 of 1515 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% (1778 of 1778 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1778 of 1778 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% (1778 of 1778 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1778 of 1778 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1777 of 1778 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1778 of 1778 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% (1515 of 1515 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% (1778 of 1778 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% (1515 of 1515 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1515 of 1515 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1778 of 1778 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% (1778 of 1778 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% (1515 of 1515 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% (1778 of 1778 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1778 of 1778 strings)

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

* Translated using Weblate (Persian)

Currently translated at 100.0% (1778 of 1778 strings)

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

* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

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

* Translated using Weblate (Hungarian)

Currently translated at 98.8% (1794 of 1814 strings)

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

* Translated using Weblate (Czech)

Currently translated at 94.2% (1710 of 1814 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% (1814 of 1814 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1813 of 1814 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1814 of 1814 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 99.6% (1807 of 1814 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1814 of 1814 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1814 of 1814 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1814 of 1814 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% (1814 of 1814 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% (1515 of 1515 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1814 of 1814 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1814 of 1814 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% (1814 of 1814 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% (1515 of 1515 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 11.2% (204 of 1814 strings)

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

* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

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

* Translated using Weblate (Ukrainian)

Currently translated at 97.1% (1764 of 1815 strings)

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

* process localizations

* removed wallpapers names

---------

Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Siavash <ciavash@proton.me>
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: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: sith-on-mars <groguko36@pm.me>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: Flavian <3zorro.1@gmail.com>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: indiandoc <marc@nymtech.net>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-05-28 11:20:52 +01:00
Stanislav Dmitrenko da1cad96fc android: fix showing empty notification (#4237)
* android: fix showing empty notification

* fix desktop concurrent notifications
2024-05-28 08:04:23 +01:00
Stanislav Dmitrenko b58ccedf23 android, desktop: enhancements to wallpapers (#4234)
* android, desktop: enhancements to wallpapers

* fixes

* unneeded
2024-05-28 08:02:45 +01:00
spaced4ndy 01cadefde7 core: avoid creating duplicate introductions between group members connecting concurrently (#4235) 2024-05-27 18:42:39 +04:00
Evgeny Poberezkin c70e7223d9 core: delete connection records when connecting (JOIN) fails (#4233)
* core: delete connection records when connecting (JOIN) fails

* show errors in commands
2024-05-27 15:32:09 +01:00
Evgeny Poberezkin a1d4f52185 5.8-beta.3: ios 220, android 214, desktop 49 2024-05-25 20:57:07 +01:00
Evgeny Poberezkin 373070f388 ui: show UI for additional group preferences (SimpleX links and per-role permissions) 2024-05-25 19:54:05 +01:00
Evgeny Poberezkin a03ccd0ba6 ios: update core library 5.8.0.3 2024-05-25 18:55:15 +01:00
Evgeny Poberezkin a7982cccf9 Merge branch 'stable' 2024-05-25 17:22:25 +01:00
Evgeny Poberezkin dccd6631af 5.7.4: ios 219, android 212, desktop 48 2024-05-25 17:06:11 +01:00
Evgeny Poberezkin b0516b6440 core: 5.7.4.1 2024-05-25 11:18:49 +01:00
Stanislav Dmitrenko bf91666f07 android, desktop: wallpapers (#4109)
* android, desktop: wallpapers

* changes

* removed unused

* changes

* backgrounds moved to themes. can be exported/imported

* changes and refactoring

* scrollable

* change

* reorder

* theme per background

* changes

* don't drop customization in same cases

* changes

* changes

* fix state update

* different defaults

* fix Android

* removed migration

* temporary

* returned theme name as uppercase back

* resilient to wrong preset name

* more

* live color change without button

* fix

* Revert "temporary"

This reverts commit 705c92ee56.

* changes

* changes

* almost candy

* old picker and ability to specify hex color

* different image

* picker

* user theme override, fixes, import/export theme with image

* revert when about to merge: useful layout for theming

* custom image displaying and deletion work correctly

* performance

* moved code up

* changes

* color changes in picker when changing themes

* reset color without closing modal

* unused

* log

* currentTheme instead of MaterialTheme

* different inheritance logic

* fix and move sent/received message colors to top

* remove background

* performance

* fix wrong base

* changes

* fix

* small

* custom image selection made normally

* better color picker

* better picker

* refactor, fixes, optimizations

* working with unknown base theme + tests

* change

* delete wallpaper dir when importing archive

* function rename

* fix bug with state update

* update colors

* fix text colors

* update images

* changes

* remote desktop and theme mode dropdown

* default theme

* additional accent 2 changes

* fix default wallpaper

* removed ChatListAlwaysVisible

* renaming

* update messages

* changes

* default theme

* unused

* member icon background color

* image quality

* fix wallpaper on empty notes screen

* update colors

* change

* update colors

* fix update on android

* fix update on both platforms

* update colors, remove serializable

* fix color

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-25 09:52:16 +01:00
Evgeny Poberezkin ab47a5a27e Revert "ui: comment smp proxy ui (#4204)"
This reverts commit a0d6ae15ab.
2024-05-24 22:59:37 +01:00
Evgeny Poberezkin 23581f59ae core: 5.8.0.3 2024-05-24 21:33:45 +01:00
Evgeny Poberezkin 291df6e9d0 core: logging of chat events (#4216)
* core: update simplexmq (persist server errors)

* fix

* same config

* logging

* logging 2

* log

* log 2

* finally

* catch better

* more logs

* logs

* fix

* more logging, context from PROHIBITED

* warning

* more logs

* logs3

* logs4

* logs in simplexmq

* log locks from simplemq

* log queue size

* log sendMessagesB in simplexmq

* update simplexmq

* logs5

* logs6

* logs7

* logs8

* logs8

* logs9

* logs10

* log11

* log12

* fix test

* more logs

* logging

* clean up

* refactor

* simplify

* tags

* log level

* remove network errors from the log

* rename
2024-05-24 21:09:21 +01:00
Evgeny Poberezkin dae0b63c22 Merge branch 'stable' 2024-05-23 22:56:04 +01:00
Evgeny Poberezkin 0964982782 core: ensure that messages are sent to different members (#4221)
* core: ensure that messages are sent to different members

* update simplexmq
2024-05-23 22:50:23 +01:00
Evgeny Poberezkin 9eb6034e1a core: 5.7.4.0 (simplexmq 5.7.4.1: networking improvements) 2024-05-22 20:30:24 +01:00
Evgeny Poberezkin c59eb06b8a 5.8-beta.2: ios 218, android 210, desktop 47 2024-05-20 21:23:40 +01:00
Evgeny Poberezkin 423fc96638 core: 5.8.0.2 (simplexmq 5.8.0.2) 2024-05-20 18:38:46 +01:00
spaced4ndy ba203faad4 android: check known relays before file reception, support user approval of unknown relays (#4196) 2024-05-20 17:58:30 +04:00
spaced4ndy ec7b35adb9 ios: check known relays before file reception, support user approval of unknown relays (#4044)
* ios: check known relays before file reception, support user approval of unknown relays

* add privacyAskToApproveRelays to AppSettings

* less text

* ui improvements, fixes

* fix ntf

* shorter alert

* simplify settings

* rename

* icon

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-20 17:49:19 +04:00
spaced4ndy d2d450d1d7 core: check known relays before file reception, support user approval of unknown relays (#4043)
* core: check known relays before file reception, support user approval of unknown relays

* comment

* reset on not approved agent error

* add privacyAskToApproveRelays to AppSettings

* filter distinct servers

* update simplexmq

* remember user_approved_relays

* refactor

* rename

* update simplexmq

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-20 17:23:29 +04:00
Evgeny Poberezkin b4caefb17c 5.8-beta.1: ios 217, android 209, desktop 46 2024-05-18 08:20:38 +01:00
Evgeny Poberezkin fd791f3fb8 ios: update core library 2024-05-17 15:54:51 +01:00
Evgeny Poberezkin 0720292ebf core: 5.8.0.1 (simplexmq: 5.8.0.1, faster reconnection when switching networks) 2024-05-17 15:39:58 +01:00
spaced4ndy a0d6ae15ab ui: comment smp proxy ui (#4204) 2024-05-17 16:36:25 +04:00
Evgeny Poberezkin 3e76a2d49c blog: image 2024-05-16 19:47:24 +01:00
Evgeny Poberezkin ed3365bb6d website: fix links 2024-05-16 18:16:00 +01:00
Evgeny Poberezkin b2a8797ed4 blog: Redefining Privacy by Making Hard Choices (#4195)
* blog: Redefining Privacy by Making Hard Choices

* update

* update

* revert

* update

* corrections

Co-authored-by: Esra'a Al Shafei <alshafei@users.noreply.github.com>

* update

---------

Co-authored-by: Esra'a Al Shafei <alshafei@users.noreply.github.com>
2024-05-16 18:02:37 +01:00
spaced4ndy d3e522e169 ui: disable send field for disabled connection (based on authErrCounter) (#4193) 2024-05-16 17:08:31 +04:00
spaced4ndy 49e09ca449 core: contact disabled event (#4194) 2024-05-16 17:08:13 +04:00
spaced4ndy d1dde3d0c8 ui: support message forwarding with custom ttl (#4192) 2024-05-16 14:12:58 +04:00
spaced4ndy ef75eceb40 core: support message forwarding with custom ttl (#4191) 2024-05-16 14:11:55 +04:00
spaced4ndy 96ce59f330 multiplatform: SMP proxy configuration buttons (#4188)
* multiplatform: SMP proxy configuration buttons

* fix

* icons

* icon

* icon
2024-05-15 20:09:51 +01:00
spaced4ndy 98a67fa2e4 multiplatform: SMP proxy support (#4179)
* android: SMP proxy support

* android types

* show in meta

* reserve

* remove comment

* texts
2024-05-15 13:56:29 +01:00
spaced4ndy 4b13512950 ios: SMP proxy support (#4178)
* ios: SMP proxy support

* statuses

* group statuses

* error texts

* update

* change icon

* texts

* texts

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-15 13:09:42 +01:00
spaced4ndy 4c0d47bbd4 core: message statuses for sending proxies (#4161)
* core: delivery path

* update simplexmq

* via proxy snd flags

* error statuses

* rework errors

* proxy expired errors

* corrections

* move backwards compatibile parser to new type

* update simplexmq

* names

* refactor, style

* simplexmq

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-15 12:30:05 +01:00
Evgeny Poberezkin 3129602a78 Merge branch 'stable' 2024-05-15 11:44:22 +01:00
Stanislav Dmitrenko a0c257962e android, desktop: fix file menu and icon (#4185)
* android, desktop: fix file menu and icon

* simplify

* space
2024-05-15 11:43:20 +01:00
Evgeny Poberezkin 93ae1145bc core: update simplexmq (use MVar for better DB connection concurrency) (#4183)
* core: update simplexmq (use MVar for better DB connection concurrency)

* focus failing tests

* add timeouts to test

* fix tests

* more delays

* increase timeouts

* prints

* delay

* delay

* empty

* more delays

* enable all

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-05-15 11:16:38 +01:00
Evgeny Poberezkin d02668386f directory: debug logging (#4104) 2024-05-14 21:32:53 +01:00
M. Sarmad Qadeer bd8c8b5a8c web: fix the links of faq & some other (#4144)
* web: fix the links of faq & some other

* web: fix links

* web: update .eleventy.js to fix links

* web: fix some links and improve the logic

* web: fix links & improve the logic

* remove semicolon

* update links

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-14 19:59:51 +01:00
Evgeny Poberezkin e359ec02f5 5.8-beta.0: ios 216, android 208, desktop 45 2024-05-13 23:34:14 +01:00
Evgeny Poberezkin a1948d549b ios: update core library 2024-05-13 22:24:10 +01:00
Evgeny Poberezkin 396b73b480 core: 5.8.0.0 2024-05-13 21:13:07 +01:00
Evgeny Poberezkin 331b4633fc core: platform independent encoding for delete command (#4176) 2024-05-13 20:39:13 +01:00
Evgeny Poberezkin 29db2b4e9b core: command to show duplicate message count (#4172)
* core: command to show duplicate message count

* update

* updated

* update

* update

* simplexmq
2024-05-13 19:55:57 +01:00
spaced4ndy f091384aa7 ui: apply model updates only for active user for switch and ratchet sync events (#4175) 2024-05-13 17:25:24 +01:00
spaced4ndy f40ba6f04d core: api to differentiate contacts and conversations (#4111) 2024-05-13 16:51:54 +04:00
Evgeny Poberezkin 06d61ea73e core: update simplexmq 2024-05-13 08:19:40 +01:00
Evgeny Poberezkin 84d7a77a9f core: update simplexmq (better subscription management) (#4131)
* core: update simplexmq (better subscription management)

* ui: update settings

* update simplexmq

* simplexmq

* simplexmq

* test output

* delay

* disable test
2024-05-13 08:04:12 +01:00
Evgeny Poberezkin 878eea774d core: save app themes as map with any text key (#4159)
* core: save app themes as map with any text key

* remove theme preset name

* list of themes

* theme id

* theme IDs

* moar

* colors

* default to dark

* fix
2024-05-12 23:35:14 +01:00
Narasimha-sc 4575dc6e30 langs: change 1-2 days to several days on fdroid (#4170) 2024-05-12 18:19:27 +01:00
Evgeny Poberezkin 554ef4eefc 5.7.3: ios 215, android 206, desktop 44 2024-05-12 11:36:30 +01:00
Evgeny Poberezkin 567e9981be core: 5.7.3.0 2024-05-11 23:48:39 +01:00
Evgeny Poberezkin 1183fe427f Merge branch 'stable' 2024-05-10 20:30:42 +01:00
Evgeny Poberezkin c49a1f42e7 5.7.2: ios 214, android 204, desktop 43 2024-05-10 18:32:07 +01:00
Narasimha-sc 4f173215c6 docs: fix broken simplex group invite links (#4155)
* Fix non-working #simplex-devs invite

* Fix #simplex-devs link in pl

* replace SimpleX-Group-2

* replace simplex-group-2 link

* Update README.md
2024-05-10 17:43:06 +01:00
Evgeny Poberezkin 41597e563e website: translations (#4165)
* Translated using Weblate (French)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Czech)

Currently translated at 98.0% (252 of 257 strings)

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

* Translated using Weblate (Russian)

Currently translated at 99.6% (256 of 257 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Czech)

Currently translated at 98.0% (252 of 257 strings)

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

* Translated using Weblate (Russian)

Currently translated at 99.6% (256 of 257 strings)

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

---------

Co-authored-by: J'informatique <hello@jinformatique.net>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: link2xt <link2xt@testrun.org>
2024-05-10 17:39:51 +01:00
Evgeny Poberezkin aa127f0cea ui: translations (#4164)
* Translated using Weblate (Japanese)

Currently translated at 100.0% (1741 of 1741 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1515 of 1515 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1741 of 1741 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% (1741 of 1741 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 25.3% (441 of 1741 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 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 10.1% (176 of 1741 strings)

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

* Translated using Weblate (Persian)

Currently translated at 26.8% (467 of 1741 strings)

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

* Translated using Weblate (Persian)

Currently translated at 33.6% (586 of 1741 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 6.0% (105 of 1741 strings)

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

* Translated using Weblate (Persian)

Currently translated at 36.8% (642 of 1741 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 9.1% (159 of 1741 strings)

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

* Translated using Weblate (Persian)

Currently translated at 39.0% (679 of 1741 strings)

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

* Translated using Weblate (Persian)

Currently translated at 39.0% (680 of 1741 strings)

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

* import/export localizations

---------

Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Siavash <ciavash@proton.me>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: Flavian <3zorro.1@gmail.com>
2024-05-10 17:38:42 +01:00
Evgeny Poberezkin f9c64ba39c ios: update core library 2024-05-10 17:22:39 +01:00
Evgeny Poberezkin 1025fa94a1 core: 5.7.2.0 (simplexmq 5.7.3.0: update protocol versions, fix file downloads) 2024-05-10 15:18:42 +01:00
Stanislav Dmitrenko a59769b91d android, desktop: fix crash in contact preferences when updating user profile (#4158) 2024-05-10 09:45:44 +01:00
spaced4ndy 76248b4878 core: on receive set file crypto args only for new files (#4152) 2024-05-09 15:40:23 +04:00
Stanislav Dmitrenko 93a7ddb128 android, desktop: fix presenting large images (#4139)
* android, desktop: fix presenting large images

* 4320 px limitation

* revert line

* onClick

* onClick
2024-05-09 10:39:49 +01:00
Evgeny Poberezkin bc5af35a3e core: wallpapers api (#4110)
* core: wallpapers api

* optional colors

* update

* api

* update

* whitespace

* typo

* test, fix

* fix color parsing

* separate UI and Theme color schemes

* update

* enable test

* multiple themes, one per color scheme

* theme overrides as a separate type

* rename

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-05-08 15:36:20 +01:00
Evgeny Poberezkin e38d5bd885 core: update simplexmq (upgrade client protocol versions SMP v7, NTF v2) 2024-05-08 13:40:25 +01:00
M. Sarmad Qadeer 10f41aa1c9 web: add scroll to navbar (#4100)
* web: add scroll to navbar

* web: add scroll to whole navbar instead of scrolling the opened menu
2024-05-08 09:31:02 +01:00
spaced4ndy 1b081197d4 multiplatform: add error to response (#4140) 2024-05-06 20:27:35 +04:00
M. Sarmad Qadeer 9615e525c0 web: fix list numbering for safari (#4106)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-06 08:36:13 +01:00
M. Sarmad Qadeer db136116d3 web: make image of full width for mobile screen (#4101) 2024-05-06 08:31:34 +01:00
Evgeny Poberezkin 98f5e5d22b 5.7.1: ios 213, android 202, desktop 42 2024-05-05 21:01:57 +01:00
Evgeny Poberezkin 9f33e5d35e website: translations (#4136)
* Translated using Weblate (German)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (257 of 257 strings)

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

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
2024-05-05 19:00:16 +01:00
Evgeny Poberezkin b8e8124faf ui: translations (#4135)
* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: summoner001 <summoner@vivaldi.net>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Polish)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Polish)

Currently translated at 99.9% (1740 of 1741 strings)

Translated using Weblate (Polish)

Currently translated at 99.1% (1727 of 1741 strings)

Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (German)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (German)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: mlanp <github@lang.xyz>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Italian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Czech)

Currently translated at 98.1% (1709 of 1741 strings)

Co-authored-by: zenobit <zen@osowoso.xyz>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1741 of 1741 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1515 of 1515 strings)

Co-authored-by: elgratea <weblate@fastmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1741 of 1741 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (1515 of 1515 strings)

Co-authored-by: z0rden <kaanpeker196@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: summoner001 <summoner@vivaldi.net>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Japanese)

Currently translated at 80.7% (1224 of 1515 strings)

Translated using Weblate (Japanese)

Currently translated at 80.3% (1218 of 1515 strings)

Co-authored-by: koreirozzu <trueworldfacts+asjfsajfhajfh@proton.me>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Japanese)

Currently translated at 80.3% (1218 of 1515 strings)

Co-authored-by: a4318 <dalse.077@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1515 of 1515 strings)

Co-authored-by: xe1st <dnzkckali@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: J R <jr@simplex.chat>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Persian)

Currently translated at 9.8% (171 of 1741 strings)

Translated using Weblate (Persian)

Currently translated at 9.4% (164 of 1741 strings)

Co-authored-by: Siavash <ciavash@proton.me>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Persian)

Currently translated at 10.1% (176 of 1741 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1741 of 1741 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1515 of 1515 strings)

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

* Translated using Weblate (Persian)

Currently translated at 11.9% (208 of 1741 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 8.5% (148 of 1741 strings)

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

* import/export localizations

* tr revert

---------

Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@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: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: koreirozzu <trueworldfacts+asjfsajfhajfh@proton.me>
Co-authored-by: a4318 <dalse.077@gmail.com>
Co-authored-by: xe1st <dnzkckali@gmail.com>
Co-authored-by: J R <jr@simplex.chat>
Co-authored-by: Siavash <ciavash@proton.me>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
2024-05-05 18:57:52 +01:00
Evgeny Poberezkin 156e41950a ios: update library 2024-05-05 18:01:14 +01:00
Evgeny Poberezkin 26c5ed4caf core: 5.7.1.0 (simplexmq 5.7.2.0: reduce "ping" traffic, remove TLS timeouts) 2024-05-05 17:43:09 +01:00
Evgeny Poberezkin d832afa7e8 docs: calls without e2e encryption (#4134) 2024-05-05 16:56:34 +01:00
Stanislav Dmitrenko 2e18b97077 android: enable Android 8 support (API 26) (#4132) 2024-05-05 16:30:17 +01:00
Evgeny Poberezkin b6e57c0fa2 core: fix connection failure because of race condition when connecting via link or joining group via invitation (#4133)
* core: fix connection failure because of race condition when connecting via link or joining group via invitation

* fix race for connection via contact address

* simplexmq
2024-05-05 13:11:30 +01:00
spaced4ndy 15a226cfd1 ui: limit length of member names in chat view (#4122) 2024-05-03 12:34:15 +01:00
Evgeny Poberezkin c4cbf751b9 Merge branch 'stable' 2024-05-02 23:28:59 +01:00
Stanislav Dmitrenko 535ff1d836 actions: add macos aarch64 build and fix openssl include path (#4107) 2024-05-02 21:41:15 +01:00
Evgeny Poberezkin fb0718adac core: forward agent errors without connections to UI (to show CRITICAL alerts) (#4120) 2024-05-02 21:40:08 +01:00
Stanislav Dmitrenko 5f501f1cb9 android, desktop: fix android video calls (#4118) 2024-05-02 16:47:52 +01:00
Evgeny Poberezkin 7cc86574fe core: update simplexmq to 5.7.1.0 2024-05-02 16:43:08 +01:00
Evgeny Poberezkin 19fc44efae rfc: commercial model for infrastructure operators (#4102) 2024-04-30 07:53:27 +01:00
spaced4ndy 37e03a838c core: forward group message before ack (fixes forwarding message that deleted connection causing error in ackMsg) (#4108) 2024-04-29 19:49:04 +04:00
spaced4ndy aeb28400e9 core: take entity lock before processing file (#4105) 2024-04-29 19:32:53 +04:00
sh d5a0c5e56a scripts/build-android: update nix and refactor (#4099) 2024-04-27 09:23:14 +01:00
Evgeny Poberezkin a28d965a65 website: fix privacy page 2024-04-26 23:24:54 +01:00
Evgeny Poberezkin 9148425eba blog: legally binding transparency, v5.7 announcement (#4097)
* blog: legally binding transparency, v5.7 announcement

* update

* update, images

* readme

* update
2024-04-26 23:06:40 +01:00
M. Sarmad Qadeer 406c35958e web: add privacy page to website (#4096)
* web: add privacy page to website

* web: fix a blog frontmatter

* web: fix privacy link from other docs

* update

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-26 23:00:49 +01:00
Evgeny Poberezkin be9ae61a32 5.7: ios 212, android 200, desktop 41 2024-04-26 20:59:21 +01:00
Stanislav Dmitrenko 9db65a1775 ios: audio device picker (#4091)
* ios: audio device picker

* removed unused

* removed logs

* correct routing

* Revert "removed unused"

This reverts commit d883d7a719.

* changes

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-26 19:59:00 +01:00
Evgeny Poberezkin 1033f55597 ios: fix sound in outgoing calls in iOS 15 2024-04-26 19:41:44 +01:00
Stanislav Dmitrenko 7f2462c936 android: black background in call (#4098) 2024-04-26 18:31:52 +01:00
Evgeny Poberezkin e675efe6f3 ios: update library 2024-04-26 17:38:57 +01:00
Evgeny Poberezkin b3f8068446 core: 5.7.0.5, increase min version of remote host/controller to 5.7.0.3 2024-04-26 15:42:13 +01:00
Evgeny Poberezkin 957eda8a78 ui: variable profile image size (#4094)
* ui: variable profile image size

* changes

* fix

* clean up

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-04-25 22:09:06 +01:00
Evgeny Poberezkin 0fe949e225 5.7-beta.3: ios 210, android 199, desktop 40 2024-04-25 15:51:23 +01:00
Evgeny Poberezkin 5325b0a543 core: update simplexmq to 5.7.0.3 2024-04-25 13:40:06 +01:00
Evgeny Poberezkin f712eb0d1f ui: add link to the release post 2024-04-25 13:16:49 +01:00
spaced4ndy fc6fa5315b android: show disappearing message timer on calls and group invitations (#4090)
* android: show disappearing message timer on calls and group invitations

* fix padding
2024-04-25 12:15:52 +01:00
Evgeny Poberezkin 3eb88ab896 5.7.0.4 (simplexmq 5.7.0.3) 2024-04-25 11:15:28 +01:00
Alexander Bondarenko 20fa366231 core: use contextless decompression (#4089)
* core: use contextless decompression

* fuse concatMap/map

* nix

* update simplexmq

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-25 10:52:26 +01:00
Evgeny Poberezkin db05436e50 Merge branch 'stable' 2024-04-25 10:42:28 +01:00
Evgeny Poberezkin a1093b0671 docs: update privacy policy (#4076) 2024-04-25 10:41:27 +01:00
spaced4ndy 6a8a8f242a ui: allow to delete any items (#4082)
* ios: allow to delete any items

* android

* remove button android

* remove button ios
2024-04-25 10:20:52 +01:00
spaced4ndy 1163fe7b56 ios: show disappearing message timer on calls and group invitations (#4086) 2024-04-25 12:41:20 +04:00
spaced4ndy 063a6dbc92 core: apply disappearing messages setting to call and group invitation chat items (#4080)
* core: apply disappearing messages setting to call and group invitation chat items

* remove comment

* fix incorrectly set edited field

* sent group invitations

* refactor

* Revert "refactor"

This reverts commit 4dd3070c2d.
2024-04-25 09:37:05 +01:00
Stanislav Dmitrenko 9e2a3fe848 android, desktop: more relaxed way of showing alerts for encryption/decryption errors (#4085) 2024-04-24 21:39:59 +01:00
Stanislav Dmitrenko 2b7f3099a6 android, desktop: customizable profile images (#4087)
* android, desktop: customizable profile images

* better

* fixes

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-24 21:22:52 +01:00
Evgeny Poberezkin cfa7e0bb28 ios: customizable profile images (#4084)
* ios: customizable profile images

* update slider

* whats new
2024-04-24 21:20:26 +01:00
Evgeny Poberezkin 1967ac0880 ui: translations (#4079)
* Translated using Weblate (German)

Currently translated at 100.0% (1738 of 1738 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (1738 of 1738 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1512 of 1512 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 100.0% (1512 of 1512 strings)

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

* update

---------

Co-authored-by: mlanp <github@lang.xyz>
2024-04-24 14:42:17 +01:00
Stanislav Dmitrenko 68966a1551 android, desktop: alert for local encryption/decryption errors (#4081)
* android, desktop: more alert in case of local encryption/decryption errors

* sending a message without a file
2024-04-24 14:39:06 +01:00
Evgeny Poberezkin 5ba7b58d7d website: translations (#4078)
* Translated using Weblate (German)

Currently translated at 100.0% (257 of 257 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (257 of 257 strings)

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

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
2024-04-24 12:45:20 +01:00
Evgeny Poberezkin 9979983742 ui: translations (#4075)
* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1507 of 1507 strings)

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

* ios: Hungarian translations

* Translated using Weblate (German)

Currently translated at 99.5% (1730 of 1738 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 100.0% (1738 of 1738 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% (1512 of 1512 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% (1738 of 1738 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% (1512 of 1512 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 100.0% (1738 of 1738 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1512 of 1512 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1738 of 1738 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% (1512 of 1512 strings)

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

* import/export

---------

Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Anonimas <Anonimas3@users.noreply.hosted.weblate.org>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
2024-04-24 09:44:44 +01:00
Evgeny Poberezkin ab76e93df7 docs: security policy (#4068)
* docs: security policy

* update

* add to website
2024-04-23 19:30:42 +01:00
Evgeny Poberezkin f30287c4df docs: FAQ (#4013)
* Addd FAQ.md (#3814)

* faq

* typos

* add troubleshooting

* update links

---------

Co-authored-by: ungespurv <87089788+ungespurv@users.noreply.github.com>
2024-04-23 19:19:51 +01:00
Evgeny Poberezkin 2807e53d4c ui: traslations (#4070)
* Translated using Weblate (Dutch)

Currently translated at 99.9% (1728 of 1729 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 99.9% (1506 of 1507 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1729 of 1729 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% (1729 of 1729 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% (1507 of 1507 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% (1730 of 1730 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% (1507 of 1507 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% (1730 of 1730 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% (1507 of 1507 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% (1730 of 1730 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 5.1% (89 of 1730 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (1736 of 1738 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 80.8% (1218 of 1507 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1738 of 1738 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 98.5% (1713 of 1738 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1507 of 1507 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 100.0% (1738 of 1738 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% (1738 of 1738 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% (1738 of 1738 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 5.3% (93 of 1738 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% (1507 of 1507 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1738 of 1738 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 98.8% (1718 of 1738 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 5.4% (94 of 1738 strings)

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

* import/export localizations

---------

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: Flavian <3zorro.1@gmail.com>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: yokoba0413 <yokoba0413@gmail.com>
Co-authored-by: Anonimas <Anonimas3@users.noreply.hosted.weblate.org>
Co-authored-by: elgratea <weblate@fastmail.com>
2024-04-23 19:16:12 +01:00
Stanislav Dmitrenko 642e6d677e android, desktop: updating delivery tab in chat item info (#4074) 2024-04-23 19:14:58 +01:00
Stanislav Dmitrenko 944a0b3aad android: longer delay before showing keyboard when creating a group (#4073) 2024-04-23 19:14:35 +01:00
Stanislav Dmitrenko e5ac472da3 android, desktop: restore message TTL in database settings if confirmation is dismissed (#4072) 2024-04-23 18:51:04 +01:00
Stanislav Dmitrenko 2f79bfb075 android: current audio device will be set in init step (#4071) 2024-04-23 18:47:15 +01:00
Evgeny Poberezkin ae9e63d1be ios: export localizations 2024-04-23 09:59:16 +01:00
Evgeny Poberezkin d864603d01 website: do not build from stable 2024-04-23 00:14:02 +01:00
Evgeny Poberezkin 06ac15b282 5.7-beta.2: ios 209, android 198, desktop 39 2024-04-23 00:11:37 +01:00
Stanislav Dmitrenko 4c1dfc76d4 android: sound from speaker fix (#4067) 2024-04-22 23:26:01 +01:00
Evgeny Poberezkin bea19f76e9 5.7.0.3 (simplexmq 5.7.0.2) 2024-04-22 22:24:00 +01:00
Stanislav Dmitrenko f80ac6dc50 android: proper hiding keyboard when entering passcode (#4066) 2024-04-22 22:13:14 +01:00
spaced4ndy 2b6764fc36 android: 5.7 what's new (#4064)
* android: 5.7 what's new

* icon

* update LT language name

* Lithuanian

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-22 22:03:18 +01:00
Esra'a Al Shafei 7c74f02d01 docs: typo in simplex-chat.md (#4037)
typo fix
2024-04-22 18:26:41 +01:00
Stanislav Dmitrenko d53aa69691 android: managing audio sources in call in a better way (#4063) 2024-04-22 18:24:26 +01:00
spaced4ndy 9e3f528d44 android: remove experimental PQ toggle (#4060) 2024-04-22 17:50:52 +01:00
spaced4ndy 22fd2d7189 ios: remove experimental PQ toggle (#4051)
* ios: remove experimental PQ toggle

* remove header
2024-04-22 17:50:28 +01:00
spaced4ndy 7567791866 core: enable PQ encryption for contacts (#4049)
* wip

* migration

* remove migration

* remove flag wip

* Revert "remove migration"

This reverts commit 9e64663f9d.

* wip

* remove vrange parameterization

* tests mostly pass

* more tests pass

* enable for upgraded contacts

* remove migration

* core: test large messages (#4061)

* update simplexmq, fix tests

* test test

* another test

* enable tests

* empty

* empty
2024-04-22 17:46:48 +01:00
spaced4ndy 529ba7a0e7 ios: 5.7 what's new (#4062)
* ios: 5.7 what's new

* add about pq

* update

* update

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-22 17:46:14 +01:00
Evgeny Poberezkin 3b3a68da15 core: 5.7.0.2 2024-04-22 08:07:42 +01:00
Evgeny Poberezkin e0e94d78b0 core, ui: revert timeout changes (#4059)
* core, ui: revert timeout changes

* update core library
2024-04-22 07:45:20 +01:00
Evgeny Poberezkin d68369b32a android, desktop: add Lithuanian language 2024-04-21 20:37:14 +01:00
Evgeny Poberezkin d29886dbd2 ui: translations (#4056)
* Translated using Weblate (French)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 99.8% (1693 of 1696 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1696 of 1696 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% (1696 of 1696 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 95.0% (1405 of 1478 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1696 of 1696 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% (1696 of 1696 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% (1696 of 1696 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% (1478 of 1478 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 82.4% (1218 of 1478 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 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% (1696 of 1696 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 8.0% (119 of 1478 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 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% (1696 of 1696 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% (1478 of 1478 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% (1696 of 1696 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 10.5% (156 of 1478 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 6.3% (108 of 1696 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 10.6% (157 of 1478 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 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% (1696 of 1696 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% (1478 of 1478 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 99.8% (1693 of 1696 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1696 of 1696 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% (1696 of 1696 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 95.0% (1405 of 1478 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1696 of 1696 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% (1696 of 1696 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% (1696 of 1696 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% (1478 of 1478 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 82.4% (1218 of 1478 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 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% (1696 of 1696 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 8.0% (119 of 1478 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 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% (1696 of 1696 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% (1478 of 1478 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% (1696 of 1696 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 10.5% (156 of 1478 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 6.3% (108 of 1696 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 10.6% (157 of 1478 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 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% (1696 of 1696 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% (1478 of 1478 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% (1696 of 1696 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% (1478 of 1478 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 64.3% (1091 of 1696 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 72.1% (1223 of 1696 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 72.4% (1228 of 1696 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1695 of 1696 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 78.4% (1330 of 1696 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 100.0% (1696 of 1696 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1695 of 1696 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 100.0% (1478 of 1478 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 6.6% (113 of 1696 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% (1702 of 1702 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% (1702 of 1702 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1702 of 1702 strings)

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

* Translated using Weblate (Chinese (Traditional))

Currently translated at 71.2% (1213 of 1702 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1702 of 1702 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% (1478 of 1478 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 7.2% (124 of 1702 strings)

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

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1703 of 1703 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 99.6% (1697 of 1703 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1703 of 1703 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1703 of 1703 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1703 of 1703 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 99.9% (1702 of 1703 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1703 of 1703 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% (1703 of 1703 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% (1703 of 1703 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% (1478 of 1478 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% (1478 of 1478 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 99.8% (1712 of 1715 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1715 of 1715 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 99.8% (1713 of 1715 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1715 of 1715 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 99.9% (1714 of 1715 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1715 of 1715 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1715 of 1715 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1715 of 1715 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 99.8% (1713 of 1715 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1715 of 1715 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% (1478 of 1478 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1715 of 1715 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1715 of 1715 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1714 of 1715 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1715 of 1715 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% (1478 of 1478 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 7.5% (130 of 1715 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 7.8% (135 of 1715 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% (1715 of 1715 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% (1478 of 1478 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% (1715 of 1715 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% (1478 of 1478 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% (1715 of 1715 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% (1478 of 1478 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% (1478 of 1478 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1715 of 1715 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% (1478 of 1478 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 99.8% (1712 of 1715 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% (1715 of 1715 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% (1478 of 1478 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% (1715 of 1715 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% (1478 of 1478 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% (1725 of 1725 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1725 of 1725 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% (1725 of 1725 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 100.0% (1725 of 1725 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1725 of 1725 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% (1725 of 1725 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% (1478 of 1478 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 99.9% (1724 of 1725 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1728 of 1728 strings)

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

* process localizations

* update RU translations

* revert PL changes for "passphrase"

---------

Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Andre <andrefeliciano@duck.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Anonimas <qdq5ih+3ewax7y4esw98@cs.email>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Anonimas <Anonimas3@users.noreply.hosted.weblate.org>
Co-authored-by: Arturro43 <Arturro43.kontakt@gmail.com>
Co-authored-by: Alex <github@lippiece.anonaddy.me>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Kingpin <radoslav.najdenov@gmail.com>
2024-04-21 20:16:08 +01:00
Evgeny Poberezkin 50d3a29715 website: translations (#4057)
* Translated using Weblate (French)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (255 of 255 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 13.7% (35 of 255 strings)

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

---------

Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: Alex <github@lippiece.anonaddy.me>
Co-authored-by: Kingpin <radoslav.najdenov@gmail.com>
2024-04-21 11:10:07 +01:00
Evgeny Poberezkin 8e3a713a49 ui: limit max size of events, sort members by role (#4058) 2024-04-21 10:57:54 +01:00
Evgeny Poberezkin 7cec79e79b 5.7-beta.1: ios 208, android 197, desktop 38 2024-04-20 22:07:04 +01:00
Evgeny Poberezkin e9db7e8e58 ios: export translations 2024-04-20 19:57:40 +01:00
Evgeny Poberezkin f53882049f ios: update core library 2024-04-20 19:54:47 +01:00
Evgeny Poberezkin 8f4c9a673a core: 5.7.0.1 2024-04-20 19:39:20 +01:00
Evgeny Poberezkin 02f980e968 core: update simplexmq (better newtork congestion handling, larger connection timeouts) (#4055)
* core: update simplexmq (better newtork congestion handling, larger connection timeouts)

* ui: update default TCP connect timeout, add receiving concurrency

* update simplexmq
2024-04-20 19:35:11 +01:00
Stanislav Dmitrenko 412f75219a android: select audio source (#4040)
* android, desktop: select audio source

* improvements

* fix possible crash

* changes
2024-04-20 19:19:37 +01:00
Evgeny Poberezkin c8c81a840b core: revert build to use two branches (#4052)
* Revert "scripts: ghc version update (#4010)"

This reverts commit 35b7f2cb1c.

* Revert "Force include hs_init_with_rtsopts (#4028)"

This reverts commit 76a33a3743.

* Revert "core: fix nix config (#4003)"

This reverts commit f8e6a78a3b.

* Revert "ci: build armv7a with 8.10.7 in the main branches (master, stable) (#3733)"

This reverts commit 0d7a32877f.
2024-04-19 21:17:22 +01:00
Stanislav Dmitrenko 925cb39397 desktop: using system sound in screenshare (#4035)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-19 17:37:47 +01:00
Stanislav Dmitrenko f6ceb89c4b android, desktop: forward ui (#4039)
* android, desktop: forward ui

* changes

* attachment icon

* reorder lines

* reorder lines

* change

* inline content + formatted text

* fix header padding

* fix

* fix2

* Revert "fix header padding"

This reverts commit 63f2b15f02.

* broken default parameter

* changes

* more checks for file forwarding

* paddings

* padding

* padding and fix

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-04-19 17:36:32 +01:00
Evgeny Poberezkin a35d392f76 core: update simplexmq 2024-04-19 17:25:34 +01:00
spaced4ndy 1306c84938 ios: in item context menu don't show forward button if file doesn't exist, add download button (#4048) 2024-04-19 17:21:35 +01:00
Stanislav Dmitrenko 6484e36b82 ios: fix mute/unmute button state (#4046) 2024-04-19 17:20:31 +01:00
Stanislav Dmitrenko 918be31f2c desktop: fix freeze that happened when new chat items arrives while scrolling via scrollbar (#4050) 2024-04-19 15:57:00 +01:00
spaced4ndy 648884044f core: prohibit forwarding file if it's not found (#4047) 2024-04-19 11:31:44 +04:00
Stanislav Dmitrenko 505c6cb062 ios: prevent a crash when exiting the app (#4041)
* ios: prevent a crash when exiting the app

* log
2024-04-19 07:23:13 +01:00
Stanislav Dmitrenko 065c8f8861 ios: fix typing using keyboard suggestions (#4045) 2024-04-19 07:17:17 +01:00
spaced4ndy 6c509027f7 docs: IP address protection rfc (#4036) 2024-04-17 13:53:45 +04:00
Evgeny Poberezkin 4eafdc3723 blog: metadata in messengers (#4038)
* blog: metadata in messengers

* readme

* call.js

* picture

* revert call.js
2024-04-16 20:18:22 +01:00
spaced4ndy 77f5c678d5 ios: forward ui (#4024)
* wip

* wip

* fixes

* improvements

* info

* fix

* dont cleanup file

* info design, text

* text

* rework with LazyVStack

* delay

* refactor

* move delay

* fix

* refactor

* refactor 2

* keep current message

* forward with quote, context icons

* info

* preserve draft

* remove newline

* improve search

* info

* layout

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-16 09:28:39 +01:00
Stanislav Dmitrenko 5e71d00ace android, desktop: workaround of missing stuns support in calls (#4033)
* android, desktop: workaround of missing stuns support in calls

* const
2024-04-16 08:38:46 +01:00
Stanislav Dmitrenko c2169f7813 desktop: fix video calls in Firefox (#4034)
* desktop: fix video calls in Firefox

* one more play()
2024-04-16 08:22:40 +01:00
spaced4ndy 7ff4b05c90 core: remember new origin for received forwarded messages (#4032) 2024-04-15 17:19:37 +04:00
Evgeny Poberezkin d7f8bff957 Merge branch 'stable' 2024-04-15 11:16:33 +01:00
sh bda0917787 github: fix cla action (#4030) 2024-04-15 10:51:24 +01:00
Evgeny Poberezkin 0eae7f56f3 5.7-beta.0: ios 207, android 196, desktop 37 2024-04-14 21:14:15 +01:00
Stanislav Dmitrenko 24e3806b25 webrtc: updated credentials (#4011)
* webrtc: updated credentials

* no udp

* change

* stuns

* added stun back

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-14 19:18:12 +01:00
Evgeny Poberezkin f606e5742c ios: update library 2024-04-14 19:11:15 +01:00
Evgeny Poberezkin c6af2c285a core: 5.7.0.0 (#4027) 2024-04-14 17:31:56 +01:00
Stanislav Dmitrenko 35b7f2cb1c scripts: ghc version update (#4010) 2024-04-14 16:42:04 +01:00
Evgeny Poberezkin 76a33a3743 Force include hs_init_with_rtsopts (#4028)
Co-authored-by: Moritz Angermann <moritz.angermann@gmail.com>
2024-04-14 16:12:34 +01:00
Evgeny Poberezkin b6fd5e61b6 Merge branch 'stable' 2024-04-13 12:12:51 +01:00
artur fe639eed48 docs: Add Polish translation (#4001)
* docs: Add polish translation

* README: Add link to polish translation

* docs: Polish version of README - Fix links

* docs: Add links to polish translation, fix

* docs: Fix polish translation thanks to support team

* docs: Add links to polish translation in english version of docs

* fix links

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-13 12:12:21 +01:00
spaced4ndy 638fd3756a core: correctly populate data for items forwarded from groups (#4025) 2024-04-13 11:52:39 +01:00
Stanislav Dmitrenko de81434b36 android, desktop: role-based preferences, SimpleX links preference (#4023)
* android, desktop: role-based preferences, SimpleX links preference

* disable for now

* different way of disabling send button

* mic icon filled

* icons

* braces

* colors

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-13 11:51:10 +01:00
Evgeny Poberezkin 433b3652fb core: simplexmq 5.6.2.2 2024-04-13 09:33:37 +01:00
Alexander Bondarenko 86fe2212c3 chat: forward files with streaming re-encryption (#4022)
* chat: forward files with streaming re-encryption

* refactor
2024-04-13 09:32:43 +01:00
Evgeny Poberezkin 182225a5b1 ios: role-based preferences, SimpleX links preference (#4021)
* ios: role-based preferences, SimpleX links preference

* disable some options
2024-04-12 11:29:58 +01:00
spaced4ndy e10c63dc64 ui: deletable field (#4019) 2024-04-12 13:10:47 +04:00
spaced4ndy 29941729d2 ui: forwarded item header (#4017) 2024-04-12 12:56:09 +04:00
spaced4ndy ee53377070 core: fix forwarded item deletion (#4018) 2024-04-12 12:55:04 +04:00
spaced4ndy 0deb6a4eb1 ui: forward types (#4008)
* ios: forward types

* android

* move
2024-04-11 13:58:56 +01:00
Stanislav Dmitrenko b84ef0ce35 android: network observer (#3992)
* android: network observer

* removed unused code

* rename

* rename

* new line

* rename

* changes in logic

* adapted to ios logic

* change

* change

* change

* networkLost

* item in settings

* reorder

* changes

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-11 13:26:24 +01:00
Stanislav Dmitrenko 34dee32def android, desktop: sound prompts and vibration (#3997)
* android, desktop: sound prompts and vibration

* moved audio playing to js

* Revert "moved audio playing to js"

This reverts commit a9355c2d88.

* sound from speaker/earpiece

* better

* changes

* license of audio

* reorder lines

* loop fix

* awaiting call receipt

* desktop

* new line
2024-04-11 13:19:00 +01:00
Stanislav Dmitrenko 94851f177b ios: noRcvUser handling while downloading a file in migration process (#4012) 2024-04-11 12:05:01 +01:00
Stanislav Dmitrenko e560b49d14 ios: sound prompts and vibration during calls (#4005)
* ios: sound prompts and vibration

* awaiting call receipt

* update

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-11 12:02:41 +01:00
Stanislav Dmitrenko d8b52ee0d3 ios: network observer (#3996)
* ios: network observer

* update

* remove metered

* update tcpTimeoutPerKb

* network connection in settings

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-11 11:31:30 +01:00
Evgeny Poberezkin a9c0f356b4 ios: update core library 2024-04-11 11:25:06 +01:00
Evgeny Poberezkin 8a3710482b core: update simplexmq 2024-04-11 10:47:51 +01:00
Evgeny Poberezkin b3a4ea8e57 core: api to update user network state (#3998)
* core: api to update user network state

* simplexmq

* update simplexmq

* simplexmq
2024-04-10 23:32:55 +01:00
Evgeny Poberezkin 4be6c69633 core: update simplexmq 2024-04-10 08:49:06 +01:00
Evgeny Poberezkin 005d99ad50 docs: trasparency reports (#4007) 2024-04-09 21:45:48 +01:00
Narasimha-sc 36f86beafd docs: device linking info on downloads page #4004 2024-04-09 20:30:08 +01:00
Evgeny Poberezkin 1fa79a2654 android, desktop: fix incorrect event type for critical/internal error alerts 2024-04-09 18:18:11 +01:00
Evgeny Poberezkin 72611084d3 core: debug events (#4006) 2024-04-09 17:31:52 +01:00
Evgeny Poberezkin a5db36469d core: api to forward messages (#3968)
* wip

* wip

* test

* mute

* tests

* simplify (only bool flag)

* re-encrypt file

* tests

* more tests (wip)

* fix relative paths, refactor

* more tests

* more locks

* fix, tests

* more tests

* rework (revert from bool to ids)

* update schema

* more tests

* add to info

* ForwardedMsg container

* Revert "ForwardedMsg container"

This reverts commit bb57f12151.

* parser

* more tests

* rework api

* more locks

* test

* move

* remove from

* view

* prohibit editing

* item info view

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-04-09 16:02:59 +04:00
Evgeny Poberezkin f8e6a78a3b core: fix nix config (#4003)
* bump

* more compilers

* i686 32bit only 8.10.7

---------

Co-authored-by: Moritz Angermann <moritz.angermann@gmail.com>
2024-04-09 08:15:29 +01:00
spaced4ndy 5b0c8e0f76 core: improve some tests (#4000) 2024-04-08 18:16:29 +04:00
Evgeny Poberezkin 2968cd0460 rfc: protocol extensions for channels/super-peers (#3980) 2024-04-05 16:46:37 +01:00
Evgeny Poberezkin 8ffb4e500e Merge branch 'stable' 2024-04-05 15:30:09 +01:00
Stanislav Dmitrenko 6133993cfe android, desktop: fix build error related to JVM version (#3995) 2024-04-05 15:29:41 +01:00
Evgeny Poberezkin 0d7a32877f ci: build armv7a with 8.10.7 in the main branches (master, stable) (#3733)
Co-authored-by: Moritz Angermann <moritz.angermann@gmail.com>
2024-04-05 12:24:34 +01:00
Evgeny Poberezkin 18efc28d16 core: additional group preferences: prohibit SimpleX links, restrict some features to specific roles (#3964)
* core: additional group preferences: prohibit SimpleX links, restrict some features to specific roles

* add role to group preference items, tests
2024-04-04 20:41:56 +01:00
spaced4ndy 069395c2a0 core: entity locks (#3962)
* core: entity locks

* more locks

* update sha256map

* add delay

* clean up

* empty

* fix tests

* empty

* empty

* more delays

* empty

* comment delays

* Revert "comment delays"

This reverts commit 4245b545fb.

* Revert "Revert "comment delays""

This reverts commit f803386945.

* take lock in the beginning of processing loop

* empty

* empty

* remove lock

* rework file locks

* empty

* fix

* empty

* add connection locks

* empty

* fix test

* empty

* remove commented delays

* add to debug locks

* update

* refactor

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-04 19:24:42 +01:00
Stanislav Dmitrenko a725d2efac desktop (windows): fix build (#3990) 2024-04-04 14:18:33 +01:00
Evgeny Poberezkin 5f9710e4bb blog: post 2024-04-04 13:17:20 +01:00
Evgeny Poberezkin ea6c5bfb0b 5.6.1: ios 206, android 193, desktop 36 2024-04-04 08:58:24 +01:00
Stanislav Dmitrenko 14c279d1e0 android: possibly, prevent TooManyRequests exception (#3989)
* android: possibly, prevent TooManyRequests exception

* new line
2024-04-03 15:15:44 +01:00
Stanislav Dmitrenko d2de81100d android: workaround of pager's bug (#3988) 2024-04-03 15:11:04 +01:00
Stanislav Dmitrenko 9b28ae6d9e desktop: remote connection host/port fix (#3987) 2024-04-03 11:58:32 +01:00
Evgeny Poberezkin ea862a8f34 core: 5.6.1.1 (simplexmq 5.6.2.1) 2024-04-03 11:43:42 +01:00
Evgeny Poberezkin 2bd1a82b7d core: revert "deps: switch to base64 via simplexmq (#3957)" (#3985)
* Revert "deps: switch to base64 via simplexmq (#3957)"

This reverts commit d65137882b.

* update simplexmq
2024-04-03 10:47:38 +01:00
Evgeny Poberezkin 97a37634ef ios: 5.6.1 build 205 2024-04-03 01:47:01 +01:00
Stanislav Dmitrenko 28fbc1cd84 desktop: correct height of a window (#3982) 2024-04-02 20:05:14 +01:00
Stanislav Dmitrenko b8ee2af5b7 deskop: show window icon (#3983)
* deskop: show window icon

* size
2024-04-02 18:57:23 +01:00
Stanislav Dmitrenko c234809894 ios: improvement of chat item context menu (#3981)
* ios: improvement of chat item context menu

* rename

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-02 17:00:24 +01:00
Evgeny Poberezkin e1a997877a rfc: groups based on super-peers (WIP) (#3917) 2024-04-01 15:04:13 +01:00
Evgeny Poberezkin 69218952c3 core: 5.6.1.0 2024-04-01 14:36:45 +01:00
Evgeny Poberezkin dc2591b0bf ios: build settings (#3978) 2024-04-01 13:55:26 +01:00
Evgeny Poberezkin 2272b77b53 ios: refactor notifications (#3976)
* ios: refactor notifications

* refactor
2024-04-01 13:52:28 +01:00
Evgeny Poberezkin d90e2f4436 core: remove mtl typeclasses to reduce overhead (#3975)
* core: remove mtl typeclasses to reduce overhead

* strict data, optimization

* update simplexmq, clean up

* un-unlift attachRevHTTP2Client

* remote

---------

Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>
2024-04-01 13:34:45 +01:00
Evgeny Poberezkin 9b6ca23dcb ios: fix UI freezes on start and when exiting background (#3972)
* ios: fix UI freezes on start and when exiting background

* remove unused code

* comments
2024-03-29 22:58:36 +00:00
Evgeny Poberezkin 1410b4bd85 ios: prevent call to apiContactInfo after the app is suspended 2024-03-29 19:43:16 +00:00
Evgeny Poberezkin 42a35e8c72 ios: prevent call to listUsers after the app is suspended and database is closed 2024-03-29 18:58:55 +00:00
Evgeny Poberezkin 86fe28f1ed core: chat hooks allowing to extend or customize chat core (#3953)
* core: chat hooks allowing to extend or customize chat core

* update

* json

* custom response

* user in db queries
2024-03-29 18:30:17 +00:00
Evgeny Poberezkin 735359c279 android: strings for permissions 2024-03-29 18:28:54 +00:00
Stanislav Dmitrenko 3d20465662 android: more user-friendly way of granting permissions in call (#3945)
* android: more user-friendly way of granting permissions in call

* changes

* ask permissions without click at first

* changes in logic and UI

* enhancements

* show alert only when non in PiP

* change

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-29 18:19:36 +00:00
Stanislav Dmitrenko b64ae90850 ios: NotificationService refactoring (#3961)
* ios: NotificationService refactoring

* refactor

* removed unused code

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-28 17:28:10 +00:00
spaced4ndy 366b58ead5 core: don't save async commands records for ack (#3904) 2024-03-28 19:52:06 +04:00
spaced4ndy 32bcaad126 ui: add missing error types (#3925) 2024-03-28 17:49:09 +04:00
Alexander Bondarenko d65137882b deps: switch to base64 via simplexmq (#3957)
* deps: switch to base64 via simplexmq

* update error text

* update nix

* set simplexmq to master

* update paths
2024-03-28 13:09:04 +00:00
spaced4ndy 095d613f01 website: translations (#3960)
* Translated using Weblate (Polish)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Finnish)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Finnish)

Currently translated at 100.0% (254 of 254 strings)

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

---------

Co-authored-by: Jakub <fioletowy.temp@tutanota.com>
Co-authored-by: whoami11 <hvhdinik@gmail.com>
Co-authored-by: You and me <trash.93m78@slmail.me>
Co-authored-by: Jiri Grönroos <jiri.gronroos@iki.fi>
2024-03-28 12:30:31 +00:00
spaced4ndy f22beefbd4 ui: translations (#3959)
* Translated using Weblate (German)

Currently translated at 100.0% (1687 of 1687 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (1687 of 1687 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1478 of 1478 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 100.0% (1478 of 1478 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1478 of 1478 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1478 of 1478 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 98.3% (1659 of 1687 strings)

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

* Translated using Weblate (Czech)

Currently translated at 98.2% (1657 of 1687 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 95.9% (1619 of 1687 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% (1687 of 1687 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1478 of 1478 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 0.3% (5 of 1478 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (1687 of 1687 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 41.7% (617 of 1478 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1478 of 1478 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 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% (1478 of 1478 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 98.4% (1661 of 1687 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 45.2% (763 of 1687 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 3.7% (55 of 1478 strings)

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

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (1687 of 1687 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 99.4% (1678 of 1687 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 3.7% (56 of 1478 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 strings)

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

* Translated using Weblate (Portuguese)

Currently translated at 7.3% (109 of 1478 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 96.7% (1430 of 1478 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 100.0% (1687 of 1687 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 5.6% (96 of 1687 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1687 of 1687 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1688 of 1688 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1688 of 1688 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1688 of 1688 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 99.4% (1470 of 1478 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 99.9% (1687 of 1688 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% (1688 of 1688 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 6.0% (102 of 1688 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% (1688 of 1688 strings)

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

* android

* ios import

* ios export

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: subjection yogirt <subjectiongithub@yogirt.com>
Co-authored-by: whoami11 <hvhdinik@gmail.com>
Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: You and me <trash.93m78@slmail.me>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: Andre <andrefeliciano@duck.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
2024-03-28 12:27:58 +00:00
spaced4ndy c9bf36291b ios: fix default (#3958) 2024-03-27 09:59:15 +00:00
spaced4ndy 42ebe8bc60 core: batch broadcast send db operations (#3956)
* core: batch broadcast send db operations

* refactor

* Update src/Simplex/Chat.hs

Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>
2024-03-27 11:49:14 +04:00
Stanislav Dmitrenko 96fb61ccfc desktop: show toast if failed to show notification (#3955)
* desktop: show toast if failed to show notification

* longer timeout

* returned old version of the lib
2024-03-26 12:43:45 +00:00
spaced4ndy 1d698c114f docs: communicate rejection rfc (#3946) 2024-03-26 11:29:28 +04:00
Stanislav Dmitrenko 154ce5843d android, desktop: update dependencies (#3954)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-25 15:59:00 +00:00
Evgeny Poberezkin a5817d9feb core: fix cabal paths (#3952)
* fixed install cabal file paths.

* updated package.yaml

* fix

---------

Co-authored-by: Andor Kesselman <andor@magic-pro-3.local>
2024-03-25 08:24:46 +00:00
Evgeny Poberezkin 72082af139 docs: update version 2024-03-23 19:20:37 +00:00
Evgeny Poberezkin eb36704f59 Merge branch 'stable' 2024-03-23 18:42:53 +00:00
Evgeny Poberezkin 84fbff6148 blog: v5.6 release, non-profit governance (#3951)
* blog: v5.6 release

* images, preview

* corrections

* update image

* update readme
2024-03-23 18:42:18 +00:00
Evgeny Poberezkin dd75d30c08 blog: update PQ encryption post (#3948)
* blog: update pq encryption post

* correction
2024-03-23 18:29:05 +00:00
spaced4ndy 52803ae976 core: add delays to some failing tests (#3947) 2024-03-22 22:01:11 +04:00
spaced4ndy ec73a31cb5 directory: fix double logic inversion on roles check, incorrect error message (#3944) 2024-03-22 15:07:01 +04:00
Evgeny Poberezkin 6ad5048b58 5.6: ios 204, android 191, desktop 35 2024-03-21 22:30:30 +00:00
Stanislav Dmitrenko ca0ce4dfdd ios: making chat state .active when starting chat, correctly handle hidden users when deleting the last profile (#3936)
* ios: making chat state .active when starting chat

* changes

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-21 19:36:05 +00:00
spaced4ndy d27502ec47 ios: restore reveal/hide animation (#3933)
* ios: restore reveal/hide animation

* remove comment

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-21 19:12:47 +00:00
spaced4ndy 655ad4d813 ui: translations (#3940)
* Translated using Weblate (Dutch)

Currently translated at 96.6% (1622 of 1679 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 96.2% (1624 of 1687 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 97.0% (1638 of 1687 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% (1687 of 1687 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 96.9% (1433 of 1478 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 98.5% (1456 of 1478 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 97.0% (1637 of 1687 strings)

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

* Translated using Weblate (German)

Currently translated at 96.6% (1631 of 1687 strings)

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

* Translated using Weblate (French)

Currently translated at 97.2% (1640 of 1687 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1687 of 1687 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 97.4% (1441 of 1478 strings)

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

* Translated using Weblate (Czech)

Currently translated at 95.2% (1607 of 1687 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 97.0% (1637 of 1687 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1687 of 1687 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1478 of 1478 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1478 of 1478 strings)

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

* Translated using Weblate (Czech)

Currently translated at 98.2% (1657 of 1687 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1686 of 1687 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 95.1% (1406 of 1478 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 97.2% (1438 of 1478 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1687 of 1687 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 99.6% (1681 of 1687 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 99.6% (1681 of 1687 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1686 of 1687 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 100.0% (1478 of 1478 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 99.8% (1685 of 1687 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 99.8% (1476 of 1478 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 95.8% (1617 of 1687 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% (1687 of 1687 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% (1478 of 1478 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% (1687 of 1687 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% (1478 of 1478 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% (1687 of 1687 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% (1478 of 1478 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1687 of 1687 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 95.9% (1619 of 1687 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 95.8% (1417 of 1478 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 strings)

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

* android

* import

* export

* ru corrections

* export/update ru

---------

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: cervezagua <cervezagua@pm.me>
Co-authored-by: jonnysemon <jonnysemon@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: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-21 19:07:12 +00:00
Evgeny Poberezkin e0566599a4 core: 5.6.0.4 (#3939) 2024-03-21 19:00:19 +00:00
Evgeny Poberezkin 2546ad5351 Translated using Weblate (Czech) (#3941)
Currently translated at 99.2% (252 of 254 strings)

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

Co-authored-by: zenobit <zen@osowoso.xyz>
2024-03-21 17:37:56 +00:00
Stanislav Dmitrenko 0706e6e464 android: stopping chat after deleting the last user (#3937)
* android: stopping chat after deleting the last user

* fix for hidden users + onboarding
2024-03-21 14:02:38 +00:00
spaced4ndy c2adf40b5a ui: align finalize migration destructive/default button colors (#3938)
* ios: align finalize migration destructive/default button colors

* android
2024-03-21 14:00:27 +00:00
Stanislav Dmitrenko b220ea23e2 ios: stop chat after deleting the last profile (#3935) 2024-03-21 13:58:04 +00:00
spaced4ndy a16e3eebd1 ui: improve "allow PQ" button (#3932)
* ios: improve "allow PQ" button

* android
2024-03-21 09:13:18 +00:00
Stanislav Dmitrenko 6d54c21774 ios: chatitem height with menu workaround (#3930)
* ios: chatitem height with menu workaround

* turned on animation

* disabled animation in some places again
2024-03-20 17:49:53 +00:00
spaced4ndy d2e6313ce3 ui: swap finalize migration buttons (make destructive harder to reach, consistent order of primary and destructive with previous page) (#3931) 2024-03-20 20:20:10 +04:00
Evgeny Poberezkin c2707d3c2b 5.6-beta.1: ios 203, android 190, desktop 34 2024-03-19 17:58:29 +00:00
Stanislav Dmitrenko 43381b5cf0 desktop: scroll bars (#3920)
* desktop: scroll bar

* more places with scrollbar

* removed unused code

* color

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-19 16:56:36 +00:00
Evgeny Poberezkin 3f1d86623a core: 5.6.0.3 2024-03-19 15:20:04 +00:00
Stanislav Dmitrenko 5fde879fea ios: better layout performance for chat item (#3911)
* ios: better layout performance for chat item

* different way of disabling menu

* two fixes

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-19 14:40:46 +00:00
Evgeny Poberezkin 157c4722ca ui: increase chunk size for new allocations in core to 64mb (#3928) 2024-03-19 14:35:40 +00:00
Alexander Bondarenko 5bc8bbe16c chat: use context-less compression (#3913)
* chat: use context-less compression

* update sha256map

* space

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-19 13:33:27 +00:00
Alexander Bondarenko d835f9df3d ios: remove recursion in receiveMsgLoop (#3922)
* ios: remove recursion in receiveMsgLoop

* comment

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-19 11:44:30 +00:00
Evgeny Poberezkin 8f04e13750 ios: add Hungarian interface language (#3927) 2024-03-19 11:34:11 +00:00
spaced4ndy 39167ab3dd multiplatform: 5.6 what's new (#3926) 2024-03-19 11:27:05 +00:00
spaced4ndy e925d87548 ios: 5.6 what's new (#3923)
* ios: 5.6 what's new

* update

* update

* release announcement stub, update link

* Hungarian

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-19 10:53:46 +00:00
Evgeny Poberezkin c2e2408394 website: translations (#3919)
* ios: update library

* Translated using Weblate (Finnish)

Currently translated at 97.2% (245 of 252 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 1.5% (4 of 254 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (254 of 254 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (254 of 254 strings)

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

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Jiri Grönroos <jiri.gronroos@iki.fi>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Float <float.hu+@gmail.com>
Co-authored-by: Jakub <fioletowy.temp@tutanota.com>
Co-authored-by: muralito <muralito@montevideo.com.uy>
Co-authored-by: N1DH0GG <janpstrunn@duck.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: Salif Mehmed <mail@salif.eu>
Co-authored-by: ActiveTK <webmaster@activetk.jp>
2024-03-19 09:53:25 +00:00
Evgeny Poberezkin bb16922634 ui: translations (#3918)
* Added translation using Weblate (Hungarian)

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1403 of 1403 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1605 of 1605 strings)

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

* Translated using Weblate (Persian)

Currently translated at 9.2% (149 of 1605 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1605 of 1605 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% (1403 of 1403 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1403 of 1403 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 100.0% (1605 of 1605 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1605 of 1605 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% (1403 of 1403 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1605 of 1605 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 100.0% (1607 of 1607 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 99.7% (1603 of 1607 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1403 of 1403 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1607 of 1607 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% (1607 of 1607 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 0.2% (4 of 1403 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 0.2% (4 of 1403 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 0.6% (9 of 1403 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 5.9% (84 of 1403 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1608 of 1608 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% (1608 of 1608 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 20.8% (292 of 1403 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% (1608 of 1608 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% (1608 of 1608 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 29.8% (419 of 1403 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 29.8% (419 of 1403 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 99.7% (1604 of 1608 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% (1608 of 1608 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 43.6% (613 of 1403 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% (1608 of 1608 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% (1403 of 1403 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1608 of 1608 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1403 of 1403 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1608 of 1608 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 98.0% (1577 of 1608 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1608 of 1608 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% (1403 of 1403 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 45.2% (727 of 1608 strings)

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (1608 of 1608 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1608 of 1608 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% (1608 of 1608 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 99.6% (1398 of 1403 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 99.6% (1398 of 1403 strings)

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

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

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

* Translated using Weblate (Persian)

Currently translated at 9.6% (155 of 1608 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1608 of 1608 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% (1403 of 1403 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1608 of 1608 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 99.9% (1607 of 1608 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1403 of 1403 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1608 of 1608 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% (1403 of 1403 strings)

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

* Translated using Weblate (Czech)

Currently translated at 95.5% (1536 of 1608 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1608 of 1608 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% (1608 of 1608 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% (1403 of 1403 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% (1611 of 1611 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1611 of 1611 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 97.3% (1568 of 1611 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 87.9% (1234 of 1403 strings)

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

* Added translation using Weblate (Vietnamese)

* Translated using Weblate (French)

Currently translated at 100.0% (1611 of 1611 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1611 of 1611 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1611 of 1611 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% (1403 of 1403 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1611 of 1611 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% (1611 of 1611 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1613 of 1613 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 99.9% (1612 of 1613 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 100.0% (1613 of 1613 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 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1403 of 1403 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 87.2% (1224 of 1403 strings)

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1612 of 1613 strings)

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

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 59.7% (838 of 1403 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1403 of 1403 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (Persian)

Currently translated at 10.0% (162 of 1613 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 1.4% (24 of 1613 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 1.4% (24 of 1613 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 88.5% (1243 of 1403 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 3.0% (49 of 1613 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 3.0% (49 of 1613 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% (1613 of 1613 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% (1613 of 1613 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 85.9% (1206 of 1403 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1613 of 1613 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% (1613 of 1613 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 4.0% (66 of 1613 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% (1613 of 1613 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1403 of 1403 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1403 of 1403 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% (1613 of 1613 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% (1403 of 1403 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% (1613 of 1613 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% (1403 of 1403 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% (1403 of 1403 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 96.4% (1555 of 1613 strings)

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

* Translated using Weblate (Vietnamese)

Currently translated at 5.0% (81 of 1613 strings)

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

* Translated using Weblate (Czech)

Currently translated at 97.5% (1574 of 1613 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 98.8% (1594 of 1613 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1403 of 1403 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1403 of 1403 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% (1613 of 1613 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% (1403 of 1403 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 5.3% (87 of 1613 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% (1403 of 1403 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1613 of 1613 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 96.1% (1349 of 1403 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1403 of 1403 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 5.6% (91 of 1613 strings)

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

* fix android strings

* ios: import

* ios: export

---------

Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: Siavash <ciavash@proton.me>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Dan Hessel Kennet Miranda Cardona <kennetmiranda@skiff.com>
Co-authored-by: Moo <hazap@hotmail.com>
Co-authored-by: Jakub <fioletowy.temp@tutanota.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Cooly <whiteglass67@proton.me>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: tomato potato <tomato.games@protonmail.com>
Co-authored-by: sr sr <sr1919os@gmail.com>
Co-authored-by: N1DH0GG <janpstrunn@duck.com>
Co-authored-by: axmfs <axmfs@proton.me>
Co-authored-by: Zhiyounihao <jilywen@outlook.com>
Co-authored-by: K0RR <rdkracz@gmail.com>
Co-authored-by: tuananh-ng <github.zvjhi@slmail.me>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: Groovy394 <groovy394@gmail.com>
Co-authored-by: Deleted User <noreply+78511@weblate.org>
Co-authored-by: ActiveTK <webmaster@activetk.jp>
Co-authored-by: sith-on-mars <groguko36@pm.me>
2024-03-19 09:53:01 +00:00
spaced4ndy a3310cd62e ios: fix decoder crashing (#3921)
* ios: fix ios decoder crashing

* change

* fix

* refactor

* simplify

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-18 18:38:49 +00:00
spaced4ndy 94a6f300ed core: fix creation of empty files (#3912) 2024-03-15 18:17:31 +04:00
spaced4ndy 1f8eb1d638 update simplexmq (xftp fixes) 2024-03-15 12:48:55 +04:00
Evgeny Poberezkin 5a016378a8 Merge branch 'stable' 2024-03-14 10:42:20 +00:00
Evgeny Poberezkin bac4e61997 blog: quantum resistant Signal algorithm (#3906)
* blog: quantum resistant Signal algorithm

* update, images

* finalize

* readme

* corrections
2024-03-14 10:41:24 +00:00
spaced4ndy f3eeb9dcc2 core: temp-folder option (#3905) 2024-03-14 10:59:20 +04:00
spaced4ndy 240ca30f91 core: remove withStoreCtx (#3903) 2024-03-13 13:57:17 +04:00
Evgeny Poberezkin 835944ab24 5.6-beta.0: ios 202, android 189, desktop 33 2024-03-12 21:21:06 +00:00
Evgeny Poberezkin d53ef24bf1 core: 5.6.0.2 2024-03-12 18:29:15 +00:00
Stanislav Dmitrenko e75be71d9a android, desktop: migration enhancements (#3901)
* adapted iOS logic

* rename everything

* title

* title

* text

* rename

* rename

* alert on strange error
2024-03-12 18:25:02 +00:00
Alexander Bondarenko 7fa2f2f72e core: organize withAckMessage (#3889)
* core: organize withAckMessage

* mark critical sections

* differentiate DB internal error from chat

* throw CRITICALs

* only CRIT on SEDatabaseError

* normalize errors

* shift MonadError into ExceptT

* simplify

* split critical handlers

* names, CRITICAL error in withAckMessage, comments

* only show critical alerts when database was locked or busy and message failed to process

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-12 17:47:38 +00:00
Evgeny Poberezkin 5fd8e6e4fe ui: exclude muted chats from filtered chats (#3900) 2024-03-12 17:33:28 +00:00
Stanislav Dmitrenko d3b255b7cb ios: migration enhancements (#3893)
* onion check

* alert and log

* correction

* refactor

* change

* refactor

* enum

* footer

* remove non-needed directory if no migration

* naming

* back

* rename everything

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-12 16:25:06 +00:00
Evgeny Poberezkin 96fba950ff core: 5.6.0.1, update simplexmq (better ACK handling) 2024-03-12 15:20:39 +00:00
Alexander Bondarenko 4a404f14d9 core: add error message to CRSndFileError (#3894)
* core: add error message to CRSndFileError

* show snd errors
2024-03-12 14:19:40 +00:00
spaced4ndy 4f893d9502 core: improve getGroupChatItemQuote_ query performance (#3897) 2024-03-12 12:51:02 +00:00
Evgeny Poberezkin 01447716fa core: update remote controller/host versions 2024-03-12 12:49:26 +00:00
Stanislav Dmitrenko c9df591e52 multiplatform: migration via link (#3854)
* multiplatform: migration via link

* onion screen

* unused code

* changes

* migrate from device

* changes

* don't allow going back on Archiving step

* changes

* correction

* correction

* change

* font

* changes

* changes

* changes

* show NEVER text for onion when socks is disabled

* onion setup

* no check

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-03-11 17:18:58 +00:00
Stanislav Dmitrenko a56bc6760b ios: migration via link (#3808)
* ios: migration via link

* changes in UI

* UI

* UI and API changes

* UI and logic

* simplify statement

* UI, API, logic

* formatting

* animation fix

* better animation

* test

* changed directory

* changes

* migrating to device

* migrate settings

* more state updates on main thread

* texts

* continue migration after restart

* toggle for saving passphrase and footer text

* no visual arthefacts when deleting a chat after migration

* saving settings before changing passphrase

* back button is looking disabled when it's disabled

* fixed starting chat issues when migrating to device

* paste and share link elements

* proper import process and refactoring UI in SimpleXInfo

* show progress on settings while starting chat

* title bold font

* changes as in Android

* brace

* changes as in Android

* rename to prevent confusion

* fixes and adapted to Android

* unused param

* comment

* don't allow going back on Archiving step

* update core library

* changes as in Android

* correction

* correction

* change

* qr code

* update network settings view

* update progress

* changes

* navigation view and focus in text field

* texts

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-03-11 14:17:28 +00:00
spaced4ndy 80690326cb multiplatform: e2e information chat items (#3891) 2024-03-11 16:36:59 +04:00
Evgeny Poberezkin 3f6c74f975 ios: e2e information chat items (#3890)
* ios: e2e information chat items

* texts
2024-03-11 10:36:36 +00:00
spaced4ndy 8b8846c7b7 ios: update library 2024-03-11 09:47:37 +00:00
Evgeny Poberezkin 6c78bbc178 core: 5.6.0.0 2024-03-11 09:26:37 +00:00
Evgeny Poberezkin eaf720a0f2 Merge pull request #3858 from simplex-chat/pq
core: post-quantum encryption support
2024-03-11 08:28:36 +00:00
Evgeny Poberezkin 0e7d81681f core: update simplexmq 2024-03-10 23:26:35 +00:00
spaced4ndy 56fcaf514e core (pq): don't compress if message fits without compression; check compressed message fits size limit (#3888)
* core (pq): don't compress if message fits without compression; check compressed message fits size limit

* refactor

* errors

* fix tests

* envelope sizes

* refactor

* comment

* more flexible test

* refactor, comment

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-10 22:54:55 +00:00
Evgeny Poberezkin 49bd866c4b core: pass version range to determine missing connection version (#3887)
* core: pass version range function to store methods

* pass current version to Connection to determine agreed version with peer

* simplify
2024-03-10 20:52:29 +00:00
spaced4ndy 8660bf420a core (pq): cross-version tests (#3885)
* core (pq): cross-version tests

* next (fails)

* enable all tests

* fix versions

* update simplexmq

* tests

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-10 18:57:57 +04:00
Evgeny Poberezkin 60a73a539e core: add agreed connection version field (#3881)
* core: add agreed connection version field

* fix

* progress

* use pqSupport and version to decide compression in messages

* pass version to encodeConnInfoPQ

* update pq enable/disable api

* remove TestConfig

* update nix dependencies

* update texts

* corrections

* create e2ee info items when connection switches from off to on first time

* corrections

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

* comment

* increase test timeout

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-03-10 11:31:14 +00:00
Evgeny Poberezkin 93d56a25bc Merge branch 'master' into pq 2024-03-09 23:16:12 +00:00
Evgeny Poberezkin 7fb3c4abdb ios: update core library 2024-03-09 23:03:13 +00:00
spaced4ndy 191d833947 core (pq): tests (#3882)
* core (pq): tests

* rename

* move

* test allow

* mute test output

* pq combinators

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-08 23:09:12 +00:00
Alexander Bondarenko 19ca4f7447 core: remove duplicate Eq orphans (#3880)
* core: remove duplicate Eq orphans

* bump nix
2024-03-08 23:06:51 +00:00
Evgeny Poberezkin b86b5578de Merge branch 'master' into pq 2024-03-08 13:47:10 +00:00
Evgeny Poberezkin 435ea9a453 core: api to pass additional information with standalone file URI (#3873)
* xftp: redirect for descriptions with more than one chunk

* handle errors

* core: api to pass additional information with standalone file URI

* cleanup

* test info with large file

* Apply suggestions from code review

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* remove db-mediated client data

* refactor

* fix

---------

Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>
2024-03-08 13:38:48 +00:00
Evgeny Poberezkin 1f93d91af5 core: simplify feature versions (#3879)
* core: simplify feature versions

* update version agreement

* fix

* remove EmptyCase
2024-03-08 13:36:09 +00:00
spaced4ndy 405348732b android: pq support; ios: fixes (#3878) 2024-03-08 16:39:15 +04:00
spaced4ndy 109b6e0cff core (pq): add pq_support field (#3877) 2024-03-08 12:24:27 +04:00
spaced4ndy b403201310 core (pq): further integrate agent api (#3874)
* core (pq): further integrate agent api

* update both pq support and ecnryption

* update

* fix

* corrections

* corrections 2

* corrections 3
2024-03-08 11:40:55 +04:00
Evgeny Poberezkin 9ff11f886e website: add group link page 2024-03-07 15:40:06 +00:00
spaced4ndy bc2b135880 core (pq): update types (#3872)
* core (pq): update types

* imports

* encode / max msg size types

* integrate new types

* update types/pq support

* tests compile

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-07 17:39:09 +04:00
spaced4ndy ce9b909495 ios: pq support (#3870)
* ios: pq support

* fix

* fix

* update

* text

* rename

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-07 16:43:10 +04:00
Evgeny Poberezkin f1c22a3308 ios: update library 2024-03-07 08:36:01 +00:00
Evgeny Poberezkin 7b7c3227e3 core: update dependencies for nix 2024-03-07 08:22:39 +00:00
Evgeny Poberezkin 2c6e4db603 Merge branch 'master' into pq 2024-03-07 00:09:16 +00:00
Evgeny Poberezkin 8d72757f62 Merge branch 'stable' 2024-03-07 00:08:58 +00:00
spaced4ndy 61a3eb32ee core (pq): global flag only affects new connections; api to allow PQ in old contacts (#3869) 2024-03-06 19:06:01 +04:00
Alexander Bondarenko 64dc758ffd core: compressed message encoding, variable vrange (#3844) 2024-03-06 18:02:19 +04:00
spaced4ndy eebf014ff7 core (pq): integrate agent api, create e2ee info items (#3859) 2024-03-05 20:27:00 +04:00
spaced4ndy 2155060ad0 core: groundwork for post-quantum encryption support (#3845) 2024-03-03 17:51:42 +04:00
Alexander Bondarenko db2ccaa450 controller: add standalone upload limit (#3853)
* controller: add standalone upload limit

* use hard limit from simplexmq
2024-03-02 19:31:11 +00:00
spaced4ndy 4b7458b58f docs: PQ integration rfc (#3847) 2024-03-01 11:27:13 +04:00
spaced4ndy 05383477d9 core: wait for delivery to avoid race between connection deletion and sending service messages about entity deletion (#3849) 2024-03-01 11:26:54 +04:00
Evgeny Poberezkin 0c4848ad9e 5.5.6: ios 201, android 187, desktop 32 2024-02-27 14:12:01 +00:00
Evgeny Poberezkin b66a3d0595 5.5.6.0: update simplexmq to 5.5.2.2 (performance improvements) 2024-02-27 00:16:41 +00:00
Stanislav Dmitrenko 8ac7677648 ios: remove passcodes if app was reinstalled (#3841)
* ios: remove passwords if app was reinstalled

* change instead of delete

* Revert "change instead of delete"

This reverts commit 1195ee5b30.

* update name and comments

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-02-26 21:24:07 +00:00
spaced4ndy c27973d202 core: restrict to delete user contact and display name (#3822) 2024-02-26 17:10:21 +04:00
spaced4ndy 51a2e09714 core: batch db operations for group leave and delete (#3807)
* core: batch db operations for group leave and delete

* remove comment

* batch delete files

* cleanup

* rename

* use new agent api

* refactor

* refactor, catch error

* refactor

* update simplexmq

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-02-26 15:36:42 +04:00
spaced4ndy ec8ae9febe docs: inactive group members rfc (simplified) (#3803) 2024-02-26 15:05:25 +04:00
Evgeny Poberezkin 7213913d51 docs: update privacy policy (#3796)
* docs: update privacy policy

* update glossary

* update

* links

* amend

* update
2024-02-24 21:28:18 +00:00
Evgeny Poberezkin e37654772f core: api to save/get app settings to migrate them as part of the database (#3824)
* rfc: migrate app settings as part of export/import/migration

* export/import app settings

* test, fix

* chat: store app settings in db (#3834)

* chat: store app settings in db

* add combining with app-defaults

* commit schema

* test with tweaked settings

* remove unused error

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>

* remove app settings from export/import

* test, more settings

---------

Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>
2024-02-24 15:00:16 +00:00
sh b7709c59d3 docs: include update instructions (#3825) 2024-02-24 13:42:11 +00:00
kimg45 5807a0a2fa website: fix links (#3828)
* Fix broken link on website

* Fix Sybil attack link

* fix MITM link

* fix supernovas.space link

* fix supernovas.space links

* remove broken github link

* remove dead github link

* fix link to readme
2024-02-24 13:40:28 +00:00
Evgeny Poberezkin 395654098c core: do not mark store as changed after passphrase test (#3833)
* core: do not mark store as changed after passphrase test

* fix
2024-02-24 13:37:09 +00:00
Evgeny Poberezkin 2d643e8d29 rfc: amend PQ double ratchet RFC 2024-02-24 09:27:55 +00:00
Evgeny Poberezkin 4e9703f0ff ios: update library 2024-02-22 12:19:42 +00:00
spaced4ndy b0b249a56a Merge branch 'stable' 2024-02-22 12:11:23 +04:00
spaced4ndy 92c89632d4 core, ui: don't mark profile updated chat item as unread (#3830)
* core, ui: don't mark profile updated chat item as unread

* android
2024-02-21 21:54:52 +00:00
Alexander Bondarenko d54b453b49 controller: fix standalone using relative paths (#3831) 2024-02-21 21:54:03 +00:00
Evgeny Poberezkin e6e27db243 5.5.5: ios 200, android 185, desktop 31 2024-02-21 18:32:53 +00:00
Evgeny Poberezkin b629c22ee0 5.5.5.0, update simplexmq to 5.5.2.1 (fix performance degradation) 2024-02-21 14:26:46 +00:00
spaced4ndy f7d7f5461f core: check user record when deleting contact and display name (#3826)
* filter out on merge

* checl contact, ldn

* fix

* corrections

* fix

* refactor

* diff

* refactor2

* remove contact id from error

* Revert "remove contact id from error"

This reverts commit f58af3dcac.

* remove Maybe from error

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-02-21 14:24:24 +00:00
spaced4ndy c544a636f6 core, ui: remove usage of inline files (send only xftp files) (#3823) 2024-02-20 13:56:31 +04:00
Evgeny Poberezkin 73de74d7e9 rfc: UX for database migration and other actions (#3810)
* rfc: UX for database migration

* update

* update
2024-02-19 12:20:12 +00:00
spaced4ndy 654a7885c3 core: read chat items with logical database errors as invalid (don't fail) (#3736) 2024-02-19 15:17:14 +04:00
Alexander Bondarenko daf67c0456 core: add direct xftp upload/download commands (#3781)
* chat: add direct xftp upload/download commands

* adapt to FileDescriptionURI record

* bump simplexmq

* add description uploading

* filter URIs by size

* cleanup

* add file meta to events

* remove focus

* auto-redirect when no URI fits

* send "upload complete" event with the original file id

* remove description upload command

* add index

* refactor

* update simplexmq

* Apply suggestions from code review

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

* fix /fc command for non-chat uploads

* fix

* rename (tests fail)

* num recipients

* update messages

* split "file complete" events for chats and standalone

* restore xftpSndFileRedirect

* remove unused store error

* add send/cancel test

* untangle standalone views

* fix confused id

* fix /fc and /fs

* resolve comments

* misc fixes

* bump simplexmq

* fix build

* handle redirect errors independently

* fix missing file status in tests

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-02-19 10:21:32 +00:00
Evgeny Poberezkin e361bcf140 ios: update core library 2024-02-18 17:52:11 +00:00
sh 5de9087207 build-android.sh: fix tag detection (#3817) 2024-02-18 15:28:12 +00:00
Alexander Bondarenko 364b62320b controller: add db passphrase test command (#3788)
* controller: add passphrase test

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-02-18 13:28:24 +00:00
Evgeny Poberezkin d83a6b7133 core: ntf server test (#3819) 2024-02-18 12:12:38 +00:00
Evgeny Poberezkin cd21a74b83 Merge branch 'stable' 2024-02-18 00:05:49 +00:00
Evgeny Poberezkin 6d523d5b4b 5.5.4: ios 199, android 183, desktop 30 2024-02-17 22:50:13 +00:00
Evgeny Poberezkin 2a321b3ff8 ios: fix showing notification on sent messages 2024-02-17 21:09:19 +00:00
Stanislav Dmitrenko 865a32c608 android, desktop: refactor alerts for slow calls (#3811)
* android, desktop: refactor alerts for slow calls

* sharing text in alerts

* more time to send message

* removed suspend modifier from processing messages

* change

* Revert "removed suspend modifier from processing messages"

This reverts commit 895e804c1b.

* Revert "change"

This reverts commit 013abf49e6.
2024-02-17 18:01:04 +00:00
Evgeny Poberezkin e3df7945d5 core: update simplexmq (updated protocol, discontinue old versions) (#3818)
* core: update simplexmq (updated protocol, discontinue old versions)

* update nix
2024-02-17 16:29:45 +00:00
sh bb1620d7d2 docker: update and fix build (#3805) 2024-02-14 20:33:48 +00:00
Stanislav Dmitrenko edc5a4c31b ios: Picture-in-picture while in calls (#3792)
* ios: Picture-in-picture while in calls

* simplify

* improvements

* back button and lots of small issues

* layout

* padding

* back button

* animation, padding, fullscreen

* end active call button

* removed unused code

* unused line

* transition

* better

* better

* deinit PiP controller

* stop camera after call end

* formatting

* stop capture if active

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-02-13 15:04:42 +00:00
spaced4ndy 4260c20012 ios: show ntf server (#3800) 2024-02-13 17:58:54 +04:00
spaced4ndy 1a7efbc333 core: update default ntf servers (#3804) 2024-02-13 15:10:40 +04:00
spaced4ndy e4984cb38d core: update sha256map.nix 2024-02-13 13:56:14 +04:00
spaced4ndy dfa9775d7e docs: add to inactive group members rfc (#3798) 2024-02-13 12:10:58 +04:00
spaced4ndy e39544dd24 core: return ntf server in APIGetNtfToken (#3797) 2024-02-12 21:21:20 +04:00
spaced4ndy 71bcfc2848 ui: uncomment block for all functionality (#3799) 2024-02-12 17:33:53 +04:00
Evgeny Poberezkin 91f10c056f docs: change download links to the latest release 2024-02-11 16:26:10 +00:00
Evgeny Poberezkin 3d8d84f978 Merge branch 'stable' 2024-02-11 11:41:13 +00:00
Evgeny Poberezkin fec34ca875 5.5.3: ios 198, android 181, desktop 29 2024-02-11 11:14:07 +00:00
Evgeny Poberezkin 3a0920e950 core: 5.5.3.0 (simplexmq 5.5.2.0) 2024-02-10 23:24:00 +00:00
Evgeny Poberezkin f4ae60756c Merge branch 'stable' 2024-02-08 13:33:06 +00:00
Stanislav Dmitrenko eedc1b2860 android: circular icon in notification while in call (#3790)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-02-08 13:32:35 +00:00
Stanislav Dmitrenko 24a35698dc android: fix applying updated instance of ended call (#3789) 2024-02-08 09:51:15 +00:00
Stanislav Dmitrenko 7e37155938 desktop: catching exception while opening non-existing web browser (#3787)
* desktop: catching exception while opening non-existing web browser

* update strings

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-02-08 09:50:24 +00:00
Stanislav Dmitrenko c8b38183c9 desktop: better decoding Android's base64 encoded image (#3786) 2024-02-08 09:46:30 +00:00
Stanislav Dmitrenko 90a866ca56 android: fix ConcurrentModification in sharing screen (#3785) 2024-02-06 17:21:47 +00:00
Evgeny Poberezkin 7e9e71ffbd core: update simplexmq (extensible smp handshake) 2024-02-06 07:39:32 +00:00
Stanislav Dmitrenko 5da8aef794 android: ability to hide active call (#3770)
* android: ability to hide active call

* enhancements

* fixed some problems and adapted to lock screen usage

* change

* reduce diff

* dealing with disable PiP by user

* fix back action

* fix hidden information on view rotation while info collapsed

* better info showing

* status bar color and user icon

* reorder

* experiment

* icon placement

* enhancements

* back button

* invitation accepted state handling

* awesome background work

* better service interaction and UI

* disabled call overlay when call ends and ability to accept a new call from the same contact while previous call is not ended

* incomming call alert

* enhancements

* text

* text2

* top area

* faster ending call

* a lot of enhancements

* paddings

* icon position

* move icon

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-02-05 21:44:02 +00:00
Evgeny Poberezkin 09bbaa1c94 5.5.2: ios 196, android 179, desktop 28 2024-02-02 15:32:25 +00:00
Evgeny Poberezkin 3a879b755b core: 5.5.2.0 (simplexmq 5.5.1.2) 2024-02-02 08:30:26 +00:00
Evgeny Poberezkin c6f4d62d6c core: update simplexmq (fix socket/memory leak on resubscriptions) 2024-02-01 16:36:32 +00:00
Stanislav Dmitrenko 5ad356172f scripts: check that all symbols were exported (#3779)
* scripts: check that all symbols were exported

* changes

* windows

---------

Co-authored-by: Avently <avently@local>
2024-01-31 14:47:10 +00:00
Stanislav Dmitrenko 0a6c464a8d desktop (windows): added a missing symbol to lib build (#3778) 2024-01-31 13:58:30 +00:00
Evgeny Poberezkin 1aa464bdb2 core: unify dependencies for GHC 8.10.7 and 9.6.3 (#3774) 2024-01-30 23:16:39 +00:00
Evgeny Poberezkin bce829ef58 v5.5.1: ios 195, android 177, desktop 27 2024-01-27 23:23:29 +00:00
Evgeny Poberezkin 7df300cf36 core: 5.5.1.0 2024-01-27 19:18:41 +00:00
Stanislav Dmitrenko 9b35ff6f11 android, desktop: possible fix of chat items race (#3520)
* android, desktop: possible fix of chat items race

* fix compose threads desynchronization

* optimization and preventing race

* removed unused logs

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-01-27 18:46:27 +00:00
M. Sarmad Qadeer c4cbb49f57 website: update contact page layout if JS is disabled (#3331)
* website: update page layout for the case if javascript is disabled in browser.

* website: add noscript tag & update heading

* website: do some changes in layout of contact page without JS

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-01-27 16:51:21 +00:00
Stanislav Dmitrenko 2b3eebb7a2 android, desktop: show different text when database migrates (#3762)
* android, desktop: show different text when database migrates

* one more check

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-01-26 23:08:48 +00:00
Evgeny Poberezkin a1328c287c core: remove unused events from api (#3764)
* core: remove unused events from api

* fix test
2024-01-26 18:54:08 +00:00
Stanislav Dmitrenko f2d498dd79 android, desktop: removed timer for some long running jobs (#3761) 2024-01-26 18:15:20 +00:00
Stanislav Dmitrenko 6b8fc6fdcf android, desktop: lower limit of terminal items for non-developers (#3763) 2024-01-26 18:14:53 +00:00
spaced4ndy 0e585d5e5b core: fix group invitation marked deleted 2024-01-26 20:30:21 +04:00
Stanislav Dmitrenko 520d8868ef android: refactor clipboard access to prevent Android error in logs (#3758) 2024-01-26 14:00:53 +00:00
spaced4ndy 7192448303 core: fix invitation as rejected when deleting group (#3759) 2024-01-26 17:56:17 +04:00
spaced4ndy 0f0f65533a android: group welcome message byte limit (#3756)
* android: group welcome message byte limit

* text

* change footer
2024-01-26 09:57:04 +00:00
spaced4ndy 78a38cb080 ios: group welcome message byte limit (#3751)
* ios: group welcome message character limit

* confirmation dialogue key

* use chatJsonLength

* text

* change footer

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-01-26 09:37:49 +00:00
Stanislav Dmitrenko f102f39147 android, desktop: protocol servers fix (#3755)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-01-25 20:59:02 +00:00
Stanislav Dmitrenko cd349e80ce desktop: propertly updating delivery tab of chat item info page (#3752) 2024-01-25 17:51:20 +00:00
Stanislav Dmitrenko 430dc5bd2e ui: don't show context menu on non-sent yet live message (#3754)
* android, desktop: don't show context menu on non-sent yet live message

* ios: don't show context menu on non-sent yet live message

---------

Co-authored-by: Avently <avently@local>
2024-01-25 17:48:40 +00:00
spaced4ndy 3e0b863b64 core: add cChatJsonLength function (#3753) 2024-01-25 18:57:38 +04:00
Stanislav Dmitrenko d6afee11bc desktop: prevent clicking enter on alert and text field at the same time (#3714) 2024-01-25 14:50:53 +00:00
spaced4ndy 6ef3a9e668 ios: fix welcome view (#3743)
* welcome view (still doesn't keep change on re-open)

* fix

* remove debug log

* rename
2024-01-25 16:08:10 +04:00
spaced4ndy fbe3353434 ui: fix link preview cancellation (#3750) 2024-01-25 14:58:39 +04:00
Evgeny Poberezkin d6d2e6e1eb Merge branch 'stable' 2024-01-24 19:55:28 +00:00
Evgeny Poberezkin 14d5078404 blog: v5.5 announcement (#3744)
* blog: v5.5 announcement

* update

* update

* readme

* images, update
2024-01-24 19:54:47 +00:00
Stanislav Dmitrenko da1d20c17f desktop: alignment for reactions (#3747) 2024-01-24 16:25:44 +00:00
Stanislav Dmitrenko afc324dc4f android, desktop: marking chat as read if it was set unread (#3746) 2024-01-24 16:24:49 +00:00
Stanislav Dmitrenko f81e457e09 android: trying to start service again in case it was destroyed (#3745) 2024-01-24 16:22:29 +00:00
Stanislav Dmitrenko bd30b80e15 desktop: custom time picker (#3741)
* desktop: custom time picker

* text color

* formatting

* changes in UI

* optimization

* desktop: opening SimpleX links inside the app (#3738)

* 5.5: ios 194, android 175, desktop 26

* docs: update downloads page

* ui: fix chat preview showing incorrect timestamp when chat is empty (#3739)

* ui: align call buttons with calls preference (#3740)

* ui: deleted item preview (#3726)

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-01-24 16:15:27 +00:00
spaced4ndy da9a7f4642 ui: exclude not ready and active contacts from list of contacts to add to group (e.g. simplex team contact) (#3737) 2024-01-24 13:56:38 +04:00
spaced4ndy 838a759a76 ui: deleted item preview (#3726) 2024-01-24 13:44:29 +04:00
spaced4ndy f1ff27218c ui: align call buttons with calls preference (#3740) 2024-01-24 13:43:18 +04:00
spaced4ndy 8738cf332f ui: fix chat preview showing incorrect timestamp when chat is empty (#3739) 2024-01-24 13:37:29 +04:00
Evgeny Poberezkin 4f602d4571 docs: update downloads page 2024-01-23 23:22:00 +00:00
Evgeny Poberezkin d0b75e0dd3 5.5: ios 194, android 175, desktop 26 2024-01-23 21:11:52 +00:00
Stanislav Dmitrenko 1bb98706a6 desktop: opening SimpleX links inside the app (#3738) 2024-01-23 17:05:19 +00:00
Evgeny Poberezkin 6b7c13f20a ui: translations (#3732)
* Translated using Weblate (Russian)

Currently translated at 100.0% (1605 of 1605 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% (1403 of 1403 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1605 of 1605 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 96.5% (1354 of 1403 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1605 of 1605 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% (1605 of 1605 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% (1605 of 1605 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% (1403 of 1403 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1605 of 1605 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 96.5% (1354 of 1403 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1605 of 1605 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% (1605 of 1605 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 99.1% (1592 of 1605 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 99.2% (1392 of 1403 strings)

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

* Added translation using Weblate (Romanian)

* Translated using Weblate (German)

Currently translated at 100.0% (1605 of 1605 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% (1403 of 1403 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% (1605 of 1605 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% (1403 of 1403 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% (1605 of 1605 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% (1403 of 1403 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1605 of 1605 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% (1605 of 1605 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 7.4% (119 of 1605 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 3.4% (56 of 1605 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 4.6% (75 of 1605 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1601 of 1605 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 100.0% (1605 of 1605 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 100.0% (1403 of 1403 strings)

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

* Translated using Weblate (Lithuanian)

Currently translated at 41.0% (659 of 1605 strings)

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

* ios: import/export localizations

* revert ar "blocked"

* corrections

---------

Co-authored-by: Artem Vorotnikov <artem@vorotnikov.me>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Siavash <ciavash@proton.me>
Co-authored-by: FalxDraco <acc.557q@goea.dev>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Moo <hazap@hotmail.com>
2024-01-22 22:00:13 +00:00
Stanislav Dmitrenko 93d2bb98b5 android, desktop: small fixes to UI (#3731) 2024-01-22 19:45:39 +00:00
Evgeny Poberezkin 3b614e95e3 ios: update library (5.5.0.4) 2024-01-22 19:35:39 +00:00
spaced4ndy 1a9e942e33 core: 5.5.0.4 2024-01-22 18:35:47 +04:00
spaced4ndy bddb9c14b7 core: update simplexmq 5.5.1.1 (optimize expired messages query) (#3730) 2024-01-22 18:33:48 +04:00
spaced4ndy afd145c979 core: improve chat list performance (indexes) (#3728) 2024-01-22 18:03:40 +04:00
Stanislav Dmitrenko 97fbf2b7fe android, desktop: switching C calls to IO threads (#3727) 2024-01-22 12:56:20 +00:00
Evgeny Poberezkin db93d29e76 ios: fix removing group link in iOS 17 (#3725) 2024-01-21 10:09:32 +00:00
Evgeny Poberezkin 10b3fe1390 5.5-beta.2: ios 191, android 174, desktop 25 2024-01-20 22:54:11 +00:00
Evgeny Poberezkin a2b9a04430 core: 5.5.0.3 2024-01-20 21:35:28 +00:00
Evgeny Poberezkin 444b92282e Merge branch 'stable' 2024-01-20 21:34:30 +00:00
Evgeny Poberezkin c35d275273 ci: fix windows desktop build (#3721) 2024-01-20 21:34:03 +00:00
Evgeny Poberezkin 052ef2037a core: update min version for remote to 5.5.0.2 (#3720) 2024-01-20 20:53:26 +00:00
Evgeny Poberezkin 0b731d818b Merge branch 'stable' 2024-01-20 20:12:39 +00:00
Stanislav Dmitrenko 1aab9f7f8a ci: fix windows build (#3719) 2024-01-20 20:12:01 +00:00
Evgeny Poberezkin bdf3ac1a36 Merge branch 'stable' 2024-01-20 19:20:45 +00:00
Evgeny Poberezkin 8159ae4aea 5.4.4: ios 190, android 172, desktop 24 2024-01-20 18:21:22 +00:00
Evgeny Poberezkin a9ba0a2e8a core: 5.5.0.2, update simplexmq 5.5.1.0 2024-01-20 15:02:03 +00:00
Evgeny Poberezkin c65a17fccb core: output messages and events while executing the CLI command passed via -e option (#3683)
* core: output messages and events while executing the CLI command passed via -e option

* option

* add option
2024-01-20 14:59:13 +00:00
Evgeny Poberezkin 5aa4b7687e website: translations (#3718)
* Translated using Weblate (Arabic)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (252 of 252 strings)

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

---------

Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
2024-01-20 13:48:45 +00:00
Evgeny Poberezkin 1016513dd3 ui: translations (#3717)
* Translated using Weblate (German)

Currently translated at 99.9% (1570 of 1571 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1571 of 1571 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% (1371 of 1371 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1571 of 1571 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% (1571 of 1571 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1571 of 1571 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% (1371 of 1371 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1571 of 1571 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% (1371 of 1371 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1571 of 1571 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% (1571 of 1571 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1371 of 1371 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 99.0% (1556 of 1571 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 97.6% (1534 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Added translation using Weblate (Persian)

* Translated using Weblate (Italian)

Currently translated at 100.0% (1571 of 1571 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% (1371 of 1371 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 99.8% (1569 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1371 of 1371 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 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Persian)

Currently translated at 4.0% (63 of 1571 strings)

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

* Translated using Weblate (Persian)

Currently translated at 5.6% (88 of 1571 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1574 of 1578 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% (1578 of 1578 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% (1583 of 1583 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 99.3% (1584 of 1594 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1594 of 1594 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1397 of 1397 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1594 of 1594 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1594 of 1594 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% (1397 of 1397 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1590 of 1594 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% (1594 of 1594 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% (1594 of 1594 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.5% (1587 of 1594 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 99.9% (1593 of 1594 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% (1594 of 1594 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% (1397 of 1397 strings)

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

* Translated using Weblate (German)

Currently translated at 99.9% (1570 of 1571 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1571 of 1571 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% (1371 of 1371 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1571 of 1571 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% (1571 of 1571 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1571 of 1571 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% (1371 of 1371 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1571 of 1571 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% (1371 of 1371 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1571 of 1571 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% (1571 of 1571 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1371 of 1371 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 99.0% (1556 of 1571 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 97.6% (1534 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Added translation using Weblate (Persian)

* Translated using Weblate (Italian)

Currently translated at 100.0% (1571 of 1571 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% (1371 of 1371 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 99.8% (1569 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1371 of 1371 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 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1571 of 1571 strings)

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

* Translated using Weblate (Persian)

Currently translated at 4.0% (63 of 1571 strings)

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

* Translated using Weblate (Persian)

Currently translated at 5.6% (88 of 1571 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1574 of 1578 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% (1578 of 1578 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% (1583 of 1583 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 99.3% (1584 of 1594 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1594 of 1594 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1397 of 1397 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1594 of 1594 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1594 of 1594 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% (1397 of 1397 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1590 of 1594 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% (1594 of 1594 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% (1594 of 1594 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.5% (1587 of 1594 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 99.9% (1593 of 1594 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% (1594 of 1594 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% (1397 of 1397 strings)

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

* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (1592 of 1592 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 99.8% (1395 of 1397 strings)

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

* android CDATA

* ios: import/export localizations

* update ja

* ios: fix directory service address in translations

* android: fix translations, CDATA

---------

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: summoner001 <summoner@vivaldi.net>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: tomato potato <tomato.games@protonmail.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: Y. Sakamoto <ysakamoto@tutanota.com>
Co-authored-by: a4318 <dalse.077@gmail.com>
Co-authored-by: hakkadaikon <hakkadaikon@yahoo.co.jp>
Co-authored-by: Siavash <ciavash@proton.me>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
2024-01-20 13:46:23 +00:00
spaced4ndy 106556812c android, desktop: block member for all (#3711)
* android: block member for all

* old buttons (revert this)

* blocked by admin text

* revise notification
2024-01-20 10:33:49 +00:00
spaced4ndy 7d2f6a3609 ios: block member for all (#3708)
* ios: block for all

* member info

* change conditions

* update ui

* blockedByAdmin

* fix

* rework

* fix, comment

* comment

* fix

* fix

* fixes for default

* fix text

* reorder

* fix

* fix

* secondary

* old buttons (revert this)

* blocked by admin text

* revise notification
2024-01-20 10:33:36 +00:00
Evgeny Poberezkin f188118643 ui: update whats new (#3716) 2024-01-20 09:07:57 +00:00
Evgeny Poberezkin cc05434b31 core: process message errors (#3709)
* core: process message errors

* update simplexmq commit sha

* style

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

* simplexmq

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-01-20 08:17:57 +00:00
Evgeny Poberezkin 68de2b7540 core: update preset smp servers (#3713) 2024-01-19 19:50:21 +00:00
Stanislav Dmitrenko 5d8bb24d1c android, desktop: withLongRunningApi when needed (#3710) 2024-01-19 17:01:33 +00:00
Stanislav Dmitrenko ab9a6dcab5 ios: allow to delete the last profile (#3707)
* ios: allow to delete the last profile

* less changes

* no flash of empty view

---------

Co-authored-by: Avently <avently@local>
2024-01-19 15:52:13 +00:00
spaced4ndy 0dd1f13d3b core: fix blocked by admin encoding 2024-01-19 19:14:35 +04:00
spaced4ndy 16f53490c5 core: block member for all (#3689)
* core: silence member wip

* change approach

* more types

* remove comment

* bool in protocol msg

* flag in items, event

* send event, process

* apply moderation

* remove comment

* filter for forward, view

* tests

* rename

* separate response, check already blocked

* add test

* fix terminal api

* add comment

* don't send profile update

* corrections

* refactor

* rework - flag blocked by admin

* blocked in intro

* fix test

* cant block unblock self

* muted view, create unknown member

* blocked by admin in members list

* create with maybe null

* protocol changes

* align code with protocol

* revert terminal api

* restrict block api for admins

* stabilize test

* rename

* update protocol/types

* refactor

* refactor2

* stabilize test

* member field

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-01-19 17:57:04 +04:00
Evgeny Poberezkin 4e502c4d13 Merge branch 'stable' 2024-01-18 21:00:59 +00:00
Evgeny Poberezkin 5236e0f201 core: 5.4.4.0 2024-01-18 20:56:45 +00:00
Evgeny Poberezkin b69b72a93c ui: What's new in v5.5 (#3705)
* ios: whatsnew v5.5

* update

* android whats new, update ios

* export ios localizations
2024-01-18 20:44:57 +00:00
Stanislav Dmitrenko 2dae9180ec ios: text color of group invitation in chat list (#3703)
* ios: text color of group invitation in chat list

* refactor

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-01-18 19:14:18 +00:00
Stanislav Dmitrenko ec57529f12 android, desktop: notes to self (#3695)
* android, desktop: notes to self

* change api

* icon

* icon

* icon

* eol

* icon

* changes

* color

* refactor

* color

* chats size

* size

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-01-18 21:56:42 +04:00
Stanislav Dmitrenko c4d75366b5 android, desktop: ability to delete the last profile (#3645)
* android, desktop: ability to delete the last profile

* hide modals to see onboarding after removing the last visible user

* removed unused checks

* make multiple profile creation usable

* deleting the last user by removing the whole database

* adapted to new logic

* changes

* not deleting the whole database

* refactor

* hide search when no profile

* changes
2024-01-18 21:16:44 +04:00
spaced4ndy ddcd7d495e core: reset address and preferences when updating profile of member without associated contact (#3701) 2024-01-18 20:07:43 +04:00
Stanislav Dmitrenko b5fe1f8364 ios: notes to self (#3690)
* ios: notes to self

* change

* icon

* changes

* no live message

* search

* alert

* better checks

* api change

* changes for review

* changes

* ios: align notes chat color with sent chat items frame color (#3704)

* changes

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-01-18 19:57:14 +04:00
spaced4ndy 3c7e37ee9d android: profile updated chat items (#3700) 2024-01-18 15:43:26 +04:00
Evgeny Poberezkin 2884ad9fde readme: update link to users group 2024-01-17 22:47:41 +00:00
Evgeny Poberezkin c130905efa docs: downloads version 2024-01-17 19:31:46 +00:00
Evgeny Poberezkin 915dc46bdc Merge branch 'stable' 2024-01-17 19:27:29 +00:00
Evgeny Poberezkin 1eb1ed92f7 ci: disable *-armv7a tags 2024-01-17 19:27:07 +00:00
Alexander Bondarenko 236daf4391 controller: add GetAgentWorkers/GetAgentWorkerDetails debug commands (#3681)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-01-17 17:37:29 +00:00
Evgeny Poberezkin 13feffb33a ios: update library 2024-01-17 15:44:03 +00:00
Evgeny Poberezkin 06d36751d7 Merge branch 'stable' 2024-01-17 15:25:29 +00:00
Evgeny Poberezkin c25e9e3b72 scripts: curl/wget security (#3693) 2024-01-17 15:23:43 +00:00
Evgeny Poberezkin 868acd18d6 core: support deleting the last profile (always create user record in agent when user is created) (#3654)
* core: only skip creating agent user when app is first started

* firstTime

* prompt

* fix test

* if

* simplexmq

* ci timeout

* skip test

* add test timeout

* log test times

* simplexmq

* timeout

* simplexmq without new batching

* Revert "simplexmq without new batching"

This reverts commit 9879bcb57c.

* without new batching again

* with builder, without sized builder

* lazy bytestring, same batching logic

* fewer chunks

* remove lazy

* optimize batching in simplexmq
2024-01-17 15:20:13 +00:00
spaced4ndy 8c1114648a core: fix 8.10.7 compilation error (#3698)
* core: fix 8.10.7 compilation error

* fix
2024-01-17 13:47:19 +00:00
Stanislav Dmitrenko 3918c5306d android, desktop: disabling user picker items when chat is stopped (#3696) 2024-01-17 12:51:26 +00:00
Stanislav Dmitrenko ab8a87acad android, desktop: fix alerts/modals when they are shown before UI init (#3697) 2024-01-17 12:50:48 +00:00
spaced4ndy 809dd1ef01 ios: profile updated chat items (#3692)
* ios: profile updated chat items

* remove vars

* refactor

* refactor

* refactor

* refactor

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-01-17 16:16:15 +04:00
Evgeny Poberezkin b874cd1910 Merge branch 'stable' 2024-01-16 23:43:18 +00:00
Evgeny Poberezkin 300223b32e core: update simplexmq 5.5.0.6 (fix race conditions) (#3691)
* core: update simplexmq (fix race conditions)

* simplexmq 5.5.0.6
2024-01-16 23:42:29 +00:00
Stanislav Dmitrenko 88640b85c4 ios: local video encryption (#3682)
* ios: local video encryption

* main thread

* new progress view

* simplify

* rename

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-01-16 11:49:44 +00:00
spaced4ndy d5cf9fbf5b core: exclude some fields from member profile when sharing in group (#3688) 2024-01-15 19:58:09 +04:00
spaced4ndy f4f8501eb8 core: members profile update, create profile update chat items (#3644) 2024-01-15 19:56:11 +04:00
Stanislav Dmitrenko be0c791c43 android, desktop: local video encryption (#3678)
* android, desktop: local video encryption

* refactor

* different look of progress indicator

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-01-15 15:00:57 +00:00
Stanislav Dmitrenko 46fe0fc671 withLongRunningApi (#3675) 2024-01-15 14:29:11 +00:00
Evgeny Poberezkin bfb274b037 Merge branch 'stable' 2024-01-15 13:52:09 +00:00
Evgeny Poberezkin 8d7dcb550a core: update simplexmq, optimize batching, remove builder (#3685)
* core: update simplexmq (optimize batching, remove builder)

* do not use builder to batch

* refactor
2024-01-15 10:46:13 +00:00
spaced4ndy 135e735dd4 ui: show observer role in list of members (#3679) 2024-01-12 20:54:51 +04:00
spaced4ndy 516410a899 android, desktop: align member name functions with ios (fixes issue with displaying unknown members) (#3680) 2024-01-12 20:54:26 +04:00
Stanislav Dmitrenko dad9716915 android, desktop: moving to single thread in api calls (#3670)
* android, desktop: moving to single thread in api calls

* more places

* more changes

* seconds

* long running api into init function

* changes

* developer options

* progress indicator

* string

* rename

* progressIndicator for stop chat
2024-01-11 18:50:25 +00:00
Alexander Bondarenko bc8a6f4833 core: add notes chat type (#3568)
* Add chat type "self"

* rename to Notes

* cover more things

* remove quote, tweak sql

* resolve comments

* constrain ACIQDirection to exclude CTLocal

* add CILocalRcv handling

* plug in migrations and tests

* cover more API, implement new folders

* working create/send/tail

* remove interaction with messages

* add note deletion (api-only)

* add folder deletion

* add getLocalChatItemIdByText

* add APICreateChatItem and files

* add protocol check for getFileTransfer protocol

* replace FTLocal with createLocalFile

* add chat previews

* add folder clear

* add reactions

* add read/unread

* add note updates

* resolve some comments

* remove local reactions

* remove folder names, deletion, add autocreate

* add file deletion check

* add preview pagination test

* add per-item file deletion check

* pull mkChatItem out of createLocal to prevent ci record updates

* use - as notes name

* bump migration ts

* update schema

* resolve comments

* add chat pagination test

* use chat queries from Direct instead

* evict note folders from createUserRecord

* switch to - for note folder chat type prefix and use empty name

* fix getLocalChatXxx

* add explicit createCCNoteFolder for tests

* use overloadedstrings for single-line queries

* add suggested chat list tests

* add notes chat to a user-creating test

* throw correct error for missing file

* remove unique check from schema

* add UndecidableInstances for ghc8.10

* switch to * for chat type sigil

* add file safety test

* add drop index

* remove indentation

* remove repeated folder

* remove redundant filter query, NoteFolderName

* don't attempt to cancel local files when deleting chat item

* rename function

* fix comment

* rename

* fix merge

* fix typo

* remove editable limit

* restore comment

* remove local file cancel

* Revert "remove editable limit"

This reverts commit 65df55caf8.

* refactor

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-01-11 17:01:44 +00:00
spaced4ndy 5b7a09f488 ui: fix unknown member UI (#3672) 2024-01-11 20:21:58 +04:00
spaced4ndy bfe5d51df7 core, ui: create dummy member record when admin forwards a message from an unknown member (#3651)
* core: create dummy member record when admin forwards a message from an unknown member

* comments

* update unknown member if announced

* change removed

* change unknown name, revert diff

* revert diff

* ios

* update ios library

* android

* remove changes in iOS project file

* rename event

* remove unknown category

* android

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-01-11 17:55:13 +04:00
Evgeny Poberezkin d9d270f00e ui: add Hungarian (Android only) and Turkish (#3671)
* ui: add Hungarian (Android only) and Turkish

* readme
2024-01-11 13:28:47 +00:00
Evgeny Poberezkin 2872b30e8c ui: translations (#3666)
* Translated using Weblate (German)

Currently translated at 100.0% (1510 of 1510 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% (1352 of 1352 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% (1510 of 1510 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% (1352 of 1352 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1510 of 1510 strings)

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

* Translated using Weblate (Czech)

Currently translated at 98.5% (1488 of 1510 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 91.4% (1236 of 1352 strings)

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (1510 of 1510 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 100.0% (1352 of 1352 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 99.9% (1509 of 1510 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 99.9% (1509 of 1510 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 99.9% (1509 of 1510 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% (1510 of 1510 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% (1510 of 1510 strings)

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (1364 of 1364 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% (1510 of 1510 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1534 of 1534 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1534 of 1534 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% (1364 of 1364 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 97.3% (1494 of 1534 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 97.5% (1330 of 1364 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% (1534 of 1534 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% (1364 of 1364 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 100.0% (1534 of 1534 strings)

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

* Translated using Weblate (Greek)

Currently translated at 14.7% (227 of 1534 strings)

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

* Translated using Weblate (Greek)

Currently translated at 1.6% (23 of 1364 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1534 of 1534 strings)

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

* Translated using Weblate (Russian)

Currently translated at 97.5% (1497 of 1534 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1364 of 1364 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1534 of 1534 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1364 of 1364 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1534 of 1534 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% (1364 of 1364 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% (1534 of 1534 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% (1364 of 1364 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 88.5% (1208 of 1364 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 90.3% (1386 of 1534 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1530 of 1534 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 91.9% (1254 of 1364 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 100.0% (1534 of 1534 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 91.0% (1399 of 1536 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 92.3% (1418 of 1536 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1536 of 1536 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1536 of 1536 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1364 of 1364 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 88.5% (1208 of 1364 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 92.7% (1424 of 1536 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1536 of 1536 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1536 of 1536 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1536 of 1536 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 36.8% (503 of 1364 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1536 of 1536 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 58.8% (803 of 1364 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1536 of 1536 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 64.0% (873 of 1364 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 97.9% (1505 of 1536 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% (1536 of 1536 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% (1536 of 1536 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% (1536 of 1536 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% (1536 of 1536 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% (1536 of 1536 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 86.1% (1175 of 1364 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1536 of 1536 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% (1536 of 1536 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% (1536 of 1536 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 87.4% (1193 of 1364 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1536 of 1536 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1364 of 1364 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1536 of 1536 strings)

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

* Translated using Weblate (Czech)

Currently translated at 97.9% (1504 of 1536 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 99.7% (1532 of 1536 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1364 of 1364 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 100.0% (1536 of 1536 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% (1536 of 1536 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 100.0% (1542 of 1542 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1542 of 1542 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1538 of 1542 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 99.2% (1549 of 1560 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1562 of 1562 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1562 of 1562 strings)

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

* fixing

* fix

* change

* fix

* import/export

* restore some lost translations

* 24hours

* Revert "24hours"

This reverts commit b715d46e6f.

* 24 hours, import

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Eric <zxmegaxqug@hldrive.com>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: J R <jr@simplex.chat>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: diodepon <diopon@mailo.com>
Co-authored-by: v1s7 <v1s7@users.noreply.hosted.weblate.org>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: 小林照幸 <koba1014@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: yokoba0413 <yokoba0413@gmail.com>
Co-authored-by: Kaan P <kaanpeker196@gmail.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-01-11 10:14:27 +00:00
Evgeny Poberezkin f45b24367c cli: short command 2024-01-11 08:21:02 +00:00
Stanislav Dmitrenko 9e369c3ac9 android, desktop: lock on changing user (#3669)
* android, desktop: lock on changing user

* rename

* change

* change
2024-01-10 21:31:16 +00:00
Evgeny Poberezkin afbb3b4e4b website: translations (#3667)
* Translated using Weblate (Arabic)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 100.0% (252 of 252 strings)

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

* correction

* correction

* revert

* keep new, revert changes in old ja strings

---------

Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Eric <zxmegaxqug@hldrive.com>
Co-authored-by: yokoba0413 <yokoba0413@gmail.com>
2024-01-10 20:35:59 +00:00
Stanislav Dmitrenko acd05c43db mobile: chat deletion avoiding race conditions (#3650)
* android, desktop: chat items deletion

* rename

* ios: chat items deletion

* correct id

* android: adding progress of deletion

* ios: text color while deleting chats

* change only text color

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-01-10 16:57:34 +00:00
Evgeny Poberezkin 61b14b22d5 5.5-beta.1: ios 189, android 171, desktop 23 2024-01-10 14:18:14 +00:00
Evgeny Poberezkin 25a4719414 core: 5.5.0.1 2024-01-10 12:06:29 +00:00
Evgeny Poberezkin f802ec75fe Merge branch 'stable' 2024-01-10 12:05:00 +00:00
Evgeny Poberezkin 045b195483 5.4.3: ios 188, android 169, desktop 22 2024-01-10 11:56:57 +00:00
spaced4ndy 283c90f5ae core: fix db method reserving extra local display name (#3659)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-01-10 11:09:09 +04:00
Stanislav Dmitrenko 99a9fb2e1f ios: self destruct improvements (#3640)
* ios: self destruct improvements

* test

* adapted to stopped chat

* wait until ctrl initialization finishes

* Revert "test"

This reverts commit 7c199293cc.

* refactor

* simplify,fix

* refactor2

* refactor3

* comment

* fix

* fix

* comment

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

* flip and rename flag

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-01-09 21:01:41 +00:00
Evgeny Poberezkin ce9d583b39 Merge branch 'stable' 2024-01-09 20:36:30 +00:00
Evgeny Poberezkin 53414608db core: 5.4.3.0 (simplexmq 5.5.0.5) 2024-01-09 20:20:14 +00:00
Stanislav Dmitrenko c7cf206585 android: fix call sound when the app in the background (#3660)
* android: fix call sound when the app in the background

* using previous notification channel

* Revert "using previous notification channel"

This reverts commit 19da9a9ce193c39b353f478e884a97bbbf002e77.

* prevent playing sound on call twice
2024-01-09 19:45:46 +00:00
Evgeny Poberezkin 6067ac3c93 ios: more aggressive GC in NSE 2024-01-09 19:34:54 +00:00
Evgeny Poberezkin fc56873f1c ios: update core library 2024-01-09 19:33:55 +00:00
Stanislav Dmitrenko a30da38af7 android, desktop: accept calls after restart (#3662) 2024-01-09 19:31:01 +00:00
Stanislav Dmitrenko 0bf3d054c6 mobile, desktop: invalid display name alert (#3664)
* ios: invalid display name alert

* android, desktop: invalid display name

---------

Co-authored-by: Avently <avently@local>
2024-01-09 19:26:47 +00:00
Stanislav Dmitrenko a55a8b116a script: changes in script for downloading libs (#3663)
* script: changes in script for downloading libs

* ios script
2024-01-09 17:23:20 +00:00
Stanislav Dmitrenko 7a207fd641 android, desktop: alerts when device was disconnected (#3483) 2024-01-09 14:21:29 +00:00
Evgeny Poberezkin 4508e0dfc1 Merge branch 'stable' 2024-01-09 11:07:04 +00:00
Stanislav Dmitrenko a853ba3a15 android, desktop: adapted code for self destruct for ios logic (#3643)
* android, desktop: adapted code for self destruct for ios logic

* init db in case of periodic && self destruct enabled
2024-01-09 09:59:21 +00:00
Evgeny Poberezkin a2f190a6c6 core: update simplexmq (better batching) 2024-01-09 09:15:35 +00:00
Stanislav Dmitrenko 267178dddb android, desktop: show alerts on critical and internal errors (#3653)
* android, desktop: show alerts on critical and internal errors

* test

* don't stop chat if it's stopped already

* show notification

* restart chat or app

* Revert "test"

This reverts commit 5b78bbae5b.

* update strings

* strings2

* refactoring

* refactoring2

* refactoring3

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-01-08 18:20:52 +00:00
spaced4ndy fadce0c140 core: create new chat controller with chatActivated set to true 2024-01-08 17:34:10 +04:00
spaced4ndy 58ad97fe6d core: pause cleanup when chat is suspended (#3658) 2024-01-08 17:28:01 +04:00
Evgeny Poberezkin 3ccd9903a7 core: do not start clean up manager in background NSE (#3657)
* core: do not start clean up manager in background NSE

* update UIs

* fix test
2024-01-08 12:53:16 +00:00
Evgeny Poberezkin e294999044 ios: fix callkit calls via NSE (#3655)
* ios: fix callkit calls via NSE

* comments

* more reliable NSE start

* remove public logs, different RTS parameters for NSE

* only suspend NSE if we have chat controller, to avoid crashes if suspension attempted without controller created

* comments

* fix

* simplify
2024-01-08 10:56:01 +00:00
Evgeny Poberezkin 2bbc687f4a core: simplexmq 5.5.0.4 2024-01-06 11:48:28 +00:00
Evgeny Poberezkin 61c507e7da core: replace deprecated memcpy (#3652) 2024-01-06 11:32:26 +00:00
Evgeny Poberezkin 64230f3545 Merge branch 'stable' 2024-01-05 20:07:35 +00:00
Evgeny Poberezkin bb61b9c658 core: update simplexmq (critical errors, worker restarts, subscription timeouts) 2024-01-05 20:07:19 +00:00
Evgeny Poberezkin 3428f4d2ee core: update simplexmq (critical errors, worker restarts, subscription timeouts) 2024-01-05 18:51:18 +00:00
Stanislav Dmitrenko fe865c5e11 android, desktop: consistent colors in themes (#3649) 2024-01-05 18:45:52 +00:00
spaced4ndy 9e87fe73a5 core: batch send profile update (#3618)
* core: batch send profile update

* redundant

* reorder

* remove type

* createSndMessages

* refactor

* batched create internal item

* create feature items for multiple contacts

* comments

* refactor call site

* synonim

* refactor createSndMessages

* more batching

* remove partitionWith

* unite filter and fold

* refactor

* refactor

* refactor

* fix merge

* add test

* rename

* refactor

* refactor

* withExceptT

* refactor

* refactor2

* remove notChanged

* deliver with sendMessagesB (#3646)

* deliver with sendMessagesB

* refactor

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>
2024-01-05 11:35:48 +04:00
Evgeny Poberezkin 0ef2c55983 core: invalid name error when it matches hidden profile (#3647) 2024-01-04 19:29:28 +00:00
spaced4ndy 8882284fb7 core: always check integrity on MSG in direct chats (#3641) 2024-01-04 16:22:16 +04:00
Stanislav Dmitrenko 767522e701 ios: better way of starting chat after stop (#3637)
Co-authored-by: Avently <avently@local>
2024-01-02 20:20:05 +00:00
sh 575d899f5a build-android: fix new arrangement of nix command (#3634) 2024-01-02 14:39:23 +00:00
Stanislav Dmitrenko d009777901 android, desktop: close gallery when media was deleted (#3636) 2024-01-02 14:38:28 +00:00
Stanislav Dmitrenko f758a5526a android, desktop: specifying text color globally (#3635)
* android, desktop: specifying text color globally

* typography
2024-01-02 14:28:36 +00:00
Stanislav Dmitrenko e6b5727003 android, desktop: run with stopped chat (#3624)
* android, desktop: run with stopped chat

* way to prevent starting a chat in case of not saved database key

* rename

* change position of a call

* new way of doing the same

* better

* exit process

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-01-02 14:21:39 +00:00
Evgeny Poberezkin c9b1d54f13 docs: update downloads 2023-12-30 22:04:01 +00:00
Evgeny Poberezkin 05065e919b 5.5-beta.0: ios 187, android 168, desktop 21 2023-12-30 21:09:01 +00:00
Evgeny Poberezkin 5399212e48 core: 5.5.0.0 2023-12-30 18:59:00 +00:00
Evgeny Poberezkin 809040c7bc ui: show secrets on tap (#3628)
* ios: show secrets on tap

* android: show secrets on tap/click

* android: clickable links in group descriptions

* android: hide secrets one by one

* ios: clickable links in welcome message preview

* refactor

* refactor2
2023-12-30 18:57:10 +00:00
Evgeny Poberezkin 4ab078bd18 ios: show clear search button when search is not empty (#3627) 2023-12-30 14:09:07 +00:00
sh 825257e898 build-android: update nix and add armv7a branch switch (#3612)
* build-android: build armv7a in seperate tag

And update nix install.

* build-android: change tag detection logic

* build-android: minor change of logic
2023-12-30 10:19:56 +00:00
Evgeny Poberezkin 644169b835 cli: prompt for database key entry if required (#3626) 2023-12-30 10:02:55 +00:00
Stanislav Dmitrenko 78eefee6cc android, desktop: search view will be shown always (#3625)
* android, desktop: search view will be shown always

* rearrange tree

* optimization
2023-12-29 21:28:11 +00:00
Alexander Bondarenko e253c55ba4 core: compatibility with GHC 8.10.7 (#3608)
* GHC-8.10 compatibility

* tweak setters

* restore membership

* remove Show Batch

* fix bytestring-10 compat

* preserve membership qualifier in names

* a few more memberships

* rename

* remove with-compiler

* ci: add 8.10 builds, limit releases to 9.6

* use matrix.asset_name as release guard

* fix windows_build

* actually use ghc version from matrix

* fix typo

* revert build/hash split

* add ghc to cache key

* Force cache between build and tests

* use explicit caching steps

* skip unneeded tasks

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-12-29 21:15:14 +00:00
spaced4ndy 478bb32cdb core: send group description to new members as welcome message after sending history (fixes welcome message being created before history) (#3623) 2023-12-29 22:42:55 +04:00
Stanislav Dmitrenko 1438fd00e2 android, desktop: self destruct becomes better (#3598)
* android, desktop: self destruct becomes better

* better way of doing it

* fix script

* firstOrNull

* changes for review

* comment

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-29 17:47:25 +00:00
spaced4ndy 05b55d3fb5 ui: group history preference, enable in new groups by default; core: create group history feature items (#3596)
* Revert "core: do not create group history item (#3586)"

This reverts commit 2834b192ce.

* ios: group history preference

* fix tests

* android

* texts

* enable in new groups ios

* enable in new groups android

* android texts

* ios texts

* remove ellipsis

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-29 17:46:28 +00:00
Stanislav Dmitrenko 9c061508a4 android, desktop: rework UX of creating new connection (#3529)
* android, desktop: rework UX of creating new connection

* different place for clipboard listener

* changes

* changes

* changes

* button, strings

* focus

* code optimization and search icon

* incognito link

* comment

* paddings

* optimization

* icon size and space in search

* appbar background color

* secondary color for icons in search bar

* lighter tool bar and avatars

* darker avatars in toolbar

* background for selected item and divider

* replacing connection view with actual chat view

* clear

* close unneeded view

* filter icon background

* filter doesn't hide current chat with empty search field

* fixes for review

* clearing focus on hiding keyboard

* fix invalid qr code message

* rename

* color

* buttons and text visibility when chat is not running yet

* loading chats label

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-12-29 15:46:45 +00:00
spaced4ndy 2bacc00a06 ios: rework UX of creating new connection (#3482)
* ios: connection UI (wip)

* custom search

* rework invite

* connect paste link ui

* scan rework, process errors, other fixes

* scan layout

* clear link on cancel

* improved search

* further improve search

* animation

* connect on paste in search

* layout

* layout

* layout

* layout, add conn

* delete unused invitation, create used invitation chat

* remove old views

* regular paste button

* new chat menu

* previews

* increase spacing

* animation, fix alerts

* swipe

* change text

* less sensitive gesture

* layout

* search cancel button transition

* slow down chat list animation (uses deprecated modifiers)

* icons

* update code scanner, layout

* manage camera permissions

* ask to delete unused invitation

* comment

* remove onDismiss

* don't filter chats on link in search, allow to paste text with link

* cleanup link after connection

* filter chat by link

* revert change

* show link descr

* disabled search

* underline

* filter own group

* simplify

* no animation

* add delay, move createInvitation

* update library

* possible fix for ios 15

* add explicit frame to qr code

* update library

* Revert "add explicit frame to qr code"

This reverts commit 95c7d31e47.

* remove comment

* fix pasteboardHasURLs, disable paste button based on it

* align help texts with changed button names

Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>

* update library

* Revert "fix pasteboardHasURLs, disable paste button based on it"

This reverts commit 46f63572e9.

* remove unused var

* restore disabled

* export localizations

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-12-29 12:29:49 +00:00
Evgeny Poberezkin d637714963 website: translations (#3617)
* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (252 of 252 strings)

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

---------

Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
2023-12-28 17:52:20 +00:00
Evgeny Poberezkin 5ff6bd15f6 ui: translations (#3615)
* Translated using Weblate (Italian)

Currently translated at 100.0% (1500 of 1500 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% (1346 of 1346 strings)

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

* Translated using Weblate (Chinese (Traditional))

Currently translated at 82.9% (1116 of 1346 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 9.2% (125 of 1346 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 80.1% (1202 of 1500 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 38.0% (571 of 1500 strings)

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

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1500 of 1500 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1500 of 1500 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 93.0% (1252 of 1346 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 94.4% (1416 of 1500 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 41.2% (619 of 1500 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 100.0% (1500 of 1500 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% (1346 of 1346 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1496 of 1500 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% (1500 of 1500 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% (1346 of 1346 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 90.9% (1224 of 1346 strings)

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

* Translated using Weblate (Czech)

Currently translated at 93.8% (1407 of 1500 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1503 of 1503 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1503 of 1503 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1503 of 1503 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1504 of 1504 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 93.8% (1411 of 1504 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 93.8% (1411 of 1504 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 93.8% (1411 of 1504 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 93.8% (1411 of 1504 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1504 of 1504 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1504 of 1504 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1504 of 1504 strings)

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

* Translated using Weblate (Czech)

Currently translated at 93.8% (1412 of 1504 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 93.8% (1412 of 1504 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 81.7% (1230 of 1504 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1504 of 1504 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% (1346 of 1346 strings)

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

* Translated using Weblate (Turkish)

Currently translated at 83.2% (1252 of 1504 strings)

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

* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1507 of 1507 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% (1507 of 1507 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1507 of 1507 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1508 of 1508 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1508 of 1508 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1508 of 1508 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1508 of 1508 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% (1346 of 1346 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 42.4% (640 of 1508 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 55.0% (830 of 1508 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 99.8% (1506 of 1508 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1504 of 1508 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 100.0% (1508 of 1508 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 99.9% (1507 of 1508 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.5% (1326 of 1346 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% (1508 of 1508 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% (1346 of 1346 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 80.4% (1213 of 1508 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1508 of 1508 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% (1346 of 1346 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 80.6% (1216 of 1508 strings)

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

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1508 of 1508 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 82.4% (1244 of 1508 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 86.4% (1304 of 1508 strings)

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

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1508 of 1508 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 99.9% (1507 of 1508 strings)

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

* Translated using Weblate (Greek)

Currently translated at 6.2% (94 of 1508 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 97.6% (1473 of 1508 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 97.6% (1473 of 1508 strings)

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

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

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

* Translated using Weblate (Greek)

Currently translated at 9.3% (141 of 1508 strings)

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

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

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

* Translated using Weblate (Greek)

Currently translated at 13.3% (201 of 1508 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1508 of 1508 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1510 of 1510 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1506 of 1510 strings)

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

* Translated using Weblate (Greek)

Currently translated at 14.2% (215 of 1510 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1510 of 1510 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% (1510 of 1510 strings)

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

* Translated using Weblate (Greek)

Currently translated at 14.8% (224 of 1510 strings)

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

* Translated using Weblate (Greek)

Currently translated at 1.1% (16 of 1346 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1510 of 1510 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% (1346 of 1346 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% (1510 of 1510 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1510 of 1510 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1510 of 1510 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1346 of 1346 strings)

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

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1510 of 1510 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% (1346 of 1346 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% (1510 of 1510 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (1510 of 1510 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1346 of 1346 strings)

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

* fix kotlin strings, import/export ios

---------

Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Corey Lin <lyfone@gmail.com>
Co-authored-by: xe1st <dnzkckali@gmail.com>
Co-authored-by: Istvan Novak <easthvan@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: 小林照幸 <koba1014@gmail.com>
Co-authored-by: inson1 <vaclav.svarc01@seznam.cz>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Eric <zxmegaxqug@hldrive.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: v1s7 <v1s7@users.noreply.hosted.weblate.org>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: diodepon <diopon@mailo.com>
2023-12-28 17:31:40 +00:00
Stanislav Dmitrenko 5b52d0e173 android, desktop: localization script enchancement (#3616) 2023-12-28 15:53:37 +00:00
Evgeny Poberezkin b4dd6941d7 core: allow quoted strings (with spaces) in network interface of remote hosts (#3592) 2023-12-28 10:06:49 +00:00
Stanislav Dmitrenko 07334b057d desktop (gradle): support specifying more versions in Gradle (#3614) 2023-12-28 09:41:17 +00:00
Evgeny Poberezkin 51bf2f413c 5.4.2: ios 186, android 166, desktop 20 2023-12-27 22:24:21 +00:00
Evgeny Poberezkin e3a69b12ba core: 5.4.2.1 (simplexmq 5.5.0.2) 2023-12-27 21:00:19 +00:00
Evgeny Poberezkin b220b5f6ec core: fix contact subscriptions (#3611) 2023-12-27 18:55:50 +00:00
Stanislav Dmitrenko 0b8346701c android, desktop: fix terminal items crash (#3607)
* android, desktop: fix terminal items crash

* test

* Revert "test"

This reverts commit 3f1e5c93ca.

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-27 14:59:38 +00:00
Evgeny Poberezkin efc873b09b core: min version for remote connection 5.4.2.0 (#3594) 2023-12-27 14:48:28 +00:00
Stanislav Dmitrenko 9f71502b51 desktop (windows): fix script that generates localization (#3606)
* desktop (windows): fix script that generates localization

* firstOrNull
2023-12-27 14:47:04 +00:00
Evgeny Poberezkin bbde6d81ee core: update simplexmq 2023-12-27 13:57:02 +00:00
Stanislav Dmitrenko 58906e1a60 desktop (windows): fixed handling non-utf8 Windows profile names (#3605) 2023-12-27 13:56:48 +00:00
Stanislav Dmitrenko ed3d234826 android, desktop: limit text length in terminal view (#3604) 2023-12-27 11:27:34 +00:00
Stanislav Dmitrenko dded56d8b8 ios: converting video to mp4 and making quality lower (#3597)
* ios: converting video to mp4 and making quality lower

Lower quality allows to play that videos on Android as well

* update export settings

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-27 11:23:46 +00:00
spaced4ndy 4d5aefa82c ui: don't share address at onboarding by default (#3603)
* ios: don't share address at onboarding by default

* android
2023-12-27 10:54:44 +00:00
Evgeny Poberezkin 9ac99ec2d9 core: update simplexmq (mark failed work items to continue processing) (#3600)
* core: update simplexmq (mark failed work items to continue processing) WIP

* simplexmq
2023-12-26 19:53:58 +00:00
spaced4ndy 37d033c7a5 core: test group members connect in group when they were previously connected as contacts (#3595) 2023-12-25 11:03:02 +04:00
spaced4ndy 5798efcf71 code: modify test 2023-12-24 20:55:03 +04:00
spaced4ndy e086719f27 core: add to tests 2023-12-24 20:44:30 +04:00
spaced4ndy bb4293eb5e fix tests 2023-12-24 20:23:09 +04:00
Evgeny Poberezkin c3c66182f2 Merge branch 'stable' 2023-12-24 14:20:58 +00:00
Evgeny Poberezkin 5b90d92ca2 core: add group tests 2023-12-24 14:20:07 +00:00
Evgeny Poberezkin af22348bf8 core: use version from config, add tests (#3588)
* core: use version from config, add tests

* comment

* refactor
2023-12-24 13:27:51 +00:00
Stanislav Dmitrenko 5a6670998c android, desktop: loading prev messages better (#3585)
* android, desktop: loading prev messages better

* better

* better

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-24 12:22:00 +00:00
spaced4ndy 700f6fa663 core, docs: drop message views if they exist, remove mentions in docs (#3589)
* core, docs: drop message views if they exist, remove mentions in docs

* fix migration
2023-12-24 11:13:34 +00:00
Stanislav Dmitrenko d474cae705 ios: saving and sharing items menu item (#3581)
* ios: saving and sharing items menu item

* refactor

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-23 23:15:31 +00:00
Evgeny Poberezkin 2834b192ce core: do not create group history item (#3586)
* core: do not create group history item

* fix tests
2023-12-23 19:56:01 +00:00
Evgeny Poberezkin b8cb954882 ios: update library 2023-12-23 17:24:30 +00:00
Evgeny Poberezkin 6aeef6f132 5.4.2.0: fix migration in simplexmq 2023-12-23 16:09:08 +00:00
Evgeny Poberezkin fa1702a566 5.4.2.0: update .cabal 2023-12-23 14:13:38 +00:00
Evgeny Poberezkin 95d6df926c 5.4.2.0 2023-12-23 13:46:11 +00:00
Evgeny Poberezkin cccd517277 core: fix simplexmq commit 2023-12-23 13:08:40 +00:00
spaced4ndy 12d1ada25e core: support batch sending in groups, batch introductions; send recent message history to new members (#3519)
* core: batch send stubs, comments

* multiple events in ChatMessage and supporting types

* Revert "multiple events in ChatMessage and supporting types"

This reverts commit 9b239b26ba.

* schema, refactor group processing for batched messages

* encoding, refactor processing

* refactor code to work with updated schema

* encoding, remove instances

* wip

* implement batching

* batch introductions

* wip

* collect and send message history

* missing new line

* rename

* test

* rework to build history via chat items

* refactor, tests

* correctly set member version range, dont include deleted items

* tests

* fix disappearing messages

* check number of errors

* comment

* check size in encodeChatMessage

* fix - don't check msg size for binary

* use builder

* rename

* rename

* rework batching

* lazy msg body

* use withStoreBatch

* refactor

* reverse batches

* comment

* possibly fix builder for single msg

* refactor batcher

* refactor

* dont repopulate msg_deliveries on down migration

* EncodedChatMessage type

* remove type

* batcher tests

* add tests

* group history preference

* test group link

* fix tests

* fix for random update

* add test testImageFitsSingleBatch

* refactor

* rename function

* refactor

* mconcat

* rename feature

* catch error on each batch

* refactor file inv retrieval

* refactor gathering item forward events

* refactor message batching

* unite migrations

* move files

* refactor

* Revert "unite migrations"

This reverts commit 0be7a3117a.

* refactor splitFileDescr

* improve tests

* Revert "dont repopulate msg_deliveries on down migration"

This reverts commit 2944c1cc28.

* fix down migration

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-23 13:07:23 +00:00
Evgeny Poberezkin f93f68e425 core: agent background mode for iOS NSE (#3574)
* core: agent background mode for iOS NSE

* change parameter for APIActivateChat

* fix

* update lib

* update lib

* simplexmq

* simplify
2023-12-23 13:06:59 +00:00
Andor Kesselman 23989aca57 Update README.md (#3553) 2023-12-22 08:48:26 +00:00
Andor Kesselman 57a6e85668 docs: fix typo (#3552) 2023-12-22 08:47:48 +00:00
Stanislav Dmitrenko 67590f3258 Revert "ios: making thumbnails faster" (#3571)
This reverts commit cd9cb8e064.
2023-12-22 08:46:55 +00:00
Stanislav Dmitrenko c83238c35a desktop: enable sending images and files with enter (#3582) 2023-12-21 22:48:32 +00:00
Stanislav Dmitrenko 8b0d2dede7 android, desktop: saving and sharing files menu item (#3580) 2023-12-21 15:19:36 +00:00
Stanislav Dmitrenko c4855313b6 android: splash screen with background color on Android 12+ (#3579) 2023-12-21 13:49:49 +00:00
Evgeny Poberezkin 2bff3b9c97 desktop, android: update api to pass controller when encrypting files (use ChaChaDRG as source of randomness) (#3578) 2023-12-21 12:49:18 +00:00
Evgeny Poberezkin aa037c0662 ios: update core library (uses GHC 9.6.3) 2023-12-21 10:05:43 +00:00
Evgeny Poberezkin d198d6a8db core: build iOS library with ghc 9.6.3 with iPhone7 etc. support (#3577)
* bump haskell.nix

* bump flake.lock

* Try openssl fix

* CFLAGS. not CCFLAGS

* Fix iOS build issues and improve static library handling

---------

Co-authored-by: Moritz Angermann <moritz.angermann@gmail.com>
2023-12-21 09:57:43 +00:00
Evgeny Poberezkin 7bcda7e54b core: use ChaChaDRG as the source of randomness (#3551)
* core: use ChaChaDRG as the source of randomness

* do not use entropy directly

* dont use RNG from agent

* simplexmq

* update iOS
2023-12-21 00:42:40 +00:00
Stanislav Dmitrenko 4a4d470859 android, desktop: try-catch composables (#3575)
* android, desktop: try-catch composables

* test

* better catching on Android

* more try-catch'es

* Revert "test"

This reverts commit adaf92b116.

* more try-catch'es

* unneeded imports
2023-12-20 18:00:44 +00:00
Evgeny Poberezkin 6ba3100d34 core: batch sending messages (#3566)
* core: batch sending messages

* batch without iorefs (#3573)

* one-pass

* simplexmq

* simplexmq

* simplexmq

* simplexmq

* revert change to ios project file

* refactor

* simplify

---------

Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>
2023-12-20 10:38:39 +04:00
Evgeny Poberezkin 7b073ba9f8 core: allow deleting last user (#3567)
* core: allow deleting last user (tests fail)

* tests, allow activating the hidden user when there is no active user

* hide logs

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

* comment

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

* comment

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-12-19 10:26:01 +00:00
Stanislav Dmitrenko 5e042d222e desktop: saving qr code as an image (#3572) 2023-12-19 10:24:13 +00:00
Stanislav Dmitrenko 26a189917b sctipt: check string formatting (#3570)
* sctipt: check string formatting

* all
2023-12-18 21:37:10 +00:00
spaced4ndy ce9218b186 ios: rework authentication (#3556) 2023-12-18 22:04:49 +04:00
Evgeny Poberezkin f0338a03d1 directory: better search, allow both simplex:/ and simplex.chat links in description (#3546)
* directory: new commands

* better search

* search test

* return group links in simplex.chat domain, allow both simplex:/ and simplex.chat links in group description
2023-12-18 10:41:08 +00:00
Evgeny Poberezkin 6fa0001ea7 ios: delay suspendChat in NSE, background schedule depends on notifications mode (#3561)
* ios: delay suspendChat in NSE

* different background refresh interval depending on the settings

* simplify

* comment

* reduce NSE suspend interval

* space
2023-12-18 10:36:25 +00:00
Stanislav Dmitrenko 974fa448b4 android, desktop: some alerts became privacy sensitive (#3554)
* android, desktop: some alerts became privacy sensitive

* changes
2023-12-14 13:11:19 +00:00
spaced4ndy 8cec5428ee core: save CIContent tag in chat_items table (#3555) 2023-12-14 17:08:40 +04:00
Evgeny Poberezkin 73130bf321 ios: update core library 2023-12-13 21:48:25 +00:00
spaced4ndy 67241ff65c ios: fix code scanners only attempting to scan once (#3548) 2023-12-13 16:13:05 +04:00
spaced4ndy b6b041490f core: improve chat list pagination performance, simplify logic by always reading chat stats and last item id for previews (#3541)
* core: improve chat list pagination performance

* fix query

* core: improve chat list pagination performance, simplify logic by always reading chat stats (#3543)

* microseconds

* fix

* update simplexmq

* simplify queries

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-13 15:32:23 +04:00
Evgeny Poberezkin 7f9f9a674c ios: fix member view freezing on iOS 15, closes #3487 (#3547) 2023-12-13 11:27:28 +00:00
Evgeny Poberezkin ae94bb6f87 core: use crypton instead of cryptonite (#3542)
* update hackage

* use crypton instead of cryptonite

* remove http2 from cabal.project

* simplexmq
2023-12-13 11:20:03 +00:00
Evgeny Poberezkin 7ec39d1ffa all: increase default TCP timeouts, update simplexmq (#3540) 2023-12-12 13:13:36 +00:00
Evgeny Poberezkin ca6dfb5ea1 docs: update latest version 2023-12-12 10:25:02 +00:00
Evgeny Poberezkin a5048db6fa ios: improve media picker for multiple images/videos (#3538)
* ios: improve media picker to work with multiple images reliably

* MainActor
2023-12-12 09:04:48 +00:00
Evgeny Poberezkin aca3a71b38 ios: update library 2023-12-11 18:57:42 +00:00
Evgeny Poberezkin d358390e3d Merge pull request #3532 from simplex-chat/ios-notifications
improve iOS notifications
2023-12-11 14:55:03 +00:00
Evgeny Poberezkin f9a125bc32 Merge branch 'master' into ios-notifications 2023-12-11 14:11:00 +00:00
Alexander Bondarenko 35c1975d66 core: chat list pagination (#3505)
* add pagination args to APIGetChats

* add search to chat list API

* rename arg to paginationTs_ to match type

* lift another condition to ids query

* collect all chat refs before sorting, then get details

* split remaining preview functions

* roll back to collecting ids first with query cleanup

* add connection join back to filter out groups

* extract and expand tests

* add fav/unread args

* WIP

* lay out the queries with favs

* tweak tests

* add fav tests

* fix order by in the before case

* build query footer wholly from pagination

* add migration for direct contacts

* fix setting contact_used

* fix setting contact_used for group link contacts

* align search x filters space with UI, support filter by either favorite or unread, optimize queries, indexes

* always set chat_ts, fix tests

* refactor tests

* fix pagination logic, more tests

* refactor, rename

* increase default pagination count

* comments

* refactor

* comment

* report errors

* refactor

* remove unused type

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-12-11 17:50:32 +04:00
Evgeny Poberezkin 0bfe37137c core: update simplexmq (message notification markers) 2023-12-11 13:11:35 +00:00
Evgeny Poberezkin 666903ae76 Merge branch 'master' into ios-notifications 2023-12-11 13:06:32 +00:00
Evgeny Poberezkin 8a41a4c214 ios: do not start chat if it was stopped, deliver "app stopped" notifications (#3535)
* add stopped notifications, remove full off mode

* core: allow initializing chat data without starting chat

* ios: ask before starting chat if it was stopped

* correct text

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

* fix comment

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-12-11 12:59:49 +00:00
Evgeny Poberezkin 79a954336c ios: communication between NSE and app via files (#3533)
* ios: communication between NSE and app via files

* clean up

* better concurrency
2023-12-11 12:34:56 +00:00
Evgeny Poberezkin f65b8a9e78 core: mark all user messages read (#3530) 2023-12-11 12:26:45 +00:00
Evgeny Poberezkin e8016adfdc simplexmq 2023-12-10 17:47:44 +00:00
Evgeny Poberezkin d3059afc99 ios, core: better notifications processing to avoid contention for database (#3485)
* core: forward notifications about message processing (for iOS notifications)

* simplexmq

* the option to keep database key, to allow re-opening the database

* export new init with keepKey and reopen DB api

* stop remote ctrl when suspending chat

* ios: close/re-open db on suspend/activate

* allow activating chat without restoring (for NSE)

* update NSE to suspend/activate (does not work)

* simplexmq

* suspend chat and close database when last notification in the process is processed

* stop reading notifications on message markers

* replace async stream with cancellable concurrent queue

* better synchronization of app and NSE

* remove outside of task

* remove unused var

* whitespace

* more debug logging, handle cancelled read after dequeue

* comments

* more comments
2023-12-09 21:59:40 +00:00
Evgeny Poberezkin 2f7632a70f 5.4.1: ios 185, android 164, desktop 19 2023-12-07 21:01:14 +00:00
Evgeny Poberezkin 27c14f32f1 core: 5.4.0.7 2023-12-07 14:30:42 +00:00
Stanislav Dmitrenko 13a32f7864 android: made minimum supported version of Android as 9 (#3525) 2023-12-07 10:49:16 +00:00
Stanislav Dmitrenko b1652b8930 desktop: fix toasts theme (#3524) 2023-12-06 21:19:30 +00:00
Stanislav Dmitrenko a9b36e8e39 desktop: fix onboarding when choosing random password (#3523) 2023-12-06 20:33:53 +00:00
Evgeny Poberezkin ee163a6540 core: add missing field 2023-12-06 12:34:10 +00:00
Evgeny Poberezkin 4fd6405113 core: update simplexmq (better suspend agent) 2023-12-06 00:19:24 +00:00
Stanislav Dmitrenko ccc62274ee android, desktop: crash handler addition (#3517)
* android, desktop: crash handler addition

* added
2023-12-05 22:50:25 +00:00
Stanislav Dmitrenko 4c6d52ba75 android, desktop: crash handler (#3516)
* android, desktop: crash handler

* test

* rename

* string

* Revert "test"

This reverts commit 530faf39c1.

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-05 21:31:49 +00:00
Evgeny Poberezkin 9df63160e5 ios: fix simplex address view (#3515)
* ios: fix simplex address view

* fix lib paths

* fix call
2023-12-05 09:48:04 +00:00
Stanislav Dmitrenko c8e9788c29 desktop: enhancements to remote desktop connect UI (#3513)
* desktop: enhancements to remote desktop connect UI

* changes

* more changes

This reverts commit e8323e8bfa.

* color

* random port
2023-12-04 21:04:58 +00:00
spaced4ndy 7099776357 docs: fix typo 2023-12-04 19:17:24 +04:00
Evgeny Poberezkin 3481d379c6 core: compatibility with GHC 8.10.7, narrow dependency ranges (#3503)
* Revert "raise lower bound on mtl to a real version (#3499)"

This reverts commit f94c0311c1.

* Revert "core: expand ranges to fit ghc 8.10 & 9.6 (#3496)"

This reverts commit 9a1c7f41f7.

* update simplexmq

* remove netword-transport fork

* simplexmq

* fix test

* fix index-state in cabal.project

* simplexmq

* simplexmq

* bytestring,simplexmq

* template-haskell, simplexmq

* simplexmq

* simplexmq

* mtl

* simplexmq
2023-12-04 10:01:37 +00:00
Evgeny Poberezkin 85c1e871dc Merge branch 'stable' 2023-12-04 00:06:53 +00:00
Evgeny Poberezkin fec5ff3f15 docs: SimpleX address (#3508)
* docs: SimpleX address

* table

* header
2023-12-03 22:21:13 +00:00
Evgeny Poberezkin acaa597c90 desktop, android: fix image not appearing in view when received (#3504)
* desktop, android: fix image not appearing in view when received

* change to KeyChangeEffect
2023-12-03 15:42:43 +00:00
Evgeny Poberezkin 6a9a67db14 cli: option to mark shown messages as read (off by default) (#3506)
* cli: option to mark shown messages as read (off by default)

* fix tests

* fix tests
2023-12-03 15:42:26 +00:00
Alexander Bondarenko f94c0311c1 raise lower bound on mtl to a real version (#3499)
* raise lower bound on mtl to a real version

* simplexmq

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-02 12:24:29 +00:00
Stanislav Dmitrenko e1ff7c88d7 desktop: allow changing listening ip and port of remote (#3498)
* desktop: allow changing listening ip and port of remote

* remove empty lines

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-12-01 20:41:08 +00:00
Alexander Bondarenko 9a1c7f41f7 core: expand ranges to fit ghc 8.10 & 9.6 (#3496)
* expand ranges to fit ghc 8.10 & 9.6

* update nix

* use hashes from mq master

* fix more deps

* use network-transport from hackage
2023-12-01 16:52:47 +00:00
Stanislav Dmitrenko 40e69ae713 desktop: enable database operations (#3495)
* desktop: enable database operations

* disconnect hosts button

* not relaying on dev tools

* different logic

* different logic 2

* toggle placement
2023-12-01 15:04:00 +00:00
spaced4ndy b74e33b958 docs: inactive group members rfc (#3419) 2023-12-01 19:02:50 +04:00
Stanislav Dmitrenko 540c8883a0 android: do not show alert too early in obboarding (#3493) 2023-11-30 19:39:16 +00:00
Stanislav Dmitrenko 0e18b13bea desktop: adapting onboarding process to linking devices (#3490)
* desktop: adapting onboarding process to linking devices

* show progress on long operations

* changes

* clearing chat cache logic

* lines

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-30 19:38:21 +00:00
spaced4ndy a4b44254bc core: update simplexmq (ghc 8.10.7 compatibility) (#3492) 2023-11-30 21:09:07 +04:00
spaced4ndy 5819e42305 core: remove CRNewContactConnection response; mobile, desktop: create pending connections based on api responses (CRNewContactConnection was being used as "event" in UI) (#3489) 2023-11-30 20:31:32 +04:00
Jesse Horne 9580b4110d desktop: remember window position and size (#3465)
* initial work on storing desktop window position and size

* removed useless imports

* updated to use app preferences

* vars to vals

* defensive programming

* fixed default

* removed default json

* do nothing if encoding to json while storing fails

* names, clean up

* move comment

* changes

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-11-30 12:43:01 +00:00
Stanislav Dmitrenko 05a64c99a2 ios: moving webrtc commands processing to another mechanism (#3480)
* ios: moving webrtc commands processing to another mechanism

* async

* decide

* handle errors

* error alert

* await

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-28 17:36:05 +00:00
Alexander Bondarenko 6a21d5c7f1 add remote host bindings (#3471)
* add remote host bindings

* group iface/address together

* rename migration

* add implementation

* update view and api

* bump upstream

* add schema

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-28 16:32:33 +00:00
Stanislav Dmitrenko 950bbe19da ios: fix calls connecting state (#3475)
* ios: fix calls connecting state

* optimization

* changes

* removed relay protocol

* simplify

* use actor

* fix loop, better onChange, some questions

* remove extra iteration

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-27 22:20:51 +00:00
Stanislav Dmitrenko f31054de4f desktop (windows): fix action (#3479) 2023-11-27 22:11:53 +00:00
Evgeny Poberezkin 05278e5a06 core: allow remote host commands without user (#3478) 2023-11-27 18:34:15 +00:00
spaced4ndy 7a54d74517 Revert "ios: update libraries (#3474)"
This reverts commit bfcb2ac230.
2023-11-27 19:16:53 +04:00
spaced4ndy bfcb2ac230 ios: update libraries (#3474) 2023-11-27 19:02:44 +04:00
spaced4ndy 3073c4a1d5 core: fix chat previews showing not the latest message, fix message ordering in direct chats; mobile: update group previews only on timestamp increase (#3473) 2023-11-27 17:14:12 +04:00
Evgeny Poberezkin d4ac1c0cf2 core, ui: add remote host/controller stop reasons to events (#3472) 2023-11-26 23:23:37 +00:00
Evgeny Poberezkin d29f1bb0cf core: use fourmolu styles (#3470) 2023-11-26 18:16:37 +00:00
Jesse Horne 75c2de8a12 desktop: closing console window no longer closes entire application (#3466)
* closing the console now doesn't close all windows

* simplify

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-26 13:40:51 +00:00
Alexander Bondarenko f20ac33e67 cli: remove clashing short option for device-name (#3468) 2023-11-26 13:16:32 +00:00
Evgeny Poberezkin 8cc0954430 Merge branch 'stable' 2023-11-26 11:50:30 +00:00
Evgeny Poberezkin 1e6891e222 blog: v5.4 announcement (#3457)
* blog: v5.4 announcement

* update

* corrections

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

* add images, CLI section

* images

* preview, readme

* correction

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-11-25 18:27:41 +00:00
Evgeny Poberezkin 962964a73d docs: update downloads page 2023-11-25 14:15:41 +00:00
Evgeny Poberezkin b9dd2f45c9 rfc: post-quantum resistant augmented double ratchet algorithm (#3463)
* rfc: post-quantum resistant augmented double ratchet algorithm

* update doc

* replace Kyber with "some KEM"
2023-11-25 12:51:05 +00:00
Evgeny Poberezkin de1c885501 ios: 5.4 build 184: switch to GHC 8.10.7 (9.6.3 crashes on older iPhone models), fix Connect to desktop closing when switching to QR code scan 2023-11-25 11:22:02 +00:00
Evgeny Poberezkin 1902b692f5 5.4: ios 183, android 162, desktop 18 2023-11-25 00:13:31 +00:00
Evgeny Poberezkin 6c05eb0ff3 directory: support group names with spaces (#3458) 2023-11-24 23:21:38 +00:00
Evgeny Poberezkin d148ce4cbb ui: translations (#3459)
* Translated using Weblate (Russian)

Currently translated at 100.0% (1500 of 1500 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% (1346 of 1346 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (Russian)

Currently translated at 100.0% (1500 of 1500 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% (1346 of 1346 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 22.1% (332 of 1500 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (1346 of 1346 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 22.3% (335 of 1500 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Polish)

Currently translated at 96.9% (1454 of 1500 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (French)

Currently translated at 100.0% (1500 of 1500 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1346 of 1346 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1346 of 1346 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1500 of 1500 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 100.0% (1346 of 1346 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 28.6% (429 of 1500 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/

* import/export/update

---------

Co-authored-by: Istvan Novak <easthvan@gmail.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
2023-11-24 23:20:28 +00:00
Evgeny Poberezkin 3d09073bfc ios: update core lib to 5.4.0.6 2023-11-24 20:46:00 +00:00
Evgeny Poberezkin da64b2e3cd android, desktop: fix translation 2023-11-24 20:37:32 +00:00
Stanislav Dmitrenko 4572fec61d desktop (windows): fix lib build (#3456) 2023-11-24 20:05:41 +00:00
Alexander Bondarenko fe9953fc49 desktop: remove GC flag when building on windows (#3455)
* desktop: remove GC flag when building on windows

* add correct define
2023-11-24 20:00:20 +00:00
Stanislav Dmitrenko e91a1f151d desktop: hide profiles screen on remote host change (#3454) 2023-11-24 19:24:16 +00:00
Evgeny Poberezkin 34d7fe3744 core: 5.4.0.6 2023-11-24 18:59:41 +00:00
Alexander Bondarenko 4327b023ed terminal: add remote user information (#3448)
* terminal: add remote user information

* rename

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-24 18:44:12 +00:00
Stanislav Dmitrenko 50bada24af desktop: better status check of loaded remote files (#3453) 2023-11-24 18:43:28 +00:00
spaced4ndy 97934c8289 android, desktop: fix alert text for deleting received message 2023-11-24 21:10:03 +04:00
Evgeny Poberezkin 4a254560c0 desktop: fix user address changes on connected mobile (#3452)
* desktop: fix user address changes on connected mobile

* close user-specific views when remote host changes
2023-11-24 16:51:31 +00:00
Stanislav Dmitrenko f9b5c673c5 android, desktop: better handling of URI's (#3450) 2023-11-24 16:19:31 +00:00
spaced4ndy 8ce9dd7ab6 android: don't show lock notice on first start (#3451) 2023-11-24 20:05:37 +04:00
spaced4ndy 9fb4b3cf40 desktop: don't show device specific network and database settings when connected to remote host (#3449) 2023-11-24 19:38:19 +04:00
Evgeny Poberezkin 7f9a490edb website: translations (#3447)
* Translated using Weblate (Arabic)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

---------

Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
2023-11-24 14:21:13 +00:00
Evgeny Poberezkin bfd13f059a ui: translations (#3446)
* Translated using Weblate (Dutch)

Currently translated at 100.0% (1502 of 1502 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% (1341 of 1341 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1503 of 1503 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1503 of 1503 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/

* Translated using Weblate (Russian)

Currently translated at 97.7% (1459 of 1493 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% (1341 of 1341 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1493 of 1493 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% (1341 of 1341 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% (1502 of 1502 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% (1341 of 1341 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1503 of 1503 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1503 of 1503 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/

* Translated using Weblate (Russian)

Currently translated at 97.7% (1459 of 1493 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% (1341 of 1341 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1493 of 1493 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% (1341 of 1341 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Russian)

Currently translated at 100.0% (1493 of 1493 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 99.8% (1339 of 1341 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (Arabic)

Currently translated at 92.4% (1380 of 1493 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1494 of 1494 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Added translation using Weblate (Hungarian)

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1495 of 1495 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 0.5% (8 of 1495 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 1.4% (21 of 1495 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 2.0% (30 of 1495 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 2.1% (32 of 1495 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 10.9% (163 of 1495 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1495 of 1495 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 12.3% (184 of 1495 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 100.0% (1495 of 1495 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 14.8% (222 of 1495 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1495 of 1495 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 21.6% (323 of 1495 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (German)

Currently translated at 97.7% (1461 of 1495 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (French)

Currently translated at 100.0% (1495 of 1495 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1341 of 1341 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Hungarian)

Currently translated at 21.9% (328 of 1495 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (1495 of 1495 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% (1341 of 1341 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (German)

Currently translated at 100.0% (1500 of 1500 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% (1341 of 1341 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1500 of 1500 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1500 of 1500 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Turkish)

Currently translated at 70.0% (1051 of 1500 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* ru: corrections

* export/import

* ios: export

* ru: corrections

---------

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Float <float.hu+@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: J R <jr@simplex.chat>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Istvan Novak <easthvan@gmail.com>
Co-authored-by: Eric <zxmegaxqug@hldrive.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: xe1st <dnzkckali@gmail.com>
2023-11-24 14:18:31 +00:00
Evgeny Poberezkin c9aec88c39 desktop: fix sending videos via connected mobile 2023-11-24 13:14:52 +00:00
Evgeny Poberezkin b1cf1656a0 core: cli remote control help section (#3445) 2023-11-24 10:48:14 +00:00
Alexander Bondarenko 74e80eb348 core: add remote stop reason and state (#3444)
* add remote stop reason and state

* rename

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-23 22:00:20 +00:00
Evgeny Poberezkin 6f3174d0a1 android, desktop: remove unnecessary serialization 2023-11-23 21:25:32 +00:00
Evgeny Poberezkin 8f0a9cd609 ios: connect remote desktop via multicast (#3436)
* ios: connect remote desktop via multicast

* works

* fix camera freeze when leaving linked devices view

* label

* fix linked devices

* fix compatible

* string
2023-11-23 21:22:29 +00:00
Stanislav Dmitrenko b2dbb558f9 android, desktop: connect remote desktop via multicast (#3442)
* android, desktop: connect remote desktop via multicast

* changes

* string

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-23 21:00:11 +00:00
Stanislav Dmitrenko f7903c5c83 desktop: close remote host connecting screen on stop of host (#3440) 2023-11-23 19:49:53 +00:00
Evgeny Poberezkin 4d3529a3e0 desktop: fix incorrect remote host for active user (#3441) 2023-11-23 17:00:13 +00:00
Alexander Bondarenko d837f87f09 fix circular cancel at rcDiscoverCtrl (#3438) 2023-11-23 11:00:57 +00:00
Evgeny Poberezkin d3f9616f9b core: report controller info when found via multicast (#3437)
* core: report controller info when found via multicast

* handle parse error
2023-11-23 10:07:26 +00:00
Evgeny Poberezkin 1b7baa244a core: track network statuses in CLI (#3434) 2023-11-23 08:39:08 +00:00
Alexander Bondarenko 954b7150af android, desktop: set RTS options for core (#3418)
* desktop: allow settings RTS options

* set initial heap and arena sizes

* add non-moving GC for even more productivity/less reallocs

* add RTS options for android too

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-22 22:37:33 +00:00
Evgeny Poberezkin d0419df396 android: close Use from desktop when disconnecting 2023-11-22 22:34:30 +00:00
Evgeny Poberezkin 01f351e65a ios: haskell RTS options (#3433) 2023-11-22 22:12:42 +00:00
Evgeny Poberezkin 2d4e99d610 cli: set device name for remote control via CLI option (#3427)
* cli: set device name for remote control via CLI option

* fix

* add property in tests
2023-11-22 22:11:32 +00:00
Evgeny Poberezkin 4af4fbae2b ios: close sheet when disconnecting from desktop (#3435) 2023-11-22 22:10:41 +00:00
spaced4ndy 15fdab597b core: shuffle members when sending messages and introductions; send to admins and owners first (#3431)
* core: shuffle members when sending messages and introductions; send to admins and owners first

* refactor

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-22 21:36:52 +00:00
Stanislav Dmitrenko 0c1d78ab08 desktop: specifying port in connect remote host page (#3432)
* desktop: specifying port in connect remote host page

* shorter string

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-22 20:17:05 +00:00
Evgeny Poberezkin 324f614e00 core: return remote controller port to UI (#3430) 2023-11-22 17:40:10 +00:00
spaced4ndy cec0fe2702 ios, android: add author group member role to fix decoding (hidden from UI) (#3429) 2023-11-22 18:47:46 +04:00
Stanislav Dmitrenko 48d7afc959 desktop: enhancements to remote hosts experience (#3428) 2023-11-22 14:35:32 +00:00
Evgeny Poberezkin 9442121efa desktop: do not switch remote host when inactive host is disconnected (#3426) 2023-11-22 12:14:49 +00:00
spaced4ndy 69acac5331 android: remove unused strings (#3424) 2023-11-22 10:19:39 +04:00
Evgeny Poberezkin aade3d359f v5.4-beta.4: ios 182, android 161, desktop 17 2023-11-21 23:32:33 +00:00
Evgeny Poberezkin c1d89f2c0f ios: move hs_init to background thread (#3411) 2023-11-21 22:21:01 +00:00
Stanislav Dmitrenko c40bfb0f43 android, desktop: show remote host info (#3423)
* android, desktop: show remote host info

* hide alerts too
2023-11-21 21:49:39 +00:00
Evgeny Poberezkin 64520a4cf4 core: 5.4.0.5, update simplexmq 2023-11-21 21:12:43 +00:00
Evgeny Poberezkin d0f43628ef ui: translations (#3421)
* Translated using Weblate (Italian)

Currently translated at 100.0% (1483 of 1483 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% (1332 of 1332 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1483 of 1483 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 97.2% (1442 of 1483 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1483 of 1483 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% (1332 of 1332 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* android: fix formatted strings

* ios: imp/exp localizations

---------

Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Eric <zxmegaxqug@hldrive.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
2023-11-21 20:30:21 +00:00
spaced4ndy febf3e0a45 ui: v5.4 what's new (#3413)
* ios: v5.4 what's new

* android

* export localizations

* update

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-21 19:38:05 +00:00
Jesse Horne 097242e7a8 desktop: add image pasting from clipboard (#3378)
* first pass at desktop image pasting for multiplatform

* removed debug println

* fixed bug with pasting text

* temp files are deleted now following simplex conventions

* optimizations

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-11-21 19:37:15 +00:00
spaced4ndy a8576c2340 core: test forwarded message deduplication, mute terminal error (#3414) 2023-11-21 19:25:50 +04:00
Alexander Bondarenko 5a08a26c9a desktop: add exception handlers to startReceiver loop (#3417)
* desktop: add exception handlers to startReceiver loop

* simplify

* more exceptions

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-11-21 14:43:52 +00:00
Alexander Bondarenko da8789ef4c desktop: fix RCP tag in AgentErrorType (#3416) 2023-11-21 12:20:04 +00:00
Evgeny Poberezkin 47cd7de1ae core: 5.4.0.4 2023-11-21 00:00:29 +00:00
Evgeny Poberezkin 624a3abba2 website: translations (#3412)
* Translated using Weblate (German)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
2023-11-20 22:29:18 +00:00
Evgeny Poberezkin 121985138a ios: export localizations 2023-11-20 22:24:19 +00:00
Evgeny Poberezkin 7f5efd8927 desktop: use correct remote host when creating/connecting via links (#3409) 2023-11-20 20:56:05 +00:00
Evgeny Poberezkin 96d3c9988c Merge pull request #3404 from simplex-chat/ep/core-add-remote-host
desktop: add remote host ID to entities
2023-11-20 17:21:56 +00:00
spaced4ndy f6b786a187 get user index by remote host id 2023-11-20 20:31:35 +04:00
spaced4ndy 11478da6ef Revert "remoteHostId in backend"
This reverts commit 72654caca6.
2023-11-20 19:56:31 +04:00
spaced4ndy 72654caca6 remoteHostId in backend 2023-11-20 19:51:56 +04:00
spaced4ndy 44c88badde remoteHostId in entities kotlin 2023-11-20 16:31:52 +04:00
Evgeny Poberezkin 53a31ec60e core: add remote host ID to entities 2023-11-20 11:51:40 +00:00
spaced4ndy 718436bf55 core: don't read all group members where unnecessary (#3403) 2023-11-20 15:27:15 +04:00
Evgeny Poberezkin 5bbf4d70a1 Merge pull request #3151 from simplex-chat/remote-desktop
use mobile from desktop
2023-11-20 11:12:01 +00:00
Evgeny Poberezkin 970ca3a409 Merge branch 'master' into remote-desktop 2023-11-20 10:35:20 +00:00
Evgeny Poberezkin c536ca7f0f core: add events not sent to connected remote desktop (#3402) 2023-11-20 10:34:24 +00:00
Evgeny Poberezkin 07ef2a0b64 android: remove ACCESS_WIFI_STATE (#3391) 2023-11-20 10:20:31 +00:00
Evgeny Poberezkin 5b7de8f8c1 desktop, android: pass remote host to API from the loaded objects, to prevent race conditions (#3397)
* desktop, android: pass remote host explicitely to API calls

* use remote host ID in model updates

* add remote host to chat console

* add remote host to notifications functions
2023-11-20 10:20:10 +00:00
Alexander Bondarenko 68cbc605be add remote session sequence to prevent stale state updates (#3390)
* add remote session sequence to prevent stale state updates

* remote RHStateKey

* add StateSeq check to controller

* clean up

* simplify

* undo withRemoteXSession API change

* simplify

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-20 10:19:00 +00:00
spaced4ndy 3a510eeaf0 core: rename forwarded fields (#3401) 2023-11-20 14:00:55 +04:00
Alexander Bondarenko ba94f76a90 core: fix remote session stuck in Starting after crashed rcConnect (#3399) 2023-11-20 09:33:43 +00:00
spaced4ndy 85e44dcb77 core: split group message forwarding tests (#3400) 2023-11-20 13:05:59 +04:00
Evgeny Poberezkin 2a8d7b8926 core: add commands that will not be forwarded to connected mobile (#3398)
* core: add commands that will not be forwarded to connected mobile

* fail if command that must be executed locally sent to remote host
2023-11-19 20:48:25 +00:00
Evgeny Poberezkin d9031cb209 Merge branch 'master' into remote-desktop 2023-11-19 11:18:08 +00:00
Evgeny Poberezkin bf8457fb40 website: translations (#3396)
* Translated using Weblate (French)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Italian)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/zh_Hans/

* Translated using Weblate (Polish)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Translated using Weblate (Russian)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ru/

* Translated using Weblate (French)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Italian)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/zh_Hans/

* Translated using Weblate (Polish)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Translated using Weblate (Russian)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ru/

---------

Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Eric <zxmegaxqug@hldrive.com>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Timur Bagautdinov <mr.bagautdinov14@gmail.com>
2023-11-19 11:14:09 +00:00
Evgeny Poberezkin 59392b361b ui: translations (#3392)
* Translated using Weblate (Polish)

Currently translated at 97.4% (1400 of 1437 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1437 of 1437 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Dutch)

Currently translated at 99.0% (1423 of 1437 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1437 of 1437 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 100.0% (1300 of 1300 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1437 of 1437 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% (1300 of 1300 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (French)

Currently translated at 100.0% (1437 of 1437 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1300 of 1300 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1437 of 1437 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% (1300 of 1300 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1437 of 1437 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% (1300 of 1300 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (German)

Currently translated at 100.0% (1437 of 1437 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% (1300 of 1300 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (German)

Currently translated at 100.0% (1439 of 1439 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% (1300 of 1300 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1439 of 1439 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1439 of 1439 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1439 of 1439 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (French)

Currently translated at 100.0% (1439 of 1439 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1439 of 1439 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1439 of 1439 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/

* update de: Meine -> Ihre

* nl: Gebruiker -> Lid

* nl: gebruiker -> lid 2

* ios, nl: gebruiker -> lid

* ios, nl: gebruiker -> lid 2

* android: fix strings

* ios: export/import localizations

---------

Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Eric <zxmegaxqug@hldrive.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Denys Rastiegaiev <daaren@gmail.com>
2023-11-19 11:06:49 +00:00
Stanislav Dmitrenko 8f0538e756 android: UI for remote connections (#3395)
* android: UI for remote connections

* camera permissions

* eol

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-19 01:07:42 +00:00
Moritz Angermann b164cc2fa6 nix: fix lib:support for armv7a (#3394) 2023-11-19 00:31:29 +00:00
Evgeny Poberezkin f9e5a56e1a ios: terminate session on network failure, add description for local network access 2023-11-18 22:20:22 +00:00
Evgeny Poberezkin 96e000e3ea ios: add user-defined device name for remote desktop connection 2023-11-18 20:28:55 +00:00
Evgeny Poberezkin ca8833c0c1 desktop: sending and receiving files via connected mobile (#3365)
* desktop: support remote files (WIP)

* working with remote files locally

* better

* working with remote file downloads

* sending files

* fixes of loading files in some situations

* image compression

* constant for remote hosts

* refactor

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-11-18 20:11:30 +00:00
Evgeny Poberezkin e95d9d0b49 core: rename migration to remote-control, comments (#3393) 2023-11-18 19:18:02 +00:00
Evgeny Poberezkin cc434cda55 Merge branch 'master' into remote-desktop 2023-11-18 18:03:13 +00:00
spaced4ndy c0e8740f50 core: group message forwarding (#3360)
* core: group message forwarding types

* xgrpmemcon

* rework xgrpmemcon to use intros table

* only forward w/t error

* forward msg

* xGrpMsgForward, check integrity outside

* deduplicate group messages

* test

* change error

* item forwarded flag

* intro_chat_protocol_version, bump version

* comment

* highly available client option

* more comments

* notify xgrpmemcon on deduplication

* member vrange

* encoding

* remove MsgForward

* remove import

* exclude files from forwarding

* refactor

* rename to align with protocol

* forward more message types

* add events

* remove unused error, function

* add x.file.cancel, x.info and x.grp.mem.new to forwarded messages

* remove unused x.msg.file.cancel

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-18 17:52:01 +00:00
Evgeny Poberezkin 80abc18371 core: update simplexmq (xrcp) 2023-11-18 15:35:06 +00:00
qvsojBJGiEnR 8f6a31ca07 Update app-settings.md (#3379) 2023-11-17 23:29:25 +00:00
Stanislav Dmitrenko c9a1de6e4b msys2 setup in different place (#3389) 2023-11-17 19:20:44 +00:00
Alexander Bondarenko 42e0400014 core: add remote controller discovery with multicast (#3369)
* draft multicast chat api

* prepare tests

* Plug discovery into chat api

* Add discovery timeout

* post-merge fixes

* rename discovery state to match others

* update for unified invitation

* fix review notices

* rename, remove stack, update simplexmq

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-17 18:50:38 +00:00
Stanislav Dmitrenko 79064e149a desktop: enabled smooth scrolling again (#3388) 2023-11-17 18:19:38 +00:00
Stanislav Dmitrenko 84e09f195c desktop (windows): fix build of CLI (#3387) 2023-11-17 18:19:02 +00:00
Evgeny Poberezkin f6c4e969e4 nix: add openssl to simplexmq, swift flag to simplex-chat (#3386)
* nix: add swift flag

* add openssl for simplexmq to nix

* add openssl to android simplemq, try iOS with enableKTLS = false flag

* fix android
2023-11-17 13:28:10 +00:00
Evgeny Poberezkin 86b916c169 Merge branch 'master' into remote-desktop 2023-11-17 13:02:54 +00:00
Alexander Bondarenko cf102da4d3 remote: add test for rejected ca detection and stability (#3382)
* add test for rejected ca detection and stability

* update mq commit
2023-11-17 11:19:33 +00:00
Evgeny Poberezkin 0d7a048988 nix: patches for armv7a, fix segfault issues, etc (#3383)
* bump mobile-core-tools

* Update deps

* 🤦

* patch

* needs p

* 32bit patches

* bump haskell.nix

* bump again

* fix broken flake.lock

* bump haskell.nix

* bump haskell.nix (to fix darwin)

---------

Co-authored-by: Moritz Angermann <moritz.angermann@gmail.com>
2023-11-16 22:54:54 +00:00
Evgeny Poberezkin d0f3a3d886 rfc: remote UI implementation (#3206) 2023-11-16 21:53:54 +00:00
Evgeny Poberezkin 64f0dbeb61 Merge branch 'master' into remote-desktop 2023-11-16 20:20:04 +00:00
Evgeny Poberezkin 0322b9708b desktop, ios: remote desktop/mobile connection (#3223)
* ui: remote desktop/mobile connection (WIP)

* add startRemoteCtrl and capability (does not work)

* re-add view

* update core library

* iOS connects to CLI

* ios: mobile ui

* multiplatform types

* update lib

* iOS and desktop connected

* fix controllers list on mobile

* remove iOS 16 paste button

* update device name

* connect existing device

* proposed model

* missing function names in exports

* unused

* remote host picker

* update type

* update lib, keep iOS session alive

* better UI

* update network statuses on switching remote/local hosts

* changes

* ios: prevent dismissing sheet/back when session is connected

* changes

* ios: fix back button asking to disconnect when not connected

* iOS: update type

* picker and session code

* multiplatform: update type

* menu fix

* ios: better ux

* desktop: better ux

* ios: options etc

* UI

* desktop: fix RemoteHostStopped event

* ios: open Use from desktop via picker

* desktop: "new mobile device"

* ios: load remote controllers synchronously, update on connect, fix alerts

* titles

* changes

* more changes to ui

* more and more changes in ui

* padding

* ios: show desktop version, handle errors

* fix stopped event

* refresh hosts always

* radical change

* optimization

* change

* ios: stop in progress session when closing window

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-11-16 16:53:44 +00:00
Alexander Bondarenko c31ae39617 remote: fix circular error handling (#3380) 2023-11-16 14:56:39 +00:00
Alexander Bondarenko 339c3d2be1 Send CRRemote*Stopped on all errors (#3376)
* Send CRRemote*Stopped on all errors

Commands use the same action, made idempotent and don't send events.

* fix tests

* get http2 cancelling back
2023-11-15 17:31:36 +00:00
Alexander Bondarenko a75fce8dfa Fix hostStore path and check before removing (#3375) 2023-11-15 15:57:29 +00:00
Evgeny Poberezkin b71daed3ec core: include session code in all session states (#3374) 2023-11-15 13:17:31 +00:00
Alexander Bondarenko fa9d61caa4 remove host store in deleteRemoteHost (#3373) 2023-11-15 13:09:52 +00:00
spaced4ndy 975f6d488e android: fix group join via invitation chat item (#3372) 2023-11-15 11:46:45 +04:00
Evgeny Poberezkin 3d617bce25 core: test JSON conversion (#3370) 2023-11-14 22:40:15 +00:00
Evgeny Poberezkin d4ba1bbe69 core: update remote host session state (#3371) 2023-11-14 22:27:21 +00:00
Evgeny Poberezkin 0a4920daae core: encrypt stored/loaded remote files (#3366)
* core: encrypt stored/loaded remote files

* simplexmq

* constant
2023-11-14 16:44:12 +00:00
spaced4ndy 36509a6d79 ios, android: new message decryption error - ratchet synchronization (#3368) 2023-11-14 19:39:32 +04:00
Evgeny Poberezkin 4da1d21c81 Merge branch 'master' into remote-desktop 2023-11-14 14:43:58 +00:00
spaced4ndy 5bbde22ffa core: new message decryption error - ratchet synchronization (#3367) 2023-11-14 18:23:05 +04:00
Evgeny Poberezkin 1e8ae6d861 docs: update windows app link 2023-11-14 09:37:24 +00:00
Evgeny Poberezkin f9df5aa41b Merge branch 'master' into remote-desktop 2023-11-13 20:41:51 +00:00
Evgeny Poberezkin c91625b32a core: update remote host session state, terminate TLS in one more case (#3364)
* core: update remote host session state, terminate TLS in one more case

* name
2023-11-13 20:16:34 +00:00
Alexander Bondarenko 598b6659cc core: better handling of remote errors (#3358)
* Allow ExitCode exceptions to do their job

* Use appropriate error type

* Close TLS server when cancelling connected remote host

* Add timeout errors

* Bump simplexmq

* extract common timeout value
2023-11-13 18:39:41 +00:00
Evgeny Poberezkin a2fe5cfb66 core: fix incorrect JSON serialization (#3361) 2023-11-13 17:45:10 +00:00
Evgeny Poberezkin 86bc70fa5a Merge branch 'master' into remote-desktop 2023-11-13 14:07:31 +00:00
Stanislav Dmitrenko 338417d963 desktop: catch unreadable crypto file (#3359) 2023-11-13 14:06:01 +00:00
Evgeny Poberezkin 72b25385ba core: event when new remote host added (#3355) 2023-11-12 21:43:43 +00:00
Evgeny Poberezkin 92e3f576ca core: return controller app info in response when connecting, validate ID key (#3353) 2023-11-12 14:40:49 +00:00
spaced4ndy 5beeff5cb6 core: take chat lock when synchronizing ratchet (#3349) 2023-11-12 12:41:41 +00:00
Evgeny Poberezkin 8e3e58cac8 core: update remote controller name (#3352) 2023-11-12 12:40:13 +00:00
Evgeny Poberezkin 8b67ff7a00 core: remote error handling (#3347)
* core: remote error handling

* fix test, show DB errors
2023-11-11 16:03:12 +00:00
Evgeny Poberezkin beb22c6f87 Merge branch 'master' into remote-desktop 2023-11-11 13:53:51 +00:00
Evgeny Poberezkin 11362941fd 5.4.0-beta.3: iOS 181, Android 160, Desktop 16 2023-11-11 12:12:04 +00:00
Evgeny Poberezkin b1101fbce4 Merge branch 'master' into remote-desktop 2023-11-11 09:49:22 +00:00
Evgeny Poberezkin f7b4e4b16a core: 5.4.0.3 2023-11-11 09:36:16 +00:00
Evgeny Poberezkin 97fd6a993e Merge branch 'master' into remote-desktop 2023-11-10 22:22:04 +00:00
Evgeny Poberezkin 83aaaa9ada translation: remove duplicate string 2023-11-10 20:45:41 +00:00
Stanislav Dmitrenko ae286124aa ios: allow sound in silent mode (#3346)
Co-authored-by: Avently <avently@local>
2023-11-10 19:27:06 +00:00
Evgeny Poberezkin 9cc232054c website: translations (#3345)
* core: notify contact about contact deletion

* Translated using Weblate (French)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Italian)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Hebrew)

Currently translated at 34.1% (86 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/he/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/es/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/zh_Hans/

* Translated using Weblate (Hebrew)

Currently translated at 41.2% (104 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/he/

* Translated using Weblate (Hebrew)

Currently translated at 74.6% (188 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/he/

* Translated using Weblate (Czech)

Currently translated at 92.0% (232 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/cs/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Hebrew)

Currently translated at 90.4% (228 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/he/

* Translated using Weblate (Hebrew)

Currently translated at 94.8% (239 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/he/

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/he/

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/he/

* Translated using Weblate (German)

Currently translated at 100.0% (252 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: ItaiShek <itaishek@gmail.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Eric <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: mlanp <github@lang.xyz>
2023-11-10 17:57:02 +00:00
Alexander Bondarenko 227007c8f6 add /switch remote host (#3342)
* Add SwitchRemoteHost

* Add message test

* Match remote prefix and the rest of the line

* Move prefix match to utils
2023-11-10 17:49:23 +00:00
Evgeny Poberezkin e17e6adefb ui: translations (#3343)
* Translated using Weblate (French)

Currently translated at 100.0% (1387 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1250 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1387 of 1387 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% (1250 of 1250 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% (1387 of 1387 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% (1250 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Japanese)

Currently translated at 98.6% (1233 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/

* Translated using Weblate (Japanese)

Currently translated at 99.2% (1376 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1383 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (German)

Currently translated at 100.0% (1387 of 1387 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% (1250 of 1250 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 98.0% (1360 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1250 of 1250 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 100.0% (1387 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (1387 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/he/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1387 of 1387 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% (1387 of 1387 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% (1250 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1387 of 1387 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% (1250 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1387 of 1387 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% (1250 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1387 of 1387 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% (1250 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Czech)

Currently translated at 100.0% (1387 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Russian)

Currently translated at 99.5% (1381 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* Translated using Weblate (Czech)

Currently translated at 100.0% (1387 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1387 of 1387 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 100.0% (1250 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Russian)

Currently translated at 100.0% (1387 of 1387 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% (1387 of 1387 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% (1250 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1387 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1250 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Czech)

Currently translated at 100.0% (1387 of 1387 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 99.9% (1249 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/cs/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1383 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Finnish)

Currently translated at 99.2% (1376 of 1387 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fi/

* Translated using Weblate (Finnish)

Currently translated at 98.9% (1237 of 1250 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fi/

* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/

* corrections

* correction

* fix android translations

* ios: import/export localizations

---------

Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: a4318 <dalse.077@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Jan Čejka <posta@jancejka.cz>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: ItaiShek <itaishek@gmail.com>
Co-authored-by: Eric <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: pazengaz <pazengaz@porcod.io>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Shamil Bikineyev <shamilbi@gmail.com>
Co-authored-by: sith-on-mars <groguko34@skiff.com>
Co-authored-by: Jiri Grönroos <jiri.gronroos@iki.fi>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
2023-11-10 16:31:59 +00:00
Evgeny Poberezkin 02225df274 core: remote control command/response encryption and signing inside TLS (#3339)
* core: remote control command/response encryption inside TLS (except files, no signing)

* sign/verify

* update simplexmq

* fix lazy

* remove RSNone
2023-11-10 16:10:10 +00:00
Stanislav Dmitrenko e7d6ed66da android: fix crash when playing recorded voice message (#3325)
* android: fix crash when playing recorded voice message

* better
2023-11-10 16:09:19 +00:00
Stanislav Dmitrenko 8d891005d9 ui: disable expanding one item (#3344)
* ui: disable expanding one item

* better

* when
2023-11-10 16:09:01 +00:00
Stanislav Dmitrenko f648086934 windows: upgrade UUID (#3341) 2023-11-10 11:50:31 +00:00
Stanislav Dmitrenko fcdd8ce7c1 windows: script for building the lib (#3340)
* windows: script for building the lib

* changes

* change

* change
2023-11-10 11:49:53 +00:00
spaced4ndy c0be36737d android: connect with contact via address (for preset simplex contact) (#3330) 2023-11-10 10:16:28 +04:00
spaced4ndy f49ded5ae5 ios: connect with contact via address (for preset simplex contact) (#3323)
* ios: connect with contact via address (for preset simplex contact)

* remove diff

* remove floating button

* refactor active

* open chat

* remove disabled

* fix incognito

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-10 10:16:06 +04:00
Alexander Bondarenko f41861c026 core: terminate remote control TLS connection on both sides (#3338)
* handle session setup errors

* add command/async wrapper

* move furniture around

* detect disconnects and force them with closeConnection

* simplify http server log

* close TLS in other cases

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-09 22:43:44 +00:00
Alexander Bondarenko 6d4febb669 core: handle remote control session setup errors (#3332)
* handle session setup errors

* add command/async wrapper

* move furniture around
2023-11-09 18:25:05 +00:00
Evgeny Poberezkin 3dd62ab05a core: remove Hello from the app remote protocol (#3336) 2023-11-09 09:37:56 +00:00
Stanislav Dmitrenko 96d94d3438 android, desktop: fix linking (#3333)
Co-authored-by: avently <avently@local>
2023-11-09 07:55:01 +00:00
Alexander Bondarenko b729144773 core: use xrcp protocol for desktop/mobile connection (#3305)
* WIP: start working on /connect remote ctrl

OOB is broken, requires fixing simplexmq bits.

* WIP: pull CtrlCryptoHandle from xrcp

* place xrcp stubs

* WIP: start switching to RemoteControl.Client types

* fix http2 sha

* fix sha256map.nix

* fix cabal.project

* update RC test

* WIP: add new remote session

* fix compilation

* simplify

* attach HTTP2 server to TLS

* starting host session in controller (WIP)

* more WIP

* compiles

* compiles2

* wip

* pass startRemote' test

* async to poll for events from host, test to send messages fails

* move xrcp handshake test to simplexmq

* detect session stops

* fix connectRemoteCtrl

* use step type

* app info

* WIP: pairing stores

* plug in hello/appInfo/pairings

* negotiate app version

* update simplexmw, remove KEM secrets from DB

* fix file tests

* tone down http2 shutdown errors

* Add stored session test

* bump simplexmq tag

* update simplexmq

* refactor, fix

* removed unused errors

* rename fields, remove unused file

* rename errors

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-08 20:13:52 +00:00
Evgeny Poberezkin 3839267f88 Merge branch 'master' into remote-desktop 2023-11-08 13:10:42 +00:00
Evgeny Poberezkin d233d07ddc ci: ghc 9.6.3 (#3328) 2023-11-08 12:50:56 +00:00
spaced4ndy 8722d35278 core: fix deletion of contact without connections (#3327) 2023-11-08 13:15:08 +04:00
spaced4ndy ee6bd0f839 core: add image to simplex contact profile (#3326) 2023-11-08 10:56:55 +04:00
Stanislav Dmitrenko e3938f6fb5 android: replaced function that requires higher API (#3324) 2023-11-07 22:58:19 +00:00
Stanislav Dmitrenko 2dc621a56c mobile: keep screen on while playing/recording media (#3317)
* android: keep screen on while playing/recording media

* ios: keep screen on while playing/recording media

* different implementation on ios

* Revert "android: keep screen on while playing/recording media"

This reverts commit d291f006e9.

* different implementation on android

* refactor

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-07 16:56:38 +00:00
Stanislav Dmitrenko 3e46c5dfaf android: fixed crash on device rotation in Create link screen (#3322) 2023-11-07 16:48:32 +00:00
spaced4ndy a04dc5d05b core: preset simplex contact (#3321) 2023-11-07 17:45:59 +04:00
Evgeny Poberezkin 2776d864a8 Merge branch 'master' into remote-desktop 2023-11-06 11:44:12 +00:00
Evgeny Poberezkin b33fe01e49 core: switch to GHC 9.6.3 (#3307)
* Various fixes aggregated
- windows definisions
- set compile rto 9.6.3
- flake adjust to 9.6.3
- update haskellNix
- add various patches

* Unbreak iOS

* update script and sha256map.nix

* ios: update core lib

---------

Co-authored-by: Moritz Angermann <moritz.angermann@gmail.com>
2023-11-06 11:43:43 +00:00
spaced4ndy 15b55f7924 ios, android: fix contactInfo response encoding (#3319) 2023-11-06 13:43:37 +04:00
Evgeny Poberezkin 177112ab18 update simplexmq 2023-11-04 19:04:40 +00:00
Evgeny Poberezkin c2a99987f3 Merge branch 'master' into remote-desktop 2023-11-04 18:54:12 +00:00
Stanislav Dmitrenko eee233bd02 android, desktop: catching decoding errors (#3314) 2023-11-04 17:21:29 +00:00
Stanislav Dmitrenko 10cbb13c26 desktop: screen sharing in video calls (#3310)
* desktop: screen sharing

* use async function

* fit/fill of the video

* disconnect camera button from screen share

* enable video on audio call

* temp

* Revert "temp"

This reverts commit 8f8a2f7f88.

* Revert "enable video on audio call"

This reverts commit 120068d09a.

* different logic

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-04 16:59:07 +00:00
Evgeny Poberezkin 4816150b99 core: contacts without connections (#3313)
* core: contacts without connections

* compiles (some tests don't pass)

* remove commented code

* filter out user contact (fixes tests)

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-11-03 18:15:07 +00:00
Stanislav Dmitrenko 3d7258fa58 android: fixed QR code sharing (#3311)
* android: fixed QR code sharing

* remove mime type change

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-02 23:11:26 +00:00
Stanislav Dmitrenko c462dd3704 android, desktop: removed unused plugin (#3309) 2023-11-02 20:59:16 +00:00
Evgeny Poberezkin 0cc26d192d update sha256map.nix 2023-11-02 14:07:51 +00:00
Evgeny Poberezkin 8546c937b2 Merge branch 'master' into remote-desktop 2023-11-02 14:04:10 +00:00
Evgeny Poberezkin 34b07d6a3b core: update simplexmq (http2 lib update to fix sending files) 2023-11-02 10:44:24 +00:00
Stanislav Dmitrenko fad5128a83 android, desktop: updated Compose and changed mac notarization tool (#3303)
* android, desktop: updated Compose and changed mac notarization tool

* imports

* desktop (mac): fix lib building

* imports

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-01 19:11:04 +00:00
Evgeny Poberezkin 8482dbfd99 core: update remote API commands/events (#3295)
* core: update remote API

* Add session verification event between tls and http2

* roll back char_ '@' parsers

* use more specific parser for verification codes

* cabal.project.local for mac

---------

Co-authored-by: IC Rainbow <aenor.realm@gmail.com>
2023-11-01 19:08:36 +00:00
Stanislav Dmitrenko 4fd38a270c desktop: adding build version code to UI (#3304) 2023-11-01 18:23:41 +00:00
Evgeny Poberezkin b2f9270452 Merge branch 'master' into remote-desktop 2023-11-01 18:05:51 +00:00
Stanislav Dmitrenko 4cc20a2d32 android, desktop: block members (#3290)
* android, desktop: block members

* fixes

* more fixes

* fix

* fix

* color

* color and icon

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-01 13:52:45 +00:00
spaced4ndy 68873464d7 docs: groups integrity DAGs rfc (#3258) 2023-11-01 17:30:40 +04:00
spaced4ndy c1a0486c1d docs: groups integrity rfc (#3128) 2023-11-01 17:30:19 +04:00
Evgeny Poberezkin c8c17a2f68 core: fix uri parse to not include trailing punctuation in URIs (#3296)
* core: fix uri parse to not include trailing punctuation in URIs

* simplify
2023-11-01 13:10:19 +00:00
Alexander Bondarenko 02c0cd5619 Cut at attaching http server/client (#3299)
* Cut at attaching http server/client

* switch to xrcp branch
2023-11-01 10:48:58 +00:00
Evgeny Poberezkin 9e8084874f ios: block members (#3248)
* ios: block members (WIP)

* CIBlocked, blocking api

* show item as blocked

* show blocked and merge multiple deleted items

* update block icons

* split sent and received deleted to two categories

* merge chat feature items, refactor CIMergedRange

* merge feature items, two profile images and names on merged items

* ensure range is withing chat items range

* merge group events

* fix/refactor

* make group member changes observable

* exclude some group events from merging

* fix states not updating and other fixes

* load list of members when tapping profile

* refactor

* fix incorrect merging of sent/received marked deleted

* fix incorrect expand/hide on single moderated items without content

* load members list when opening member via item

* comments

* fix member counting in case of name collision
2023-10-31 09:44:57 +00:00
spaced4ndy 07173f7b2f core: add delays to testXFTPMarkToReceive test (#3294) 2023-10-31 10:51:20 +04:00
spaced4ndy 42458a2715 ios, android: process new group link events (#3293) 2023-10-31 10:51:02 +04:00
spaced4ndy b1fdc936a6 Merge branch 'master' into remote-desktop 2023-10-30 20:58:39 +04:00
spaced4ndy f34bbdbd9c core: improve group link protocol (immediately establish group connection without first creating contact) (#3288) 2023-10-30 20:40:20 +04:00
Alexander Bondarenko be44632b0b implement some of the robust discovery rfc (#3283)
* implement robust discovery

* remove qualified

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-30 14:00:54 +00:00
Evgeny Poberezkin b48690dee6 Merge branch 'master' into remote-desktop 2023-10-29 19:15:08 +00:00
Evgeny Poberezkin d90da57f12 core: store/get remote files (#3289)
* core: store remote files (wip)

* fix/test store remote file

* get remote file

* get file

* validate remote file metadata before sending to controller

* CLI commands, test

* update store method
2023-10-29 19:06:32 +00:00
Evgeny Poberezkin 9568279b0f update simplexmq 2023-10-29 18:21:51 +00:00
Evgeny Poberezkin 9fb2b7fe73 Merge branch 'master' into remote-desktop 2023-10-29 18:05:03 +00:00
spaced4ndy a7b5dfb74c android: create new group with incognito membership (#3285) 2023-10-27 09:33:59 +04:00
spaced4ndy 7102723c23 ios: create new group with incognito membership (#3284)
* ios: create new group with incognito membership

* layout

* fix button

* update layout

* layout

* layout

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-26 18:51:45 +04:00
Evgeny Poberezkin 16bda26022 core: derive JSON with TH (#3275)
* core: derive JSON with TH

* fix tests

* simplify events

* reduce diff

* fix

* update simplexmq

* update simplexmq
2023-10-26 15:44:50 +01:00
spaced4ndy 4a5fdd3e0e ios, android: show progress indicator on joining group (#3281) 2023-10-26 10:32:11 +04:00
Evgeny Poberezkin 3790752378 Merge branch 'master' into remote-desktop 2023-10-26 00:00:58 +01:00
Alexander Bondarenko cd98fabe43 robust discovery RFC (#3276)
* add new discovery RFC

* update

* update

* update ports

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-25 16:39:46 +01:00
Evgeny Poberezkin 4a8da196ad core: more permissive display name validation, only allow single quotes in CLI for the names with spaces (#3282) 2023-10-25 11:55:06 +01:00
Stanislav Dmitrenko 743597e848 ios: making message text view working better (#3279)
* ios: making message text view working better

* style for ternaries

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-25 09:56:59 +01:00
spaced4ndy b0f55d6de5 core: update simplexmq (check snd queue) (#3280) 2023-10-25 10:45:36 +04:00
Evgeny Poberezkin 6185971827 Merge branch 'master' into remote-desktop 2023-10-24 23:19:49 +01:00
Stanislav Dmitrenko 1dcd2760b0 ui: show alert after saving profile with existing name (#3273)
* android, desktop: show alert after saving profile with existing name

* ios: show alert after saving profile with existing name

* return statements

* better way of showing alert

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-24 23:01:47 +01:00
Stanislav Dmitrenko 10f79aae66 android: alert on unsupported file path when sharing (#3265)
* android: alert on unsupported file path when sharing

* update text

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-24 21:39:43 +01:00
Stanislav Dmitrenko b58d61c339 android: delete files after sharing correctly (#3264) 2023-10-24 21:27:58 +01:00
spaced4ndy 239765e482 core: create new group with incognito membership (#3277) 2023-10-24 20:59:06 +04:00
spaced4ndy f8332bac7f core: take chat lock earlier when joining group (#3272) 2023-10-24 18:13:19 +04:00
spaced4ndy ed1eef7362 core: update simplexmq (inv locks) (#3274) 2023-10-24 17:38:16 +04:00
Evgeny Poberezkin 66d8bb94d6 website: downloads page 2023-10-23 21:16:36 +01:00
Evgeny Poberezkin 6eb09625ab website: update copy 2023-10-23 20:53:12 +01:00
Alexander Bondarenko e1bd6a93af use multicast address for announce (#3241)
* use multicast address for announce

* Add explicit multicast group membership

* join multicast group on a correct side

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-23 13:44:04 +01:00
Evgeny Poberezkin 93800268e4 Merge branch 'master' into remote-desktop 2023-10-23 10:04:51 +01:00
Evgeny Poberezkin 0bd59364fd 5.4.0-beta.2: iOS 180, Android 159, Desktop 15 2023-10-22 22:43:23 +01:00
Evgeny Poberezkin 795c54343a android, desktop: reduce browser call logs, check Worker availability directly (#3256) 2023-10-22 20:51:08 +01:00
Evgeny Poberezkin f026a38a75 ios: update core library 2023-10-22 19:22:46 +01:00
Stanislav Dmitrenko 530ec70171 android, desktop: support calls on desktop and moved www dir to different root (#3219)
* android, desktop: support calls on desktop and moved www dir to different root

* add page title, fix links on Android, change timeouts

* using worker in desktop Chrome and Safari

* ui changes

* end call button in app bar

* fix android

* a lot of enhancements

* fix after merge master

* layout

* sound play on call

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-22 18:47:27 +01:00
Era Dorta 1401f56288 cli: update docker image to use ghc 9.6.2 (#3234) 2023-10-22 18:15:15 +01:00
Evgeny Poberezkin d172b0cb6d Merge branch 'stable' 2023-10-22 17:51:30 +01:00
Evgeny Poberezkin 3e0b6826bf ios: 5.3.2 build 179 2023-10-22 17:50:08 +01:00
Evgeny Poberezkin 79275424ea core: 5.4.0.2 2023-10-22 15:06:55 +01:00
Evgeny Poberezkin b25c2e3a09 ui: add 10 minutes SimpleX Lock delay (#3255) 2023-10-22 14:56:51 +01:00
Evgeny Poberezkin 8891314507 core: update simplexmq (fixes ordering issue during message delivery) 2023-10-22 14:19:24 +01:00
Evgeny Poberezkin 5c57987e9f add smp11, 12 and 14 to preset servers 2023-10-22 13:58:51 +01:00
Evgeny Poberezkin b5e114d834 Merge branch 'master' into remote-desktop 2023-10-22 13:04:15 +01:00
Alexander Bondarenko 0d1a080a6e remote protocol (#3225)
* draft remote protocol types and external api

* types (it compiles)

* add error

* move remote controller from http to remote host client protocol

* refactor (doesnt compile)

* fix compile

* Connect remote session

* WIP: wire in remote protocol

* add commands and events

* cleanup

* fix desktop shutdown

* prepare for testing remote files

* Add file IO

* update simplexmq to master

with http2 to 4.1.4

* use json transcoder

* update simplexmq

* collapse RemoteHostSession states

* fold RemoteHello back into the protocol command
move http-command-response-http wrapper to protocol

* use sendRemoteCommand with optional attachments
use streaming request/response

* ditch lazy body streaming

* fix formatting

* put body builder/processor closer together

* wrap handleRemoteCommand around sending files

* handle ChatError's too

* remove binary, use 32-bit encoding for JSON bodies

* enable tests

* refactor

* refactor request handling

* return ChatError

* Flatten remote host

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-22 09:42:19 +01:00
Evgeny Poberezkin 0444367002 Merge branch 'master' into remote-desktop 2023-10-21 19:07:30 +01:00
spaced4ndy 87d84cfccc core: filter connection plan query results by user_id (#3251) 2023-10-21 19:13:32 +04:00
spaced4ndy c090b68bdd ios, android: ask to notify contact or not on contact deletion (#3247) 2023-10-19 19:52:59 +04:00
Evgeny Poberezkin 2219cea026 core: fix type for JSON 2023-10-18 21:15:37 +01:00
spaced4ndy 852e77b1d9 android: connect plan (#3242) 2023-10-18 16:58:33 +04:00
Evgeny Poberezkin 706d6bf65b core, ui: prevent old sent items re-added to chat, and "new" status overriding "sent" (#3246)
* core, ui: prevent old sent items re-added to chat, and "new" status overriding "sent"

* clear item statuses when changing current chat

* remove iOS hack

* remote state/published from chatItemStatuses
2023-10-18 11:23:35 +01:00
Evgeny Poberezkin a02886ca5d core: fix editing and status changes removing reactions from view (#3245)
* core: fix editing and status changes removing reactions from view

* refactor

* refactor 2

* case
2023-10-18 10:19:24 +01:00
Evgeny Poberezkin 29c8ab7c9b ui: file & media preference for groups (#3243) 2023-10-17 18:05:16 +01:00
spaced4ndy d8d47d706d ios: connection plan improvements; remove browser mode for simplex links (#3237) 2023-10-17 12:56:12 +04:00
spaced4ndy 99c458406f android: remove browser mode for simplex links (#3239) 2023-10-17 11:44:35 +04:00
Evgeny Poberezkin 92eae012b3 Merge branch 'master' into remote-desktop 2023-10-16 21:38:54 +01:00
spaced4ndy e4c8386f3f core: replace simplex:/ with simplex.chat links in view; remove trustedUri flag from simplex links markdown format (#3235) 2023-10-16 19:23:38 +04:00
spaced4ndy 9ed31261e1 core: check saved links and hashes by both connection request uri schemas for connection plan (#3233) 2023-10-16 16:16:03 +04:00
spaced4ndy 4b6df43e97 core: confirm to reconnect via address plan (#3212)
* core: confirm to reconnect plan

* rework query to prefer connections with contacts
2023-10-16 16:10:56 +04:00
Evgeny Poberezkin 43b67ba157 ui: set local file encryption in the core (#3227) 2023-10-15 20:58:39 +01:00
Evgeny Poberezkin e6b0983c3e Merge branch 'stable' 2023-10-15 18:52:46 +01:00
Evgeny Poberezkin c2a320640b core: local encryption for auto-received inline files (e.g. small voice messages) (#3224)
* core: local encryption for auto-received inline files

* update view, test
2023-10-15 18:16:12 +01:00
Evgeny Poberezkin 838751fe78 ios: fix Protect screen not hiding message previews (#3226) 2023-10-15 18:12:13 +01:00
Evgeny Poberezkin fc1bba8817 remote: refactor (WIP) (#3222)
* remote: refactor (WIP)

* refactor discoverRemoteCtrls

* refactor processRemoteCommand, storeRemoteFile

* refactor fetchRemoteFile

* refactor startRemoteHost, receiving files

* refactor relayCommand
2023-10-15 14:17:36 +01:00
Evgeny Poberezkin 41b86e07f1 core: update api (#3221) 2023-10-15 00:18:04 +01:00
Evgeny Poberezkin f5e9bd4f8b core: add set display name (#3216)
* core: add set display name

* enable all tests
2023-10-14 13:10:06 +01:00
Evgeny Poberezkin 5e6aaffb09 simplify remote api, add ios api (#3213) 2023-10-13 22:35:30 +01:00
Evgeny Poberezkin a35dc263b7 website: remove address from connect page 2023-10-13 22:28:55 +01:00
Alexander Bondarenko 193361c09a core: fix remote handshake test (#3209)
* Fix remoteHandshakeTest

Sidesteps some yet to be uncovered bug when
mobile stops its side before the desktop.

* remove ambiguous update warning

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-13 18:53:04 +01:00
Evgeny Poberezkin 392447ea33 core: fix test 2023-10-13 17:52:27 +01:00
Evgeny Poberezkin 5d4006f291 Merge branch 'master' into remote-desktop 2023-10-13 17:46:14 +01:00
spaced4ndy c609303348 ios: connect plan (#3205)
* ios: connect plan

* improvements

* wording

* fixes

* rework to use dismissAllSheets with callback

* rework

* update texts

* Update apps/ios/Shared/Views/NewChat/NewChatButton.swift

* Update apps/ios/Shared/Views/NewChat/NewChatButton.swift

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-13 19:19:00 +04:00
Evgeny Poberezkin 07047a3ef3 ios: fix pattern match 2023-10-13 14:29:48 +01:00
Evgeny Poberezkin ab290fb068 core: track network statuses, use in commands/events (#3211)
* core: track network statuses, use in commands/events

* ui types, test

* remove comment
2023-10-13 11:51:01 +01:00
Stanislav Dmitrenko 675fc19745 rfc: desktop calls (#3208)
* rfc: desktop calls

* errors

* html

* link

* screen sharing

* additions

* addition

* correction

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-13 00:05:06 +01:00
Alexander Bondarenko fe6c65f75c rfc: remote profile (#3051)
* Add session UX for mobile and desktop

* Resolve some feedback

* Resolve more feedback

Add QR note for desktops.
Add TLS handshake notice.

* Add details
2023-10-12 15:19:19 +01:00
Stanislav Dmitrenko 8ffe1c23c1 android, desktop: better handling of parallel updates of chats (#3204)
* android, desktop: better handling of parallel updates of chats

* one more case
2023-10-12 13:19:57 +01:00
Evgeny Poberezkin 6dca71cc87 Merge branch 'master' into remote-desktop 2023-10-12 11:40:23 +01:00
Alexander Bondarenko adc1f8c983 android, desktop: remote kotlin types (#3200)
* Add remote types to Kotlin

* update response info for chat console

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-12 10:58:59 +01:00
Evgeny Poberezkin 73652e4bba Merge branch 'master' into remote-desktop 2023-10-12 10:43:59 +01:00
spaced4ndy 5d078bec53 tests: simplify testMemberContactInvitedConnectionReplaced (for stable) 2023-10-12 12:21:03 +04:00
spaced4ndy b956988a83 tests: simplify testMemberContactInvitedConnectionReplaced (for stable) 2023-10-12 12:20:31 +04:00
spaced4ndy 247f2c9e61 tests: modify testMemberContactInvitedConnectionReplaced to not rely on chat item order, print output (#3198) 2023-10-12 11:55:38 +04:00
spaced4ndy 7b488c7f1b tests: improve tests (#3203) 2023-10-12 11:52:14 +04:00
Evgeny Poberezkin 4df8ea2e78 ui: update types for notification and member settings (#3201) 2023-10-11 23:07:05 +01:00
Evgeny Poberezkin 8ff6b392c2 core: rename "reference" to "mention" 2023-10-11 21:15:31 +01:00
Evgeny Poberezkin c2a858b06e core: convert single-field to tagged JSON encoding (#3183)
* core: convert single-field to tagged JSON encoding

* rename

* rename

* fixes, test

* refactor
2023-10-11 19:11:01 +01:00
Evgeny Poberezkin bca9473d77 core: settings to hide member messages, to show only reply (and mention) notifications (#3190)
* core: settings to hide member messages, to show only reply (and mention) notifications

* change type for showMessages

* commands for member settings

* member and notification settings

* test

* take member settings into account when showing messages and notifications

* fix to show sent messages

* store blocked items

* types

* rename to MFMentions
2023-10-11 19:10:38 +01:00
spaced4ndy b03fe183bb tests: modify testMemberContactInvitedConnectionReplaced to not rely on chat item order, print output (#3198) 2023-10-11 15:26:44 +04:00
Evgeny Poberezkin 4ecf94dfad core: move CLI notifications and active chat to view layer (for remote CLI) (#3196)
* core: move CLI notifications to view layer (to allow notifications in remote CLI)

* remove unused

* refactor activeTo

* move activeTo to ChatTerminal

* refactor

* move back

* remove extension
2023-10-11 09:50:11 +01:00
Alexander Bondarenko 6f5ba54f7b core: remote session files (#3189)
* Receiving files on CRRcvFileComplete

* Add remote /fr test

* Add broken startFileTransfer notice

* Sending files with SendFile/SendImage

With tests for SendFile.

* Add APISendMessage handling

* Test file preconditions

No files should be in stores before actual sending.

* Fix mobile paths in storeFile
2023-10-11 09:45:05 +01:00
spaced4ndy a67b79952b core: connection plan api; check connection plan before connecting in terminal api (#3176) 2023-10-10 21:19:04 +04:00
Evgeny Poberezkin eb5081624a Merge branch 'stable' 2023-10-09 19:52:30 +01:00
Evgeny Poberezkin 86c2f29920 5.3.2: ios 178, android 157, desktop 14 2023-10-09 18:30:59 +01:00
Evgeny Poberezkin dffbd32c76 Merge branch 'stable' 2023-10-09 18:04:11 +01:00
Evgeny Poberezkin 3ddf7b2680 ios: close database connections when app is terminating (#3188)
* ios: close database connections when app is terminating

* update

* remove ()

* close when suspended too

* additional check

* fix

* refactore

* reset "terminating" flag
2023-10-09 18:03:03 +01:00
Evgeny Poberezkin c0e22d74c4 core: 5.4.0.1 2023-10-09 17:30:48 +01:00
Evgeny Poberezkin 2b228a893a Merge branch 'master' into remote-desktop 2023-10-09 17:21:47 +01:00
Stanislav Dmitrenko d764b3485a desktop (windows): Github action for packaging (#3167)
* desktop (windows): Github action for packaging

* env

* path changes
2023-10-09 17:10:47 +01:00
Evgeny Poberezkin 09e5798d59 ios: correctly parse json responses (#3193) 2023-10-09 16:56:42 +01:00
Evgeny Poberezkin f31b4e4632 Merge branch 'stable' 2023-10-09 16:00:24 +01:00
spaced4ndy d72c04682f Merge pull request #3174 from simplex-chat/contact-merge-improvements
contact merge improvements
2023-10-09 18:05:46 +04:00
Evgeny Poberezkin 20995c6912 core: 5.3.2.0 2023-10-09 14:35:44 +01:00
Moritz Angermann 73b3ea3648 Drop entropy patch (#3191)
* Drop entropy patch

We don't need the patch anymore. We can set -fDoNotGetEntropy these days to achieve the same.

* remove entropy.patch

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-09 14:04:29 +01:00
Evgeny Poberezkin 2eb213741c Merge branch 'master' into remote-desktop 2023-10-09 10:35:38 +01:00
Evgeny Poberezkin bc26c23d58 fix MobileTests (add single field JSON tag) 2023-10-09 10:35:13 +01:00
spaced4ndy 4a581cb292 Merge branch 'master' into contact-merge-improvements 2023-10-09 10:21:54 +04:00
spaced4ndy ab46cbc5dd core: relax contact probing: don't send probe hashes to new contacts except group link hosts; still send probe hashes to group members (#3180) 2023-10-09 09:46:58 +04:00
Evgeny Poberezkin 985b9837c3 core: api to close database connection (#3186) 2023-10-08 16:22:53 +01:00
Moritz Angermann d50c7ad7f6 bump hackage (#3185) 2023-10-08 08:37:28 +01:00
Evgeny Poberezkin 82faaebb33 Merge branch 'stable' 2023-10-08 08:17:05 +01:00
Stanislav Dmitrenko 76fb5b6dca android: fix lock not showing (#3181)
* android: fix lock not showing

* better fix
2023-10-07 19:00:40 +01:00
Alexander Bondarenko 91561da351 core: http transport for remote session (#3178)
* Wire some of the session endpoints

* Start sending remote commands

* Expand remote controller

- Fix queues for pumping to remote
- Add 3-way test
- WIP: Add TTY wrapper for remote hosts
- Stop remote controller w/o ids to match starting

* Fix view events

* Drop notifications, add message test

* refactor, receive test

* hunt down stray asyncs

* Take discovery sockets in brackets

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-07 14:23:24 +01:00
Evgeny Poberezkin 3ac342782b Merge branch 'master' into remote-desktop 2023-10-07 13:05:22 +01:00
Evgeny Poberezkin b05a45f559 core: updated simplexmq (add tag to platform-specific sum type encoding that uses single field objects with swift/iOS) 2023-10-07 12:32:39 +01:00
spaced4ndy c738c6c522 Merge branch 'master' into contact-merge-improvements 2023-10-06 14:38:56 +04:00
spaced4ndy 1be70169ba docs: contact merge issues rfc (#3179) 2023-10-06 14:27:13 +04:00
Evgeny Poberezkin a273c68596 core: rename migration, pin dependencies 2023-10-05 22:33:48 +01:00
Stanislav Dmitrenko 34e1e44338 android, desktop: profile names (remove full name) (#3177)
* desktop, android: profile names (remove full name)

* rename back

* disallow spaces only in names

* ios: disallow spaces only in names

* changes
2023-10-05 21:49:18 +01:00
Alexander Bondarenko fc9db9c381 core: add FromJSON instance to ChatResponse (#3129)
* Start adding FromJSON instances to ChatResponse

* progress

* FromJSON instance for ChatResponse compiles

* restore removed encodings

* remove comment

* diff

* update simplexmq, use TH for JSON

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-05 19:49:20 +01:00
Evgeny Poberezkin 27e8a81c9f Merge branch 'master' into remote-desktop 2023-10-05 14:15:25 +01:00
spaced4ndy 303d0eedf5 core: merge new contacts with existing contacts and group members (#3173) 2023-10-04 20:58:22 +04:00
Evgeny Poberezkin 0d8558a6d0 ios: profile names (remove full name) (#3168)
* ios: profile names (remove full name)

* create/update groups

* focus display name
2023-10-04 17:45:39 +01:00
Stanislav Dmitrenko 91fc238ddc desktop: libs refactoring (#3169)
* desktop: libs refactoring

* mac fix

* windows fix

* .gitignore

* unused lines

* desktop (windows): adapting Windows build to new libs

* removed unused code

---------

Co-authored-by: avently <avently@local>
2023-10-04 17:06:23 +01:00
Evgeny Poberezkin 7959c75df7 Merge branch 'master' into remote-desktop 2023-10-04 16:37:15 +01:00
Alexander Bondarenko 0bcf5c9c66 Add commands for remote session credentials (#3161)
* Add remote host commands

* Make startRemoteHost async

* Add tests

* Trim randomStorePath to 16 chars

* Add chat command tests

* add view, use view output in test

* enable all tests

* Fix discovery listener host

Must use any, not broadcast on macos.

* Fix missing do

* address, names

* Fix session host flow

* fix test

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-04 16:36:10 +01:00
Stanislav Dmitrenko cc95fa6b30 desktop: paste files/images to attach to message (#3165)
* desktop: paste files/images to attach to message

* Windows

* copy files inside the app

* change

* encrypted files support

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-03 13:46:17 +01:00
Evgeny Poberezkin 38be27271f core: profile names with spaces (#3105)
* core: profile names with spaces

* test

* more test

* update name validation, export C API

* refactor

* validate name when creating profile in CLI

* validate display name in all APIs when it is changed
2023-10-02 21:56:11 +01:00
zenobit da2a94578a typo (#3121) 2023-10-02 21:21:26 +01:00
Stanislav Dmitrenko 77db70139b windows: shortcut for installator (#3156)
Co-authored-by: avently <avently@local>
2023-10-02 17:25:49 +01:00
Stanislav Dmitrenko fdf3da73aa desktop: making chat list item to have a hover effect (#3162)
* desktop: making chat list item to have a hover effect

* changes

* fix

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-02 17:23:38 +01:00
Stanislav Dmitrenko 0d93dab692 android, desktop: added useful logs (#3163) 2023-10-02 15:46:30 +01:00
spaced4ndy d4cbef1ba1 core: notify about contact deletion only if contact is ready, catch errors (#3160) 2023-10-02 16:29:13 +04:00
Evgeny Poberezkin 8545a1e8f9 ci: make docs update rebuild website 2023-10-01 20:46:30 +01:00
Evgeny Poberezkin 157ea59ebb docs: update downloads page 2023-10-01 18:53:58 +01:00
Evgeny Poberezkin 7231201c3c v5.4-beta.0: ios 176, android 156, desktop 12
* desktop: v5.4-beta.0 build 12

* v5.4-beta.0: ios 176, android 156, desktop 12
2023-10-01 18:31:52 +01:00
Stanislav Dmitrenko 695d47da2d desktop: Windows build (#3143)
* desktop: Windows build

* temp

* temp

* new way of libs loading

* new way of libs loading

* Revert "new way of libs loading"

This reverts commit 8632f8a8f7.

* made VLC working on Windows

* unused lib

* scripts

* updated script

* fix path

* fix lib loading

* fix lib loading

* packaging options

* different file manager implementation on Windows

---------

Co-authored-by: Avently <avently.local>
Co-authored-by: avently <avently@local>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-01 13:33:15 +01:00
Evgeny Poberezkin 968d8e9c34 core: 5.4.0.0 2023-10-01 13:19:32 +01:00
Stanislav Dmitrenko d72c9a6de0 desktop: ability to always show terminal view (#3074)
* desktop: ability to always show terminal view

* only show toggle with dev tools enabled

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-01 12:12:17 +01:00
IC Rainbow bf7917bd67 Merge remote-tracking branch 'origin/master' into ab/remote-discover-upd 2023-09-29 18:42:59 +03:00
Alexander Bondarenko 5ce388522e Move toView and withStore* to a common module (#3147) 2023-09-29 15:50:20 +01:00
IC Rainbow 6c0d1b5f15 Notify about handover errors 2023-09-29 16:53:05 +03:00
Evgeny Poberezkin 70a65e8969 core: close stores before import/delete/encryption operations to make compatible with windows, make encryption more resilient (#3146)
* core: close stores before import/delete/encryption operations to make compatible with windows, make encryption more resilient

* remove file names

* do not remove files if already removed
2023-09-29 13:09:48 +01:00
IC Rainbow af2df8d489 Rewrite remote controller 2023-09-29 15:01:05 +03:00
Evgeny Poberezkin 1d34500fba core: revert stop/close changes made for Windows (#3145)
* Revert "core: return error response when wrong passphrase is passed to start"

This reverts commit ea319313f1.

* Revert "core: support closing/re-opening store on chat stop/start (#3132)"

This reverts commit 3c7fc6b0ee.
2023-09-29 11:14:10 +01:00
spaced4ndy bc7baf560b core: filter out connections of deleted contacts and group members on subscribe (#3144) 2023-09-29 11:24:16 +04:00
Stanislav Dmitrenko c1854b7d50 desktop: fix script for building the lib (#3141) 2023-09-28 11:39:43 +01:00
spaced4ndy 682dfe503c android, desktop: notify contact about contact deletion (#3139)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-28 13:52:43 +04:00
spaced4ndy 957f3b3eb0 core: delete unused contact silently (#3140) 2023-09-28 13:16:03 +04:00
Evgeny Poberezkin dea96df27b docs: update join team 2023-09-28 09:26:54 +01:00
Evgeny Poberezkin 942e5eb8c4 docs: update branches 2023-09-27 22:19:20 +01:00
Evgeny Poberezkin ea319313f1 core: return error response when wrong passphrase is passed to start 2023-09-27 21:15:19 +01:00
spaced4ndy bbe329072e ios: notify contact about contact deletion (#3135) 2023-09-27 20:07:32 +04:00
spaced4ndy c64d1e8361 core: notify contact about contact deletion (#3131) 2023-09-27 19:36:13 +04:00
IC Rainbow cccb3e33fb Plug discovery into remote controller UI 2023-09-27 18:24:38 +03:00
Stanislav Dmitrenko 7e17ed7b1b desktop (mac): removing rpaths (#3136)
* desktop (mac): removing rpaths

* one more lib

* added check for dir existence in linking

* new line

* patching libapp on mac
2023-09-27 15:34:46 +01:00
Evgeny Poberezkin 3c7fc6b0ee core: support closing/re-opening store on chat stop/start (#3132)
* core: support closing/re-opening store on chat stop/start

* update .nix refs

* kotlin: types

* add test

* update simplexmq
2023-09-27 15:26:03 +01:00
IC Rainbow 77410e5d5e Add remote host discovery 2023-09-27 13:40:19 +03:00
Stanislav Dmitrenko 8709ad6ff3 desktop: enhanced video player + inline player (#3130)
* desktop: enhanced video player + inline player

* simplify

* simplify

* removed unused code

* follow up

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-27 10:19:48 +01:00
Alexander Bondarenko 3e29c664ac core: remote host/controller types (#3104)
* Start sprinkling ZoneId everywhere

* Draft zone/satellite/host api

* Add zone dispatching

* Add command relaying handler

* Parse commands and begin DB

* Implement discussed things

* Resolve some comments

* Resolve more stuff

* Make bots ignore remoteHostId from queues

* Fix tests and stub more

* Untangle cmd relaying

* Resolve comments

* Add more http2 client funs

* refactor, rename

* rename

* remove empty tests

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-27 09:41:02 +01:00
Evgeny Poberezkin 50d624ef6b blog: move image 2023-09-25 20:09:08 +01:00
Evgeny Poberezkin 11e448267d website: update post, downloads page 2023-09-25 18:12:47 +01:00
Evgeny Poberezkin aacf741ef5 ci: exclude -fdroid tags from github builds 2023-09-25 16:51:10 +01:00
spaced4ndy 420d80ad6c 5.3.1: android 154, ios 174, desktop 11
* 5.3.1

* 5.3.1: ios 174, desktop 11

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-25 16:41:53 +01:00
spaced4ndy 343131c64e core: 5.3.1.0 2023-09-25 17:43:03 +04:00
spaced4ndy 9b107fbdeb core: fix invited member contact (do not display invitation context in UI) (#3122) 2023-09-25 16:39:27 +04:00
spaced4ndy 60d13e258e ios, android: show rcv integrity error items based on developer tools default (#3123) 2023-09-25 16:38:48 +04:00
Evgeny Poberezkin 4f42c2b0d8 blog: v5.3 announcement (#3093)
* blog: v5.3 announcement draft

* update

* update post

* add images and previews

* website: add imageWide property

* website: add .float-to-left class

* update

* update images

* update readme

* fix typo

---------

Co-authored-by: M Sarmad Qadeer <MSarmadQadeer@gmail.com>
2023-09-25 09:32:27 +01:00
Stanislav Dmitrenko 48ae1111a6 desktop: fix lib copy (#3120) 2023-09-25 09:30:44 +01:00
Stanislav Dmitrenko 76dbe32cfc desktop: fix JNI (#3119) 2023-09-25 09:30:21 +01:00
Evgeny Poberezkin 120f42cbba readme: update languages 2023-09-23 18:37:03 +01:00
Evgeny Poberezkin 5f46433f40 docs: update translations in readme 2023-09-23 18:33:54 +01:00
Evgeny Poberezkin 7b71078c76 update downloads page 2023-09-23 17:36:44 +01:00
Evgeny Poberezkin d6b62d0c18 5.3: ios 173, android 152, desktop 10 2023-09-22 21:09:36 +01:00
Evgeny Poberezkin ba4c427bec ios: update core libraries 2023-09-22 17:43:03 +01:00
Evgeny Poberezkin a179154e87 core: 5.3.0.10 2023-09-22 17:20:30 +01:00
Stanislav Dmitrenko 5eea3da7f4 desktop: check chat id before changing chat items (#3103) 2023-09-22 14:59:14 +01:00
Evgeny Poberezkin b3e880ee54 core: optimize C apis (#3100)
* core: optimize C apis

* more

* fix tests

* use pokeByteOff

* write lazy bytestring to buffer without conversion to strict

* avoid conversion of JSON to strict bytestrings
2023-09-22 13:45:16 +01:00
Stanislav Dmitrenko 08ea5dc2e7 desktop: ability to send a video (#3102) 2023-09-22 12:43:45 +01:00
M. Sarmad Qadeer 20f90ee865 website: add feeds filter (#3098) 2023-09-22 09:39:18 +01:00
spaced4ndy 5ca2ab6138 ios: fix delete contact crashing from chat view (#3099) 2023-09-22 12:23:53 +04:00
Evgeny Poberezkin ba61b15225 docs: update downloads 2023-09-22 08:21:00 +01:00
Stanislav Dmitrenko 9ac13a3433 action: prevent AppImage generator from failing a job (#3096)
* action: prevent AppImage generator from failing a job

* corrected
2023-09-21 22:43:48 +01:00
Evgeny Poberezkin b9407c0157 v5.3-beta.9: ios 172, android 151, desktop 9 2023-09-21 20:05:39 +01:00
Evgeny Poberezkin 5e8cfec653 ios: update core library 2023-09-21 19:10:19 +01:00
Evgeny Poberezkin cb10f8b080 ui: optionally encrypt received SMP files (#3095) 2023-09-21 19:02:47 +01:00
Evgeny Poberezkin b7c562fb10 ui: increast default timeouts per KB for XFTP (#3094) 2023-09-21 18:21:49 +01:00
Stanislav Dmitrenko 2d7655281f desktop: video and audio players (#3052)
* desktop: video and audio players

* making player working without preinstalled VLC

* mac support

* don't use vlc lib when not needed

* updated jna version

* changes in script

* video player lazy loading

* mac script changes

* updated build gradle for preserving atrributes of file while copying

* apply the same file stats on libs to make VLC checker happy

* updated script

* changes

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-21 18:03:47 +01:00
Evgeny Poberezkin 6de0ed4766 core: 5.3.0.9 2023-09-21 17:03:56 +01:00
Stanislav Dmitrenko 5b87206c22 desktop: AppImage metadata (#2952)
* desktop: AppImage metadata

* update appimage metadata

* add screenshots

* update screenshots

* update

* update URLs

* update link

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-21 13:19:24 +01:00
Evgeny Poberezkin be3eb740a7 website: redirect to connect to the team 2023-09-21 13:01:18 +01:00
Evgeny Poberezkin bbd778a6be core: update simplexmq (fix xftp agent) 2023-09-21 12:01:21 +01:00
Evgeny Poberezkin 027ce2c559 website: enable Japanese language 2023-09-21 09:34:36 +01:00
Evgeny Poberezkin 02864a894e website: add missing files 2023-09-21 09:28:58 +01:00
Evgeny Poberezkin 3419ce293b website: downloads page (#3088)
* website: downloads page

* link

* website: fix h2 headers issue

* website: fix sidebar issue

* website: fix language changer for downloads page in navbar

* update, add security assessment section

---------

Co-authored-by: M Sarmad Qadeer <MSarmadQadeer@gmail.com>
2023-09-21 09:28:12 +01:00
Evgeny Poberezkin b08768ea71 5.3-beta.8: desktop 8 (#3086)
* unpin unix package

* desktop: 1.6.0, build 8

* action: file hashes (#3087)

* action: file hashes

* better output

* correct name

---------

Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-09-20 21:21:56 +01:00
Evgeny Poberezkin 6f481356f7 5.3-beta.8: ios 171, android 150 (#3085)
* ios: build 171

* android: build 150

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-09-20 18:21:51 +01:00
M. Sarmad Qadeer 0a2513c9e7 website: add careers page (#3039)
* website: add careers page

* website: pagename from careers to career

* website: change pagename from career to jobs

* website: add jobs string to english language strings file

* website: add job tabs

* update

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-20 17:54:02 +01:00
spaced4ndy ae6996b2ee android: create contacts with group members (#3078) 2023-09-20 17:58:10 +04:00
Evgeny Poberezkin 648a9761f9 core: 5.3.0.8 2023-09-20 14:54:46 +01:00
Evgeny Poberezkin ba71a42aa0 website: translations (#3084)
* Translated using Weblate (Dutch)

Currently translated at 100.0% (245 of 245 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% (245 of 245 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>
2023-09-20 14:51:54 +01:00
Evgeny Poberezkin f16388323b ui: translations (#3083)
* Translated using Weblate (Russian)

Currently translated at 100.0% (1381 of 1381 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% (1244 of 1244 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (French)

Currently translated at 100.0% (1381 of 1381 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1244 of 1244 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1381 of 1381 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% (1244 of 1244 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% (1381 of 1381 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% (1244 of 1244 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Arabic)

Currently translated at 99.5% (1375 of 1381 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 100.0% (1381 of 1381 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 100.0% (1244 of 1244 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1244 of 1244 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 100.0% (1381 of 1381 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Russian)

Currently translated at 100.0% (1381 of 1381 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% (1244 of 1244 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (French)

Currently translated at 100.0% (1381 of 1381 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1244 of 1244 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1381 of 1381 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% (1244 of 1244 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% (1381 of 1381 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% (1244 of 1244 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Arabic)

Currently translated at 99.5% (1375 of 1381 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 100.0% (1381 of 1381 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 100.0% (1244 of 1244 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1244 of 1244 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 100.0% (1381 of 1381 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1381 of 1381 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.2% (1235 of 1244 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* import/export localizations

---------

Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: Citrus <cwuni@126.com>
2023-09-20 14:48:26 +01:00
Evgeny Poberezkin 92ac3e2a8a core: update contact and member profiles for both sides when contact is created with member (WIP) (#3081)
* core: update contact and member profiles for both sides when contact is created with member (WIP)

* send both sides, correctly process update

* refactor

* revert diff

* comments

* test

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-09-20 16:45:04 +04:00
Evgeny Poberezkin 52966e7e3d core: optionally encrypt SMP files (#3082)
* core: optionally encrypt SMP files

* encrypt to temp file and rename or remove encryption args if it fails

* fix file encryption error handling
2023-09-20 13:05:09 +01:00
Evgeny Poberezkin f19fae615d ios: add Bulgarian language 2023-09-20 10:53:54 +01:00
spaced4ndy 0dab4491e2 ios: create contacts with group members (#3077)
* wip

* observed

* network status

* contact ready

* add padding

* Update apps/ios/Shared/Views/Chat/ComposeMessage/ContextInvitingContactMemberView.swift

* setContactNetworkStatus

* update text

* different context view

* update text, icon

* spinner

* reload all chats on swipe

* Revert "reload all chats on swipe"

This reverts commit 22c8372301.

* export localizations

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-20 09:26:16 +01:00
spaced4ndy 1928256b09 core: connect existing contacts to new members when profile matches, enable skipping direct connections in groups (#3056)
* core: test group members are assigned different LDNs in group when direct connections aren't created

* disable test output

* core: connect existing contacts to new members when profile matches (#3059)

* core: connect existing contacts to new members when profile matches

* fix migration

* progress

* xInfoProbeOk for member

* fix tests

* add test

* fix tests

* tests

* remove deleteSentProbe

* remove deleteContactProfile_

* views

* don't check connections in deleteUnusedProfile_

* Revert "don't check connections in deleteUnusedProfile_"

This reverts commit 2016a0efde.

* fix test

* core: update member merge

* update saved schema

* fix queries and tests

* rename tables to original names

* remove index, corrections

* update schema dump

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-19 21:26:03 +01:00
Evgeny Poberezkin ed3fb0b222 core: refactor incognito membership (#3079) 2023-09-19 18:50:10 +01:00
Evgeny Poberezkin 2524609a97 Merge branch 'master-ghc9' 2023-09-18 22:15:20 +01:00
Evgeny Poberezkin 0d0097326e core: update simplexmq 2023-09-18 21:55:39 +01:00
Evgeny Poberezkin f1101b09ce core: update for GHC 9.6.2 2023-09-18 21:52:51 +01:00
Evgeny Poberezkin 904b758e79 Merge branch 'master' into master-ghc9 2023-09-18 21:46:27 +01:00
Evgeny Poberezkin fb1e944744 docs: new branches and process (#3068)
* docs: new branches and process

* update

* update
2023-09-18 21:29:56 +01:00
Evgeny Poberezkin 3cd279bd20 website: translations (#3072)
* Translated using Weblate (Dutch)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/zh_Hans/

* Translated using Weblate (Polish)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ja/

* Translated using Weblate (Bulgarian)

Currently translated at 0.4% (1 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/bg/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/zh_Hans/

* Translated using Weblate (Polish)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ja/

* Translated using Weblate (Bulgarian)

Currently translated at 0.4% (1 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/bg/

---------

Co-authored-by: John m <jvanmanen@gmail.com>
Co-authored-by: Float <float.hu+@gmail.com>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: a4318 <dalse.077@gmail.com>
Co-authored-by: elgratea <weblate@fastmail.com>
2023-09-18 16:22:44 +01:00
Evgeny Poberezkin 2e231209d1 ui: translations (#3071)
* Translated using Weblate (German)

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.9% (1368 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1369 of 1369 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% (1232 of 1232 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% (1369 of 1369 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% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Japanese)

Currently translated at 99.1% (1358 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1365 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fi/

* Translated using Weblate (Bulgarian)

Currently translated at 89.8% (1107 of 1232 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 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/

* Translated using Weblate (French)

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Japanese)

Currently translated at 98.8% (1220 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1371 of 1371 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 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1367 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (German)

Currently translated at 100.0% (1371 of 1371 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% (1234 of 1234 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% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fi/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fi/

* Translated using Weblate (Russian)

Currently translated at 98.9% (1357 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Japanese)

Currently translated at 99.2% (1361 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Czech)

Currently translated at 98.7% (1354 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1371 of 1371 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% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (German)

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.9% (1368 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1369 of 1369 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% (1232 of 1232 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% (1369 of 1369 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% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Japanese)

Currently translated at 99.1% (1358 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1365 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fi/

* Translated using Weblate (Bulgarian)

Currently translated at 89.8% (1107 of 1232 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 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/

* Translated using Weblate (French)

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1369 of 1369 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Japanese)

Currently translated at 98.8% (1220 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1371 of 1371 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 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1367 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (German)

Currently translated at 100.0% (1371 of 1371 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% (1234 of 1234 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% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fi/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fi/

* Translated using Weblate (Russian)

Currently translated at 98.9% (1357 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1371 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Japanese)

Currently translated at 99.2% (1361 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Czech)

Currently translated at 98.7% (1354 of 1371 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1371 of 1371 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% (1234 of 1234 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* android: fix translations formatting

* ios: import/export localizations

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Float <float.hu+@gmail.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: John m <jvanmanen@gmail.com>
Co-authored-by: a4318 <dalse.077@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: petri <pkajander@gmail.com>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: 小连招 <onecombo666@gmail.com>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: pazengaz <pazengaz@porcod.io>
Co-authored-by: 橙子 <legiorange@163.com>
Co-authored-by: zenobit <zen@osowoso.xyz>
2023-09-18 16:19:02 +01:00
Evgeny Poberezkin 603e745aa1 ui: new in v5.3 (#3070)
* ios: new in v5.3

* correction, blog placeholder

* android: new in v5.3

* export localizations
2023-09-18 13:45:13 +01:00
spaced4ndy 071d6b3686 Merge pull request #3064 from simplex-chat/member-contact
core: api to create contacts with group members
2023-09-18 12:55:21 +04:00
Stanislav Dmitrenko 82e3310c54 desktop: disabled gestures (#3045)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-17 09:41:01 +01:00
spaced4ndy 04770fb30d core: terminal api to send message to / connect with member contact (#3065)
* core: terminal api to send message to / connect with member contact

* style

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-16 21:30:20 +04:00
spaced4ndy 0e5b16498a core: api to create contacts with group members (#3053)
* core: api to create contacts with group members

* implementation

* fix contact replace, more tests

* comment

* rename fields

* fix

* fix

* test group is still incognito

* fix

* replace connection instead of contact

* fix

* check version

* style, names

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-16 17:55:48 +04:00
Stanislav Dmitrenko b5e4f127a4 action: fix building CLI on Windows (#3058)
* action: fix building on Windows

* fix package version on Windows

* tail
2023-09-15 17:17:55 +01:00
spaced4ndy 8178e8183e core: show rcv file error (#3054) 2023-09-13 15:28:46 +04:00
Evgeny Poberezkin 70fb10189b website: "linux" images 2023-09-12 18:35:25 +01:00
Evgeny Poberezkin c6dbbcc84e website: add desktop app images 2023-09-12 18:01:38 +01:00
spaced4ndy 7c70577822 ios, android: add new error types (#3050) 2023-09-12 18:29:14 +04:00
spaced4ndy a1790d6ac0 core: use JVersionRange in UI facing types (#3048) 2023-09-12 17:59:09 +04:00
spaced4ndy 01f99baaac Revert "core: direct messages in group (#2994)"
This reverts commit 5fddf64adb.
2023-09-12 17:36:47 +04:00
spaced4ndy 75f18bc5f0 docs: group member contacts rfc (#3049) 2023-09-12 17:24:41 +04:00
Stanislav Dmitrenko 4b88a2abfd multiplatform: voice playing fix (#3046) 2023-09-11 20:32:31 +01:00
spaced4ndy 5fddf64adb core: direct messages in group (#2994) 2023-09-11 18:38:57 +04:00
Evgeny Poberezkin 614b724602 core: fix version of unix package to 2.8.1.1 2023-09-11 13:17:37 +01:00
Evgeny Poberezkin 181323ce13 ios: update team ID in Apple .well-known site associations 2023-09-11 09:08:50 +01:00
Evgeny Poberezkin 28e1d5fb1b Merge branch 'master' into master-ghc9 2023-09-10 23:23:57 +01:00
Evgeny Poberezkin b0c28e77c4 v5.3.0-beta.7: ios 170, android 149, desktop 1.5.0 (7) 2023-09-10 23:23:35 +01:00
Evgeny Poberezkin fd5b40fd8e Merge branch 'master' into master-ghc9 2023-09-10 21:13:52 +01:00
Evgeny Poberezkin ff657a444c core: 5.3.0.7 2023-09-10 21:12:52 +01:00
Evgeny Poberezkin fedc31c72c Merge branch 'master' into master-ghc9 2023-09-10 21:11:35 +01:00
Alexander Bondarenko 2dff6c8859 core: do not subscribe to new connections from iOS NSE (subscribe=off flag), subscribe in app when it activates (#3016)
* Trace auto-subs flag

* Replace Bool with SubscriptionMode

* Add subscriptionMode to chat controller

* Start using subscriptionMode in event handlers

* Add need_subs to chat connections

* Add onlyNeeded to subscribeUserConnections

* Post-rebase fixes

* Pass onlyNeeded to Store functions

* Drop needs_sub for connections registered with agent

* update simplexmq, fix activate

* fix rebase, reduce diff

* fix rebase, tests

* fix rebase, executeMany, always subscribe on activate

* test

* update queries

* Update src/Simplex/Chat.hs

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

* unset connections to subscribe on start

* update simplexmq

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-09-10 20:40:15 +01:00
Evgeny Poberezkin 7b582b2cf9 android, desktop: update SOCKS notice 2023-09-10 20:04:50 +01:00
Evgeny Poberezkin 55954a004b android, desktop: notices about SOCKS proxy limitations (#3044) 2023-09-10 18:53:34 +01:00
Stanislav Dmitrenko 54e1e10382 multiplatform: local file encryption (#3043)
* multiplatform: file encryption

* setting

* fixed sharing

* check

* fixes, change lock icon

* update JNI bindings (crashes on desktop)

* fix JNI

* fix errors and warnings

* fix saving

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-10 17:05:12 +01:00
Evgeny Poberezkin a87aaa50c7 website: add nostr.json for NIP-05 2023-09-10 11:21:40 +01:00
Evgeny Poberezkin fdef37e8f3 Merge branch 'stable' 2023-09-10 11:01:42 +01:00
Evgeny Poberezkin 364d889056 docs: add mastodon rel=me to readme 2023-09-10 10:53:38 +01:00
Evgeny Poberezkin 923a5e2984 Merge branch 'stable' 2023-09-10 10:45:46 +01:00
Evgeny Poberezkin 272b02b686 docs: readme follow updates section, add rel=me for mastodon link 2023-09-10 10:45:30 +01:00
Evgeny Poberezkin 281d9c7f79 ios: add Finnish and Ukranian interface languages (#3040) 2023-09-08 13:21:56 +01:00
sh 45682aa7ce website: fix the apple-app-site-association (#3038) 2023-09-08 11:45:22 +01:00
Stanislav Dmitrenko ad65622407 desktop: catch Toast exception (#3028) 2023-09-07 22:45:00 +01:00
Evgeny Poberezkin 113a57c7c7 ios: update chat_read_file (#3037) 2023-09-07 22:43:51 +01:00
Stanislav Dmitrenko e76440ee66 desktop: local alias update (#3026)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-07 20:32:47 +01:00
Evgeny Poberezkin 82fd3b9004 core: change encoding of the result returned by chat_read_file C API (#3036)
* core: change encoding of the result returned by chat_read_file C API

* remove unused dependency

* remove pointer cast
2023-09-07 20:18:43 +01:00
Evgeny Poberezkin b5a0269aa2 core: support unicode filenames and catch IO exceptions in C API for local file encryption (#3035)
* core: support unicode filenames in C API

* catch IO exceptions and return as errors
2023-09-07 13:44:37 +01:00
Evgeny Poberezkin 7cd4a417e7 ios: fix type that was preventing sent item status update 2023-09-07 11:51:17 +01:00
Evgeny Poberezkin 748572ace9 ui: types and stubs to encrypt local files (#3003)
* ui: types and stubs to encrypt local files

* ios: encrypt automatically received images in local storage

* encrypt sent images, marked to be received via NSE

* ios: encrypt sent and received local voice files

* encrypt sent and received local files

* fix NSE

* remove comment

* decrypt files in background thread
2023-09-07 11:28:37 +01:00
Stanislav Dmitrenko a27f30ce12 android: changing a chat on user change (#3027)
* android: changing a chat on user change

* test

* test2

* Revert "test2"

This reverts commit 198873ecad.

* Revert "test"

This reverts commit 6e0e3d4930.

* style

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-07 10:59:37 +01:00
Seth For Privacy a90641c1d1 Fix broken RSS feed source URL (#3033) 2023-09-07 10:03:32 +01:00
Evgeny Poberezkin 47b783e727 core: export chat_encrypt_file/chat_decrypt_file 2023-09-06 20:21:43 +01:00
Evgeny Poberezkin edeaf36e8b core: C api to encrypt/decrypt local app files (#3029)
* core: C api to encrypt/decrypt local app files

* do not call CF.hPut with empty chunk
2023-09-06 19:54:13 +01:00
spaced4ndy 5e8e4c295c Merge pull request #2995 from simplex-chat/chat-version-negotiation
core: communicate connection chat version range; don't create direct connections in group (disabled)
2023-09-06 18:06:57 +04:00
spaced4ndy 37eef3c6c9 core: enable creation of direct connections in group (revert this instead of #3022) (#3025) 2023-09-06 18:05:42 +04:00
spaced4ndy b6c23b59ca core: change logic of checking if peer supports feature (check if peer version is compatible) (#3024) 2023-09-06 17:48:37 +04:00
spaced4ndy e6baca5610 core: rename conn vrange into peer vrange (#3023) 2023-09-06 11:41:23 +04:00
spaced4ndy 0c4b843a3f Merge branch 'master' into chat-version-negotiation 2023-09-06 10:41:06 +04:00
spaced4ndy 68f359c904 core: enable creation of direct connections in group for chat protocol v2 (for beta; to be reverted for full release) (#3022) 2023-09-06 10:15:32 +04:00
Stanislav Dmitrenko e60dbf6add multiplatform: reduce variables that is controlling running chat (#3021)
* multiplatform: reduce variables that is controlling running chat

* removed second variable
2023-09-05 18:54:31 +01:00
Stanislav Dmitrenko 67d5b6eace desktop: open database dir (#3019)
* desktop: open database dir

* alert

* move button

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-05 18:24:39 +01:00
spaced4ndy 43e233f0eb core: don't create direct connections in group (#2996) 2023-09-05 20:15:50 +04:00
Evgeny Poberezkin 83b939d215 android: add Arabic, Finnish, Hebrew (#3018)
* android: add Arabic, Finnish, Hebrew

* update localization lib to support Hebrew

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-09-05 15:07:37 +01:00
Evgeny Poberezkin 4d6283630a website: translations (#3017)
* Translated using Weblate (Arabic)

Currently translated at 100.0% (244 of 244 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Polish)

Currently translated at 100.0% (244 of 244 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Added translation using Weblate (Hebrew)

* Translated using Weblate (French)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (German)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Italian)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/es/

* Translated using Weblate (Japanese)

Currently translated at 22.4% (55 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ja/

* Added translation using Weblate (Finnish)

* Translated using Weblate (Arabic)

Currently translated at 100.0% (244 of 244 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Polish)

Currently translated at 100.0% (244 of 244 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Added translation using Weblate (Hebrew)

* Translated using Weblate (French)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (German)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Italian)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/es/

* Translated using Weblate (Japanese)

Currently translated at 22.4% (55 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ja/

* Added translation using Weblate (Finnish)

* Translated using Weblate (Hebrew)

Currently translated at 30.6% (75 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/he/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (245 of 245 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fi/

---------

Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: a4318 <dalse.077@gmail.com>
Co-authored-by: ItaiShek <itaishek@gmail.com>
Co-authored-by: petri <pkajander@gmail.com>
2023-09-05 12:50:11 +01:00
Evgeny Poberezkin 6ff3024238 mobile: translations (#3015)
* Translated using Weblate (Chinese (Simplified))

Currently translated at 93.6% (1154 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Japanese)

Currently translated at 96.5% (1311 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fi/

* Translated using Weblate (Finnish)

Currently translated at 19.4% (240 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fi/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Hebrew)

Currently translated at 99.9% (1357 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/he/

* Translated using Weblate (French)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1358 of 1358 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.9% (1231 of 1232 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% (1358 of 1358 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% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Japanese)

Currently translated at 99.5% (1227 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/

* Translated using Weblate (Japanese)

Currently translated at 99.0% (1345 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1354 of 1358 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 3.7% (46 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ar/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fi/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fi/

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/he/

* Translated using Weblate (Hebrew)

Currently translated at 51.7% (637 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/he/

* Translated using Weblate (Japanese)

Currently translated at 99.8% (1230 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/

* Translated using Weblate (Japanese)

Currently translated at 99.8% (1356 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Czech)

Currently translated at 99.5% (1352 of 1358 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 99.0% (1220 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/cs/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.2% (1334 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pt_BR/

* Translated using Weblate (Japanese)

Currently translated at 99.0% (1220 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/

* Translated using Weblate (Japanese)

Currently translated at 99.2% (1348 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/

* Translated using Weblate (Japanese)

Currently translated at 99.2% (1223 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/

* Translated using Weblate (Japanese)

Currently translated at 99.2% (1348 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Japanese)

Currently translated at 98.8% (1218 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/

* Translated using Weblate (Japanese)

Currently translated at 98.9% (1344 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Japanese)

Currently translated at 98.6% (1339 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* ios: import/export translations, android: formatted string tags

---------

Co-authored-by: 小连招 <onecombo666@gmail.com>
Co-authored-by: a4318 <dalse.077@gmail.com>
Co-authored-by: petri <pkajander@gmail.com>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: ItaiShek <itaishek@gmail.com>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: John m <jvanmanen@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: marfS2 <work.j6nnu@slmail.me>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
2023-09-05 12:44:21 +01:00
Stanislav Dmitrenko aff71c58d7 desktop: setup passphrase during onboarding (#2987)
* desktop: setup passphrase during onboarding

* updated logic

* removed unused code

* button and starting chat action

* better

* removed debug code

* fallback

* focusing and moving focus on desktop text fields

* different logic

* removed unused variable

* divided logic in two functions

* enabled keyboard enter

* rollback when db deleted by hand on desktop

* update texts, font size

* stopping chat before other actions

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-05 11:45:09 +01:00
Stanislav Dmitrenko 8aed568199 multiplatform: layout fix on link creation page and self destruct option (#3012) 2023-09-04 23:21:29 +01:00
Evgeny Poberezkin 0ec3e0c18d core: add debug info for subscriptions (#3014) 2023-09-04 23:19:24 +01:00
Stanislav Dmitrenko c7f1af8742 android: sharing of files with plain text (#3011) 2023-09-04 18:37:53 +01:00
Evgeny Poberezkin 4793173465 core: update return type of read/write file C api, tests (#3010) 2023-09-03 22:25:19 +01:00
Evgeny Poberezkin aa67692465 rfc: local file encryption (#2342) 2023-09-03 08:32:21 +01:00
Evgeny Poberezkin af02a92442 core: fix WebRTC encryption, test (#3005) 2023-09-02 23:34:00 +01:00
Evgeny Poberezkin 461142b875 core: update simplexmq (import stateTVar) 2023-09-01 22:27:03 +01:00
Evgeny Poberezkin 0b214acf97 core: support encrypted local files (#2989)
* core: support encrypted local files

* add migration

* update agent api, chat api

* fix query, exported functions to read/write files

* update simplexmq

* remove formatting changes

* test, fix file size

* reduce diff

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

* fail when receiving SMP files with local encryption

* update simplexmq

* remove style changes

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-09-01 19:43:27 +01:00
spaced4ndy 1c90eb0a2e docs: groups improvements rfc (#2988) 2023-09-01 19:43:07 +04:00
spaced4ndy 7a5d4a5a3d core: communicate connection chat version range (#2886)
* core: communicate connection chat version range

* encoding

* type

* implementation wip

* contact requests

* tests

* more tests

* refactor

* remove comment

* change encoding

* remove Maybe

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-01 19:20:07 +04:00
Stanislav Dmitrenko 215020b1df desktop (mac): fixed linking (#2993) 2023-08-30 16:27:36 +01:00
Evgeny Poberezkin 5d580c3a1b Merge branch 'master' into master-ghc9 2023-08-30 16:27:11 +01:00
Stanislav Dmitrenko 7103524174 desktop: signing and notarizing mac build in Github action (#2986)
* desktop: signing and notarizing mac build in Github action

* changed path
2023-08-29 08:22:04 +01:00
Evgeny Poberezkin 4aac3c7922 website: update comparison 2023-08-28 22:23:49 +01:00
Evgeny Poberezkin 134465fd9d Merge branch 'stable' 2023-08-28 20:33:07 +01:00
Evgeny Poberezkin 0f076d9ac9 docs: update technical details and limitations 2023-08-28 20:32:44 +01:00
Stanislav Dmitrenko 95d57bc4e1 desktop: fixed gradle (#2982)
* fix gradle

* correct cert identity

* proper file paths

* moving to secrets

* order of lines

* returned back
2023-08-28 08:23:37 +01:00
M. Sarmad Qadeer 10f8b8086e Sq/website fdroid page (#2980)
* website: change height of f-droid page main section

* website: update lang strings for f-droid page

* website: fix fdroid page broken in other languages

* update translations

* website: add language navigation to fdroid page link

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-27 17:45:13 +01:00
Stanislav Dmitrenko 38ff7d173c desktop: fixed gradle (#2982)
* fix gradle

* correct cert identity

* proper file paths

* moving to secrets

* order of lines

* returned back
2023-08-27 09:16:29 +01:00
Evgeny Poberezkin 3cefe19264 Merge branch 'master' into master-ghc9 2023-08-26 21:02:07 +01:00
Evgeny Poberezkin 7504a82cb3 v5.3.0-beta.6: ios 169, android 148, desktop 1.4.0 (6) 2023-08-26 21:00:26 +01:00
Evgeny Poberezkin a2aac72dd1 Merge branch 'master' into master-ghc9 2023-08-26 18:44:34 +01:00
Evgeny Poberezkin ebb4c860b7 5.3.0.6: update simplexmq (create database path) 2023-08-26 18:36:34 +01:00
Evgeny Poberezkin 79e1bdaf61 rfc: improving iOS notifications 2023-08-26 16:51:05 +01:00
Evgeny Poberezkin b1a6dec9b5 desktop (mac): signing and notarization (#2981)
* mac: signing and notarization

* updated example

* updated action

* update build script

* move mac CI script to file

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-08-26 16:32:03 +01:00
Evgeny Poberezkin 960482f527 docs: correct year in privacy policy 2023-08-26 12:03:45 +01:00
Evgeny Poberezkin 7ef8ae9f42 Merge branch 'master' into master-ghc9 2023-08-25 17:50:01 +01:00
Stanislav Dmitrenko 96b253c3e7 dekstop: image compression (#2979)
* dekstop: image compression

* refactor
2023-08-25 17:28:39 +01:00
Evgeny Poberezkin 7fc108e6fa website: translations (#2978)
* Translated using Weblate (French)

Currently translated at 100.0% (248 of 248 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (German)

Currently translated at 100.0% (248 of 248 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (248 of 248 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (248 of 248 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Italian)

Currently translated at 100.0% (248 of 248 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (248 of 248 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/es/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (248 of 248 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/uk/

* Added translation using Weblate (Bulgarian)

---------

Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: John m <jvanmanen@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
2023-08-25 17:05:56 +01:00
Evgeny Poberezkin 9134624e2a Merge branch 'master' into master-ghc9 2023-08-25 14:13:30 +01:00
Evgeny Poberezkin 3a93954c50 core: debug agent subscriptions (#2976)
* core: debug agent subscriptions

* update commands to include subscriptions summary
2023-08-25 14:10:40 +01:00
Evgeny Poberezkin fde39e74ee Merge branch 'master' into master-ghc9 2023-08-25 11:32:37 +01:00
Evgeny Poberezkin 22dc58b735 android, desktop: add Ukrainian language 2023-08-25 11:31:15 +01:00
Evgeny Poberezkin bcc265a3b1 ios: remove empty Localizable.strings files from NSE 2023-08-25 11:18:58 +01:00
Evgeny Poberezkin 5b258384f4 mobile: translations (#2977)
* Translated using Weblate (German)

Currently translated at 100.0% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (French)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1358 of 1358 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% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1358 of 1358 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.9% (1231 of 1232 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% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/uk/

* Translated using Weblate (Bulgarian)

Currently translated at 51.7% (638 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/

* Translated using Weblate (Russian)

Currently translated at 100.0% (1358 of 1358 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% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* ios: import/export localizations

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: John m <jvanmanen@gmail.com>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: elgratea <weblate@fastmail.com>
2023-08-25 11:17:05 +01:00
Stanislav Dmitrenko bdc08698c8 multiplatform: reduce recompositions in ChatView while entering text (#2974) 2023-08-25 10:12:06 +01:00
Stanislav Dmitrenko 7f894abbad desktop: better autoscroll to bottom on new message (#2973) 2023-08-25 10:09:21 +01:00
Moritz Angermann 761ddac55d core: use GHC 9.6.2 (#2641)
* Make it compiler with 9.6

Can be built with:

cabal build all -j --allow-newer=base --allow-newer=ghc-prim --allow-newer=template-haskell --allow-newer=bytestring --allow-newer=memory --allow-newer=cryptonite

Using ghc 9.6

It mostly runs afoul of https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0366-no-ambiguous-field-access.rst

* compile with GHC 9.6.2: dependencies, imports, code

* update GHC version in CI

* update GHC version in desktop build scripts

* update simplexmq, sha256map.nix

* update compiler

* update simplexmq, direct-sqlcipher

* remove missing files from .cabal

* building on desktop

* mac build changes

* added version back

* building libffi from source

* update simplexmq

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-08-24 21:56:37 +01:00
Stanislav Dmitrenko 06369e277c android: update contacts on profile update (#2969)
* android: update contacts on profile update

* returned back

* change
2023-08-23 18:43:21 +01:00
Stanislav Dmitrenko 16792de67a ios: update contacts on profile update (#2970)
* ios: update contacts on profile update

* change

* remove init

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-23 18:43:06 +01:00
Stanislav Dmitrenko 9639fd26b8 ios: making thumbnails faster (#2972)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-23 17:27:44 +01:00
Stanislav Dmitrenko 9537940494 ios: fullscreen player fix (#2968)
* ios: fullscreen player fix

* disable playing in some cases

* simpler conditions

* disabled video play button

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-23 17:11:39 +01:00
Evgeny Poberezkin 971e71727a core: specify compiler 2023-08-23 13:24:34 +01:00
Evgeny Poberezkin 4e861cc93a core: only send changed contacts in api response on user profile update (#2971) 2023-08-22 19:16:38 +01:00
Evgeny Poberezkin c98b9cda85 core: change profile update API to return updated contacts (#2967) 2023-08-22 16:13:57 +01:00
Evgeny Poberezkin a35ab7f9bc mobile: remove most user data from responses, to reduce noice in errors/console (#2966)
* mobile: remove most user data from responses, to reduce noice in errors/console

* small change for desktop

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-08-22 12:20:21 +01:00
Evgeny Poberezkin e804df9d58 Merge branch 'stable' 2023-08-22 09:11:12 +01:00
Evgeny Poberezkin b1ecbb0355 docs: translations 2023-08-22 09:05:31 +01:00
Evgeny Poberezkin 55eab0976e mobile: add Thai language 2023-08-22 00:06:01 +01:00
Evgeny Poberezkin 3145095611 mobile: translations (#2964)
* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/

* Translated using Weblate (French)

Currently translated at 98.8% (1338 of 1353 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 98.7% (1336 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1353 of 1353 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 100.0% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (French)

Currently translated at 100.0% (1353 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Dutch)

Currently translated at 99.0% (1340 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Thai)

Currently translated at 97.8% (1201 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/th/

* Translated using Weblate (Thai)

Currently translated at 98.5% (1334 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/th/

* Translated using Weblate (Bulgarian)

Currently translated at 99.0% (1340 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1353 of 1353 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% (1228 of 1228 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% (1353 of 1353 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% (1228 of 1228 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 98.5% (1333 of 1353 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 98.4% (1209 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/cs/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1353 of 1353 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% (1228 of 1228 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1353 of 1353 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1349 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (German)

Currently translated at 100.0% (1353 of 1353 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1353 of 1353 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 93.4% (1265 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 94.3% (1277 of 1353 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% (1353 of 1353 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% (1228 of 1228 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% (1353 of 1353 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Bulgarian)

Currently translated at 4.9% (61 of 1228 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 100.0% (1353 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Turkish)

Currently translated at 76.5% (1036 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Bulgarian)

Currently translated at 6.4% (79 of 1228 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 100.0% (1356 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (French)

Currently translated at 100.0% (1358 of 1358 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% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Bulgarian)

Currently translated at 19.9% (245 of 1228 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 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1358 of 1358 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Bulgarian)

Currently translated at 22.2% (273 of 1228 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 42.1% (517 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Bulgarian)

Currently translated at 46.6% (573 of 1228 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 47.7% (586 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/

* Translated using Weblate (German)

Currently translated at 100.0% (1358 of 1358 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1358 of 1358 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1354 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/he/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1358 of 1358 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% (1228 of 1228 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/uk/

* Update translation files

Updated by "Cleanup translation files" hook in Weblate.

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/

* Translated using Weblate (French)

Currently translated at 98.8% (1338 of 1353 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 98.7% (1336 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1353 of 1353 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 100.0% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (French)

Currently translated at 100.0% (1353 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Dutch)

Currently translated at 99.0% (1340 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Thai)

Currently translated at 97.8% (1201 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/th/

* Translated using Weblate (Thai)

Currently translated at 98.5% (1334 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/th/

* Translated using Weblate (Bulgarian)

Currently translated at 99.0% (1340 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1353 of 1353 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% (1228 of 1228 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% (1353 of 1353 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% (1228 of 1228 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 98.5% (1333 of 1353 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 98.4% (1209 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/cs/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1353 of 1353 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% (1228 of 1228 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1353 of 1353 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1349 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (German)

Currently translated at 100.0% (1353 of 1353 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1353 of 1353 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 93.4% (1265 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 94.3% (1277 of 1353 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% (1353 of 1353 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% (1228 of 1228 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% (1353 of 1353 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Bulgarian)

Currently translated at 4.9% (61 of 1228 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 100.0% (1353 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Turkish)

Currently translated at 76.5% (1036 of 1353 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Bulgarian)

Currently translated at 6.4% (79 of 1228 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 100.0% (1356 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (French)

Currently translated at 100.0% (1358 of 1358 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% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Bulgarian)

Currently translated at 19.9% (245 of 1228 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 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1358 of 1358 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Bulgarian)

Currently translated at 22.2% (273 of 1228 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 42.1% (517 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Bulgarian)

Currently translated at 46.6% (573 of 1228 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 47.7% (586 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/

* Translated using Weblate (German)

Currently translated at 100.0% (1358 of 1358 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1358 of 1358 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1354 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/he/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1358 of 1358 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% (1228 of 1228 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% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1228 of 1228 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/uk/

* Translated using Weblate (Russian)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* correction

* android: CDATA added

* Translated using Weblate (Russian)

Currently translated at 100.0% (1232 of 1232 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* ios: import/export localizations

---------

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: John m <jvanmanen@gmail.com>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Titapa (PunPun) Chaiyakiturajai <titapapunne@gmail.com>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: random r <epsilin@yopmail.com>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Víctor <bellzebu@hotmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Andrew Elliot <Memorytoco@gmail.com>
Co-authored-by: xe1st <dnzkckali@gmail.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: ItaiShek <itaishek@gmail.com>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
2023-08-21 23:45:50 +01:00
Evgeny Poberezkin 05426842cd ios: export localizations 2023-08-21 21:53:15 +01:00
Evgeny Poberezkin 75d11c2b4f core: update simplexmq (fix repeated HELLO message) (#2962)
* core: update simplexmq (fix repeated HELLO message)

* add callstack to tests
2023-08-21 21:45:16 +01:00
Stanislav Dmitrenko 36e5fc64a8 multiplatform: section item text width limitation (#2955) 2023-08-21 20:40:21 +01:00
Stanislav Dmitrenko 788ee15942 multiplatform: fix handling HTML in some places (#2963) 2023-08-21 20:14:23 +01:00
M. Sarmad Qadeer 538cdd16de website: add f-droid page (#2960)
* website: add f-droid page

* update fdroid page

* website: improve the layout

* website: add strings to translation file

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-21 19:10:10 +01:00
Evgeny Poberezkin 63dd6e36b3 ios: fix view model update not on main thread 2023-08-21 13:56:53 +01:00
Evgeny Poberezkin c3ffc2abb8 ios: fix chat console not showing command and response before re-opening 2023-08-21 13:52:09 +01:00
Evgeny Poberezkin 04cc0e8065 ios: fix incorrectly showing previous address when it is deleted and created without closing the view (#2961) 2023-08-21 13:21:43 +01:00
Evgeny Poberezkin 75c9b40262 core: update simplexmq (sequential sending of batches) (#2957)
* core: update simplexmq (sequential sending of batches)

* update simplexmq
2023-08-20 18:47:30 +01:00
Evgeny Poberezkin 847252f61e Merge branch 'stable' 2023-08-19 12:10:11 +01:00
Evgeny Poberezkin c38af98a01 readme: add USDT address 2023-08-19 12:09:53 +01:00
Evgeny Poberezkin ca3fd2ec36 docs: update "join team" 2023-08-19 09:13:01 +01:00
Evgeny Poberezkin 664954bc5c docs: update "join team" 2023-08-19 09:12:34 +01:00
Evgeny Poberezkin 212c2bdc1c docs: join the team (#2954) 2023-08-19 09:04:56 +01:00
Evgeny Poberezkin 14217227d8 docs: join the team (#2954) 2023-08-19 09:04:03 +01:00
Evgeny Poberezkin 41c68c82ac directory: add to website, send terms, sort search results (#2950)
* directory: add to website, send terms, sort search results

* corrections
2023-08-18 14:31:42 +01:00
spaced4ndy addace9faf ios: fix group receipts override (#2951) 2023-08-18 17:02:11 +04:00
Evgeny Poberezkin eb223f0c53 Merge branch 'stable' 2023-08-18 11:04:25 +01:00
Evgeny Poberezkin 4a99f58b93 docs: update privacy policy, directory service doc/terms (#2910)
* docs: update privacy policy, directory service doc/terms

* update

* correction

* corrections

* update doc

* heading

* amended

* correction
2023-08-18 11:03:55 +01:00
spaced4ndy bb39a04d4f 5.3.0-beta.5: ios 168, android 147 2023-08-18 11:27:17 +04:00
Evgeny Poberezkin 8bb19db1ff core: 5.3.0.5 2023-08-17 23:16:23 +01:00
spaced4ndy b829bd0c06 ios: fix Speak Screen repeating messages (#2897)
* ios: fix Speak Screen repeating messages

* fix

* different modifier

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-17 23:05:19 +04:00
Evgeny Poberezkin 01a95f88bb ios: more responsive UI, especially during app start (#2942)
* ios: more responsive UI, especially during app start

* move terminal items to actor

* fix for iOS 15/16
2023-08-17 18:21:05 +01:00
M. Sarmad Qadeer 45b7d09f83 website: lowercase the website urls (#2893) 2023-08-17 16:27:55 +01:00
Stanislav Dmitrenko f1c86d20c9 desktop: cursor on hover over clickable link (#2946)
* desktop: cursor on hover over clickable link

* simplex link

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-17 16:25:52 +01:00
Stanislav Dmitrenko ea397049f8 multiplatform: ChatView enhancements (#2945)
* multiplatform: ChatView enhancements

* removed unused code

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-17 15:26:11 +01:00
Stanislav Dmitrenko 63ca7a34ff desktop: clickable links in quoted messages (#2943) 2023-08-17 15:20:27 +01:00
Stanislav Dmitrenko 107b6e1aec multiplatform: mark read fix (#2932)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-17 15:06:42 +01:00
spaced4ndy 1d8a370c58 android: show chat previews & save last draft toggles (#2941)
* android: show chat previews & save last draft toggles

* wip

* Revert "wip"

This reverts commit 01b570913f.

* comment

* add to model

* toggle text and icon

* show draft

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-17 15:04:16 +01:00
spaced4ndy faea5e90ac android: members connected aggregated item; group layout (#2934) 2023-08-17 15:56:43 +04:00
Evgeny Poberezkin 590644a359 ios: show draft even when messages in the list are hidden (#2944) 2023-08-17 12:52:03 +01:00
spaced4ndy a5940962c7 ios: show chat previews & save last draft toggles (#2940)
* ios: show chat previews & save last draft toggles

* better view, toggle name

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-17 12:04:17 +01:00
Stanislav Dmitrenko 6cf9f0303b desktop: handling keyboard in auth screen (#2938)
* desktop: handling keyboard in auth screen

* numpad support

* numPadEnter

* padding
2023-08-16 18:50:27 +01:00
spaced4ndy 34cf672bc6 core: show count and average time for slow queries (#2939) 2023-08-16 21:21:12 +04:00
spaced4ndy 4a5dd0a3a4 core: add indexes to improve slow queries performance (#2931)
* core: add indexes to improve slow queries performance

* idx_chat_items_group_id

* update simplexmq, schema

* update simplexmq

* remove index

* update simplexmq

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-16 10:41:52 +04:00
Evgeny Poberezkin a5642928eb ios: improve group layout (#2925)
* ios: improve group layout

* different font

* fix formatting

* returns

* localized strings

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-08-15 13:02:23 +01:00
Stanislav Dmitrenko 21dcb3b856 multiplatform: better draft (#2926)
* multiplatform: better draft

* added context item to check for emptyness

* show draft in preview when chat is active

* state sync

* clear draft when sending message
2023-08-15 12:04:24 +01:00
Evgeny Poberezkin 5a9ed86d1b ios: send button color for incognito conversations (#2918) 2023-08-14 22:55:18 +01:00
Stanislav Dmitrenko 67acc89dbf desktop: close info panel on chat deletion (#2927)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-14 22:45:29 +01:00
Stanislav Dmitrenko 5bcb62b306 desktop: alert style in protocol servers (#2928) 2023-08-14 22:26:36 +01:00
Stanislav Dmitrenko 4ccc4c1b82 multiplatform: do not remove focus from search field on member selection (#2923) 2023-08-14 21:31:41 +01:00
Stanislav Dmitrenko 58e6a408ea multiplatform: handling wrongly pasted link (#2922) 2023-08-14 21:21:19 +01:00
Stanislav Dmitrenko 45f58e34d5 multiplatform: do not close non-active chat on delete/leave (#2921)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-14 21:19:16 +01:00
Stanislav Dmitrenko 782355ccb5 desktop: better logic when switching chats (#2898)
* desktop: better logic when switching chats

* auto scroll to top when selected chat changes

* multiplatform: members page performance

* preloading group members

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-14 21:05:53 +01:00
spaced4ndy 8dcb70c019 ios: members connected aggregated item (#2900)
* ios: members connected aggregated item

* wrapping hstack wip

* Revert "wrapping hstack wip"

This reverts commit 75af7473fc.

* redesign

* fix scroll

* revert

* comment

* remove padding

* brackets

* texts, icon

* optimize - collect only member names

* refactor

* check different index

* refactor 2

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-14 17:34:22 +04:00
Evgeny Poberezkin e326227d06 cli: change default member role from "admin" to "member" (#2915) 2023-08-14 07:37:04 +01:00
Evgeny Poberezkin 1cc14346b0 ios: optmize chat console performance (#2912) 2023-08-14 07:36:39 +01:00
Evgeny Poberezkin 4f9683f678 5.3.0-beta.4: ios 167, android 146 2023-08-12 23:28:36 +01:00
Evgeny Poberezkin 48261b7e8f core: 5.3.0.4 2023-08-12 22:00:25 +01:00
Evgeny Poberezkin d0f4533a09 Merge branch 'stable' 2023-08-12 21:21:45 +01:00
Evgeny Poberezkin 8f9134b494 5.2.3: ios 166, android 144 2023-08-12 21:00:33 +01:00
Evgeny Poberezkin 113669ac16 core: track slow SQL queries (#2904)
* core: track slow SQL queries

* fixes

* update simplexmq
2023-08-12 18:27:10 +01:00
Moritz Angermann 85ddb646af core: explicitly set encoding to utf-8 (fixes unicode filenames on mobile) (#2908)
* Explicitly set encoding to utf-8 on mobile

GHC's rts tries to obtain the encoding from iconv, however this is not
really available on iOS. It therefore defaults to US-ASCII, and then
breaks with unicode data. We now explicitly set this to utf-8 here.

* ormolu

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-12 18:15:11 +01:00
Evgeny Poberezkin cee0dffd46 core: 5.2.3.0 2023-08-12 14:33:17 +01:00
Evgeny Poberezkin a2fef15440 android: disable app data backup competely (#2907) 2023-08-12 14:17:00 +01:00
Evgeny Poberezkin 0176bc3b2c core: improve members query performance (#2903) 2023-08-12 13:53:08 +01:00
Evgeny Poberezkin 42324b515d ios: only show "entity" notifications if the are enabled in the conversation (#2899) 2023-08-11 16:55:00 +01:00
Stanislav Dmitrenko 1bc880877d desktop: changing language without reload (#2896)
* desktop: changing language without reload

* comment

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-11 11:00:48 +01:00
Evgeny Poberezkin 7a41957d7b android: add Bulgarian UI language 2023-08-11 10:40:04 +01:00
Evgeny Poberezkin 837b6dcf46 directory: do not send welcome message to members joining the group (#2895) 2023-08-11 10:38:56 +01:00
sh 77a20f1ae3 docs: update and include tor installation section (#2806) 2023-08-10 22:12:04 +01:00
Stanislav Dmitrenko e2dfc2071f desktop: fix scrolling in some cases (#2888) 2023-08-10 22:10:11 +01:00
Stanislav Dmitrenko b8f289039a multiplatform: better performance in two cases (#2879)
* multiplatform: better performance in two cases

* remove unused API

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-10 22:00:18 +01:00
Stanislav Dmitrenko b02eb79a2c multiplatform: showing progress indicator while sending a text message (#2880)
* multiplatform: showing progress indicator while sending a text message

* progress indicator after timeout

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-10 21:49:44 +01:00
Stanislav Dmitrenko 6ce00b45aa ios: show progress after send with timeout correctly (#2887)
* ios: show progress after send with timeout correctly

* was wrong idea

* remove unused property

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-10 21:38:11 +01:00
Evgeny Poberezkin 97a1a00f17 website: translations (#2891)
* Translated using Weblate (Arabic)

Currently translated at 100.0% (234 of 234 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (234 of 234 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (234 of 234 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/es/

* Translated using Weblate (German)

Currently translated at 99.5% (233 of 234 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

---------

Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Pixelcode <pixelcode@dismail.de>
2023-08-10 21:15:31 +01:00
Stanislav Dmitrenko 121bca83aa multiplatform: format translations (#2892)
* multiplatform: format translations

* update strings

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-10 21:14:32 +01:00
Evgeny Poberezkin 18041ae471 mobile: translations (#2884)
* Translated using Weblate (Dutch)

Currently translated at 100.0% (1324 of 1324 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% (1216 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Arabic)

Currently translated at 62.7% (831 of 1324 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 62.7% (831 of 1324 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% (1324 of 1324 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 71.9% (953 of 1324 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% (1324 of 1324 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% (1216 of 1216 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% (1324 of 1324 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% (1216 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Korean)

Currently translated at 71.2% (943 of 1324 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ko/

* Translated using Weblate (German)

Currently translated at 100.0% (1324 of 1324 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% (1216 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1324 of 1324 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% (1216 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Czech)

Currently translated at 100.0% (1324 of 1324 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% (1216 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/cs/

* Translated using Weblate (Arabic)

Currently translated at 77.3% (1024 of 1324 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 82.1% (1088 of 1324 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (1324 of 1324 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/he/

* Translated using Weblate (Hebrew)

Currently translated at 43.4% (528 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/he/

* Translated using Weblate (Turkish)

Currently translated at 53.4% (708 of 1324 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (German)

Currently translated at 100.0% (1325 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (French)

Currently translated at 100.0% (1325 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1325 of 1325 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 86.7% (1150 of 1325 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% (1325 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Turkish)

Currently translated at 1.3% (17 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/

* Translated using Weblate (Turkish)

Currently translated at 53.4% (708 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Arabic)

Currently translated at 87.2% (1156 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Thai)

Currently translated at 94.7% (1152 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/th/

* Translated using Weblate (Thai)

Currently translated at 95.7% (1269 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/th/

* Translated using Weblate (German)

Currently translated at 100.0% (1325 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (French)

Currently translated at 100.0% (1325 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1216 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1325 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1325 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Japanese)

Currently translated at 99.6% (1321 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Czech)

Currently translated at 100.0% (1325 of 1325 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 99.8% (1323 of 1325 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 3.7% (46 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ar/

* Translated using Weblate (Thai)

Currently translated at 94.7% (1152 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/th/

* Translated using Weblate (Thai)

Currently translated at 95.7% (1269 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/th/

* Translated using Weblate (Bulgarian)

Currently translated at 43.9% (582 of 1325 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1326 of 1326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Bulgarian)

Currently translated at 45.7% (607 of 1326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Bulgarian)

Currently translated at 46.9% (623 of 1326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Bulgarian)

Currently translated at 47.5% (631 of 1326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Bulgarian)

Currently translated at 53.2% (706 of 1326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Bulgarian)

Currently translated at 59.3% (787 of 1326 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1328 of 1328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Bulgarian)

Currently translated at 76.3% (1014 of 1328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Turkish)

Currently translated at 5.3% (65 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/

* Translated using Weblate (Turkish)

Currently translated at 7.4% (90 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1328 of 1328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1328 of 1328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Turkish)

Currently translated at 58.2% (773 of 1328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Turkish)

Currently translated at 58.2% (774 of 1328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Turkish)

Currently translated at 7.5% (92 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/

* Translated using Weblate (Turkish)

Currently translated at 63.9% (849 of 1328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1328 of 1328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Finnish)

Currently translated at 94.2% (1252 of 1328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fi/

* Translated using Weblate (Finnish)

Currently translated at 19.9% (242 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fi/

* Translated using Weblate (Turkish)

Currently translated at 68.5% (910 of 1328 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1356 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (German)

Currently translated at 99.5% (1350 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (French)

Currently translated at 100.0% (1356 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1356 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Turkish)

Currently translated at 70.2% (953 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (German)

Currently translated at 100.0% (1356 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Bulgarian)

Currently translated at 85.9% (1165 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Bulgarian)

Currently translated at 90.2% (1224 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1353 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Thai)

Currently translated at 100.0% (1216 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/th/

* Translated using Weblate (Thai)

Currently translated at 100.0% (1356 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/th/

* Translated using Weblate (Bulgarian)

Currently translated at 1.0% (13 of 1216 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 100.0% (1356 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1356 of 1356 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% (1356 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Turkish)

Currently translated at 70.3% (954 of 1356 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1356 of 1356 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% (1216 of 1216 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1358 of 1358 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 99.7% (1355 of 1358 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 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (German)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (French)

Currently translated at 100.0% (1358 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (Turkish)

Currently translated at 77.2% (1049 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Dutch)

Currently translated at 99.9% (1357 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Lithuanian)

Currently translated at 45.4% (617 of 1358 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/lt/

* export localizations

* update text

* fix German translations

* revert change in French

* remove "read" receipts translations in Japanese

* remove "read" receipts from Japanese

* revert French translations

* import/export localizations

---------

Co-authored-by: John m <jvanmanen@gmail.com>
Co-authored-by: Mosaab Emam <mosaab.emam123@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: fxxk3rrth4ng <baech00@kakao.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: ItaiShek <itaishek@gmail.com>
Co-authored-by: p1ns <dnzkckali@gmail.com>
Co-authored-by: random r <epsilin@yopmail.com>
Co-authored-by: Titapa (PunPun) Chaiyakiturajai <titapapunne@gmail.com>
Co-authored-by: Pixelcode <pixelcode@dismail.de>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Y. Sakamoto <ysakamoto@tutanota.com>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Dennis <snap-roofing0h@icloud.com>
Co-authored-by: petri <pkajander@gmail.com>
Co-authored-by: 0xMarius <tech@marmakas.lt>
2023-08-10 17:59:42 +01:00
spaced4ndy de3fdde2f6 docs: create groups without establishing direct connections RFC (#2890) 2023-08-10 20:33:11 +04:00
spaced4ndy 0cf2af916b docs: contact-groups rfc (#2775) 2023-08-10 20:32:18 +04:00
Evgeny Poberezkin 2ab938db60 mobile: remove item status alerts (#2883) 2023-08-09 22:38:18 +01:00
Stanislav Dmitrenko 9543af4784 android: workaround of system restricted background (#2873)
* android: workaround of system restricted background

* strings

* exclude lockscreen call from requirements to unrestrict

* texts

* added button and changed behaviour

* texts 2

* button instead of alert

* padding

* bigger padding

* refactor

* don't jump on button hide

* no exceptions for lockscreen

* sometimes do not show off alert

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-09 19:56:53 +01:00
Evgeny Poberezkin 38dc14f041 core: update simplexmq (revert DB busy error handling) 2023-08-09 16:45:31 +01:00
Evgeny Poberezkin 5353b466a9 directory: remove welcome when contact joins via group, member count in approval, chat commands via bot (#2872)
* directory: remove welcome when contact joins via group, member count in approval, chat commands via bot

* disable bot tests

* rename command
2023-08-08 16:06:56 +01:00
Stanislav Dmitrenko b28a51106f desktop: small fix to AppImage action (#2862) 2023-08-08 15:56:08 +01:00
spaced4ndy b095c09283 android: rework incognito mode - choose when making connection (#2867)
* android: rework incognito mode - choose when making connection

* remove commented code

* remove commented code

* change text

* text editor border

* smaller qr code

* chat preview height

* fix spacing

* desktop dialogue

* remove import

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-08 17:28:18 +04:00
spaced4ndy 1a567c88db ios: rework incognito mode - choose when making connection (#2851)
* wip

* layout

* more layout

* fix focus

* show incognito

* change icon layout

* remove presentation detents

* smaller button icon

* bigger icon

* show incognito profile status in connection info, layout, icons

* fix some lint warnings, update labels, add incognito label, conditionally hide toolbar to avoid jumping on iOS 17

* remove ignored color

* s/incognitoEnabled/incognito/

* shorter text

* remove parameter label

* restore note when creating a group

* add incognito icon to pending connections

* refactor

* refactor chat list action sheet

* revert to using new value in onChange

* remove unused variable

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-08 17:26:56 +04:00
spaced4ndy d80ee14f77 Revert "Revert "core: rework incognito mode - set per connection (#2838)""
This reverts commit b003d659e4.
2023-08-08 17:25:28 +04:00
Evgeny Poberezkin b374b5b753 Merge branch 'stable' 2023-08-07 21:04:33 +01:00
Evgeny Poberezkin 34c5658560 Merge pull request #2854 from simplex-chat/directory-service
SimpleX Directory Service
2023-08-07 12:49:30 +01:00
Evgeny Poberezkin 53662ef077 directory: store log (#2863)
* directory: store log

* store log test (fails)

* fix store log
2023-08-07 08:25:15 +01:00
Evgeny Poberezkin 4826a62d36 directory: list groups with group member counts (#2855)
* directory: list groups with group member counts

* list groups, test

* superuser can list all groups

* rename command

* remove type synonym

* add member count to search results

* fix test
2023-08-06 11:56:40 +01:00
Evgeny Poberezkin 8cd362eed8 5.3-beta.3: android 141, ios 164, desktop 1.1.0 2023-08-05 22:24:02 +01:00
Evgeny Poberezkin b7ac1b1b55 core: 5.3.0.2 2023-08-05 15:15:53 +01:00
Stanislav Dmitrenko 5952fd5290 desktop: font for emoji (#2853)
* desktop: font for emoji

* heart emoji for Mac

* limit font size

* alignment

* padding

* emoji item layout

* padding on desktop

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-04 22:28:09 +01:00
Stanislav Dmitrenko 353fe4539c desktop: package name for Mac (#2857)
* desktop: package name for Mac

* added Windows
2023-08-04 21:29:25 +01:00
Evgeny Poberezkin b003d659e4 Revert "core: rework incognito mode - set per connection (#2838)"
This reverts commit 4e27a4ea4f.
2023-08-04 16:55:55 +01:00
Evgeny Poberezkin 8f72328136 directory: delist/relist groups when service or owner roles change (#2844)
* directory: delist/relist groups when service or owner roles change

* test role changes

* correction

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

* directory: suspend and resume group listing (#2848)

* directory: suspend and resume group listing

* correction

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-08-04 09:23:16 +01:00
Stanislav Dmitrenko 6d113ae2e2 multiplatform: limit link preview width (#2847) 2023-08-03 16:40:29 +01:00
Stanislav Dmitrenko f264470e14 desktop: fix saving files and images (#2846) 2023-08-03 16:34:35 +01:00
Stanislav Dmitrenko 65391756ef desktop: files Drag & Drop support (#2843)
* desktop: files Drag&Drop support

* reduce diff

* move

* move 2

* move 3

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-03 16:24:43 +01:00
spaced4ndy 4e27a4ea4f core: rework incognito mode - set per connection (#2838) 2023-08-03 17:41:23 +04:00
Stanislav Dmitrenko b23b109b00 desktop: fixed shift+enter (#2842) 2023-08-03 12:04:26 +01:00
spaced4ndy 8bf830ced9 android: don't show file cancelled error alerts for automatically received files (#2818) 2023-08-03 14:26:23 +04:00
spaced4ndy 80a77a1104 ios: change logic of not showing alerts on file auto-receive - only don't show on file cancelled errors (#2833) 2023-08-03 14:25:56 +04:00
Stanislav Dmitrenko 760282cdfd desktop: edit previous message with Up arrow (#2841) 2023-08-03 10:32:01 +01:00
Evgeny Poberezkin 497275646d directory: registration of duplicate groups (#2840)
* directory: confirm registration of duplicate groups

* do not send duplicate groups for approval

* add test
2023-08-03 09:21:48 +01:00
Stanislav Dmitrenko 105a6afb4b ci: Github Action to build desktop app binaries (#2814)
* desktop: Github Action for desktop

* only on tag

* AppImage support
2023-08-02 22:45:58 +01:00
Stanislav Dmitrenko 061125ab63 desktop: AppImage support (#2839) 2023-08-02 22:30:24 +01:00
Stanislav Dmitrenko 2f10633d1d multiplatform: update compose version (#2835)
* multiplatform: update compose version

* Revert "desktop: fix freeze in some situations (#2820)"

This reverts commit 6268f0a32b.

* Revert "desktop: prevent deadlock (#2785)"

This reverts commit d77980e50e.

* restore debug commands in comments

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-02 17:20:15 +01:00
Evgeny Poberezkin e2d5ad0e48 Merge branch 'master' into directory-service 2023-08-02 16:25:56 +01:00
Evgeny Poberezkin e34a8ef719 Merge branch 'stable' 2023-08-02 16:23:17 +01:00
spaced4ndy 2bb2042d7d ios, android: alert on connect via member address button (#2819)
* ios: alert on connect via member address button

* android

* Update apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>

* Update apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>

* ios texts

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-02 12:10:11 +04:00
spaced4ndy 0a6133fe5b ios: update error types (#2821) 2023-08-02 11:10:29 +04:00
spaced4ndy a4a6e2418a android: update error types (#2827) 2023-08-02 11:09:54 +04:00
Evgeny Poberezkin 2b69103055 SimpleX Directory Service (#2766)
* SimpleX Directory Service

* more events

* update events

* fix

* Apply suggestions from code review

metavar

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

* metavar 2

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>

* process events

* remove command serialization

* update

* update

* process group profile update

* basic group registration flow

* search works

* better messages

* improve messages

* test broadcast bot

* test for directory service

* better processing of group profile change, test

* refactor

* de-list group when owner or service is removed from the group, tests

* fix: removing any member or any member leaving should not delist the group

* refactor

* more tests, fixes

* disable bot tests in CI

* remove comment

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2023-08-01 20:54:51 +01:00
spaced4ndy 7344398826 ios: don't show error alerts for automatically received files (#2813) 2023-08-01 18:18:14 +04:00
Stanislav Dmitrenko 7f662ec7cc desktop: theme detector try-catch (#2817) 2023-08-01 15:08:04 +01:00
Stanislav Dmitrenko 298dd9744f desktop: include more libs for copying (#2823)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-08-01 15:07:10 +01:00
Stanislav Dmitrenko 6268f0a32b desktop: fix freeze in some situations (#2820)
* desktop: fix freeze in some situations

* old fashion

* small change
2023-08-01 14:58:26 +01:00
Evgeny Poberezkin f0d64a30e9 5.3-beta.2: ios 163, android 140, desktop 1.0.1 (#2812) 2023-07-31 17:57:56 +01:00
Evgeny Poberezkin d08df4cfbf core: 5.3.0.1 2023-07-31 16:13:19 +01:00
Evgeny Poberezkin 8e84b9e85f Merge branch 'stable' 2023-07-31 16:02:01 +01:00
spaced4ndy c935e8aff3 core: fix status parsing 2 (#2809) 2023-07-31 15:52:42 +01:00
spaced4ndy a0a567f5f7 core: fix status parsing (#2807) 2023-07-31 15:52:02 +01:00
spaced4ndy ddd97baf5a core: 5.2.1.0 2023-07-31 15:49:53 +01:00
spaced4ndy 98e68c8e74 core: read unparsable item status as unknown (#2805) 2023-07-31 15:46:31 +01:00
Evgeny Poberezkin 03edde18eb core: update preset smp relays (#2804) 2023-07-31 15:19:28 +01:00
Stanislav Dmitrenko 8e7e5209d3 desktop: include openssl lib on Mac (#2810) 2023-07-31 13:46:00 +01:00
Evgeny Poberezkin 631dfff5e9 Merge branch 'stable' 2023-07-29 16:54:50 +01:00
M. Sarmad Qadeer f69c842ba6 website: simplex explained graphics animation (#2713)
* website: animate simplex explained graphics

* website: update simplex network animation

* website: add lottie.min.js through node_modules

* website: update lottie.min.js copy command location
2023-07-29 14:20:51 +01:00
Evgeny Poberezkin 18c802159b android: build 138 2023-07-28 22:58:03 +01:00
Stanislav Dmitrenko 45e557fd80 android: make tmpDir (#2797) 2023-07-28 22:57:06 +01:00
Evgeny Poberezkin d50562cfee 5.3-beta.1: Android 137 2023-07-28 20:11:04 +01:00
Stanislav Dmitrenko 15d3d3b11a desktop: encoding utf8 (#2795)
* desktop: encoding utf8

* rename functions

* logs
2023-07-28 19:38:31 +01:00
Stanislav Dmitrenko 2b715a0d8c desktop: notifications support (#2754)
* desktop: notifications support

* adapted external lib for interacting with notificatioins

* disabled some functions
2023-07-28 19:01:08 +01:00
Stanislav Dmitrenko 02d00944ff desktop: fix creating tmpDir and providing name for file to save (#2789)
* desktop: creating tmpDir

* provide name for saved file

* directories only selection on Mac

* specified filename for file savers

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-28 17:57:48 +01:00
spaced4ndy 71d6410604 5.3-beta.0: iOS 161, Android 136 2023-07-28 14:11:39 +04:00
spaced4ndy 141611293f android: group snd status (#2784) 2023-07-28 13:25:39 +04:00
spaced4ndy c9400fe932 ios: group snd status (#2779) 2023-07-28 13:16:52 +04:00
spaced4ndy 445a8e75fe 5.3.0.0 2023-07-28 11:09:14 +04:00
Stanislav Dmitrenko 9d30a3495e multiplatform: open SimpleX links inside the app (#2778)
* multiplatform: open SimpleX links inside the app

* one more place

* exclude via browser links
2023-07-27 20:21:53 +01:00
Stanislav Dmitrenko d77980e50e desktop: prevent deadlock (#2785)
* desktop: prevent deadlock

* debug info
2023-07-27 15:59:06 +01:00
Stanislav Dmitrenko bb02f07370 desktop: distribution changes (#2782)
* desktop: distribution

* icons update

* package name

* windows

* icons

* package name

* Update apps/multiplatform/desktop/build.gradle.kts

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-27 15:58:24 +01:00
Stanislav Dmitrenko a3cd7ca89e desktop: enter + shift+enter keybindings (#2787) 2023-07-27 13:44:35 +01:00
Stanislav Dmitrenko 976fc68cc3 desktop: parsing html into annotated string (#2786) 2023-07-27 12:33:04 +01:00
Stanislav Dmitrenko 7c7e931aa9 desktop: bound long click to right click too (#2783)
* desktop: bound long click to right click too

* changes
2023-07-27 09:57:21 +01:00
Stanislav Dmitrenko e8e619effa desktop: small fixes in initial setup (#2781)
* desktop: small fixes in initial setup

* small changes

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-27 08:47:11 +01:00
Stanislav Dmitrenko bd0139eaab desktop: Linux lib path (#2780) 2023-07-26 20:13:06 +01:00
Stanislav Dmitrenko e9f77e1064 desktop: development alerts (#2777)
* desktop: development alerts

* strings

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-26 14:31:21 +01:00
Stanislav Dmitrenko 677b75f368 multiplatform: possible race in ChatList (#2757)
* multiplatform: possible race in ChatList

* more changes

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-26 13:27:54 +01:00
Stanislav Dmitrenko 92d13591f3 desktop: change libs path (#2776)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-26 12:44:33 +01:00
Stanislav Dmitrenko 6be8476f90 desktop: decoding utf8 (#2774) 2023-07-26 12:38:49 +01:00
spaced4ndy ae9b83515c core: group snd status (#2763)
* core: group snd status

* schema, implementation

* refactor direct, tests

* configure, tests

* item info

* refactor

* refactor

* remove do

* rename

* remove receipts on events

* refactor

* refactor

* refactor

* refactor

* tests

* rename tests

* aggregates

* fix name

* refactor

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-26 14:49:35 +04:00
Stanislav Dmitrenko 26a233ab1a desktop: adapted UI (#2755)
* desktop: adapted UI

* more changes

* divider fix

* do not close screens on non-desktop in terminal view

* background click to close views and small changes

* dark theme detection on supported OSes

* fix text color after theme change

* placement of desktop text field

* marked as @Composable

* padding of text view

* window sizes

* screen layout

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-26 09:35:29 +01:00
Evgeny Poberezkin c7783a7039 Merge branch 'stable' 2023-07-22 20:09:03 +01:00
Evgeny Poberezkin 0c34a545fa Merge branch 'stable' 2023-07-22 16:27:37 +01:00
Evgeny Poberezkin 1d4afe591e Merge pull request #2750 from simplex-chat/ep/move-prefs
core: split preferences to separate file
2023-07-22 11:41:30 +01:00
Evgeny Poberezkin 10ec3dd8b6 Merge pull request #2746 from simplex-chat/multiplatform
desktop (multiplatform) app 🚀
2023-07-21 21:34:05 +01:00
Evgeny Poberezkin a715e847ad core: split preferences to separate file 2023-07-21 21:32:28 +01:00
Evgeny Poberezkin 9ac0f30c5a Merge branch 'master' into multiplatform 2023-07-21 13:12:05 +01:00
Evgeny Poberezkin 7996194f92 Merge pull request #2741 from simplex-chat/av/multiplatform-merge-master
multiplatform: merged master
2023-07-21 13:06:43 +01:00
Avently c2054b5ccf Merge branch 'master' into av/multiplatform-merge-master 2023-07-21 15:47:51 +07:00
Avently 1cb500bc16 Merge branch 'master' into av/multiplatform-merge-master 2023-07-20 20:43:35 +07:00
Avently f5825d20e4 follow up 2023-07-20 20:43:17 +07:00
Avently 77d249cc37 Merge branch 'master' into av/multiplatform-merge-master 2023-07-20 20:35:08 +07:00
Avently 3f905f59df Merge branch 'master' into av/multiplatform-merge-master 2023-07-20 20:30:12 +07:00
Stanislav Dmitrenko 27f4661ac4 desktop: send images and files (#2691)
* desktop: send images and files

* expect/actual

* file filter on non-Linux OSes

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-19 10:26:37 +01:00
Stanislav Dmitrenko 2389e870b3 desktop: do not show scan QR code screen (#2686)
* desktop: do not show scan QR code screen

* expect/actual and different button text

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-19 09:36:42 +01:00
Stanislav Dmitrenko d61ff0f2a7 desktop: expanded dropdown menu (#2687)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-18 22:52:18 +01:00
spaced4ndy f5d61e7838 Merge pull request #2694 from simplex-chat/av/multiplatform-merged-master2
multiplatform: merged master
2023-07-14 17:52:43 +04:00
spaced4ndy e762923410 Merge pull request #2685 from simplex-chat/av/multiplatform-merged-master
multiplatform: merged master
2023-07-14 17:40:41 +04:00
spaced4ndy d87b86199c Merge branch 'multiplatform' into av/multiplatform-merged-master 2023-07-14 17:29:04 +04:00
Stanislav Dmitrenko a7a66c2b55 multiplatform: adjusted database export path (#2698) 2023-07-14 17:28:13 +04:00
Avently f970ef264a Merge branch 'master' into av/multiplatform-merged-master2 2023-07-14 18:23:21 +07:00
Evgeny Poberezkin 3793cd138e Merge branch 'multiplatform' into av/multiplatform-merged-master 2023-07-14 12:01:48 +01:00
Stanislav Dmitrenko 8dd90733b8 multiplatform: default files and directories were changed (#2683)
* multiplatform: default files and directories were changed

* changes in paths and location of declaration

* more renames

* different paths

* update linux paths

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-14 12:00:37 +01:00
Stanislav Dmitrenko 0bdd96ae8a multiplatform: scripts for building the lib (#2682)
* multiplatform: scripts for building the lib

* refactor mac script

* fix path

* changes in Linux script

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-13 11:02:38 +01:00
Avently dd62b1cccb Merge branch 'master' into av/multiplatform-merged-master 2023-07-12 22:43:57 +07:00
Stanislav Dmitrenko 38f40fec3d multiplatform: split common/android/desktop (#2672)
* multiplatform: relocated code to its new place

* code becomes better

* renamed file

* fixes for BASE64 and images, and changes for appFileUri

* different Base64 for both platforms

* fix file saving on long click

* platformCallbacks refactoring

* renamed callbacks to platform

* eol

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-12 14:42:10 +01:00
Stanislav Dmitrenko ff7c22e114 multiplatform: divided files in pieces (#2664)
* multiplatform: divided files in pieces

* whitespace

* whitespace 2

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-07-07 11:44:22 +01:00
1394 changed files with 270762 additions and 75931 deletions
+268 -28
View File
@@ -8,6 +8,8 @@ on:
- users
tags:
- "v*"
- "!*-fdroid"
- "!*-armv7a"
pull_request:
jobs:
@@ -41,7 +43,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build:
name: build-${{ matrix.os }}
name: build-${{ matrix.os }}-${{ matrix.ghc }}
if: always()
needs: prepare-release
runs-on: ${{ matrix.os }}
@@ -50,17 +52,33 @@ jobs:
matrix:
include:
- os: ubuntu-20.04
ghc: "8.10.7"
cache_path: ~/.cabal/store
- os: ubuntu-20.04
ghc: "9.6.3"
cache_path: ~/.cabal/store
asset_name: simplex-chat-ubuntu-20_04-x86-64
desktop_asset_name: simplex-desktop-ubuntu-20_04-x86_64.deb
- os: ubuntu-22.04
ghc: "9.6.3"
cache_path: ~/.cabal/store
asset_name: simplex-chat-ubuntu-22_04-x86-64
desktop_asset_name: simplex-desktop-ubuntu-22_04-x86_64.deb
- os: macos-latest
ghc: "9.6.3"
cache_path: ~/.cabal/store
asset_name: simplex-chat-macos-aarch64
desktop_asset_name: simplex-desktop-macos-aarch64.dmg
- os: macos-13
ghc: "9.6.3"
cache_path: ~/.cabal/store
asset_name: simplex-chat-macos-x86-64
desktop_asset_name: simplex-desktop-macos-x86_64.dmg
- os: windows-latest
ghc: "9.6.3"
cache_path: C:/cabal
asset_name: simplex-chat-windows-x86-64
desktop_asset_name: simplex-desktop-windows-x86_64.msi
steps:
- name: Configure pagefile (Windows)
if: matrix.os == 'windows-latest'
@@ -74,18 +92,19 @@ jobs:
uses: actions/checkout@v3
- name: Setup Haskell
uses: haskell/actions/setup@v2
uses: haskell-actions/setup@v2
with:
ghc-version: "8.10.7"
cabal-version: "latest"
ghc-version: ${{ matrix.ghc }}
cabal-version: "3.10.1.0"
- name: Cache dependencies
uses: actions/cache@v3
- name: Restore cached build
id: restore_cache
uses: actions/cache/restore@v3
with:
path: |
${{ matrix.cache_path }}
dist-newstyle
key: ${{ matrix.os }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }}
key: ${{ matrix.os }}-ghc${{ matrix.ghc }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }}
# / Unix
@@ -93,14 +112,36 @@ jobs:
if: matrix.os == 'macos-latest'
shell: bash
run: |
echo "ignore-project: False" >> cabal.project.local
echo "package direct-sqlcipher" >> cabal.project.local
echo " extra-include-dirs: /usr/local/opt/openssl@1.1/include" >> cabal.project.local
echo " extra-lib-dirs: /usr/local/opt/openssl@1.1/lib" >> cabal.project.local
echo " flags: +openssl" >> cabal.project.local
echo "ignore-project: False" >> cabal.project.local
echo "package simplexmq" >> cabal.project.local
echo " extra-include-dirs: /opt/homebrew/opt/openssl@1.1/include" >> cabal.project.local
echo " extra-lib-dirs: /opt/homebrew/opt/openssl@1.1/lib" >> cabal.project.local
echo "" >> cabal.project.local
echo "package direct-sqlcipher" >> cabal.project.local
echo " extra-include-dirs: /opt/homebrew/opt/openssl@1.1/include" >> cabal.project.local
echo " extra-lib-dirs: /opt/homebrew/opt/openssl@1.1/lib" >> cabal.project.local
echo " flags: +openssl" >> cabal.project.local
- name: Unix prepare cabal.project.local for Mac
if: matrix.os == 'macos-13'
shell: bash
run: |
echo "ignore-project: False" >> cabal.project.local
echo "package simplexmq" >> cabal.project.local
echo " extra-include-dirs: /usr/local/opt/openssl@1.1/include" >> cabal.project.local
echo " extra-lib-dirs: /usr/local/opt/openssl@1.1/lib" >> cabal.project.local
echo "" >> cabal.project.local
echo "package direct-sqlcipher" >> cabal.project.local
echo " extra-include-dirs: /usr/local/opt/openssl@1.1/include" >> cabal.project.local
echo " extra-lib-dirs: /usr/local/opt/openssl@1.1/lib" >> cabal.project.local
echo " flags: +openssl" >> cabal.project.local
- name: Install AppImage dependencies
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04'
run: sudo apt install -y desktop-file-utils
- name: Install pkg-config for Mac
if: matrix.os == 'macos-latest'
if: matrix.os == 'macos-latest' || matrix.os == 'macos-13'
run: brew install pkg-config
- name: Unix prepare cabal.project.local for Ubuntu
@@ -111,47 +152,195 @@ jobs:
echo "package direct-sqlcipher" >> cabal.project.local
echo " flags: +openssl" >> cabal.project.local
- name: Unix build
id: unix_build
- name: Unix build CLI
id: unix_cli_build
if: matrix.os != 'windows-latest'
shell: bash
run: |
cabal build --enable-tests
echo "::set-output name=bin_path::$(cabal list-bin simplex-chat)"
path=$(cabal list-bin simplex-chat)
echo "bin_path=$path" >> $GITHUB_OUTPUT
echo "bin_hash=$(echo SHA2-512\(${{ matrix.asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
- name: Unix upload binary to release
if: startsWith(github.ref, 'refs/tags/v') && matrix.os != 'windows-latest'
- name: Unix upload CLI binary to release
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os != 'windows-latest'
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ steps.unix_build.outputs.bin_path }}
file: ${{ steps.unix_cli_build.outputs.bin_path }}
asset_name: ${{ matrix.asset_name }}
tag: ${{ github.ref }}
- name: Unix update CLI binary hash
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os != 'windows-latest'
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
append_body: true
body: |
${{ steps.unix_cli_build.outputs.bin_hash }}
- name: Setup Java
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name
uses: actions/setup-java@v3
with:
distribution: 'corretto'
java-version: '17'
cache: 'gradle'
- name: Linux build desktop
id: linux_desktop_build
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04')
shell: bash
run: |
scripts/desktop/build-lib-linux.sh
cd apps/multiplatform
./gradlew packageDeb
path=$(echo $PWD/release/main/deb/simplex_*_amd64.deb)
echo "package_path=$path" >> $GITHUB_OUTPUT
echo "package_hash=$(echo SHA2-512\(${{ matrix.desktop_asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
- name: Linux make AppImage
id: linux_appimage_build
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04'
shell: bash
run: |
scripts/desktop/make-appimage-linux.sh
path=$(echo $PWD/apps/multiplatform/release/main/*imple*.AppImage)
echo "appimage_path=$path" >> $GITHUB_OUTPUT
echo "appimage_hash=$(echo SHA2-512\(simplex-desktop-x86_64.AppImage\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
- name: Mac build desktop
id: mac_desktop_build
if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'macos-latest' || matrix.os == 'macos-13')
shell: bash
env:
APPLE_SIMPLEX_SIGNING_KEYCHAIN: ${{ secrets.APPLE_SIMPLEX_SIGNING_KEYCHAIN }}
APPLE_SIMPLEX_NOTARIZATION_APPLE_ID: ${{ secrets.APPLE_SIMPLEX_NOTARIZATION_APPLE_ID }}
APPLE_SIMPLEX_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_SIMPLEX_NOTARIZATION_PASSWORD }}
run: |
scripts/ci/build-desktop-mac.sh
path=$(echo $PWD/apps/multiplatform/release/main/dmg/SimpleX-*.dmg)
echo "package_path=$path" >> $GITHUB_OUTPUT
echo "package_hash=$(echo SHA2-512\(${{ matrix.desktop_asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
- name: Linux upload desktop package to release
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04')
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ steps.linux_desktop_build.outputs.package_path }}
asset_name: ${{ matrix.desktop_asset_name }}
tag: ${{ github.ref }}
- name: Linux update desktop package hash
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04')
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
append_body: true
body: |
${{ steps.linux_desktop_build.outputs.package_hash }}
- name: Linux upload AppImage to release
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04'
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ steps.linux_appimage_build.outputs.appimage_path }}
asset_name: simplex-desktop-x86_64.AppImage
tag: ${{ github.ref }}
- name: Linux update AppImage hash
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04'
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
append_body: true
body: |
${{ steps.linux_appimage_build.outputs.appimage_hash }}
- name: Mac upload desktop package to release
if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'macos-latest' || matrix.os == 'macos-13')
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ steps.mac_desktop_build.outputs.package_path }}
asset_name: ${{ matrix.desktop_asset_name }}
tag: ${{ github.ref }}
- name: Mac update desktop package hash
if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'macos-latest' || matrix.os == 'macos-13')
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
append_body: true
body: |
${{ steps.mac_desktop_build.outputs.package_hash }}
- name: Cache unix build
uses: actions/cache/save@v3
if: matrix.os != 'windows-latest'
with:
path: |
${{ matrix.cache_path }}
dist-newstyle
key: ${{ steps.restore_cache.outputs.cache-primary-key }}
- name: Unix test
if: matrix.os != 'windows-latest'
timeout-minutes: 30
timeout-minutes: 40
shell: bash
run: cabal test --test-show-details=direct
# Unix /
# / Windows
# rm -rf dist-newstyle/src/direct-sq* is here because of the bug in cabal's dependency which prevents second build from finishing
- name: 'Setup MSYS2'
if: matrix.os == 'windows-latest'
uses: msys2/setup-msys2@v2
with:
msystem: ucrt64
update: true
install: >-
git
perl
make
pacboy: >-
toolchain:p
cmake:p
# * In powershell multiline commands do not fail if individual commands fail - https://github.community/t/multiline-commands-on-windows-do-not-fail-if-individual-commands-fail/16753
# * And GitHub Actions does not support parameterizing shell in a matrix job - https://github.community/t/using-matrix-to-specify-shell-is-it-possible/17065
- name: Windows build
id: windows_build
if: matrix.os == 'windows-latest'
shell: cmd
shell: msys2 {0}
run: |
cabal build --enable-tests
cabal list-bin simplex-chat > tmp_bin_path
set /p bin_path= < tmp_bin_path
echo ::set-output name=bin_path::%bin_path%
export PATH=$PATH:/c/ghcup/bin:$(echo /c/tools/ghc-*/bin || echo)
scripts/desktop/prepare-openssl-windows.sh
openssl_windows_style_path=$(echo `pwd`/dist-newstyle/openssl-1.1.1w | sed 's#/\([a-zA-Z]\)#\1:#' | sed 's#/#\\#g')
rm cabal.project.local 2>/dev/null || true
echo "ignore-project: False" >> cabal.project.local
echo "package direct-sqlcipher" >> cabal.project.local
echo " flags: +openssl" >> cabal.project.local
echo " extra-include-dirs: $openssl_windows_style_path\include" >> cabal.project.local
echo " extra-lib-dirs: $openssl_windows_style_path" >> cabal.project.local
- name: Windows upload binary to release
rm -rf dist-newstyle/src/direct-sq*
sed -i "s/, unix /--, unix /" simplex-chat.cabal
cabal build --enable-tests
rm -rf dist-newstyle/src/direct-sq*
path=$(cabal list-bin simplex-chat | tail -n 1)
echo "bin_path=$path" >> $GITHUB_OUTPUT
echo "bin_hash=$(echo SHA2-512\(${{ matrix.asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
- name: Windows upload CLI binary to release
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'windows-latest'
uses: svenstaro/upload-release-action@v2
with:
@@ -160,4 +349,55 @@ jobs:
asset_name: ${{ matrix.asset_name }}
tag: ${{ github.ref }}
- name: Windows update CLI binary hash
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'windows-latest'
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
append_body: true
body: |
${{ steps.windows_build.outputs.bin_hash }}
- name: Windows build desktop
id: windows_desktop_build
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'windows-latest'
shell: msys2 {0}
run: |
export PATH=$PATH:/c/ghcup/bin:$(echo /c/tools/ghc-*/bin || echo)
scripts/desktop/build-lib-windows.sh
cd apps/multiplatform
./gradlew packageMsi
path=$(echo $PWD/release/main/msi/*imple*.msi | sed 's#/\([a-z]\)#\1:#' | sed 's#/#\\#g')
echo "package_path=$path" >> $GITHUB_OUTPUT
echo "package_hash=$(echo SHA2-512\(${{ matrix.desktop_asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
- name: Windows upload desktop package to release
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'windows-latest'
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ steps.windows_desktop_build.outputs.package_path }}
asset_name: ${{ matrix.desktop_asset_name }}
tag: ${{ github.ref }}
- name: Windows update desktop package hash
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'windows-latest'
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
append_body: true
body: |
${{ steps.windows_desktop_build.outputs.package_hash }}
- name: Cache windows build
uses: actions/cache/save@v3
if: matrix.os == 'windows-latest'
with:
path: |
${{ matrix.cache_path }}
dist-newstyle
key: ${{ steps.restore_cache.outputs.cache-primary-key }}
# Windows /
+9 -3
View File
@@ -5,14 +5,20 @@ on:
pull_request_target:
types: [opened, closed, synchronize]
permissions:
actions: write
contents: write
pull-requests: write
statuses: write
jobs:
CLAssistant:
runs-on: ubuntu-latest
steps:
- name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request'
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
# Beta Release
uses: cla-assistant/github-action@v2.1.3-beta
uses: cla-assistant/github-action@v2.3.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret
@@ -33,4 +39,4 @@ jobs:
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
#use-dco-flag: true - If you are using DCO instead of CLA
#use-dco-flag: true - If you are using DCO instead of CLA
+1 -1
View File
@@ -4,11 +4,11 @@ on:
push:
branches:
- master
- stable
paths:
- website/**
- images/**
- blog/**
- docs/**
- .github/workflows/web.yml
jobs:
+2
View File
@@ -53,6 +53,8 @@ website/src/docs/
website/translations.json
website/src/img/images/
website/src/images/
website/src/js/lottie.min.js
website/src/privacy.md
# Generated files
website/package/generated*
+27 -18
View File
@@ -1,32 +1,41 @@
FROM ubuntu:focal AS build
ARG TAG=22.04
# Install curl and simplex-chat-related dependencies
RUN apt-get update && apt-get install -y curl git build-essential libgmp3-dev zlib1g-dev libssl-dev
FROM ubuntu:${TAG} AS build
### Build stage
# Install curl and git and simplex-chat dependencies
RUN apt-get update && apt-get install -y curl git build-essential libgmp3-dev zlib1g-dev llvm-12 llvm-12-dev libnuma-dev libssl-dev
# Specify bootstrap Haskell versions
ENV BOOTSTRAP_HASKELL_GHC_VERSION=9.6.3
ENV BOOTSTRAP_HASKELL_CABAL_VERSION=3.10.1.0
# Install ghcup
RUN a=$(arch); curl https://downloads.haskell.org/~ghcup/$a-linux-ghcup -o /usr/bin/ghcup && \
chmod +x /usr/bin/ghcup
# Install ghc
RUN ghcup install ghc 8.10.7
# Install cabal
RUN ghcup install cabal
# Set both as default
RUN ghcup set ghc 8.10.7 && \
ghcup set cabal
COPY . /project
WORKDIR /project
RUN curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 sh
# Adjust PATH
ENV PATH="/root/.cabal/bin:/root/.ghcup/bin:$PATH"
# Set both as default
RUN ghcup set ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}" && \
ghcup set cabal "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
COPY . /project
WORKDIR /project
# Adjust build
RUN cp ./scripts/cabal.project.local.linux ./cabal.project.local
# Compile simplex-chat
RUN cabal update
RUN cabal install
RUN cabal build exe:simplex-chat
# Strip the binary from debug symbols to reduce size
RUN bin=$(find /project/dist-newstyle -name "simplex-chat" -type f -executable) && \
mv "$bin" ./ && \
strip ./simplex-chat
# Copy compiled app from build stage
FROM scratch AS export-stage
COPY --from=build /root/.cabal/bin/simplex-chat /
COPY --from=build /project/simplex-chat /
+125 -46
View File
@@ -1,96 +1,175 @@
# SimpleX Chat Terms & Privacy Policy
---
layout: layouts/privacy.html
permalink: /privacy/index.html
---
SimpleX Chat is the first communication platform that has no user profile IDs of any kind, not even random numbers. Not only it has no access to your messages (thanks to open-source double-ratchet end-to-end encryption protocol and additional encryption layers), it also has no access to your profile and contacts - we cannot observe your connections graph.
# SimpleX Chat Privacy Policy and Conditions of Use
If you believe that some of the clauses in this document are not aligned with our mission or principles, please raise it with us via [email](chat@simplex.chat) or [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).
SimpleX Chat is the first communication network based on a new protocol stack that builds on the same ideas of complete openness and decentralization as email and web, with the focus on providing security and privacy of communications, and without compromising on usability.
SimpleX Chat communication protocol is the first protocol that has no user profile IDs of any kind, not even random numbers, cryptographic keys or hashes that identify the users. SimpleX Chat apps allow their users to send messages and files via relay server infrastructure. Relay server owners and providers do not have any access to your messages, thanks to double-ratchet end-to-end encryption algorithm (also known as Signal algorithm - do not confuse with Signal protocols or platform) and additional encryption layers, and they also have no access to your profile and contacts - as they do not provide any user accounts.
Double ratchet algorithm has such important properties as [forward secrecy](/docs/GLOSSARY.md#forward-secrecy), sender [repudiation](/docs/GLOSSARY.md#) and break-in recovery (also known as [post-compromise security](/docs/GLOSSARY.md#post-compromise-security)).
If you believe that any part of this document is not aligned with our mission or values, please raise it with us via [email](mailto:chat@simplex.chat) or [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).
## Privacy Policy
SimpleX Chat Ltd. ("SimpleX Chat") uses the best industry practices for security and end-to-end encryption to provide secure end-to-end encrypted messaging via private connections. SimpleX Chat is built on top of SimpleX messaging and application platform that uses a new message routing protocol that allows establishing private connection without having any kind of addresses that identify its users - we don't use emails, phone numbers, usernames, identity keys or any other user identifiers to pass messages between the users.
SimpleX Chat Ltd uses the best industry practices for security and encryption to provide client and server software for secure [end-to-end encrypted](/docs/GLOSSARY.md#end-to-end-encryption) messaging via private connections. This encryption cannot be compromised by the relays servers, even if they are modified or compromised, via [man-in-the-middle attack](/docs/GLOSSARY.md#man-in-the-middle-attack), unlike most other communication platforms, services and networks.
SimpleX Chat security audit was performed in October 2022 by [Trail of Bits](https://www.trailofbits.com/about), and most fixes were released in v4.2.0 see [the announcement](./blog/20221108-simplex-chat-v4.2-security-audit-new-website.md).
SimpleX Chat software is built on top of SimpleX messaging and application protocols, based on a new message routing protocol allowing to establish private connections without having any kind of addresses or other identifiers assigned to its users - it does not use emails, phone numbers, usernames, identity keys or any other user profile identifiers to pass messages between the user applications.
### Information you provide
SimpleX Chat software is similar in its design approach to email clients and browsers - it allows you to have full control of your data and freely choose the relay server providers, in the same way you choose which website or email provider to use, or use your own relay servers, simply by changing the configuration of the client software. The only current restriction to that is Apple push notifications - at the moment they can only be delivered via the preset servers that we operate, as explained below. We are exploring the solutions to deliver push notifications to iOS devices via other providers or users' own servers.
We do not store user profiles. The profile you create in the app is local to your device. When you create a user profile, no records are created on our servers, and we have no access to any part of your profile information, and even to the fact that you created a profile - it is a local record stored only on your device. That means that if you delete the app, and have no backup, you will permanently lose all the data and the private connections you create with other users.
While SimpleX Chat Ltd is not a communication service provider, and provide public preset relays "as is", as experimental, without any guarantees of availability or data retention, we are committed to maintain a high level of availability, reliability and security of these preset relays. We will be adding alternative preset infrastructure providers to the software in the future, and you will continue to be able to use any other providers or your own servers.
Messages. SimpleX Chat cannot decrypt or otherwise access the content or even size of your messages (each message is padded to a fixed size of 16kb). SimpleX Chat temporarily stores end-to-end encrypted messages on its servers for delivery to the devices that are offline, these messages are permanently removed as soon as they are delivered. Your message history is stored only on your own devices.
We see users and data sovereignty, and device and provider portability as critically important properties for any communication system.
Connections with other users. When you create a connection with another user, two messaging queues (you can think about them as about mailboxes) are created on our servers, or on the servers that you configured in the app, in case it allows such configuration (SimpleX uses separate queues for direct and response messages, that the client applications prefer to create on two different servers, in case you have more than one server configured in the app, which is the default). At the time of updating this document all our client applications allow configuring the servers. Our servers do not store information about which queues are linked to your profile on the device, and they do not collect any information that would allow us to establish that these queues are related to your device or your profile - the access to each queue is authorized by a set of anonymous unique cryptographic keys, different for each queue, and separate for sender and recipient of the messages. The exception to that is when you choose to use instant push notifications in our iOS app, because the design of push notifications requires storing the device token on notification server, and the server can observe how many messaging queues your device uses, and approximate how many messages are sent to each queue. It does not allow though to determine the actual addresses of these queues, as a separate address is used to subscibe to the notifications (unless notification and messaging servers exchange information), and who, or even how many contacts, send messages to you, as notifications are delivered to your device end-to-end encrypted by the messaging servers. It also does not allow to see message content or sizes, as the actual messages are not sent via the notification service, only the fact that the message is available and where it can be received from (the latter information is encrypted, so that the notification server cannot see it). You can read more about the design of iOS push notifications [here](https://simplex.chat/blog/20220404-simplex-chat-instant-notifications.html#our-ios-approach-has-one-trade-off).
SimpleX Chat security assessment was done in October 2022 by [Trail of Bits](https://www.trailofbits.com/about), and most fixes were released in v4.2 see [the announcement](/blog/20221108-simplex-chat-v4.2-security-audit-new-website.md).
Additional technical information can be stored on our servers, including randomly generated authentication tokens, keys, push tokens, and other material that is necessary to transmit messages. SimpleX Chat limits this additional technical information to the minimum required to operate the Services.
### Your information
User Support. If you contact SimpleX Chat any personal data you may share with us 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.
#### User profiles
Servers used by SimpleX Chat apps do not create, store or identify user profiles. The profiles you can create in the app are local to your device, and can be removed at any time via the app.
When you create the local profile, no records are created on any of the relay servers, and infrastructure providers, whether SimpleX Chat Ltd or any other, have no access to any part of your information, and even to the fact that you created a profile - it is a local record stored only on your device. That means that if you delete the app, and have no backup, you will permanently lose all your data and the private connections you created with other software users.
You can transfer the profile to another device by creating a backup of the app data and restoring it on the new device, but you cannot use more than one device with the copy of the same profile at the same time - it will disrupt any active conversations on either or both devices, as a security property of end-to-end encryption.
#### Messages and Files
SimpleX relay servers cannot decrypt or otherwise access the content or even the size of your messages and files you send or receive. Each message is padded to a fixed size of 16kb. Each file is sent in chunks of 64kb, 256kb, 1mb or 8mb via all or some of the configured file relay servers. Both messages and files are sent end-to-end encrypted, and the servers do not have technical means to compromise this encryption, because part of the [key exchange](/docs/GLOSSARY.md#key-exchange) happens out-of-band.
Your message history is stored only on your own device and the devices of your contacts. While the recipients' devices are offline, messaging relay servers temporarily store end-to-end encrypted messages you can configure which relay servers are used to receive the messages from the new contacts, and you can manually change them for the existing contacts too.
You do not have control over which servers are used to send messages to your contacts - they are chosen by them. To send messages your client needs to connect to these servers, therefore the servers chosen by your contacts can observe your IP address. You can use VPN or some overlay network (e.g., Tor) to hide your IP address from the servers chosen by your contacts. In the near future we will add the layer in the messaging protocol that will route sent message via the relays chosen by you as well.
The messages are permanently removed from the used relay servers as soon as they are delivered, as long as these servers used unmodified published code. Undelivered messages are deleted after the time that is configured in the messaging servers you use (21 days for preset messaging servers).
The files are stored on file relay servers for the time configured in the relay servers you use (48 hours for preset file servers).
If a messaging servers are restarted, the encrypted message can be stored in a backup file until it is overwritten by the next restart (usually within 1 week for preset relay servers).
As this software is fully open-source and provided under AGPLv3 license, all infrastructure providers and owners, and the developers of the client and server applications who use the SimpleX Chat source code, are required to publish any changes to this software under the same AGPLv3 license - including any modifications to the provided servers.
In addition to the AGPLv3 license terms, SimpleX Chat Ltd is committed to the software users that the preset relays that we provide via the apps will always be compiled from the [published open-source code](https://github.com/simplex-chat/simplexmq), without any modifications.
#### Connections with other users
When you create a connection with another user, two messaging queues (you can think about them as mailboxes) are created on messaging relay servers (chosen by you and your contact each), that can be the preset servers or the servers that you and your contact configured in the app. SimpleX messaging protocol uses separate queues for direct and response messages, and the apps prefer to create these queues on two different relay servers for increased privacy, in case you have more than one relay server configured in the app, which is the default.
SimpleX relay servers do not store information about which queues are linked to your profile on the device, and they do not collect any information that would allow infrastructure owners and providers to establish that these queues are related to your device or your profile - the access to each queue is authorized by two anonymous unique cryptographic keys, different for each queue, and separate for sender and recipient of the messages.
#### Connection links privacy
When you create a connection with another user, the app generates a link/QR code that can be shared with the user to establish the connection via any channel (email, any other messenger, or a video call). This link is safe to share via insecure channels, as long as you can identify the recipient and also trust that this channel did not replace this link (to mitigate the latter risk you can validate the security code via the app).
While the connection "links" contain SimpleX Chat Ltd domain name `simplex.chat`, this site is never accessed by the app, and is only used for these purposes:
- to direct the new users to the app download instructions,
- to show connection QR code that can be scanned via the app,
- to "namespace" these links,
- to open links directly in the installed app when it is clicked outside of the app.
You can always safely replace the initial part of the link `https://simplex.chat/` either with `simplex:/` (which is a URI scheme provisionally registered with IANA) or with any other domain name where you can self-host the app download instructions and show the connection QR code (but in case it is your domain, it will not open in the app). Also, while the page renders QR code, all the information needed to render it is only available to the browser, as the part of the "link" after `#` symbol is not sent to the website server.
#### iOS Push Notifications
When you choose to use instant push notifications in SimpleX iOS app, because the design of push notifications requires storing the device token on notification server, the notifications server can observe how many messaging queues your device has notifications enabled for, and approximately how many messages are sent to each queue.
Preset notification server cannot observe the actual addresses of these queues, as a separate address is used to subscribe to the notifications. It also cannot observe who sends messages to you. Apple push notifications servers can only observe how many notifications are sent to you, but not from how many contacts, or from which messaging relays, as notifications are delivered to your device end-to-end encrypted by one of the preset notification servers - these notifications only contain end-to-end encrypted metadata, not even encrypted message content, and they look completely random to Apple push notification servers.
You can read more about the design of iOS push notifications [here](./blog/20220404-simplex-chat-instant-notifications.md#our-ios-approach-has-one-trade-off).
#### Another information stored on the servers
Additional technical information can be stored on our servers, including randomly generated authentication tokens, keys, push tokens, and other material that is necessary to transmit messages. SimpleX Chat design limits this additional technical information to the minimum required to operate the software and servers. To prevent server overloading or attacks, the servers can temporarily store data that can link to particular users or devices, including IP addresses, geographic location, or information related to the transport sessions. This information is not stored for the absolute majority of the app users, even for those who use the servers very actively.
#### SimpleX Directory
[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).
#### User Support
If you contact SimpleX Chat Ltd, any personal data you share with us 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.
### Information we may share
We operate our Services using third parties. While we do not share any user data, these third party may access the encrypted user data as it is stored or transmitted via our servers.
SimpleX Chat Ltd operates preset relay servers using third parties. While we do not have access and cannot share any user data, these third parties may access the encrypted user messages (but NOT the actual unencrypted message content or size) as it is stored or transmitted via our servers. Hosting providers can also store IP addresses and other transport information as part of their logs.
We use Third party to provide email services - if you ask for support via email, your and SimpleX Chat email providers may access these emails according their privacy policies and terms of service.
We use a third party for email services - if you ask for support via email, your and SimpleX Chat Ltd email providers may access these emails according to their privacy policies and terms. When the request is sensitive, we recommend contacting us via SimpleX Chat or using encrypted email using PGP key published at [openpgp.org](https://keys.openpgp.org/search?q=chat%40simplex.chat).
The cases when SimpleX Chat may need to share the data we temporarily store on the servers:
The cases when SimpleX Chat Ltd may share the data temporarily stored on the servers:
- To meet any applicable law, regulation, legal process or enforceable governmental request.
- To enforce applicable Terms, including investigation of potential violations.
- To meet any applicable law, or enforceable governmental request or court order.
- To enforce applicable terms, including investigation of potential violations.
- To detect, prevent, or otherwise address fraud, security, or technical issues.
- To protect against harm to the rights, property, or safety of SimpleX Chat, our users, or the public as required or permitted by law.
- To protect against harm to the rights, property, or safety of software users, SimpleX Chat Ltd, or the public as required or permitted by law.
At the time of updating this document, we have never provided or have been requested the access to our servers or any information from our servers by any third parties. If we are ever requested to provide such access or information, we will follow the due legal process.
At the time of updating this document, we 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 we are ever requested to provide such access or information, we will follow the due legal process to limit any information shared with the third parties to the minimally required by law.
We will publish information we are legally allowed to share about such requests in the [Transparency reports](./docs/TRANSPARENCY.md).
### Updates
We will update this privacy policy as needed so that it is current, accurate, and as clear as possible. Your continued use of our Services confirms your acceptance of our updated Privacy Policy.
We will update this Privacy Policy as needed so that it is current, accurate, and as clear as possible. Your continued use of our software applications and preset relays infrastructure confirms your acceptance of our updated Privacy Policy.
Please also read our Terms of Service.
Please also read our Conditions of Use of Software and Infrastructure below.
If you have questions about our Privacy Policy please contact us at chat@simplex.chat.
If you have questions about our Privacy Policy please contact us via [email](mailto:chat@simplex.chat) or [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).
## Terms of Service
## Conditions of Use of Software and Infrastructure
You accept to our Terms of Service ("Terms") by installing or using any of our apps or services ("Services").
You accept the Conditions of Use of Software and Infrastructure ("Conditions") by installing or using any of our software or using any of our server infrastructure (collectively referred to as "Applications"), whether preset in the software or not.
**Minimal age**. You must be at least 13 years old to use our Services. The minimum age to use our Services without parental approval may be higher in your country.
**Minimal age**. You must be at least 13 years old to use our Applications. The minimum age to use our Applications without parental approval may be higher in your country.
**Accessing the servers**. For the efficiency of the network access, the apps access all queues you create on any server via the same network (TCP/IP) connection. Our servers do not collect information about which queues were accessed via the same connection, so we do cannot establish which queues belong to the same users. Whoever might observe your network traffic would know which servers you use, and how much data you send, but not to whom it is sent - the data that leaves the servers is always different from the data they receive - there are no identifiers or cyphertext in common. Please refer to our [technical design document](https://github.com/simplex-chat/simplexmq/blob/master/protocol/overview-tjr.md) for more information about our privacy model and known security and privacy risks.
**Infrastructure**. Our Infrastructure includes preset messaging and file relay servers, and iOS push notification servers provided by SimpleX Chat Ltd for public use. Our infrastructure does not have any modifications from the [published open-source code](https://github.com/simplex-chat/simplexmq) available under AGPLv3 license. Any infrastructure provider, whether commercial or not, is required by the Affero clause (named after Affero Inc. company that pioneered the community-based Q&A sites in early 2000s) to publish any modifications under the same license. The statements in relation to Infrastructure and relay servers anywhere in this document assume no modifications to the published code, even in the cases when it is not explicitly stated.
**Privacy of user data**. We do not retain any data we transmit for any longer than necessary to provide the Services. We only collect aggregate statistics across all users, not per user - we do not have information about how many people use SimpleX Chat (we only know an approximate number of app installations and the aggregate traffic through our servers). In any case, we do not and will not sell or in any way monetize user data.
**Client applications**. Our client application Software (referred to as "app" or "apps") also has no modifications compared with published open-source code, and any developers of the alternative client apps based on our code are required to publish any modifications under the same AGPLv3 license. Client applications should not include any tracking or analytics code, and do not share any information with SimpleX Chat Ltd or any other third parties. If you ever discover any tracking or analytics code, please report it to us, so we can remove it.
**Operating our services**. For the purpose of operating our Services, you agree that your end-to-end encrypted messages are transferred via our servers in the United Kingdom, the United States and other countries where we have or use facilities and service providers or partners.
**Accessing the infrastructure**. For the efficiency of the network access, the client Software by default accesses all queues your app creates on any relay server within one user profile via the same network (TCP/IP) connection. At the cost of additional traffic this configuration can be changed to use different transport session for each connection. Relay servers do not collect information about which queues were created or accessed via the same connection, so the relay servers cannot establish which queues belong to the same user profile. Whoever might observe your network traffic would know which relay servers you use, and how much data you send, but not to whom it is sent - the data that leaves the servers is always different from the data they receive - there are no identifiers or ciphertext in common, even inside TLS encryption layer. Please refer to our [technical design document](https://github.com/simplex-chat/simplexmq/blob/master/protocol/overview-tjr.md) for more information about our privacy model and known security and privacy risks.
**Software**. You agree to downloading and installing updates to our Services when they are available; they would only be automatic if you configure your devices in this way.
**Privacy of user data**. Servers do not retain any data we transmit for any longer than necessary to deliver the messages between apps. SimpleX Chat Ltd collects aggregate statistics across all its servers, as supported by published code and can be enabled by any infrastructure provider, but not any statistics per-user, or per geographic location, or per IP address, or per transport session. We do not have information about how many people use SimpleX Chat applications, we only know an approximate number of app installations and the aggregate traffic through the preset servers. In any case, we do not and will not sell or in any way monetize user data. Our future business model assumes charging for some optional Software features instead, in a transparent and fair way.
**Traffic and device costs**. You are solely responsible for the traffic and device costs on which you use our Services, and any associated taxes.
**Operating our Infrastructure**. For the purpose of using our Software, if you continue using preset servers, you agree that your end-to-end encrypted messages are transferred via the preset servers in any countries where we have or use facilities and service providers or partners. The information about geographic location of the servers will be made available in the apps in the near future.
**Legal and acceptable usage**. You agree to use our Services only for legal and acceptable purposes. You will not use (or assist others in using) our Services in ways that: 1) violate or infringe the rights of SimpleX Chat, our users, or others, including privacy, publicity, intellectual property, or other proprietary rights; 2) involve sending illegal or impermissible communications, e.g. spam.
**Software**. You agree to downloading and installing updates to our Applications when they are available; they would only be automatic if you configure your devices in this way.
**Damage to SimpleX Chat**. You must not (or assist others to) access, use, modify, distribute, transfer, or exploit our Services in unauthorized manners, or in ways that harm SimpleX Chat, our Services, or systems. For example, you must not 1) access our Services or systems without authorization, other than by using the apps; 2) disrupt the integrity or performance of our Services; 3) collect information about our users in any manner; or 4) sell, rent, or charge for our Services.
**Traffic and device costs**. You are solely responsible for the traffic and device costs that you incur while using our Applications, and any associated taxes.
**Keeping your data secure**. SimpleX Chat is the first messaging platform that is 100% private by design - we neither have ability to access your messages, nor we have information about who you communicate with. That means that you are solely responsible for keeping your device and your user profile safe and secure. If you lose your phone or remove the app, you will not be able to recover the lost data, unless you made a back up.
**Legal usage**. You agree to use our Applications only for legal purposes. You will not use (or assist others in using) our Applications in ways that: 1) violate or infringe the rights of Software users, SimpleX Chat Ltd, or others, including privacy, publicity, intellectual property, or other proprietary rights; 2) involve sending illegal communications, e.g. spam. While we cannot access content or identify messages or groups, in some cases the links to the illegal communications available via our Applications can be shared publicly on social media or websites. We reserve the right to remove such links from the preset servers and disrupt the conversations that send illegal content via our servers, whether they were reported by the users or discovered by our team.
**Storing the messages on the device**. Currently the messages are stored in the database on your device without encryption. It means that if you make a backup of the app and store it unecrypted, the backup provider may be able to access the messages.
**Damage to SimpleX Chat Ltd**. You must not (or assist others to) access, use, modify, distribute, transfer, or exploit our Applications in unauthorized manners, or in ways that harm Software users, SimpleX Chat Ltd, our Infrastructure, or any other systems. For example, you must not 1) access our Infrastructure or systems without authorization, in any way other than by using the Software; 2) disrupt the integrity or performance of our Infrastructure; 3) collect information about our users in any manner; or 4) sell, rent, or charge for our 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.
**No Access to Emergency Services**. Our Services do not provide access to emergency service providers like the police, fire department, hospitals, or other public safety organizations. Make sure you can contact emergency service providers through a mobile, fixed-line telephone, or other service.
**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.
**Third-party services**. Our Services may allow you to access, use, or interact with third-party websites, apps, content, and other products and services. When you use third-party services, their terms and privacy policies govern your use of those services.
**Storing the messages on the device**. The messages are stored in the encrypted database on your device. Whether and how database passphrase is stored is determined by the configuration of the Software you use. The databases created prior to 2023 or in CLI (terminal) app may remain unencrypted, and it will be indicated in the app interface. In this case, if you make a backup of the data and store it unencrypted, the backup provider may be able to access the messages. Please note, that the desktop apps can be configured to store the database passphrase in the configuration file in plaintext, and unless you set the passphrase when first running the app, a random passphrase will be used and stored on the device. You can remove it from the device via the app settings.
**Your Rights**. You own the mesasges and information you transmit through our Services. Your recipients are able to retain the messages you receive from you; there is no technical ability to delete data from their devices.
**Storing the files on the device**. The files currently sent and received in the apps by default (except CLI app) are stored on your device encrypted using unique keys, different for each file, that are stored in the database. Once the message that the file was attached to is removed, even if the copy of the encrypted file is retained, it should be impossible to recover the key allowing to decrypt the file. This local file encryption may affect app performance, and it can be disabled via the app settings. This change will only affect the new files. If you later re-enable the encryption, it will also affect only the new files. If you make a backup of the app data and store it unencrypted, the backup provider will be able to access any unencrypted files. In any case, irrespective of the storage setting, the files are always sent by all apps end-to-end encrypted.
**License**. SimpleX Chat grants you a limited, revocable, non-exclusive, and non-transferable license to use our Services in accordance with these Terms. The source-code of services is available and can be used under [AGPL v3 licence](https://github.com/simplex-chat/simplex-chat/blob/stable/LICENSE)
**No Access to Emergency Services**. Our Applications do not provide access to emergency service providers like the police, fire department, hospitals, or other public safety organizations. Make sure you can contact emergency service providers through a mobile, fixed-line telephone, or other service.
**SimpleX Chat Rights**. We own all copyrights, trademarks, domains, logos, trade secrets, and other intellectual property rights associated with our Services. You may not use our copyrights, trademarks, domains, logos, and other intellectual property rights unless you have our written permission, and unless under an open-source license distributed together with the source code. To report copyright, trademark, or other intellectual property infringement, please contact chat@simplex.chat.
**Third-party services**. Our Applications may allow you to access, use, or interact with our or third-party websites, apps, content, and other products and services. When you use third-party services, their terms and privacy policies govern your use of those services.
**Disclaimers**. YOU USE OUR SERVICES AT YOUR OWN RISK AND SUBJECT TO THE FOLLOWING DISCLAIMERS. WE PROVIDE OUR SERVICES ON AN “AS IS” BASIS WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, AND FREEDOM FROM COMPUTER VIRUS OR OTHER HARMFUL CODE. SIMPLEX DOES NOT WARRANT THAT ANY INFORMATION PROVIDED BY US IS ACCURATE, COMPLETE, OR USEFUL, THAT OUR SERVICES WILL BE OPERATIONAL, ERROR-FREE, SECURE, OR SAFE, OR THAT OUR SERVICES WILL FUNCTION WITHOUT DISRUPTIONS, DELAYS, OR IMPERFECTIONS. WE DO NOT CONTROL, AND ARE NOT RESPONSIBLE FOR, CONTROLLING HOW OR WHEN OUR USERS USE OUR SERVICES. WE ARE NOT RESPONSIBLE FOR THE ACTIONS OR INFORMATION (INCLUDING CONTENT) OF OUR USERS OR OTHER THIRD PARTIES. YOU RELEASE US, AFFILIATES, DIRECTORS, OFFICERS, EMPLOYEES, PARTNERS, AND AGENTS ("SIMPLEX PARTIES") FROM ANY CLAIM, COMPLAINT, CAUSE OF ACTION, CONTROVERSY, OR DISPUTE (TOGETHER, "CLAIM") AND DAMAGES, KNOWN AND UNKNOWN, RELATING TO, ARISING OUT OF, OR IN ANY WAY CONNECTED WITH ANY SUCH CLAIM YOU HAVE AGAINST ANY THIRD PARTIES.
**Your Rights**. You own the messages and the information you transmit through our Applications. Your recipients are able to retain the messages they receive from you; there is no technical ability to delete data from their devices. While there are various app features that allow deleting messages from the recipients' devices, such as _disappearing messages_ and _full message deletion_, their functioning on your recipients' devices cannot be guaranteed or enforced, as the device may be offline or have a modified version of the Software. At the same time, repudiation property of the end-to-end encryption algorithm allows you to plausibly deny having sent the message, like you can deny what you said in a private face-to-face conversation, as the recipient cannot provide any proof to the third parties, by design.
**Limitation of liability**. THE SIMPLEX PARTIES WILL NOT BE LIABLE TO YOU FOR ANY LOST PROFITS OR CONSEQUENTIAL, SPECIAL, PUNITIVE, INDIRECT, OR INCIDENTAL DAMAGES RELATING TO, ARISING OUT OF, OR IN ANY WAY IN CONNECTION WITH OUR TERMS, US, OR OUR SERVICES, EVEN IF THE SIMPLEX PARTIES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. OUR AGGREGATE LIABILITY RELATING TO, ARISING OUT OF, OR IN ANY WAY IN CONNECTION WITH OUR TERMS, US, OR OUR SERVICES WILL NOT EXCEED ONE DOLLAR ($1). THE FOREGOING DISCLAIMER OF CERTAIN DAMAGES AND LIMITATION OF LIABILITY WILL APPLY TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW. THE LAWS OF SOME JURISDICTIONS MAY NOT ALLOW THE EXCLUSION OR LIMITATION OF CERTAIN DAMAGES, SO SOME OR ALL OF THE EXCLUSIONS AND LIMITATIONS SET FORTH ABOVE MAY NOT APPLY TO YOU. NOTWITHSTANDING ANYTHING TO THE CONTRARY IN OUR TERMS, IN SUCH CASES, THE LIABILITY OF THE SIMPLEX PARTIES WILL BE LIMITED TO THE EXTENT PERMITTED BY APPLICABLE LAW.
**License**. SimpleX Chat Ltd grants you a limited, revocable, non-exclusive, and non-transferable license to use our Applications in accordance with these Conditions. The source-code of Applications is available and can be used under [AGPL v3 license](https://github.com/simplex-chat/simplex-chat/blob/stable/LICENSE).
**Availability**. Our Services may be interrupted, including for maintenance, upgrades, or network or equipment failures. We may discontinue some or all of our Services, including certain features and the support for certain devices and platforms, at any time.
**SimpleX Chat Ltd Rights**. We own all copyrights, trademarks, domains, logos, trade secrets, and other intellectual property rights associated with our Applications. You may not use our copyrights, trademarks, domains, logos, and other intellectual property rights unless you have our written permission, and unless under an open-source license distributed together with the source code. To report copyright, trademark, or other intellectual property infringement, please contact chat@simplex.chat.
**Resolving disputes**. You agree to resolve any Claim you have with us relating to or arising from our Terms, us, or our Services in the courts of England and Wales. You also agree to submit to the personal jurisdiction of such courts for the purpose of resolving all such disputes. The laws of England govern our Terms, as well as any disputes, whether in court or arbitration, which might arise between SimpleX Chat and you, without regard to conflict of law provisions.
**Disclaimers**. YOU USE OUR APPLICATIONS AT YOUR OWN RISK AND SUBJECT TO THE FOLLOWING DISCLAIMERS. WE PROVIDE OUR APPLICATIONS ON AN “AS IS” BASIS WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, AND FREEDOM FROM COMPUTER VIRUS OR OTHER HARMFUL CODE. SIMPLEX CHAT LTD DOES NOT WARRANT THAT ANY INFORMATION PROVIDED BY US IS ACCURATE, COMPLETE, OR USEFUL, THAT OUR APPLICATIONS WILL BE OPERATIONAL, ERROR-FREE, SECURE, OR SAFE, OR THAT OUR APPLICATIONS WILL FUNCTION WITHOUT DISRUPTIONS, DELAYS, OR IMPERFECTIONS. WE DO NOT CONTROL, AND ARE NOT RESPONSIBLE FOR, CONTROLLING HOW OR WHEN OUR USERS USE OUR APPLICATIONS. WE ARE NOT RESPONSIBLE FOR THE ACTIONS OR INFORMATION (INCLUDING CONTENT) OF OUR USERS OR OTHER THIRD PARTIES. YOU RELEASE US, AFFILIATES, DIRECTORS, OFFICERS, EMPLOYEES, PARTNERS, AND AGENTS ("SIMPLEX PARTIES") FROM ANY CLAIM, COMPLAINT, CAUSE OF ACTION, CONTROVERSY, OR DISPUTE (TOGETHER, "CLAIM") AND DAMAGES, KNOWN AND UNKNOWN, RELATING TO, ARISING OUT OF, OR IN ANY WAY CONNECTED WITH ANY SUCH CLAIM YOU HAVE AGAINST ANY THIRD PARTIES.
**Changes to the terms**. SimpleX Chat may update the Terms from time to time. Your continued use of our Services confirms your acceptance of our updated Terms and supersedes any prior Terms. You will comply with all applicable export control and trade sanctions laws. Our Terms cover the entire agreement between you and SimpleX Chat regarding our Services. If you do not agree with our Terms, you should stop using our Services.
**Limitation of liability**. THE SIMPLEX PARTIES WILL NOT BE LIABLE TO YOU FOR ANY LOST PROFITS OR CONSEQUENTIAL, SPECIAL, PUNITIVE, INDIRECT, OR INCIDENTAL DAMAGES RELATING TO, ARISING OUT OF, OR IN ANY WAY IN CONNECTION WITH OUR CONDITIONS, US, OR OUR APPLICATIONS, EVEN IF THE SIMPLEX PARTIES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. OUR AGGREGATE LIABILITY RELATING TO, ARISING OUT OF, OR IN ANY WAY IN CONNECTION WITH OUR CONDITIONS, US, OR OUR APPLICATIONS WILL NOT EXCEED ONE DOLLAR ($1). THE FOREGOING DISCLAIMER OF CERTAIN DAMAGES AND LIMITATION OF LIABILITY WILL APPLY TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW. THE LAWS OF SOME JURISDICTIONS MAY NOT ALLOW THE EXCLUSION OR LIMITATION OF CERTAIN DAMAGES, SO SOME OR ALL OF THE EXCLUSIONS AND LIMITATIONS SET FORTH ABOVE MAY NOT APPLY TO YOU. NOTWITHSTANDING ANYTHING TO THE CONTRARY IN OUR CONDITIONS, IN SUCH CASES, THE LIABILITY OF THE SIMPLEX PARTIES WILL BE LIMITED TO THE EXTENT PERMITTED BY APPLICABLE LAW.
**Enforcing the terms**. If we fail to enforce any of our Terms, that does not mean we waive the right to enforce them. If any provision of the Terms is deemed unlawful, void, or unenforceable, that provision shall be deemed severable from our Terms and shall not affect the enforceability of the remaining provisions. Our Services are not intended for distribution to or use in any country where such distribution or use would violate local law or would subject us to any regulations in another country. We reserve the right to limit our Services in any country. If you have specific questions about these Terms, please contact us at chat@simplex.chat.
**Availability**. Our Applications may be disrupted, including for maintenance, upgrades, or network or equipment failures. We may discontinue some or all of our Applications, including certain features and the support for certain devices and platforms, at any time.
**Ending these Terms**. You may end these Terms with SimpleX Chat at any time by deleting SimpleX Chat app(s) from your device and discontinuing use of our Services. The provisions related to Licenses, Disclaimers, Limitation of Liability, Resolving dispute, Availability, Changes to the terms, Enforcing the terms, and Ending these Terms will survive termination of your relationship with SimpleX Chat.
**Resolving disputes**. You agree to resolve any Claim you have with us relating to or arising from our Conditions, us, or our Applications in the courts of England and Wales. You also agree to submit to the personal jurisdiction of such courts for the purpose of resolving all such disputes. The laws of England govern our Conditions, as well as any disputes, whether in court or arbitration, which might arise between SimpleX Chat Ltd and you, without regard to conflict of law provisions.
Updated November 8, 2022
**Changes to the conditions**. SimpleX Chat Ltd may update the Conditions from time to time. Your continued use of our Applications confirms your acceptance of our updated Conditions and supersedes any prior Conditions. You will comply with all applicable export control and trade sanctions laws. Our Conditions cover the entire agreement between you and SimpleX Chat Ltd regarding our Applications. If you do not agree with our Conditions, you should stop using our Applications.
**Enforcing the conditions**. If we fail to enforce any of our Conditions, that does not mean we waive the right to enforce them. If any provision of the Conditions is deemed unlawful, void, or unenforceable, that provision shall be deemed severable from our Conditions and shall not affect the enforceability of the remaining provisions. Our Applications are not intended for distribution to or use in any country where such distribution or use would violate local law or would subject us to any regulations in another country. We reserve the right to limit our Applications in any country. If you have specific questions about these Conditions, please contact us at chat@simplex.chat.
**Ending these conditions**. You may end these Conditions with SimpleX Chat Ltd at any time by deleting our Applications from your devices and discontinuing use of our Infrastructure. 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.
Updated April 24, 2024
+90 -45
View File
@@ -2,9 +2,9 @@
[![GitHub downloads](https://img.shields.io/github/downloads/simplex-chat/simplex-chat/total)](https://github.com/simplex-chat/simplex-chat/releases)
[![GitHub release](https://img.shields.io/github/v/release/simplex-chat/simplex-chat)](https://github.com/simplex-chat/simplex-chat/releases)
[![Join on Reddit](https://img.shields.io/reddit/subreddit-subscribers/SimpleXChat?style=social)](https://www.reddit.com/r/SimpleXChat)
[![Follow on Mastodon](https://img.shields.io/mastodon/follow/108619463746856738?domain=https%3A%2F%2Fmastodon.social&style=social)](https://mastodon.social/@simplex)
<a rel="me" href="https://mastodon.social/@simplex">![Follow on Mastodon](https://img.shields.io/mastodon/follow/108619463746856738?domain=https%3A%2F%2Fmastodon.social&style=social)</a>
| 30/03/2023 | EN, [FR](/docs/lang/fr/README.md), [CZ](/docs/lang/cs/README.md) |
| 30/03/2023 | EN, [FR](/docs/lang/fr/README.md), [CZ](/docs/lang/cs/README.md), [PL](/docs/lang/pl/README.md) |
<img src="images/simplex-chat-logo.svg" alt="SimpleX logo" width="100%">
@@ -15,10 +15,10 @@
## Welcome to SimpleX Chat!
1. 📲 [Install the app](#install-the-app).
2. ↔️ [Connect to the team](#connect-to-the-team-via-the-app) and [join user groups](#join-user-groups).
2. ↔️ [Connect to the team](#connect-to-the-team), [join user groups](#join-user-groups) and [follow our updates](#follow-our-updates).
3. 🤝 [Make a private connection](#make-a-private-connection) with a friend.
4. 🔤 [Help translating SimpleX Chat](#help-translating-simplex-chat).
5. ⚡️ [Contribute](#contribute) and [help us with donations](#help-us-with-donations).
5. ⚡️ [Contribute](#contribute) and [support us with donations](#please-support-us-with-your-donations).
[Learn more about SimpleX Chat](#contents).
@@ -40,21 +40,29 @@
- 🚀 [TestFlight preview for iOS](https://testflight.apple.com/join/DWuT2LQu) with the new features 1-2 weeks earlier - **limited to 10,000 users**!
- 🖥 Available as a terminal (console) [app / CLI](#zap-quick-installation-of-a-terminal-app) on Linux, MacOS, Windows.
## Connect to the team via the app
## Connect to the team
You can connect to the team via the app using "chat with the developers button" available when you have no conversations in the profile, "Send questions and ideas" in the app settings or via our [SimpleX address](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). Please connect to:
- to ask any questions
- to suggest any improvements
- to share anything relevant
We are replying the questions manually, so it is not instant it can take up to 24 hours.
If you are interested in helping us to integrate open-source language models, and in [joining our team](./docs/JOIN_TEAM.md), please get in touch.
## Join user groups
You can join the groups created by other users via the new [directory service](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). We are not responsible for the content shared in these groups.
**Please note**: The groups below are created for the users to be able to ask questions, make suggestions and ask questions about SimpleX Chat only.
You also can:
- criticize the app, and make comparisons with other messengers.
- share new messengers you think could be interesting for privacy, as long as you don't spam.
- share some privacy related publications, infrequently.
- having preliminary approved with the admin in direct message, share the link to a group you created.
- having preliminary approved with the admin in direct message, share the link to a group you created, but only once. Once the group has more than 10 members it can be submitted to [SimpleX Directory Service](./docs/DIRECTORY.md) where the new users will be able to discover it.
You must:
- be polite to other users
@@ -64,9 +72,9 @@ You must:
Messages not following these rules will be deleted, the right to send messages may be revoked, and the access to the new members to the group may be temporarily restricted, to prevent re-joining under a different name - our imperfect group moderation does not have a better solution at the moment.
You can join an English-speaking users group if you want to ask any questions: [#SimpleX-Group-4](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2Fw2GlucRXtRVgYnbt_9ZP-kmt76DekxxS%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEA0tJhTyMGUxznwmjb7aT24P1I1Wry_iURTuhOFlMb1Eo%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22WoPxjFqGEDlVazECOSi2dg%3D%3D%22%7D)
You can join an English-speaking users group if you want to ask any questions: [#SimpleX users group](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2Fos8FftfoV8zjb2T89fUEjJtF7y64p5av%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAQqMgh0fw2lPhjn3PDIEfAKA_E0-gf8Hr8zzhYnDivRs%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22lBPiveK2mjfUH43SN77R0w%3D%3D%22%7D)
There is also a group [#simplex-devs](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2F6eHqy7uAbZPOcA6qBtrQgQquVlt4Ll91%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAqV_pg3FF00L98aCXp4D3bOs4Sxv_UmSd-gb0juVoQVs%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22XonlixcHBIb2ijCehbZoiw%3D%3D%22%7D) for developers who build on SimpleX platform:
There is also a group [#simplex-devs](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FvYCRjIflKNMGYlfTkuHe4B40qSlQ0439%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAHNdcqNbzXZhyMoSBjT2R0-Eb1EPaLyUg3KZjn-kmM1w%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22PD20tcXjw7IpkkMCfR6HLA%3D%3D%22%7D) for developers who build on SimpleX platform:
- chat bots and automations
- integrations with other apps
@@ -79,6 +87,15 @@ There are groups in other languages, that we have the apps interface translated
You can join either by opening these links in the app or by opening them in a desktop browser and scanning the QR code.
## Follow our updates
We publish our updates and releases via:
- [Reddit](https://www.reddit.com/r/SimpleXChat/), [Twitter](https://twitter.com/SimpleXChat), [Lemmy](https://lemmy.ml/c/simplex), [Mastodon](https://mastodon.social/@simplex) and [Nostr](https://snort.social/p/npub1exv22uulqnmlluszc4yk92jhs2e5ajcs6mu3t00a6avzjcalj9csm7d828).
- SimpleX Chat [team profile](#connect-to-the-team).
- [blog](https://simplex.chat/blog/) and [RSS feed](https://simplex.chat/feed.rss).
- [mailing list](https://simplex.chat/#join-simplex), very rarely.
## Make a private connection
You need to share a link with your friend or scan a QR code from their phone, in person or during a video call, to make a connection and start messaging.
@@ -102,17 +119,24 @@ Join our translators to help SimpleX grow!
|locale|language |contributor|[Android](https://play.google.com/store/apps/details?id=chat.simplex.app) and [iOS](https://apps.apple.com/us/app/simplex-chat/id1605771084)|[website](https://simplex.chat)|Github docs|
|:----:|:-------:|:---------:|:---------:|:---------:|:---------:|
|🇬🇧 en|English | |✓|✓|✓|✓|
|ar|العربية |[jermanuts](https://github.com/jermanuts)||[![website](https://hosted.weblate.org/widgets/simplex-chat/ar/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/ar/)||
|ar|العربية |[jermanuts](https://github.com/jermanuts)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/ar/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/ar/)<br>-|[![website](https://hosted.weblate.org/widgets/simplex-chat/ar/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/ar/)||
|🇧🇬 bg|Български | |[![android app](https://hosted.weblate.org/widgets/simplex-chat/bg/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/bg/)<br>[![ios app](https://hosted.weblate.org/widget/simplex-chat/ios/bg/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/bg/)|||
|🇨🇿 cs|Čeština |[zen0bit](https://github.com/zen0bit)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/cs/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/cs/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/cs/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/cs/)|[![website](https://hosted.weblate.org/widgets/simplex-chat/cs/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/cs/)|[](https://github.com/simplex-chat/simplex-chat/tree/master/docs/lang/cs)|
|🇩🇪 de|Deutsch |[mlanp](https://github.com/mlanp)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/de/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/de/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/de/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/de/)|[![website](https://hosted.weblate.org/widgets/simplex-chat/de/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/de/)||
|🇪🇸 es|Español |[Mateyhv](https://github.com/Mateyhv)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/es/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/es/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/es/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/es/)|[![website](https://hosted.weblate.org/widgets/simplex-chat/es/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/es/)||
|🇫🇮 fi|Suomi | |[![android app](https://hosted.weblate.org/widgets/simplex-chat/fi/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/fi/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/fi/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/fi/)|[![website](https://hosted.weblate.org/widgets/simplex-chat/fi/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/fi/)||
|🇫🇷 fr|Français |[ishi_sama](https://github.com/ishi-sama)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/fr/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/fr/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/fr/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/fr/)|[![website](https://hosted.weblate.org/widgets/simplex-chat/fr/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/fr/)|[](https://github.com/simplex-chat/simplex-chat/tree/master/docs/lang/fr)|
|🇮🇱 he|עִברִית | |[![android app](https://hosted.weblate.org/widgets/simplex-chat/he/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/he/)<br>-|||
|🇭🇺 hu|Magyar | |[![android app](https://hosted.weblate.org/widgets/simplex-chat/hu/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/hu/)<br>-|||
|🇮🇹 it|Italiano |[unbranched](https://github.com/unbranched)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/it/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/it/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/it/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/it/)|[![website](https://hosted.weblate.org/widgets/simplex-chat/it/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/it/)||
|🇯🇵 ja|Japanese ||[![android app](https://hosted.weblate.org/widgets/simplex-chat/it/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/ja/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/ja/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/ja/)|||
|🇯🇵 ja|日本語 | |[![android app](https://hosted.weblate.org/widgets/simplex-chat/ja/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/ja/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/ja/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/ja/)|[![website](https://hosted.weblate.org/widgets/simplex-chat/ja/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/ja/)||
|🇳🇱 nl|Nederlands|[mika-nl](https://github.com/mika-nl)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/nl/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/nl/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/nl/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/nl/)|[![website](https://hosted.weblate.org/widgets/simplex-chat/nl/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/nl/)||
|🇵🇱 pl|Polski |[BxOxSxS](https://github.com/BxOxSxS)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/pl/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/ru/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/ru/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/pl/)|||
|🇵🇱 pl|Polski |[BxOxSxS](https://github.com/BxOxSxS)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/pl/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/pl/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/pl/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/pl/)|||
|🇧🇷 pt-BR|Português||[![android app](https://hosted.weblate.org/widgets/simplex-chat/pt_BR/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/pt_BR/)<br>-|[![website](https://hosted.weblate.org/widgets/simplex-chat/pt_BR/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/pt_BR/)||
|🇷🇺 ru|Русский ||[![android app](https://hosted.weblate.org/widgets/simplex-chat/ru/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/ru/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/ru/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/ru/)|||
|🇹🇭 th|ภาษาไทย |[titapa-punpun](https://github.com/titapa-punpun)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/th/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/th/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/th/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/th/)|||
|🇹🇷 tr|Türkçe | |[![android app](https://hosted.weblate.org/widgets/simplex-chat/tr/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/tr/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/tr/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/tr/)|||
|🇺🇦 uk|Українська| |[![android app](https://hosted.weblate.org/widgets/simplex-chat/uk/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/uk/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/uk/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/uk/)|[![website](https://hosted.weblate.org/widgets/simplex-chat/uk/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/uk/)||
|🇨🇳 zh-CHS|简体中文|[sith-on-mars](https://github.com/sith-on-mars)<br><br>[Float-hu](https://github.com/Float-hu)|[![android app](https://hosted.weblate.org/widgets/simplex-chat/zh_Hans/android/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/)<br>[![ios app](https://hosted.weblate.org/widgets/simplex-chat/zh_Hans/ios/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/)<br>&nbsp;|<br><br>[![website](https://hosted.weblate.org/widgets/simplex-chat/zh_Hans/website/svg-badge.svg)](https://hosted.weblate.org/projects/simplex-chat/website/zh_Hans/)||
Languages in progress: Arabic, Japanese, Korean, Portuguese and [others](https://hosted.weblate.org/projects/simplex-chat/#languages). We will be adding more languages as some of the already added are completed please suggest new languages, review the [translation guide](./docs/TRANSLATIONS.md) and get in touch with us!
@@ -126,7 +150,7 @@ We would love to have you join the development! You can help us with:
- contributing to SimpleX Chat knowledge-base.
- developing features - please connect to us via chat so we can help you get started.
## Help us with donations
## Please support us with your donations
Huge thank you to everybody who donated to SimpleX Chat!
@@ -134,17 +158,19 @@ We are prioritizing users privacy and security - it would be impossible without
Our pledge to our users is that SimpleX protocols are and will remain open, and in public domain, - so anybody can build the future implementations of the clients and the servers. We are building SimpleX platform based on the same principles as email and web, but much more private and secure.
Your donations help us raise more funds any amount, even the price of the cup of coffee, would make a big difference for us.
Your donations help us raise more funds - any amount, even the price of the cup of coffee, would make a big difference for us.
It is possible to donate via:
- [GitHub](https://github.com/sponsors/simplex-chat) - it is commission-free for us.
- [OpenCollective](https://opencollective.com/simplex-chat) - it charges a commission, and also accepts donations in crypto-currencies.
- Monero address: 8568eeVjaJ1RQ65ZUn9PRQ8ENtqeX9VVhcCYYhnVLxhV4JtBqw42so2VEUDQZNkFfsH5sXCuV7FN8VhRQ21DkNibTZP57Qt
- Bitcoin address: 1bpefFkzuRoMY3ZuBbZNZxycbg7NYPYTG
- BCH address: 1bpefFkzuRoMY3ZuBbZNZxycbg7NYPYTG
- Ethereum address: 0x83fd788f7241a2be61780ea9dc72d2151e6843e2
- Solana address: 43tWFWDczgAcn4Rzwkpqg2mqwnQETSiTwznmCgA2tf1L
- [GitHub](https://github.com/sponsors/simplex-chat) (commission-free) or [OpenCollective](https://opencollective.com/simplex-chat) (~10% commission).
- Bitcoin: bc1qd74rc032ek2knhhr3yjq2ajzc5enz3h4qwnxad
- Monero: 8568eeVjaJ1RQ65ZUn9PRQ8ENtqeX9VVhcCYYhnVLxhV4JtBqw42so2VEUDQZNkFfsH5sXCuV7FN8VhRQ21DkNibTZP57Qt
- BCH: bitcoincash:qq6c8vfvxqrk6rhdysgvkhqc24sggkfsx5nqvdlqcg
- Ethereum: 0xD9ee7Db0AD0dc1Dfa7eD53290199ED06beA04692
- USDT:
- Ethereum: 0xD9ee7Db0AD0dc1Dfa7eD53290199ED06beA04692
- Solana: 7JCf5m3TiHmYKZVr6jCu1KeZVtb9Y1jRMQDU69p5ARnu
- please ask if you want to donate any other coins.
Thank you,
@@ -164,7 +190,7 @@ SimpleX Chat founder
- [News and updates](#news-and-updates)
- [Quick installation of a terminal app](#zap-quick-installation-of-a-terminal-app)
- [SimpleX Platform design](#simplex-platform-design)
- [Privacy: technical details and limitations](#privacy-technical-details-and-limitations)
- [Privacy and security: technical details and limitations](#privacy-and-security-technical-details-and-limitations)
- [For developers](#for-developers)
- [Roadmap](#roadmap)
- [Disclaimers, Security contact, License](#disclaimers)
@@ -205,24 +231,32 @@ You can use SimpleX with your own servers and still communicate with people usin
## News and updates
Recent updates:
Recent and important updates:
[July 22, 2023. SimpleX Chat: v5.2 released with message delivery receipts](./blog/20230722-simplex-chat-v5-2-message-delivery-receipts.md).
[Aug 14, 2024. SimpleX network: the investment from Jack Dorsey and Asymmetric, v6.0 released with the new user experience and private message routing](./blog/20240814-simplex-chat-vision-funding-v6-private-routing-new-user-experience.md)
[Jun 4, 2024. SimpleX network: private message routing, v5.8 released with IP address protection and chat themes](./blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md)
[Apr 26, 2024. SimpleX network: legally binding transparency, v5.7 released with better calls and messages.](./blog/20240426-simplex-legally-binding-transparency-v5-7-better-user-experience.md)
[Mar 23, 2024. SimpleX network: real privacy and stable profits, non-profits for protocols, v5.6 released with quantum resistant e2e encryption and simple profile migration.](./blog/20240323-simplex-network-privacy-non-profit-v5-6-quantum-resistant-e2e-encryption-simple-migration.md)
[Mar 14, 2024. SimpleX Chat v5.6 beta: adding quantum resistance to Signal double ratchet algorithm.](./blog/20240314-simplex-chat-v5-6-quantum-resistance-signal-double-ratchet-algorithm.md)
[Jan 24, 2024. SimpleX Chat: free infrastructure from Linode, v5.5 released with private notes, group history and a simpler UX to connect.](./blog/20240124-simplex-chat-infrastructure-costs-v5-5-simplex-ux-private-notes-group-history.md)
[Nov 25, 2023. SimpleX Chat v5.4 released: link mobile and desktop apps via quantum resistant protocol, and much better groups](./blog/20231125-simplex-chat-v5-4-link-mobile-desktop-quantum-resistant-better-groups.md).
[Sep 25, 2023. SimpleX Chat v5.3 released: desktop app, local file encryption, improved groups and directory service](./blog/20230925-simplex-chat-v5-3-desktop-app-local-file-encryption-directory-service.md).
[Jul 22, 2023. SimpleX Chat: v5.2 released with message delivery receipts](./blog/20230722-simplex-chat-v5-2-message-delivery-receipts.md).
[May 23, 2023. SimpleX Chat: v5.1 released with message reactions and self-destruct passcode](./blog/20230523-simplex-chat-v5-1-message-reactions-self-destruct-passcode.md).
[Apr 22, 2023. SimpleX Chat: vision and funding, v5.0 released with videos and files up to 1gb](./blog/20230422-simplex-chat-vision-funding-v5-videos-files-passcode.md).
[Mar 28, 2023. v4.6 released - with Android 8+ and ARMv7a support, hidden profiles, community moderation, improved audio/video calls and reduced battery usage](./blog/20230328-simplex-chat-v4-6-hidden-profiles.md).
[Mar 1, 2023. SimpleX File Transfer Protocol send large files efficiently, privately and securely, soon to be integrated into SimpleX Chat apps.](./blog/20230301-simplex-file-transfer-protocol.md).
[Feb 4, 2023. v4.5 released - with multiple user profiles, message draft, transport isolation and Italian interface](./blog/20230204-simplex-chat-v4-5-user-chat-profiles.md).
[Jan 3, 2023. v4.4 released - with disappearing messages, "live" messages, connection security verifications, GIFs and stickers and with French interface language](./blog/20230103-simplex-chat-v4.4-disappearing-messages.md).
[Dec 6, 2022. November reviews and v4.3 released - with instant voice messages, irreversible deletion of sent messages and improved server configuration](./blog/20221206-simplex-chat-v4.3-voice-messages.md).
[Nov 8, 2022. Security audit by Trail of Bits, the new website and v4.2 released](./blog/20221108-simplex-chat-v4.2-security-audit-new-website.md).
[Sep 28, 2022. v4.0: encrypted local chat database and many other changes](./blog/20220928-simplex-chat-v4-encrypted-database.md).
@@ -255,7 +289,7 @@ See [SimpleX whitepaper](https://github.com/simplex-chat/simplexmq/blob/stable/p
See [SimpleX Chat Protocol](./docs/protocol/simplex-chat.md) for the format of messages sent between chat clients over [SimpleX Messaging Protocol](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/simplex-messaging.md).
## Privacy: technical details and limitations
## Privacy and security: technical details and limitations
SimpleX Chat is a work in progress we are releasing improvements as they are ready. You have to decide if the current state is good enough for your usage scenario.
@@ -268,18 +302,23 @@ What is already implemented:
3. [Double ratchet](./docs/GLOSSARY.md#double-ratchet-algorithm) end-to-end encryption in each conversation between two users (or group members). This is the same algorithm that is used in Signal and many other messaging apps; it provides OTR messaging with [forward secrecy](./docs/GLOSSARY.md#forward-secrecy) (each message is encrypted by its own ephemeral key) and [break-in recovery](./docs/GLOSSARY.md#post-compromise-security) (the keys are frequently re-negotiated as part of the message exchange). Two pairs of Curve448 keys are used for the initial [key agreement](./docs/GLOSSARY.md#key-agreement-protocol), initiating party passes these keys via the connection link, accepting side - in the header of the confirmation message.
4. Additional layer of encryption using NaCL cryptobox for the messages delivered from the server to the recipient. This layer avoids having any ciphertext in common between sent and received traffic of the server inside TLS (and there are no identifiers in common as well).
5. Several levels of [content padding](./docs/GLOSSARY.md#message-padding) to frustrate message size attacks.
6. Starting from v2 of SMP protocol (the current version is v4) all message metadata, including the time when the message was received by the server (rounded to a second) is sent to the recipients inside an encrypted envelope, so even if TLS is compromised it cannot be observed.
6. All message metadata, including the time when the message was received by the server (rounded to a second) is sent to the recipients inside an encrypted envelope, so even if TLS is compromised it cannot be observed.
7. Only TLS 1.2/1.3 are allowed for client-server connections, limited to cryptographic algorithms: CHACHA20POLY1305_SHA256, Ed25519/Ed448, Curve25519/Curve448.
8. To protect against replay attacks SimpleX servers require [tlsunique channel binding](https://www.rfc-editor.org/rfc/rfc5929.html) as session ID in each client command signed with per-queue ephemeral key.
9. To protect your IP address all SimpleX Chat clients support accessing messaging servers via Tor - see [v3.1 release announcement](./blog/20220808-simplex-chat-v3.1-chat-groups.md) for more details.
10. Local database encryption with passphrase - your contacts, groups and all sent and received messages are stored encrypted. If you used SimpleX Chat before v4.0 you need to enable the encryption via the app settings.
11. Transport isolation - different TCP connections and Tor circuits are used for traffic of different user profiles, optionally - for different contacts and group member connections.
12. Manual messaging queue rotations to move conversation to another SMP relay.
13. Sending end-to-end encrypted files using [XFTP protocol](https://simplex.chat/blog/20230301-simplex-file-transfer-protocol.html).
14. Local files encryption.
We plan to add soon:
We plan to add:
1. Automatic message queue rotation. 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. Local files encryption. Currently the images and files you send and receive are stored in the app unencrypted, you can delete them via `Settings / Database passphrase & export`.
3. Message "mixing" - adding latency to message delivery, to protect against traffic correlation by message time.
1. Senders' SMP relays and recipients' XFTP relays to reduce traffic and conceal IP addresses from the relays chosen, and potentially controlled, by another party.
2. Post-quantum resistant key exchange in double ratchet protocol.
3. 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).
4. Message "mixing" - adding latency to message delivery, to protect against traffic correlation by message time.
5. 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.
## For developers
@@ -340,22 +379,28 @@ Please also join [#simplex-devs](https://simplex.chat/contact#/?v=1-2&smp=smp%3A
- ✅ Message editing history
- ✅ Reduced battery and traffic usage in large groups.
- ✅ Message delivery confirmation (with sender opt-out per contact).
- 🏗 Desktop client.
- Desktop client.
- ✅ Encryption of local files stored in the app.
- ✅ Using mobile profiles from the desktop app.
- ✅ Private notes.
- ✅ Improve sending videos (including encryption of locally stored videos).
- ✅ Post-quantum resistant key exchange in double ratchet protocol.
- ✅ Message delivery relay for senders (to conceal IP address from the recipients' servers and to reduce the traffic).
- 🏗 Improve stability and reduce battery usage.
- 🏗 Improve experience for the new users.
- 🏗 Large groups, communities and public channels.
- Privacy & security slider - a simple way to set all settings at once.
- SMP queue redundancy and rotation (manual is supported).
- Include optional message into connection request sent via contact address.
- Local app files encryption.
- Improved navigation and search in the conversation (expand and scroll to quoted message, scroll to search results, etc.).
- Large groups, communities and public channels.
- Feeds/broadcasts.
- Ephemeral/disappearing/OTR conversations with the existing contacts.
- Privately share your location.
- Web widgets for custom interactivity in the chats.
- Programmable chat automations / rules (automatic replies/forward/deletion/sending, reminders, etc.).
- Supporting the same profile on multiple devices.
- Privacy-preserving identity server for optional DNS-based contact/group addresses to simplify connection and discovery, but not used to deliver messages:
- keep all your contacts and groups even if you lose the domain.
- the server doesn't have information about your contacts and groups.
- Message delivery relay for senders (to conceal IP address from the recipients' servers and to reduce the traffic).
- High capacity multi-node SMP relays.
## Disclaimers
@@ -372,13 +417,13 @@ We have never provided or have been requested access to our servers or any infor
We do not log IP addresses of the users and we do not perform any traffic correlation on our servers. If transport level security is critical you must use Tor or some other similar network to access messaging servers. We will be improving the client applications to reduce the opportunities for traffic correlation.
Please read more in [Terms & privacy policy](./PRIVACY.md).
Please read more in [Privacy Policy](./PRIVACY.md).
## Security contact
To report a security vulnerability, please send us email to chat@simplex.chat. We will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues.
Please see our [Security Policy](./docs/SECURITY.md) on how to report security vulnerabilities to us. We will coordinate the fix and disclosure.
Please treat any findings of possible traffic correlation attacks allowing to correlate two different conversations to the same user, other than covered in [the threat model](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md#threat-model), as security vulnerabilities, and follow this disclosure process.
Please do NOT report security vulnerabilities via GitHub issues.
## License
+97 -21
View File
@@ -9,31 +9,20 @@
import Foundation
import UIKit
import SimpleXChat
import SwiftUI
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
logger.debug("AppDelegate: didFinishLaunchingWithOptions")
application.registerForRemoteNotifications()
if #available(iOS 17.0, *) { trackKeyboard() }
NotificationCenter.default.addObserver(self, selector: #selector(pasteboardChanged), name: UIPasteboard.changedNotification, object: nil)
removePasscodesIfReinstalled()
prepareForLaunch()
return true
}
@available(iOS 17.0, *)
private func trackKeyboard() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@available(iOS 17.0, *)
@objc func keyboardWillShow(_ notification: Notification) {
if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
ChatModel.shared.keyboardHeight = keyboardFrame.cgRectValue.height
}
}
@available(iOS 17.0, *)
@objc func keyboardWillHide(_ notification: Notification) {
ChatModel.shared.keyboardHeight = 0
@objc func pasteboardChanged() {
ChatModel.shared.pasteboardHasStrings = UIPasteboard.general.hasStrings
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
@@ -42,6 +31,7 @@ class AppDelegate: NSObject, UIApplicationDelegate {
let m = ChatModel.shared
let deviceToken = DeviceToken(pushProvider: PushProvider(env: pushEnvironment), token: token)
m.deviceToken = deviceToken
// savedToken is set in startChat, when it is started before this method is called
if m.savedToken != nil {
registerToken(token: deviceToken)
}
@@ -55,7 +45,6 @@ class AppDelegate: NSObject, UIApplicationDelegate {
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
logger.debug("AppDelegate: didReceiveRemoteNotification")
print("*** userInfo", userInfo)
let m = ChatModel.shared
if let ntfData = userInfo["notificationData"] as? [AnyHashable : Any],
m.notificationMode != .off {
@@ -81,7 +70,7 @@ class AppDelegate: NSObject, UIApplicationDelegate {
}
} else if let checkMessages = ntfData["checkMessages"] as? Bool, checkMessages {
logger.debug("AppDelegate: didReceiveRemoteNotification: checkMessages")
if appStateGroupDefault.get().inactive && m.ntfEnablePeriodic {
if m.ntfEnablePeriodic && allowBackgroundRefresh() && BGManager.shared.lastRanLongAgo {
receiveMessages(completionHandler)
} else {
completionHandler(.noData)
@@ -121,17 +110,104 @@ class AppDelegate: NSObject, UIApplicationDelegate {
BGManager.shared.receiveMessages(complete)
}
private func removePasscodesIfReinstalled() {
// Check for the database existence, because app and self destruct passcodes
// will be saved and restored by iOS when a user deletes and re-installs the app.
// In this case the database and settings will be deleted, but the passcodes won't be.
// Deleting passcodes ensures that the user will not get stuck on "Opening app..." screen.
if (kcAppPassword.get() != nil || kcSelfDestructPassword.get() != nil) &&
!UserDefaults.standard.bool(forKey: DEFAULT_PERFORM_LA) && !hasDatabase() {
_ = kcAppPassword.remove()
_ = kcSelfDestructPassword.remove()
_ = kcDatabasePassword.remove()
}
}
private func prepareForLaunch() {
try? FileManager.default.createDirectory(at: getWallpaperDirectory(), withIntermediateDirectories: true)
}
static func keepScreenOn(_ on: Bool) {
UIApplication.shared.isIdleTimerDisabled = on
}
}
class SceneDelegate: NSObject, ObservableObject, UIWindowSceneDelegate {
var window: UIWindow?
static var windowStatic: UIWindow?
var windowScene: UIWindowScene?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
UITableView.appearance().backgroundColor = .clear
guard let windowScene = scene as? UIWindowScene else { return }
self.windowScene = windowScene
window = windowScene.keyWindow
window?.tintColor = UIColor(cgColor: getUIAccentColorDefault())
window?.overrideUserInterfaceStyle = getUserInterfaceStyleDefault()
SceneDelegate.windowStatic = windowScene.keyWindow
migrateAccentColorAndTheme()
ThemeManager.applyTheme(currentThemeDefault.get())
ThemeManager.adjustWindowStyle()
}
private func migrateAccentColorAndTheme() {
let defs = UserDefaults.standard
/// For checking migration
// themeOverridesDefault.set([])
// currentThemeDefault.set(DefaultTheme.SYSTEM_THEME_NAME)
// defs.set(0.5, forKey: DEFAULT_ACCENT_COLOR_RED)
// defs.set(0.3, forKey: DEFAULT_ACCENT_COLOR_GREEN)
// defs.set(0.8, forKey: DEFAULT_ACCENT_COLOR_BLUE)
let userInterfaceStyle = getUserInterfaceStyleDefault()
if defs.double(forKey: DEFAULT_ACCENT_COLOR_GREEN) == 0 && userInterfaceStyle == .unspecified {
// No migration needed or already migrated
return
}
let defaultAccentColor = Color(cgColor: CGColor(red: 0.000, green: 0.533, blue: 1.000, alpha: 1))
let accentColor = Color(cgColor: getUIAccentColorDefault())
if accentColor != defaultAccentColor {
let colors = ThemeColors(primary: accentColor.toReadableHex())
var overrides = themeOverridesDefault.get()
var themeIds = currentThemeIdsDefault.get()
switch userInterfaceStyle {
case .light:
let light = ThemeOverrides(base: DefaultTheme.LIGHT, colors: colors, wallpaper: ThemeWallpaper(preset: PresetWallpaper.school.filename))
overrides.append(light)
themeOverridesDefault.set(overrides)
themeIds[DefaultTheme.LIGHT.themeName] = light.themeId
currentThemeIdsDefault.set(themeIds)
ThemeManager.applyTheme(DefaultTheme.LIGHT.themeName)
case .dark:
let dark = ThemeOverrides(base: DefaultTheme.DARK, colors: colors, wallpaper: ThemeWallpaper(preset: PresetWallpaper.school.filename))
overrides.append(dark)
themeOverridesDefault.set(overrides)
themeIds[DefaultTheme.DARK.themeName] = dark.themeId
currentThemeIdsDefault.set(themeIds)
ThemeManager.applyTheme(DefaultTheme.DARK.themeName)
case .unspecified:
let light = ThemeOverrides(base: DefaultTheme.LIGHT, colors: colors, wallpaper: ThemeWallpaper(preset: PresetWallpaper.school.filename))
let dark = ThemeOverrides(base: DefaultTheme.DARK, colors: colors, wallpaper: ThemeWallpaper(preset: PresetWallpaper.school.filename))
overrides.append(light)
overrides.append(dark)
themeOverridesDefault.set(overrides)
themeIds[DefaultTheme.LIGHT.themeName] = light.themeId
themeIds[DefaultTheme.DARK.themeName] = dark.themeId
currentThemeIdsDefault.set(themeIds)
ThemeManager.applyTheme(DefaultTheme.SYSTEM_THEME_NAME)
@unknown default: ()
}
} else if userInterfaceStyle != .unspecified {
let themeName = switch userInterfaceStyle {
case .light: DefaultTheme.LIGHT.themeName
case .dark: DefaultTheme.DARK.themeName
default: DefaultTheme.SYSTEM_THEME_NAME
}
ThemeManager.applyTheme(themeName)
}
defs.removeObject(forKey: DEFAULT_ACCENT_COLOR_RED)
defs.removeObject(forKey: DEFAULT_ACCENT_COLOR_GREEN)
defs.removeObject(forKey: DEFAULT_ACCENT_COLOR_BLUE)
defs.removeObject(forKey: DEFAULT_USER_INTERFACE_STYLE)
}
}
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "wallpaper_cats@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "wallpaper_cats@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "wallpaper_cats@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "wallpaper_flowers@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "wallpaper_flowers@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "wallpaper_flowers@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "wallpaper_hearts@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "wallpaper_hearts@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "wallpaper_hearts@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "wallpaper_kids@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "wallpaper_kids@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "wallpaper_kids@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "wallpaper_school@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "wallpaper_school@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "wallpaper_school@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "wallpaper_travel@1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "wallpaper_travel@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "wallpaper_travel@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

+213 -89
View File
@@ -14,11 +14,16 @@ struct ContentView: View {
@ObservedObject var alertManager = AlertManager.shared
@ObservedObject var callController = CallController.shared
@Environment(\.colorScheme) var colorScheme
@Binding var doAuthenticate: Bool
@Binding var userAuthorized: Bool?
@Binding var canConnectCall: Bool
@Binding var lastSuccessfulUnlock: TimeInterval?
@Binding var showInitializationView: Bool
@EnvironmentObject var theme: AppTheme
@EnvironmentObject var sceneDelegate: SceneDelegate
var contentAccessAuthenticationExtended: Bool
@Environment(\.scenePhase) var scenePhase
@State private var automaticAuthenticationAttempted = false
@State private var canConnectViewCall = false
@State private var lastSuccessfulUnlock: TimeInterval? = nil
@AppStorage(DEFAULT_SHOW_LA_NOTICE) private var prefShowLANotice = false
@AppStorage(DEFAULT_LA_NOTICE_SHOWN) private var prefLANoticeShown = false
@AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false
@@ -28,17 +33,68 @@ struct ContentView: View {
@State private var showWhatsNew = false
@State private var showChooseLAMode = false
@State private var showSetPasscode = false
@State private var waitingForOrPassedAuth = true
@State private var chatListActionSheet: ChatListActionSheet? = nil
private let callTopPadding: CGFloat = 50
private enum ChatListActionSheet: Identifiable {
case planAndConnectSheet(sheet: PlanAndConnectActionSheet)
var id: String {
switch self {
case let .planAndConnectSheet(sheet): return sheet.id
}
}
}
private var accessAuthenticated: Bool {
chatModel.contentViewAccessAuthenticated || contentAccessAuthenticationExtended
}
var body: some View {
if #available(iOS 16.0, *) {
allViews()
.scrollContentBackground(.hidden)
} else {
// on iOS 15 scroll view background disabled in SceneDelegate
allViews()
}
}
@ViewBuilder func allViews() -> some View {
ZStack {
contentView()
let showCallArea = chatModel.activeCall != nil && chatModel.activeCall?.callState != .waitCapabilities && chatModel.activeCall?.callState != .invitationAccepted
// contentView() has to be in a single branch, so that enabling authentication doesn't trigger re-rendering and close settings.
// i.e. with separate branches like this settings are closed: `if prefPerformLA { ... contentView() ... } else { contentView() }
if !prefPerformLA || accessAuthenticated {
contentView()
.padding(.top, showCallArea ? callTopPadding : 0)
} else {
lockButton()
.padding(.top, showCallArea ? callTopPadding : 0)
}
if showCallArea, let call = chatModel.activeCall {
VStack {
activeCallInteractiveArea(call)
Spacer()
}
}
if chatModel.showCallView, let call = chatModel.activeCall {
callView(call)
}
if !showSettings, let la = chatModel.laRequest {
LocalAuthView(authRequest: la)
.onDisappear {
// this flag is separate from accessAuthenticated to show initializationView while we wait for authentication
waitingForOrPassedAuth = accessAuthenticated
}
} else if showSetPasscode {
SetAppPasscodeView {
chatModel.contentViewAccessAuthenticated = true
prefPerformLA = true
showSetPasscode = false
privacyLocalAuthModeDefault.set(.passcode)
@@ -48,15 +104,10 @@ struct ContentView: View {
showSetPasscode = false
alertManager.showAlert(laPasscodeNotSetAlert())
}
} else if chatModel.chatDbStatus == nil && AppChatState.shared.value != .stopped && waitingForOrPassedAuth {
initializationView()
}
}
.onAppear {
if prefPerformLA { requestNtfAuthorization() }
initAuthenticate()
}
.onChange(of: doAuthenticate) { _ in
initAuthenticate()
}
.alert(isPresented: $alertManager.presentAlert) { alertManager.alertView! }
.sheet(isPresented: $showSettings) {
SettingsView(showSettings: $showSettings)
@@ -65,14 +116,55 @@ struct ContentView: View {
Button("System authentication") { initialEnableLA() }
Button("Passcode entry") { showSetPasscode = true }
}
.onChange(of: scenePhase) { phase in
logger.debug("scenePhase was \(String(describing: scenePhase)), now \(String(describing: phase))")
switch (phase) {
case .background:
// also see .onChange(of: scenePhase) in SimpleXApp: on entering background
// it remembers enteredBackgroundAuthenticated and sets chatModel.contentViewAccessAuthenticated to false
automaticAuthenticationAttempted = false
canConnectViewCall = false
case .active:
canConnectViewCall = !prefPerformLA || contentAccessAuthenticationExtended || unlockedRecently()
// condition `!chatModel.contentViewAccessAuthenticated` is required for when authentication is enabled in settings or on initial notice
if prefPerformLA && !chatModel.contentViewAccessAuthenticated {
if AppChatState.shared.value != .stopped {
if contentAccessAuthenticationExtended {
chatModel.contentViewAccessAuthenticated = true
} else {
if !automaticAuthenticationAttempted {
automaticAuthenticationAttempted = true
// authenticate if call kit call is not in progress
if !(CallController.useCallKit() && chatModel.showCallView && chatModel.activeCall != nil) {
authenticateContentViewAccess()
}
}
}
} else {
// when app is stopped automatic authentication is not attempted
chatModel.contentViewAccessAuthenticated = contentAccessAuthenticationExtended
}
}
default:
break
}
}
.onAppear {
reactOnDarkThemeChanges()
}
.onChange(of: colorScheme) { scheme in
// It's needed to update UI colors when iOS wants to make screenshot after going to background,
// so when a user changes his global theme from dark to light or back, the app will adapt to it
reactOnDarkThemeChanges()
}
.onChange(of: theme.name) { _ in
ThemeManager.adjustWindowStyle()
}
}
@ViewBuilder private func contentView() -> some View {
if prefPerformLA && userAuthorized != true {
lockButton()
} else if chatModel.chatDbStatus == nil && showInitializationView {
initializationView()
} else if let status = chatModel.chatDbStatus, status != .ok {
if let status = chatModel.chatDbStatus, status != .ok {
DatabaseErrorView(status: status)
} else if !chatModel.v3DBMigration.startChat {
MigrateToAppGroupView()
@@ -80,6 +172,11 @@ struct ContentView: View {
if case .onboardingComplete = step,
chatModel.currentUser != nil {
mainView()
.actionSheet(item: $chatListActionSheet) { sheet in
switch sheet {
case let .planAndConnectSheet(sheet): return planAndConnectActionSheet(sheet, dismiss: false)
}
}
} else {
OnboardingView(onboarding: step)
}
@@ -90,11 +187,11 @@ struct ContentView: View {
if CallController.useCallKit() {
ActiveCallView(call: call, canConnectCall: Binding.constant(true))
.onDisappear {
if userAuthorized == false && doAuthenticate { runAuthenticate() }
if prefPerformLA && !accessAuthenticated { authenticateContentViewAccess() }
}
} else {
ActiveCallView(call: call, canConnectCall: $canConnectCall)
if prefPerformLA && userAuthorized != true {
ActiveCallView(call: call, canConnectCall: $canConnectViewCall)
if prefPerformLA && !accessAuthenticated {
Rectangle()
.fill(colorScheme == .dark ? .black : .white)
.frame(maxWidth: .infinity, maxHeight: .infinity)
@@ -103,25 +200,64 @@ struct ContentView: View {
}
}
@ViewBuilder private func activeCallInteractiveArea(_ call: Call) -> some View {
HStack {
Text(call.contact.displayName).font(.body).foregroundColor(.white)
Spacer()
CallDuration(call: call)
}
.padding(.horizontal)
.frame(height: callTopPadding - 10)
.background(Color(uiColor: UIColor(red: 47/255, green: 208/255, blue: 88/255, alpha: 1)))
.onTapGesture {
chatModel.activeCallViewIsCollapsed = false
}
}
struct CallDuration: View {
let call: Call
@State var text: String = ""
@State var timer: Timer? = nil
var body: some View {
Text(text).frame(minWidth: text.count <= 5 ? 52 : 77, alignment: .leading).offset(x: 4).font(.body).foregroundColor(.white)
.onAppear {
timer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: true) { timer in
if let connectedAt = call.connectedAt {
text = durationText(Int(Date.now.timeIntervalSince1970 - connectedAt.timeIntervalSince1970))
}
}
}
.onDisappear {
_ = timer?.invalidate()
}
}
}
private func lockButton() -> some View {
Button(action: runAuthenticate) { Label("Unlock", systemImage: "lock") }
Button(action: authenticateContentViewAccess) { Label("Unlock", systemImage: "lock") }
}
private func initializationView() -> some View {
VStack {
ProgressView().scaleEffect(2)
Text("Opening database")
Text("Opening app")
.padding()
}
.frame(maxWidth: .infinity, maxHeight: .infinity )
.background(
Rectangle()
.fill(theme.colors.background)
)
}
private func mainView() -> some View {
ZStack(alignment: .top) {
ChatListView(showSettings: $showSettings).privacySensitive(protectScreen)
.onAppear {
if !prefPerformLA { requestNtfAuthorization() }
requestNtfAuthorization()
// Local Authentication notice is to be shown on next start after onboarding is complete
if (!prefLANoticeShown && prefShowLANotice && !chatModel.chats.isEmpty) {
if (!prefLANoticeShown && prefShowLANotice && chatModel.chats.count > 2) {
prefLANoticeShown = true
alertManager.showAlert(laNoticeAlert())
} else if !chatModel.showCallView && CallController.shared.activeCallInvitation == nil {
@@ -132,7 +268,9 @@ struct ContentView: View {
}
}
prefShowLANotice = true
connectViaUrl()
}
.onChange(of: chatModel.appOpenUrl) { _ in connectViaUrl() }
.sheet(isPresented: $showWhatsNew) {
WhatsNewView()
}
@@ -169,48 +307,37 @@ struct ContentView: View {
}
}
private func initAuthenticate() {
logger.debug("initAuthenticate")
if CallController.useCallKit() && chatModel.showCallView && chatModel.activeCall != nil {
userAuthorized = false
} else if doAuthenticate {
runAuthenticate()
}
}
private func runAuthenticate() {
logger.debug("DEBUGGING: runAuthenticate")
if !prefPerformLA {
userAuthorized = true
private func unlockedRecently() -> Bool {
if let lastSuccessfulUnlock = lastSuccessfulUnlock {
return ProcessInfo.processInfo.systemUptime - lastSuccessfulUnlock < 2
} else {
logger.debug("DEBUGGING: before dismissAllSheets")
dismissAllSheets(animated: false) {
logger.debug("DEBUGGING: in dismissAllSheets callback")
chatModel.chatId = nil
justAuthenticate()
}
return false
}
}
private func justAuthenticate() {
userAuthorized = false
let laMode = privacyLocalAuthModeDefault.get()
authenticate(reason: NSLocalizedString("Unlock app", comment: "authentication reason"), selfDestruct: true) { laResult in
logger.debug("DEBUGGING: authenticate callback: \(String(describing: laResult))")
switch (laResult) {
case .success:
userAuthorized = true
canConnectCall = true
lastSuccessfulUnlock = ProcessInfo.processInfo.systemUptime
case .failed:
if laMode == .passcode {
AlertManager.shared.showAlert(laFailedAlert())
private func authenticateContentViewAccess() {
logger.debug("DEBUGGING: authenticateContentViewAccess")
dismissAllSheets(animated: false) {
logger.debug("DEBUGGING: authenticateContentViewAccess, in dismissAllSheets callback")
chatModel.chatId = nil
authenticate(reason: NSLocalizedString("Unlock app", comment: "authentication reason"), selfDestruct: true) { laResult in
logger.debug("DEBUGGING: authenticate callback: \(String(describing: laResult))")
switch (laResult) {
case .success:
chatModel.contentViewAccessAuthenticated = true
canConnectViewCall = true
lastSuccessfulUnlock = ProcessInfo.processInfo.systemUptime
case .failed:
chatModel.contentViewAccessAuthenticated = false
if privacyLocalAuthModeDefault.get() == .passcode {
AlertManager.shared.showAlert(laFailedAlert())
}
case .unavailable:
prefPerformLA = false
canConnectViewCall = true
AlertManager.shared.showAlert(laUnavailableTurningOffAlert())
}
case .unavailable:
userAuthorized = true
prefPerformLA = false
canConnectCall = true
AlertManager.shared.showAlert(laUnavailableTurningOffAlert())
}
}
}
@@ -241,6 +368,7 @@ struct ContentView: View {
authenticate(reason: NSLocalizedString("Enable SimpleX Lock", comment: "authentication reason")) { laResult in
switch laResult {
case .success:
chatModel.contentViewAccessAuthenticated = true
prefPerformLA = true
alertManager.showAlert(laTurnedOnAlert())
case .failed:
@@ -265,36 +393,32 @@ struct ContentView: View {
secondaryButton: .cancel()
)
}
}
func connectViaUrl() {
let m = ChatModel.shared
if let url = m.appOpenUrl {
m.appOpenUrl = nil
AlertManager.shared.showAlert(connectViaUrlAlert(url))
func connectViaUrl() {
dismissAllSheets() {
let m = ChatModel.shared
if let url = m.appOpenUrl {
m.appOpenUrl = nil
var path = url.path
if (path == "/contact" || path == "/invitation") {
path.removeFirst()
let link = url.absoluteString.replacingOccurrences(of: "///\(path)", with: "/\(path)")
planAndConnect(
link,
showAlert: showPlanAndConnectAlert,
showActionSheet: { chatListActionSheet = .planAndConnectSheet(sheet: $0) },
dismiss: false,
incognito: nil
)
} else {
AlertManager.shared.showAlert(Alert(title: Text("Error: URL is invalid")))
}
}
}
}
}
func connectViaUrlAlert(_ url: URL) -> Alert {
var path = url.path
logger.debug("ChatListView.connectViaUrlAlert path: \(path)")
if (path == "/contact" || path == "/invitation") {
path.removeFirst()
let action: ConnReqType = path == "contact" ? .contact : .invitation
let link = url.absoluteString.replacingOccurrences(of: "///\(path)", with: "/\(path)")
let title: LocalizedStringKey
if case .contact = action { title = "Connect via contact link?" }
else { title = "Connect via one-time link?" }
return Alert(
title: Text(title),
message: Text("Your profile will be sent to the contact that you received this link from"),
primaryButton: .default(Text("Connect")) {
connectViaLink(link)
},
secondaryButton: .cancel()
)
} else {
return Alert(title: Text("Error: URL is invalid"))
private func showPlanAndConnectAlert(_ alert: PlanAndConnectAlert) {
AlertManager.shared.showAlert(planAndConnectAlert(alert, dismiss: false))
}
}
+41 -3
View File
@@ -46,6 +46,7 @@ class AudioRecorder {
audioRecorder?.record(forDuration: MAX_VOICE_MESSAGE_LENGTH)
await MainActor.run {
AppDelegate.keepScreenOn(true)
recordingTimer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { timer in
guard let time = self.audioRecorder?.currentTime else { return }
self.onTimer?(time)
@@ -57,6 +58,10 @@ class AudioRecorder {
}
return nil
} catch let error {
await MainActor.run {
AppDelegate.keepScreenOn(false)
}
try? av.setCategory(AVAudioSession.Category.soloAmbient)
logger.error("AudioRecorder startAudioRecording error \(error.localizedDescription)")
return .error(error.localizedDescription)
}
@@ -71,6 +76,8 @@ class AudioRecorder {
timer.invalidate()
}
recordingTimer = nil
AppDelegate.keepScreenOn(false)
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.soloAmbient)
}
private func checkPermission() async -> Bool {
@@ -103,9 +110,15 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
self.onFinishPlayback = onFinishPlayback
}
func start(fileName: String, at: TimeInterval?) {
let url = getAppFilePath(fileName)
audioPlayer = try? AVAudioPlayer(contentsOf: url)
func start(fileSource: CryptoFile, at: TimeInterval?) {
let url = getAppFilePath(fileSource.filePath)
if let cfArgs = fileSource.cryptoArgs {
if let data = try? readCryptoFile(path: url.path, cryptoArgs: cfArgs) {
audioPlayer = try? AVAudioPlayer(data: data)
}
} else {
audioPlayer = try? AVAudioPlayer(contentsOf: url)
}
audioPlayer?.delegate = self
audioPlayer?.prepareToPlay()
if let at = at {
@@ -115,14 +128,19 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
playbackTimer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { timer in
if self.audioPlayer?.isPlaying ?? false {
AppDelegate.keepScreenOn(true)
guard let time = self.audioPlayer?.currentTime else { return }
self.onTimer?(time)
AudioPlayer.changeAudioSession(true)
} else {
AudioPlayer.changeAudioSession(false)
}
}
}
func pause() {
audioPlayer?.pause()
AppDelegate.keepScreenOn(false)
}
func play() {
@@ -143,6 +161,8 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
func stop() {
if let player = audioPlayer {
player.stop()
AppDelegate.keepScreenOn(false)
AudioPlayer.changeAudioSession(false)
}
audioPlayer = nil
if let timer = playbackTimer {
@@ -151,6 +171,24 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
playbackTimer = nil
}
static func changeAudioSession(_ playback: Bool) {
// When there is a audio recording, setting any other category will disable sound
if AVAudioSession.sharedInstance().category == .playAndRecord {
return
}
if playback {
if AVAudioSession.sharedInstance().category != .playback {
logger.log("AudioSession: playback")
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: [.duckOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
}
} else {
if AVAudioSession.sharedInstance().category != .soloAmbient {
logger.log("AudioSession: soloAmbient")
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.soloAmbient)
}
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
stop()
self.onFinishPlayback?()
+28 -6
View File
@@ -15,7 +15,13 @@ private let receiveTaskId = "chat.simplex.app.receive"
// TCP timeout + 2 sec
private let waitForMessages: TimeInterval = 6
private let bgRefreshInterval: TimeInterval = 450
// This is the smallest interval between refreshes, and also target interval in "off" mode
private let bgRefreshInterval: TimeInterval = 600 // 10 minutes
// This intervals are used for background refresh in instant and periodic modes
private let periodicBgRefreshInterval: TimeInterval = 1200 // 20 minutes
private let maxBgRefreshInterval: TimeInterval = 2400 // 40 minutes
private let maxTimerCount = 9
@@ -33,14 +39,14 @@ class BGManager {
}
}
func schedule() {
func schedule(interval: TimeInterval? = nil) {
if !ChatModel.shared.ntfEnableLocal {
logger.debug("BGManager.schedule: disabled")
return
}
logger.debug("BGManager.schedule")
let request = BGAppRefreshTaskRequest(identifier: receiveTaskId)
request.earliestBeginDate = Date(timeIntervalSinceNow: bgRefreshInterval)
request.earliestBeginDate = Date(timeIntervalSinceNow: interval ?? runInterval)
do {
try BGTaskScheduler.shared.submit(request)
} catch {
@@ -48,20 +54,34 @@ class BGManager {
}
}
var runInterval: TimeInterval {
switch ChatModel.shared.notificationMode {
case .instant: maxBgRefreshInterval
case .periodic: periodicBgRefreshInterval
case .off: bgRefreshInterval
}
}
var lastRanLongAgo: Bool {
Date.now.timeIntervalSince(chatLastBackgroundRunGroupDefault.get()) > runInterval
}
private func handleRefresh(_ task: BGAppRefreshTask) {
if !ChatModel.shared.ntfEnableLocal {
logger.debug("BGManager.handleRefresh: disabled")
return
}
logger.debug("BGManager.handleRefresh")
schedule()
if appStateGroupDefault.get().inactive {
let shouldRun_ = lastRanLongAgo
if allowBackgroundRefresh() && shouldRun_ {
schedule()
let completeRefresh = completionHandler {
task.setTaskCompleted(success: true)
}
task.expirationHandler = { completeRefresh("expirationHandler") }
receiveMessages(completeRefresh)
} else {
schedule(interval: shouldRun_ ? bgRefreshInterval : runInterval)
logger.debug("BGManager.completionHandler: already active, not started")
task.setTaskCompleted(success: true)
}
@@ -90,20 +110,22 @@ class BGManager {
}
self.completed = false
DispatchQueue.main.async {
chatLastBackgroundRunGroupDefault.set(Date.now)
let m = ChatModel.shared
if (!m.chatInitialized) {
setAppState(.bgRefresh)
do {
try initializeChat(start: true)
} catch let error {
fatalError("Failed to start or load chats: \(responseError(error))")
}
}
activateChat(appState: .bgRefresh)
if m.currentUser == nil {
completeReceiving("no current user")
return
}
logger.debug("BGManager.receiveMessages: starting chat")
activateChat(appState: .bgRefresh)
let cr = ChatReceiver()
self.chatReceiver = cr
cr.start()
+525 -157
View File
@@ -11,28 +11,149 @@ import Combine
import SwiftUI
import SimpleXChat
actor TerminalItems {
private var terminalItems: [TerminalItem] = []
static let shared = TerminalItems()
func items() -> [TerminalItem] {
terminalItems
}
func add(_ item: TerminalItem) async {
addTermItem(&terminalItems, item)
let m = ChatModel.shared
if m.showingTerminal {
await MainActor.run {
addTermItem(&m.terminalItems, item)
}
}
}
func addCommand(_ start: Date, _ cmd: ChatCommand, _ resp: ChatResponse) async {
await add(.cmd(start, cmd))
await add(.resp(.now, resp))
}
}
private func addTermItem(_ items: inout [TerminalItem], _ item: TerminalItem) {
if items.count >= 200 {
items.removeFirst()
}
items.append(item)
}
class ItemsModel: ObservableObject {
static let shared = ItemsModel()
private let publisher = ObservableObjectPublisher()
private var bag = Set<AnyCancellable>()
var reversedChatItems: [ChatItem] = [] {
willSet { publisher.send() }
}
var itemAdded = false {
willSet { publisher.send() }
}
// Publishes directly to `objectWillChange` publisher,
// this will cause reversedChatItems to be rendered without throttling
@Published var isLoading = false
@Published var showLoadingProgress = false
init() {
publisher
.throttle(for: 0.25, scheduler: DispatchQueue.main, latest: true)
.sink { self.objectWillChange.send() }
.store(in: &bag)
}
func loadOpenChat(_ chatId: ChatId, willNavigate: @escaping () -> Void = {}) {
let navigationTimeout = Task {
do {
try await Task.sleep(nanoseconds: 250_000000)
await MainActor.run {
willNavigate()
ChatModel.shared.chatId = chatId
}
} 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()
await MainActor.run {
self.isLoading = false
self.showLoadingProgress = false
willNavigate()
ChatModel.shared.chatId = chatId
}
}
}
}
}
class NetworkModel: ObservableObject {
// map of connections network statuses, key is agent connection id
@Published var networkStatuses: Dictionary<String, NetworkStatus> = [:]
static let shared = NetworkModel()
private init() { }
func setContactNetworkStatus(_ contact: Contact, _ status: NetworkStatus) {
if let conn = contact.activeConn {
networkStatuses[conn.agentConnId] = status
}
}
func contactNetworkStatus(_ contact: Contact) -> NetworkStatus {
if let conn = contact.activeConn {
networkStatuses[conn.agentConnId] ?? .unknown
} else {
.unknown
}
}
}
final class ChatModel: ObservableObject {
@Published var onboardingStage: OnboardingStage?
@Published var setDeliveryReceipts = false
@Published var v3DBMigration: V3DBMigrationState = v3DBMigrationDefault.get()
@Published var currentUser: User?
@Published var currentUser: User? {
didSet {
ThemeManager.applyTheme(currentThemeDefault.get())
}
}
@Published var users: [UserInfo] = []
@Published var chatInitialized = false
@Published var chatRunning: Bool?
@Published var chatDbChanged = false
@Published var chatDbEncrypted: Bool?
@Published var chatDbStatus: DBMigrationResult?
@Published var ctrlInitInProgress: Bool = false
// local authentication
@Published var contentViewAccessAuthenticated: Bool = false
@Published var laRequest: LocalAuthRequest?
// list of chat "previews"
@Published var chats: [Chat] = []
// map of connections network statuses, key is agent connection id
@Published var networkStatuses: Dictionary<String, NetworkStatus> = [:]
@Published var deletedChats: Set<String> = []
// current chat
@Published var chatId: String?
@Published var reversedChatItems: [ChatItem] = []
var chatItemStatuses: Dictionary<Int64, CIStatus> = [:]
@Published var chatToTop: String?
@Published var groupMembers: [GroupMember] = []
@Published var groupMembers: [GMember] = []
@Published var groupMembersIndexes: Dictionary<Int64, Int> = [:] // groupMemberId to index in groupMembers list
@Published var membersLoaded = false
// items in the terminal view
@Published var showingTerminal = false
@Published var terminalItems: [TerminalItem] = []
@Published var userAddress: UserContactLink?
@Published var chatItemTTL: ChatItemTTL = .none
@@ -42,24 +163,28 @@ final class ChatModel: ObservableObject {
@Published var tokenRegistered = false
@Published var tokenStatus: NtfTknStatus?
@Published var notificationMode = NotificationsMode.off
@Published var notificationServer: String?
@Published var notificationPreview: NotificationPreviewMode = ntfPreviewModeGroupDefault.get()
@Published var incognito: Bool = incognitoGroupDefault.get()
// pending notification actions
@Published var ntfContactRequest: ChatId?
@Published var ntfContactRequest: NTFContactRequest?
@Published var ntfCallInvitationAction: (ChatId, NtfCallAction)?
// current WebRTC call
@Published var callInvitations: Dictionary<ChatId, RcvCallInvitation> = [:]
@Published var activeCall: Call?
@Published var callCommand: WCallCommand?
let callCommand: WebRTCCommandProcessor = WebRTCCommandProcessor()
@Published var showCallView = false
// currently showing QR code
@Published var connReqInv: String?
@Published var activeCallViewIsCollapsed = false
// remote desktop
@Published var remoteCtrlSession: RemoteCtrlSession?
// currently showing invitation
@Published var showingInvitation: ShowingInvitation?
@Published var migrationState: MigrationToState? = MigrationToDeviceState.makeMigrationState()
// audio recording and playback
@Published var stopPreviousRecPlay: URL? = nil // coordinates currently playing source
@Published var draft: ComposeState?
@Published var draftChatId: String?
// tracks keyboard height via subscription in AppDelegate
@Published var keyboardHeight: CGFloat = 0
@Published var pasteboardHasStrings: Bool = UIPasteboard.general.hasStrings
@Published var networkInfo = UserNetworkInfo(networkType: .other, online: true)
var messageDelivery: Dictionary<Int64, () -> Void> = [:]
@@ -67,14 +192,18 @@ final class ChatModel: ObservableObject {
static let shared = ChatModel()
let im = ItemsModel.shared
static var ok: Bool { ChatModel.shared.chatDbStatus == .ok }
var ntfEnableLocal: Bool {
notificationMode == .off || ntfEnableLocalGroupDefault.get()
}
let ntfEnableLocal = true
var ntfEnablePeriodic: Bool {
notificationMode == .periodic || ntfEnablePeriodicGroupDefault.get()
notificationMode != .off
}
var activeRemoteCtrl: Bool {
remoteCtrlSession?.active ?? false
}
func getUser(_ userId: Int64) -> User? {
@@ -97,7 +226,7 @@ final class ChatModel: ObservableObject {
}
func removeUser(_ user: User) {
if let i = getUserIndex(user), users[i].user.userId != currentUser?.userId {
if let i = getUserIndex(user) {
users.remove(at: i)
}
}
@@ -120,19 +249,63 @@ final class ChatModel: ObservableObject {
}
}
func getGroupChat(_ groupId: Int64) -> Chat? {
chats.first { chat in
if case let .group(groupInfo) = chat.chatInfo {
return groupInfo.groupId == groupId
} else {
return false
}
}
}
func populateGroupMembersIndexes() {
groupMembersIndexes.removeAll()
for (i, member) in groupMembers.enumerated() {
groupMembersIndexes[member.groupMemberId] = i
}
}
func getGroupMember(_ groupMemberId: Int64) -> GMember? {
if let i = groupMembersIndexes[groupMemberId] {
return groupMembers[i]
}
return nil
}
func loadGroupMembers(_ groupInfo: GroupInfo, updateView: @escaping () -> Void = {}) async {
let groupMembers = await apiListMembers(groupInfo.groupId)
await MainActor.run {
if chatId == groupInfo.id {
self.groupMembers = groupMembers.map { GMember.init($0) }
self.populateGroupMembersIndexes()
self.membersLoaded = true
updateView()
}
}
}
private func getChatIndex(_ id: String) -> Int? {
chats.firstIndex(where: { $0.id == id })
}
func addChat(_ chat: Chat, at position: Int = 0) {
withAnimation {
chats.insert(chat, at: position)
func addChat(_ chat: Chat) {
if chatId == nil {
withAnimation { addChat_(chat, at: 0) }
} else {
addChat_(chat, at: 0)
}
popChatCollector.throttlePopChat(chat.chatInfo.id, currentPosition: 0)
}
func addChat_(_ chat: Chat, at position: Int = 0) {
chats.insert(chat, at: position)
}
func updateChatInfo(_ cInfo: ChatInfo) {
if let i = getChatIndex(cInfo.id) {
chats[i].chatInfo = cInfo
chats[i].created = Date.now
}
}
@@ -146,7 +319,7 @@ final class ChatModel: ObservableObject {
func updateContactConnectionStats(_ contact: Contact, _ connectionStats: ConnectionStats) {
var updatedConn = contact.activeConn
updatedConn.connectionStats = connectionStats
updatedConn?.connectionStats = connectionStats
var updatedContact = contact
updatedContact.activeConn = updatedConn
updateContact(updatedContact)
@@ -200,10 +373,11 @@ final class ChatModel: ObservableObject {
}
}
} else {
addChat(Chat(c), at: i)
addChat_(Chat(c), at: i)
}
}
NtfManager.shared.setNtfBadgeCount(totalUnreadCountForAllUsers())
popChatCollector.clear()
}
// func addGroup(_ group: SimpleXChat.Group) {
@@ -211,22 +385,32 @@ final class ChatModel: ObservableObject {
// }
func addChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem) {
// mark chat non deleted
if case let .direct(contact) = cInfo, contact.chatDeleted {
var updatedContact = contact
updatedContact.chatDeleted = false
updateContact(updatedContact)
}
// update previews
if let i = getChatIndex(cInfo.id) {
chats[i].chatItems = [cItem]
if case .rcvNew = cItem.meta.itemStatus {
chats[i].chatStats.unreadCount = chats[i].chatStats.unreadCount + 1
increaseUnreadCounter(user: currentUser!)
}
if i > 0 {
if chatId == nil {
withAnimation { popChat_(i) }
} else if chatId == cInfo.id {
chatToTop = cInfo.id
chats[i].chatItems = switch cInfo {
case .group:
if let currentPreviewItem = chats[i].chatItems.first {
if cItem.meta.itemTs >= currentPreviewItem.meta.itemTs {
[cItem]
} else {
[currentPreviewItem]
}
} else {
popChat_(i)
[cItem]
}
default:
[cItem]
}
if case .rcvNew = cItem.meta.itemStatus {
unreadCollector.changeUnreadCounter(cInfo.id, by: 1)
}
popChatCollector.throttlePopChat(cInfo.id, currentPosition: i)
} else {
addChat(Chat(chatInfo: cInfo, chatItems: [cItem]))
}
@@ -241,7 +425,7 @@ final class ChatModel: ObservableObject {
var res: Bool
if let chat = getChat(cInfo.id) {
if let pItem = chat.chatItems.last {
if pItem.id == cItem.id || (chatId == cInfo.id && reversedChatItems.first(where: { $0.id == cItem.id }) == nil) {
if pItem.id == cItem.id || (chatId == cInfo.id && im.reversedChatItems.first(where: { $0.id == cItem.id }) == nil) {
chat.chatItems = [cItem]
}
} else {
@@ -252,19 +436,27 @@ final class ChatModel: ObservableObject {
addChat(Chat(chatInfo: cInfo, chatItems: [cItem]))
res = true
}
if cItem.isDeletedContent || cItem.meta.itemDeleted != nil {
VoiceItemState.stopVoiceInChatView(cInfo, cItem)
}
// update current chat
return chatId == cInfo.id ? _upsertChatItem(cInfo, cItem) : res
}
private func _upsertChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem) -> Bool {
if let i = getChatItemIndex(cItem) {
withAnimation {
withConditionalAnimation {
_updateChatItem(at: i, with: cItem)
}
return false
} else {
withAnimation(itemAnimation()) {
reversedChatItems.insert(cItem, at: hasLiveDummy ? 1 : 0)
withConditionalAnimation(itemAnimation()) {
var ci = cItem
if let status = chatItemStatuses.removeValue(forKey: ci.id), case .sndNew = ci.meta.itemStatus {
ci.meta.itemStatus = status
}
im.reversedChatItems.insert(ci, at: hasLiveDummy ? 1 : 0)
im.itemAdded = true
}
return true
}
@@ -277,32 +469,28 @@ final class ChatModel: ObservableObject {
}
}
func updateChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem) {
func updateChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem, status: CIStatus? = nil) {
if chatId == cInfo.id, let i = getChatItemIndex(cItem) {
withAnimation {
withConditionalAnimation {
_updateChatItem(at: i, with: cItem)
}
} else if let status = status {
chatItemStatuses.updateValue(status, forKey: cItem.id)
}
}
private func _updateChatItem(at i: Int, with cItem: ChatItem) {
let ci = reversedChatItems[i]
reversedChatItems[i] = cItem
reversedChatItems[i].viewTimestamp = .now
// on some occasions the confirmation of message being accepted by the server (tick)
// arrives earlier than the response from API, and item remains without tick
if case .sndNew = cItem.meta.itemStatus {
reversedChatItems[i].meta.itemStatus = ci.meta.itemStatus
}
im.reversedChatItems[i] = cItem
im.reversedChatItems[i].viewTimestamp = .now
}
private func getChatItemIndex(_ cItem: ChatItem) -> Int? {
reversedChatItems.firstIndex(where: { $0.id == cItem.id })
func getChatItemIndex(_ cItem: ChatItem) -> Int? {
im.reversedChatItems.firstIndex(where: { $0.id == cItem.id })
}
func removeChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem) {
if cItem.isRcvNew {
decreaseUnreadCounter(cInfo)
unreadCollector.changeUnreadCounter(cInfo.id, by: -1)
}
// update previews
if let chat = getChat(cInfo.id) {
@@ -314,23 +502,24 @@ final class ChatModel: ObservableObject {
if chatId == cInfo.id {
if let i = getChatItemIndex(cItem) {
_ = withAnimation {
self.reversedChatItems.remove(at: i)
im.reversedChatItems.remove(at: i)
}
}
}
VoiceItemState.stopVoiceInChatView(cInfo, cItem)
}
func nextChatItemData<T>(_ chatItemId: Int64, previous: Bool, map: @escaping (ChatItem) -> T?) -> T? {
guard var i = reversedChatItems.firstIndex(where: { $0.id == chatItemId }) else { return nil }
guard var i = im.reversedChatItems.firstIndex(where: { $0.id == chatItemId }) else { return nil }
if previous {
while i < reversedChatItems.count - 1 {
while i < im.reversedChatItems.count - 1 {
i += 1
if let res = map(reversedChatItems[i]) { return res }
if let res = map(im.reversedChatItems[i]) { return res }
}
} else {
while i > 0 {
i -= 1
if let res = map(reversedChatItems[i]) { return res }
if let res = map(im.reversedChatItems[i]) { return res }
}
}
return nil
@@ -348,10 +537,21 @@ final class ChatModel: ObservableObject {
}
}
func updateCurrentUserUiThemes(uiThemes: ThemeModeOverrides?) {
guard var current = currentUser else { return }
current.uiThemes = uiThemes
let i = users.firstIndex(where: { $0.user.userId == current.userId })
if let i {
users[i].user = current
}
currentUser = current
}
func addLiveDummy(_ chatInfo: ChatInfo) -> ChatItem {
let cItem = ChatItem.liveDummy(chatInfo.chatType)
withAnimation {
reversedChatItems.insert(cItem, at: 0)
im.reversedChatItems.insert(cItem, at: 0)
im.itemAdded = true
}
return cItem
}
@@ -359,15 +559,15 @@ final class ChatModel: ObservableObject {
func removeLiveDummy(animated: Bool = true) {
if hasLiveDummy {
if animated {
withAnimation { _ = reversedChatItems.removeFirst() }
withAnimation { _ = im.reversedChatItems.removeFirst() }
} else {
_ = reversedChatItems.removeFirst()
_ = im.reversedChatItems.removeFirst()
}
}
}
private var hasLiveDummy: Bool {
reversedChatItems.first?.isLiveDummy == true
im.reversedChatItems.first?.isLiveDummy == true
}
func markChatItemsRead(_ cInfo: ChatInfo) {
@@ -384,7 +584,7 @@ final class ChatModel: ObservableObject {
private func markCurrentChatRead(fromIndex i: Int = 0) {
var j = i
while j < reversedChatItems.count {
while j < im.reversedChatItems.count {
markChatItemRead_(j)
j += 1
}
@@ -398,7 +598,7 @@ final class ChatModel: ObservableObject {
var unreadBelow = 0
var j = i - 1
while j >= 0 {
if case .rcvNew = self.reversedChatItems[j].meta.itemStatus {
if case .rcvNew = self.im.reversedChatItems[j].meta.itemStatus {
unreadBelow += 1
}
j -= 1
@@ -432,51 +632,147 @@ final class ChatModel: ObservableObject {
}
// clear current chat
if chatId == cInfo.id {
reversedChatItems = []
chatItemStatuses = [:]
im.reversedChatItems = []
}
}
func markChatItemRead(_ cInfo: ChatInfo, _ cItem: ChatItem) {
// update preview
decreaseUnreadCounter(cInfo)
// update current chat
if chatId == cInfo.id, let i = getChatItemIndex(cItem) {
markChatItemRead_(i)
}
}
private func markChatItemRead_(_ i: Int) {
let meta = reversedChatItems[i].meta
if case .rcvNew = meta.itemStatus {
reversedChatItems[i].meta.itemStatus = .rcvRead
reversedChatItems[i].viewTimestamp = .now
if meta.itemLive != true, let ttl = meta.itemTimed?.ttl {
reversedChatItems[i].meta.itemTimed?.deleteAt = .now + TimeInterval(ttl)
func markChatItemRead(_ cInfo: ChatInfo, _ cItem: ChatItem) async {
if chatId == cInfo.id,
let itemIndex = getChatItemIndex(cItem),
im.reversedChatItems[itemIndex].isRcvNew {
await MainActor.run {
withTransaction(Transaction()) {
// update current chat
markChatItemRead_(itemIndex)
// update preview
unreadCollector.changeUnreadCounter(cInfo.id, by: -1)
}
}
}
}
func decreaseUnreadCounter(_ cInfo: ChatInfo) {
if let i = getChatIndex(cInfo.id) {
chats[i].chatStats.unreadCount = chats[i].chatStats.unreadCount - 1
decreaseUnreadCounter(user: currentUser!)
private let unreadCollector = UnreadCollector()
class UnreadCollector {
private let subject = PassthroughSubject<Void, Never>()
private var bag = Set<AnyCancellable>()
private var unreadCounts: [ChatId: Int] = [:]
init() {
subject
.debounce(for: 1, scheduler: DispatchQueue.main)
.sink {
let m = ChatModel.shared
for (chatId, count) in self.unreadCounts {
if let i = m.getChatIndex(chatId) {
m.changeUnreadCounter(i, by: count)
}
}
self.unreadCounts = [:]
}
.store(in: &bag)
}
func changeUnreadCounter(_ chatId: ChatId, by count: Int) {
DispatchQueue.main.async {
self.unreadCounts[chatId] = (self.unreadCounts[chatId] ?? 0) + count
}
subject.send()
}
}
func increaseUnreadCounter(user: User) {
let popChatCollector = PopChatCollector()
class PopChatCollector {
private let subject = PassthroughSubject<Void, Never>()
private var bag = Set<AnyCancellable>()
private var chatsToPop: [ChatId: Date] = [:]
private let popTsComparator = KeyPathComparator<Chat>(\.popTs, order: .reverse)
init() {
subject
.throttle(for: 2, scheduler: DispatchQueue.main, latest: true)
.sink { self.popCollectedChats() }
.store(in: &bag)
}
func throttlePopChat(_ chatId: ChatId, currentPosition: Int) {
let m = ChatModel.shared
if currentPosition > 0 && m.chatId == chatId {
m.chatToTop = chatId
}
if currentPosition > 0 || !chatsToPop.isEmpty {
chatsToPop[chatId] = Date.now
subject.send()
}
}
func clear() {
chatsToPop = [:]
}
func popCollectedChats() {
let m = ChatModel.shared
var ixs: IndexSet = []
var chs: [Chat] = []
// collect chats that received updates
for (chatId, popTs) in self.chatsToPop {
// Currently opened chat is excluded, removing it from the list would navigate out of it
// It will be popped to top later when user exits from the list.
if m.chatId != chatId, let i = m.getChatIndex(chatId) {
ixs.insert(i)
let ch = m.chats[i]
ch.popTs = popTs
chs.append(ch)
}
}
let removeInsert = {
m.chats.remove(atOffsets: ixs)
// sort chats by pop timestamp in descending order
m.chats.insert(contentsOf: chs.sorted(using: self.popTsComparator), at: 0)
}
if m.chatId == nil {
withAnimation { removeInsert() }
} else {
removeInsert()
}
self.chatsToPop = [:]
}
}
private func markChatItemRead_(_ i: Int) {
let meta = im.reversedChatItems[i].meta
if case .rcvNew = meta.itemStatus {
im.reversedChatItems[i].meta.itemStatus = .rcvRead
im.reversedChatItems[i].viewTimestamp = .now
if meta.itemLive != true, let ttl = meta.itemTimed?.ttl {
im.reversedChatItems[i].meta.itemTimed?.deleteAt = .now + TimeInterval(ttl)
}
}
}
func changeUnreadCounter(_ chatIndex: Int, by count: Int) {
chats[chatIndex].chatStats.unreadCount = chats[chatIndex].chatStats.unreadCount + count
changeUnreadCounter(user: currentUser!, by: count)
}
func increaseUnreadCounter(user: any UserLike) {
changeUnreadCounter(user: user, by: 1)
NtfManager.shared.incNtfBadgeCount()
}
func decreaseUnreadCounter(user: User, by: Int = 1) {
func decreaseUnreadCounter(user: any UserLike, by: Int = 1) {
changeUnreadCounter(user: user, by: -by)
NtfManager.shared.decNtfBadgeCount(by: by)
}
private func changeUnreadCounter(user: User, by: Int) {
if let i = users.firstIndex(where: { $0.user.id == user.id }) {
private func changeUnreadCounter(user: any UserLike, by: Int) {
if let i = users.firstIndex(where: { $0.user.userId == user.userId }) {
users[i].unreadCount += by
}
NtfManager.shared.changeNtfBadgeCount(by: by)
}
func totalUnreadCountForAllUsers() -> Int {
@@ -484,16 +780,65 @@ final class ChatModel: ObservableObject {
users.filter { !$0.user.activeUser }.reduce(0, { unread, next -> Int in unread + next.unreadCount })
}
func getPrevChatItem(_ ci: ChatItem) -> ChatItem? {
if let i = getChatItemIndex(ci), i < reversedChatItems.count - 1 {
return reversedChatItems[i + 1]
// this function analyses "connected" events and assumes that each member will be there only once
func getConnectedMemberNames(_ chatItem: ChatItem) -> (Int, [String]) {
var count = 0
var ns: [String] = []
if let ciCategory = chatItem.mergeCategory,
var i = getChatItemIndex(chatItem) {
while i < im.reversedChatItems.count {
let ci = im.reversedChatItems[i]
if ci.mergeCategory != ciCategory { break }
if let m = ci.memberConnected {
ns.append(m.displayName)
}
count += 1
i += 1
}
}
return (count, ns)
}
// returns the index of the passed item and the next item (it has smaller index)
func getNextChatItem(_ ci: ChatItem) -> (Int?, ChatItem?) {
if let i = getChatItemIndex(ci) {
(i, i > 0 ? im.reversedChatItems[i - 1] : nil)
} else {
return nil
(nil, nil)
}
}
// returns the index of the first item in the same merged group (the first hidden item)
// and the previous visible item with another merge category
func getPrevShownChatItem(_ ciIndex: Int?, _ ciCategory: CIMergeCategory?) -> (Int?, ChatItem?) {
guard var i = ciIndex else { return (nil, nil) }
let fst = im.reversedChatItems.count - 1
while i < fst {
i = i + 1
let ci = im.reversedChatItems[i]
if ciCategory == nil || ciCategory != ci.mergeCategory {
return (i - 1, ci)
}
}
return (i, nil)
}
// 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) {
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)
}
}
return (prevMember, memberIds.count)
}
func popChat(_ id: String) {
if let i = getChatIndex(id) {
// no animation here, for it not to look like it just moved when leaving the chat
popChat_(i)
}
}
@@ -504,14 +849,16 @@ final class ChatModel: ObservableObject {
}
func dismissConnReqView(_ id: String) {
if let connReqInv = connReqInv,
let c = getChat(id),
case let .contactConnection(contactConnection) = c.chatInfo,
connReqInv == contactConnection.connReqInv {
if id == showingInvitation?.connId {
markShowingInvitationUsed()
dismissAllSheets()
}
}
func markShowingInvitationUsed() {
showingInvitation?.connChatUsed = true
}
func removeChat(_ id: String) {
withAnimation {
chats.removeAll(where: { $0.id == id })
@@ -526,13 +873,17 @@ final class ChatModel: ObservableObject {
}
// update current chat
if chatId == groupInfo.id {
if let i = groupMembers.firstIndex(where: { $0.id == member.id }) {
if let i = groupMembersIndexes[member.groupMemberId] {
withAnimation(.default) {
self.groupMembers[i] = member
self.groupMembers[i].wrapped = member
self.groupMembers[i].created = Date.now
}
return false
} else {
withAnimation { groupMembers.append(member) }
withAnimation {
groupMembers.append(GMember(member))
groupMembersIndexes[member.groupMemberId] = groupMembers.count - 1
}
return true
}
} else {
@@ -541,11 +892,10 @@ final class ChatModel: ObservableObject {
}
func updateGroupMemberConnectionStats(_ groupInfo: GroupInfo, _ member: GroupMember, _ connectionStats: ConnectionStats) {
if let conn = member.activeConn {
var updatedConn = conn
updatedConn.connectionStats = connectionStats
if var conn = member.activeConn {
conn.connectionStats = connectionStats
var updatedMember = member
updatedMember.activeConn = updatedConn
updatedMember.activeConn = conn
_ = upsertGroupMember(groupInfo, updatedMember)
}
}
@@ -554,51 +904,54 @@ final class ChatModel: ObservableObject {
var i = 0
var totalBelow = 0
var unreadBelow = 0
while i < reversedChatItems.count - 1 && !itemsInView.contains(reversedChatItems[i].viewId) {
while i < im.reversedChatItems.count - 1 && !itemsInView.contains(im.reversedChatItems[i].viewId) {
totalBelow += 1
if reversedChatItems[i].isRcvNew {
if im.reversedChatItems[i].isRcvNew {
unreadBelow += 1
}
i += 1
}
return UnreadChatItemCounts(totalBelow: totalBelow, unreadBelow: unreadBelow)
return UnreadChatItemCounts(
// TODO these thresholds account for the fact that items are still "visible" while
// covered by compose area, they should be replaced with the actual height in pixels below the screen.
isNearBottom: totalBelow < 15,
isReallyNearBottom: totalBelow < 2,
unreadBelow: unreadBelow
)
}
func topItemInView(itemsInView: Set<String>) -> ChatItem? {
let maxIx = reversedChatItems.count - 1
let maxIx = im.reversedChatItems.count - 1
var i = 0
let inView = { itemsInView.contains(self.reversedChatItems[$0].viewId) }
let inView = { itemsInView.contains(self.im.reversedChatItems[$0].viewId) }
while i < maxIx && !inView(i) { i += 1 }
while i < maxIx && inView(i) { i += 1 }
return reversedChatItems[min(i - 1, maxIx)]
}
func setContactNetworkStatus(_ contact: Contact, _ status: NetworkStatus) {
networkStatuses[contact.activeConn.agentConnId] = status
}
func contactNetworkStatus(_ contact: Contact) -> NetworkStatus {
networkStatuses[contact.activeConn.agentConnId] ?? .unknown
}
func addTerminalItem(_ item: TerminalItem) {
if terminalItems.count >= 500 {
terminalItems.remove(at: 0)
}
terminalItems.append(item)
return im.reversedChatItems[min(i - 1, maxIx)]
}
}
struct UnreadChatItemCounts {
var totalBelow: Int
struct ShowingInvitation {
var connId: String
var connChatUsed: Bool
}
struct NTFContactRequest {
var incognito: Bool
var chatId: String
}
struct UnreadChatItemCounts: Equatable {
var isNearBottom: Bool
var isReallyNearBottom: Bool
var unreadBelow: Int
}
final class Chat: ObservableObject, Identifiable {
final class Chat: ObservableObject, Identifiable, ChatLike {
@Published var chatInfo: ChatInfo
@Published var chatItems: [ChatItem]
@Published var chatStats: ChatStats
var created = Date.now
fileprivate var popTs: Date?
init(_ cData: ChatData) {
self.chatInfo = cData.chatInfo
@@ -626,6 +979,8 @@ final class Chat: ObservableObject, Identifiable {
case let .group(groupInfo):
let m = groupInfo.membership
return m.memberActive && m.memberRole >= .member
case .local:
return true
default: return false
}
}
@@ -646,40 +1001,53 @@ final class Chat: ObservableObject, Identifiable {
public static var sampleData: Chat = Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: [])
}
enum NetworkStatus: Decodable, Equatable {
case unknown
case connected
case disconnected
case error(String)
final class GMember: ObservableObject, Identifiable {
@Published var wrapped: GroupMember
var created = Date.now
var statusString: LocalizedStringKey {
get {
switch self {
case .connected: return "connected"
case .error: return "error"
default: return "connecting"
}
}
init(_ member: GroupMember) {
self.wrapped = member
}
var statusExplanation: LocalizedStringKey {
get {
switch self {
case .connected: return "You are connected to the server used to receive messages from this contact."
case let .error(err): return "Trying to connect to the server used to receive messages from this contact (error: \(err))."
default: return "Trying to connect to the server used to receive messages from this contact."
}
}
var id: String { wrapped.id }
var groupId: Int64 { wrapped.groupId }
var groupMemberId: Int64 { wrapped.groupMemberId }
var displayName: String { wrapped.displayName }
var viewId: String { get { "\(wrapped.id) \(created.timeIntervalSince1970)" } }
static let sampleData = GMember(GroupMember.sampleData)
}
struct RemoteCtrlSession {
var ctrlAppInfo: CtrlAppInfo?
var appVersion: String
var sessionState: UIRemoteCtrlSessionState
func updateState(_ state: UIRemoteCtrlSessionState) -> RemoteCtrlSession {
RemoteCtrlSession(ctrlAppInfo: ctrlAppInfo, appVersion: appVersion, sessionState: state)
}
var imageName: String {
get {
switch self {
case .unknown: return "circle.dotted"
case .connected: return "circle.fill"
case .disconnected: return "ellipsis.circle.fill"
case .error: return "exclamationmark.circle.fill"
}
var active: Bool {
if case .connected = sessionState { true } else { false }
}
var discovery: Bool {
if case .searching = sessionState { true } else { false }
}
var sessionCode: String? {
switch sessionState {
case let .pendingConfirmation(_, sessionCode): sessionCode
case let .connected(_, sessionCode): sessionCode
default: nil
}
}
}
enum UIRemoteCtrlSessionState {
case starting
case searching
case found(remoteCtrl: RemoteCtrlInfo, compatible: Bool)
case connecting(remoteCtrl_: RemoteCtrlInfo?)
case pendingConfirmation(remoteCtrl_: RemoteCtrlInfo?, sessionCode: String)
case connected(remoteCtrl: RemoteCtrlInfo, sessionCode: String)
}
-291
View File
@@ -1,291 +0,0 @@
//
// ImageUtils.swift
// SimpleX (iOS)
//
// Created by Evgeny on 24/12/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import Foundation
import SimpleXChat
import SwiftUI
import AVKit
func getLoadedFilePath(_ file: CIFile?) -> String? {
if let fileName = getLoadedFileName(file) {
return getAppFilePath(fileName).path
}
return nil
}
func getLoadedFileName(_ file: CIFile?) -> String? {
if let file = file,
file.loaded,
let fileName = file.filePath {
return fileName
}
return nil
}
func getLoadedImage(_ file: CIFile?) -> UIImage? {
let loadedFilePath = getLoadedFilePath(file)
if let loadedFilePath = loadedFilePath, let fileName = file?.filePath {
let filePath = getAppFilePath(fileName)
do {
let data = try Data(contentsOf: filePath)
let img = UIImage(data: data)
try img?.setGifFromData(data, levelOfIntegrity: 1.0)
return img
} catch {
return UIImage(contentsOfFile: loadedFilePath)
}
}
return nil
}
func getLoadedVideo(_ file: CIFile?) -> URL? {
let loadedFilePath = getLoadedFilePath(file)
if loadedFilePath != nil, let fileName = file?.filePath {
let filePath = getAppFilePath(fileName)
if FileManager.default.fileExists(atPath: filePath.path) {
return filePath
}
}
return nil
}
func saveAnimImage(_ image: UIImage) -> String? {
let fileName = generateNewFileName("IMG", "gif")
guard let imageData = image.imageData else { return nil }
return saveFile(imageData, fileName)
}
func saveImage(_ uiImage: UIImage) -> String? {
let hasAlpha = imageHasAlpha(uiImage)
let ext = hasAlpha ? "png" : "jpg"
if let imageDataResized = resizeImageToDataSize(uiImage, maxDataSize: MAX_IMAGE_SIZE, hasAlpha: hasAlpha) {
let fileName = generateNewFileName("IMG", ext)
return saveFile(imageDataResized, fileName)
}
return nil
}
func cropToSquare(_ image: UIImage) -> UIImage {
let size = image.size
let side = min(size.width, size.height)
let newSize = CGSize(width: side, height: side)
var origin = CGPoint.zero
if size.width > side {
origin.x -= (size.width - side) / 2
} else if size.height > side {
origin.y -= (size.height - side) / 2
}
return resizeImage(image, newBounds: CGRect(origin: .zero, size: newSize), drawIn: CGRect(origin: origin, size: size), hasAlpha: imageHasAlpha(image))
}
func resizeImageToDataSize(_ image: UIImage, maxDataSize: Int64, hasAlpha: Bool) -> Data? {
var img = image
var data = hasAlpha ? img.pngData() : img.jpegData(compressionQuality: 0.85)
var dataSize = data?.count ?? 0
while dataSize != 0 && dataSize > maxDataSize {
let ratio = sqrt(Double(dataSize) / Double(maxDataSize))
let clippedRatio = min(ratio, 2.0)
img = reduceSize(img, ratio: clippedRatio, hasAlpha: hasAlpha)
data = hasAlpha ? img.pngData() : img.jpegData(compressionQuality: 0.85)
dataSize = data?.count ?? 0
}
logger.debug("resizeImageToDataSize final \(dataSize)")
return data
}
func resizeImageToStrSize(_ image: UIImage, maxDataSize: Int64) -> String? {
var img = image
let hasAlpha = imageHasAlpha(image)
var str = compressImageStr(img, hasAlpha: hasAlpha)
var dataSize = str?.count ?? 0
while dataSize != 0 && dataSize > maxDataSize {
let ratio = sqrt(Double(dataSize) / Double(maxDataSize))
let clippedRatio = min(ratio, 2.0)
img = reduceSize(img, ratio: clippedRatio, hasAlpha: hasAlpha)
str = compressImageStr(img, hasAlpha: hasAlpha)
dataSize = str?.count ?? 0
}
logger.debug("resizeImageToStrSize final \(dataSize)")
return str
}
func compressImageStr(_ image: UIImage, _ compressionQuality: CGFloat = 0.85, hasAlpha: Bool) -> String? {
let ext = hasAlpha ? "png" : "jpg"
if let data = hasAlpha ? image.pngData() : image.jpegData(compressionQuality: compressionQuality) {
return "data:image/\(ext);base64,\(data.base64EncodedString())"
}
return nil
}
private func reduceSize(_ image: UIImage, ratio: CGFloat, hasAlpha: Bool) -> UIImage {
let newSize = CGSize(width: floor(image.size.width / ratio), height: floor(image.size.height / ratio))
let bounds = CGRect(origin: .zero, size: newSize)
return resizeImage(image, newBounds: bounds, drawIn: bounds, hasAlpha: hasAlpha)
}
private func resizeImage(_ image: UIImage, newBounds: CGRect, drawIn: CGRect, hasAlpha: Bool) -> UIImage {
let format = UIGraphicsImageRendererFormat()
format.scale = 1.0
format.opaque = !hasAlpha
return UIGraphicsImageRenderer(bounds: newBounds, format: format).image { _ in
image.draw(in: drawIn)
}
}
func imageHasAlpha(_ img: UIImage) -> Bool {
if let cgImage = img.cgImage {
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
if let context = CGContext(data: nil, width: cgImage.width, height: cgImage.height, bitsPerComponent: 8, bytesPerRow: cgImage.width * 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) {
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: cgImage.width, height: cgImage.height))
if let data = context.data {
let data = data.assumingMemoryBound(to: UInt8.self)
let size = cgImage.width * cgImage.height * 4
var i = 0
while i < size {
if data[i] < 255 { return true }
i += 4
}
}
}
}
return false
}
func saveFileFromURL(_ url: URL) -> String? {
let savedFile: String?
if url.startAccessingSecurityScopedResource() {
do {
let fileData = try Data(contentsOf: url)
let fileName = uniqueCombine(url.lastPathComponent)
savedFile = saveFile(fileData, fileName)
} catch {
logger.error("FileUtils.saveFileFromURL error: \(error.localizedDescription)")
savedFile = nil
}
} else {
logger.error("FileUtils.saveFileFromURL startAccessingSecurityScopedResource returned false")
savedFile = nil
}
url.stopAccessingSecurityScopedResource()
return savedFile
}
func saveFileFromURLWithoutLoad(_ url: URL) -> String? {
let savedFile: String?
do {
let fileName = uniqueCombine(url.lastPathComponent)
try FileManager.default.moveItem(at: url, to: getAppFilePath(fileName))
ChatModel.shared.filesToDelete.remove(url)
savedFile = fileName
} catch {
logger.error("FileUtils.saveFileFromURLWithoutLoad error: \(error.localizedDescription)")
savedFile = nil
}
return savedFile
}
func generateNewFileName(_ prefix: String, _ ext: String) -> String {
uniqueCombine("\(prefix)_\(getTimestamp()).\(ext)")
}
private func uniqueCombine(_ fileName: String) -> String {
func tryCombine(_ fileName: String, _ n: Int) -> String {
let ns = fileName as NSString
let name = ns.deletingPathExtension
let ext = ns.pathExtension
let suffix = (n == 0) ? "" : "_\(n)"
let f = "\(name)\(suffix).\(ext)"
return (FileManager.default.fileExists(atPath: getAppFilePath(f).path)) ? tryCombine(fileName, n + 1) : f
}
return tryCombine(fileName, 0)
}
private var tsFormatter: DateFormatter?
private func getTimestamp() -> String {
var df: DateFormatter
if let tsFormatter = tsFormatter {
df = tsFormatter
} else {
df = DateFormatter()
df.dateFormat = "yyyyMMdd_HHmmss"
df.locale = Locale(identifier: "US")
df.timeZone = TimeZone(secondsFromGMT: 0)
tsFormatter = df
}
return df.string(from: Date())
}
func dropImagePrefix(_ s: String) -> String {
dropPrefix(dropPrefix(s, "data:image/png;base64,"), "data:image/jpg;base64,")
}
private func dropPrefix(_ s: String, _ prefix: String) -> String {
s.hasPrefix(prefix) ? String(s.dropFirst(prefix.count)) : s
}
extension AVAsset {
func generatePreview() -> (UIImage, Int)? {
let generator = AVAssetImageGenerator(asset: self)
generator.appliesPreferredTrackTransform = true
var actualTime = CMTimeMake(value: 0, timescale: 0)
if let image = try? generator.copyCGImage(at: CMTimeMakeWithSeconds(0.0, preferredTimescale: 1), actualTime: &actualTime) {
return (UIImage(cgImage: image), Int(duration.seconds))
}
return nil
}
}
extension UIImage {
func replaceColor(_ from: UIColor, _ to: UIColor) -> UIImage {
if let cgImage = cgImage {
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
if let context = CGContext(data: nil, width: cgImage.width, height: cgImage.height, bitsPerComponent: 8, bytesPerRow: cgImage.width * 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) {
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: cgImage.width, height: cgImage.height))
if let data = context.data {
var fromAlpha: CGFloat = 0
var fromRed: CGFloat = 0
var fromGreen: CGFloat = 0
var fromBlue: CGFloat = 0
var toAlpha: CGFloat = 0
var toRed: CGFloat = 0
var toGreen: CGFloat = 0
var toBlue: CGFloat = 0
from.getRed(&fromRed, green: &fromGreen, blue: &fromBlue, alpha: &fromAlpha)
to.getRed(&toRed, green: &toGreen, blue: &toBlue, alpha: &toAlpha)
let fAlpha = UInt8(UInt8(fromAlpha * 255))
let fRed = UInt8(fromRed * 255)
let fGreen = UInt8(fromGreen * 255)
let fBlue = UInt8(fromBlue * 255)
let tAlpha = UInt8(toAlpha * 255)
let tRed = UInt8(toRed * 255)
let tGreen = UInt8(toGreen * 255)
let tBlue = UInt8(toBlue * 255)
let data = data.assumingMemoryBound(to: UInt8.self)
let size = cgImage.width * cgImage.height * 4
var i = 0
while i < size {
if data[i] == fAlpha && data[i + 1] == fRed && data[i + 2] == fGreen && data[i + 3] == fBlue {
data[i + 0] = tAlpha
data[i + 1] = tRed
data[i + 2] = tGreen
data[i + 3] = tBlue
}
i += 4
}
}
if let img = context.makeImage() {
return UIImage(cgImage: img)
}
}
}
return self
}
}
+83
View File
@@ -0,0 +1,83 @@
//
// NSESubscriber.swift
// SimpleXChat
//
// Created by Evgeny on 09/12/2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import Foundation
import SimpleXChat
private var nseSubscribers: [UUID:NSESubscriber] = [:]
// timeout for active notification service extension going into "suspending" state.
// If in two seconds the state does not change, we assume that it was not running and proceed with app activation/answering call.
private let SUSPENDING_TIMEOUT: TimeInterval = 2
// timeout should be larger than SUSPENDING_TIMEOUT
func waitNSESuspended(timeout: TimeInterval, suspended: @escaping (Bool) -> Void) {
if timeout <= SUSPENDING_TIMEOUT {
logger.warning("waitNSESuspended: small timeout \(timeout), using \(SUSPENDING_TIMEOUT + 1)")
}
var state = nseStateGroupDefault.get()
if case .suspended = state {
DispatchQueue.main.async { suspended(true) }
return
}
let id = UUID()
var suspendedCalled = false
checkTimeout()
nseSubscribers[id] = nseMessageSubscriber { msg in
if case let .state(newState) = msg {
state = newState
logger.debug("waitNSESuspended state: \(state.rawValue)")
if case .suspended = newState {
notifySuspended(true)
}
}
}
return
func notifySuspended(_ ok: Bool) {
logger.debug("waitNSESuspended notifySuspended: \(ok)")
if !suspendedCalled {
logger.debug("waitNSESuspended notifySuspended: calling suspended(\(ok))")
suspendedCalled = true
nseSubscribers.removeValue(forKey: id)
DispatchQueue.main.async { suspended(ok) }
}
}
func checkTimeout() {
if !suspending() {
checkSuspendingTimeout()
} else if state == .suspending {
checkSuspendedTimeout()
}
}
func suspending() -> Bool {
suspendedCalled || state == .suspended || state == .suspending
}
func checkSuspendingTimeout() {
DispatchQueue.global().asyncAfter(deadline: .now() + SUSPENDING_TIMEOUT) {
logger.debug("waitNSESuspended check suspending timeout")
if !suspending() {
notifySuspended(false)
} else if state != .suspended {
checkSuspendedTimeout()
}
}
}
func checkSuspendedTimeout() {
DispatchQueue.global().asyncAfter(deadline: .now() + min(timeout - SUSPENDING_TIMEOUT, 1)) {
logger.debug("waitNSESuspended check suspended timeout")
if state != .suspended {
notifySuspended(false)
}
}
}
}
@@ -0,0 +1,73 @@
//
// NetworkObserver.swift
// SimpleX (iOS)
//
// Created by Avently on 05.04.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import Foundation
import Network
import SimpleXChat
class NetworkObserver {
static let shared = NetworkObserver()
private let queue: DispatchQueue = DispatchQueue(label: "chat.simplex.app.NetworkObserver")
private var prevInfo: UserNetworkInfo? = nil
private var monitor: NWPathMonitor?
private let monitorLock: DispatchQueue = DispatchQueue(label: "chat.simplex.app.monitorLock")
func restartMonitor() {
monitorLock.sync {
monitor?.cancel()
let mon = NWPathMonitor()
mon.pathUpdateHandler = { [weak self] path in
self?.networkPathChanged(path: path)
}
mon.start(queue: queue)
monitor = mon
}
}
private func networkPathChanged(path: NWPath) {
let info = UserNetworkInfo(
networkType: networkTypeFromPath(path),
online: path.status == .satisfied
)
if (prevInfo != info) {
prevInfo = info
setNetworkInfo(info)
}
}
private func networkTypeFromPath(_ path: NWPath) -> UserNetworkType {
if path.usesInterfaceType(.wiredEthernet) {
.ethernet
} else if path.usesInterfaceType(.wifi) {
.wifi
} else if path.usesInterfaceType(.cellular) {
.cellular
} else if path.usesInterfaceType(.other) {
.other
} else {
.none
}
}
private static var networkObserver: NetworkObserver? = nil
private func setNetworkInfo(_ info: UserNetworkInfo) {
logger.debug("setNetworkInfo Network changed: \(String(describing: info))")
DispatchQueue.main.sync {
ChatModel.shared.networkInfo = info
}
if !hasChatCtrl() { return }
self.monitorLock.sync {
do {
try apiSetNetworkInfo(info)
} catch let err {
logger.error("setNetworkInfo error: \(responseError(err))")
}
}
}
}
+24 -18
View File
@@ -12,6 +12,7 @@ import UIKit
import SimpleXChat
let ntfActionAcceptContact = "NTF_ACT_ACCEPT_CONTACT"
let ntfActionAcceptContactIncognito = "NTF_ACT_ACCEPT_CONTACT_INCOGNITO"
let ntfActionAcceptCall = "NTF_ACT_ACCEPT_CALL"
let ntfActionRejectCall = "NTF_ACT_REJECT_CALL"
@@ -41,12 +42,13 @@ class NtfManager: NSObject, UNUserNotificationCenterDelegate, ObservableObject {
userId != chatModel.currentUser?.userId {
changeActiveUser(userId, viewPwd: nil)
}
if content.categoryIdentifier == ntfCategoryContactRequest && action == ntfActionAcceptContact,
if content.categoryIdentifier == ntfCategoryContactRequest && (action == ntfActionAcceptContact || action == ntfActionAcceptContactIncognito),
let chatId = content.userInfo["chatId"] as? String {
let incognito = action == ntfActionAcceptContactIncognito
if case let .contactRequest(contactRequest) = chatModel.getChat(chatId)?.chatInfo {
Task { await acceptContactRequest(contactRequest) }
Task { await acceptContactRequest(incognito: incognito, contactRequest: contactRequest) }
} else {
chatModel.ntfContactRequest = chatId
chatModel.ntfContactRequest = NTFContactRequest(incognito: incognito, chatId: chatId)
}
} else if let (chatId, ntfAction) = ntfCallAction(content, action) {
if let invitation = chatModel.callInvitations.removeValue(forKey: chatId) {
@@ -55,7 +57,9 @@ class NtfManager: NSObject, UNUserNotificationCenterDelegate, ObservableObject {
chatModel.ntfCallInvitationAction = (chatId, ntfAction)
}
} else {
chatModel.chatId = content.targetContentIdentifier
if let chatId = content.targetContentIdentifier {
ItemsModel.shared.loadOpenChat(chatId)
}
}
handler()
}
@@ -134,11 +138,17 @@ class NtfManager: NSObject, UNUserNotificationCenterDelegate, ObservableObject {
UNUserNotificationCenter.current().setNotificationCategories([
UNNotificationCategory(
identifier: ntfCategoryContactRequest,
actions: [UNNotificationAction(
identifier: ntfActionAcceptContact,
title: NSLocalizedString("Accept", comment: "accept contact request via notification"),
options: .foreground
)],
actions: [
UNNotificationAction(
identifier: ntfActionAcceptContact,
title: NSLocalizedString("Accept", comment: "accept contact request via notification"),
options: .foreground
), UNNotificationAction(
identifier: ntfActionAcceptContactIncognito,
title: NSLocalizedString("Accept incognito", comment: "accept contact request via notification"),
options: .foreground
)
],
intentIdentifiers: [],
hiddenPreviewsBodyPlaceholder: NSLocalizedString("New contact request", comment: "notification")
),
@@ -203,17 +213,17 @@ class NtfManager: NSObject, UNUserNotificationCenterDelegate, ObservableObject {
center.delegate = self
}
func notifyContactRequest(_ user: User, _ contactRequest: UserContactRequest) {
func notifyContactRequest(_ user: any UserLike, _ contactRequest: UserContactRequest) {
logger.debug("NtfManager.notifyContactRequest")
addNotification(createContactRequestNtf(user, contactRequest))
}
func notifyContactConnected(_ user: User, _ contact: Contact) {
func notifyContactConnected(_ user: any UserLike, _ contact: Contact) {
logger.debug("NtfManager.notifyContactConnected")
addNotification(createContactConnectedNtf(user, contact))
}
func notifyMessageReceived(_ user: User, _ cInfo: ChatInfo, _ cItem: ChatItem) {
func notifyMessageReceived(_ user: any UserLike, _ cInfo: ChatInfo, _ cItem: ChatItem) {
logger.debug("NtfManager.notifyMessageReceived")
if cInfo.ntfsEnabled {
addNotification(createMessageReceivedNtf(user, cInfo, cItem))
@@ -230,12 +240,8 @@ class NtfManager: NSObject, UNUserNotificationCenterDelegate, ObservableObject {
ntfBadgeCountGroupDefault.set(count)
}
func decNtfBadgeCount(by count: Int = 1) {
setNtfBadgeCount(max(0, UIApplication.shared.applicationIconBadgeNumber - count))
}
func incNtfBadgeCount(by count: Int = 1) {
setNtfBadgeCount(UIApplication.shared.applicationIconBadgeNumber + count)
func changeNtfBadgeCount(by count: Int = 1) {
setNtfBadgeCount(max(0, UIApplication.shared.applicationIconBadgeNumber + count))
}
private func addNotification(_ content: UNMutableNotificationContent) {
File diff suppressed because it is too large Load Diff
+112 -19
View File
@@ -9,51 +9,75 @@
import Foundation
import UIKit
import SimpleXChat
import SwiftUI
private let suspendLockQueue = DispatchQueue(label: "chat.simplex.app.suspend.lock")
let appSuspendTimeout: Int = 15 // seconds
let bgSuspendTimeout: Int = 5 // seconds
let terminationTimeout: Int = 3 // seconds
let activationDelay: TimeInterval = 1.5
let nseSuspendTimeout: TimeInterval = 5
private func _suspendChat(timeout: Int) {
if ChatModel.ok {
appStateGroupDefault.set(.suspending)
// this is a redundant check to prevent logical errors, like the one fixed in this PR
let state = AppChatState.shared.value
if !state.canSuspend {
logger.error("_suspendChat called, current state: \(state.rawValue)")
} else if ChatModel.ok {
AppChatState.shared.set(.suspending)
apiSuspendChat(timeoutMicroseconds: timeout * 1000000)
let endTask = beginBGTask(chatSuspended)
DispatchQueue.global().asyncAfter(deadline: .now() + Double(timeout) + 1, execute: endTask)
} else {
appStateGroupDefault.set(.suspended)
AppChatState.shared.set(.suspended)
}
}
let seSubscriber = seMessageSubscriber {
switch $0 {
case let .state(state):
switch state {
case .inactive:
if AppChatState.shared.value.inactive { activateChat() }
case .sendingMessage:
if AppChatState.shared.value.canSuspend { suspendChat() }
}
}
}
func suspendChat() {
suspendLockQueue.sync {
if appStateGroupDefault.get() != .stopped {
_suspendChat(timeout: appSuspendTimeout)
}
_suspendChat(timeout: appSuspendTimeout)
}
}
func suspendBgRefresh() {
suspendLockQueue.sync {
if case .bgRefresh = appStateGroupDefault.get() {
if case .bgRefresh = AppChatState.shared.value {
_suspendChat(timeout: bgSuspendTimeout)
}
}
}
func terminateChat() {
logger.debug("terminateChat")
suspendLockQueue.sync {
switch appStateGroupDefault.get() {
switch AppChatState.shared.value {
case .suspending:
// suspend instantly if already suspending
_chatSuspended()
// when apiSuspendChat is called with timeout 0, it won't send any events on suspension
if ChatModel.ok { apiSuspendChat(timeoutMicroseconds: 0) }
case .stopped: ()
chatCloseStore()
case .suspended:
chatCloseStore()
case .stopped:
chatCloseStore()
default:
// the store will be closed in _chatSuspended when event is received
_suspendChat(timeout: terminationTimeout)
}
}
@@ -61,7 +85,7 @@ func terminateChat() {
func chatSuspended() {
suspendLockQueue.sync {
if case .suspending = appStateGroupDefault.get() {
if case .suspending = AppChatState.shared.value {
_chatSuspended()
}
}
@@ -69,16 +93,23 @@ func chatSuspended() {
private func _chatSuspended() {
logger.debug("_chatSuspended")
appStateGroupDefault.set(.suspended)
AppChatState.shared.set(.suspended)
if ChatModel.shared.chatRunning == true {
ChatReceiver.shared.stop()
}
chatCloseStore()
}
func setAppState(_ appState: AppState) {
suspendLockQueue.sync {
AppChatState.shared.set(appState)
}
}
func activateChat(appState: AppState = .active) {
logger.debug("DEBUGGING: activateChat")
suspendLockQueue.sync {
appStateGroupDefault.set(appState)
AppChatState.shared.set(appState)
if ChatModel.ok { apiActivateChat() }
logger.debug("DEBUGGING: activateChat: after apiActivateChat")
}
@@ -87,24 +118,86 @@ func activateChat(appState: AppState = .active) {
func initChatAndMigrate(refreshInvitations: Bool = true) {
let m = ChatModel.shared
if (!m.chatInitialized) {
m.v3DBMigration = v3DBMigrationDefault.get()
if AppChatState.shared.value == .stopped && storeDBPassphraseGroupDefault.get() && kcDatabasePassword.get() != nil {
initialize(start: true, confirmStart: true)
} else {
initialize(start: true)
}
}
func initialize(start: Bool, confirmStart: Bool = false) {
do {
m.v3DBMigration = v3DBMigrationDefault.get()
try initializeChat(start: m.v3DBMigration.startChat, refreshInvitations: refreshInvitations)
try initializeChat(start: m.v3DBMigration.startChat && start, confirmStart: m.v3DBMigration.startChat && confirmStart, refreshInvitations: refreshInvitations)
} catch let error {
fatalError("Failed to start or load chats: \(responseError(error))")
AlertManager.shared.showAlertMsg(
title: start ? "Error starting chat" : "Error opening chat",
message: "Please contact developers.\nError: \(responseError(error))"
)
}
}
}
func startChatAndActivate() {
func startChatForCall() {
logger.debug("DEBUGGING: startChatForCall")
if ChatModel.shared.chatRunning == true {
ChatReceiver.shared.start()
logger.debug("DEBUGGING: startChatForCall: after ChatReceiver.shared.start")
}
if .active != AppChatState.shared.value {
logger.debug("DEBUGGING: startChatForCall: before activateChat")
activateChat()
logger.debug("DEBUGGING: startChatForCall: after activateChat")
}
}
func startChatAndActivate(_ completion: @escaping () -> Void) {
logger.debug("DEBUGGING: startChatAndActivate")
if ChatModel.shared.chatRunning == true {
ChatReceiver.shared.start()
logger.debug("DEBUGGING: startChatAndActivate: after ChatReceiver.shared.start")
}
if .active != appStateGroupDefault.get() {
if case .active = AppChatState.shared.value {
completion()
} else if nseStateGroupDefault.get().inactive {
activate()
} else {
// setting app state to "activating" to notify NSE that it should suspend
setAppState(.activating)
waitNSESuspended(timeout: nseSuspendTimeout) { ok in
if !ok {
// if for some reason NSE failed to suspend,
// e.g., it crashed previously without setting its state to "suspended",
// set it to "suspended" state anyway, so that next time app
// does not have to wait when activating.
nseStateGroupDefault.set(.suspended)
}
if AppChatState.shared.value == .activating {
activate()
}
}
}
func activate() {
logger.debug("DEBUGGING: startChatAndActivate: before activateChat")
activateChat()
completion()
logger.debug("DEBUGGING: startChatAndActivate: after activateChat")
}
}
// appStateGroupDefault must not be used in the app directly, only via this singleton
class AppChatState {
static let shared = AppChatState()
private var value_ = appStateGroupDefault.get()
var value: AppState {
value_
}
func set(_ state: AppState) {
appStateGroupDefault.set(state)
sendAppState(state)
value_ = state
}
}
+48 -49
View File
@@ -16,17 +16,15 @@ struct SimpleXApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject private var chatModel = ChatModel.shared
@ObservedObject var alertManager = AlertManager.shared
@Environment(\.scenePhase) var scenePhase
@AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false
@State private var userAuthorized: Bool?
@State private var doAuthenticate = false
@State private var enteredBackground: TimeInterval? = nil
@State private var canConnectCall = false
@State private var lastSuccessfulUnlock: TimeInterval? = nil
@State private var showInitializationView = false
@State private var enteredBackgroundAuthenticated: TimeInterval? = nil
init() {
hs_init(0, nil)
DispatchQueue.global(qos: .background).sync {
haskell_init()
// hs_init(0, nil)
}
UserDefaults.standard.register(defaults: appDefaults)
setGroupDefaults()
registerGroupDefaults()
@@ -36,53 +34,62 @@ struct SimpleXApp: App {
}
var body: some Scene {
return WindowGroup {
ContentView(
doAuthenticate: $doAuthenticate,
userAuthorized: $userAuthorized,
canConnectCall: $canConnectCall,
lastSuccessfulUnlock: $lastSuccessfulUnlock,
showInitializationView: $showInitializationView
)
WindowGroup {
// contentAccessAuthenticationExtended has to be passed to ContentView on view initialization,
// so that it's computed by the time view renders, and not on event after rendering
ContentView(contentAccessAuthenticationExtended: !authenticationExpired())
.environmentObject(chatModel)
.environmentObject(AppTheme.shared)
.onOpenURL { url in
logger.debug("ContentView.onOpenURL: \(url)")
chatModel.appOpenUrl = url
}
.onAppear() {
showInitializationView = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
initChatAndMigrate()
// Present screen for continue migration if it wasn't finished yet
if chatModel.migrationState != nil {
// It's important, otherwise, user may be locked in undefined state
onboardingStageDefault.set(.step1_SimpleXInfo)
chatModel.onboardingStage = onboardingStageDefault.get()
} else if kcAppPassword.get() == nil || kcSelfDestructPassword.get() == nil {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
initChatAndMigrate()
}
}
}
.onChange(of: scenePhase) { phase in
logger.debug("scenePhase was \(String(describing: scenePhase)), now \(String(describing: phase))")
AppSheetState.shared.scenePhaseActive = phase == .active
switch (phase) {
case .background:
// --- authentication
// see ContentView .onChange(of: scenePhase) for remaining authentication logic
if chatModel.contentViewAccessAuthenticated {
enteredBackgroundAuthenticated = ProcessInfo.processInfo.systemUptime
}
chatModel.contentViewAccessAuthenticated = false
// authentication ---
if CallController.useCallKit() && chatModel.activeCall != nil {
CallController.shared.shouldSuspendChat = true
} else {
suspendChat()
BGManager.shared.schedule()
}
if userAuthorized == true {
enteredBackground = ProcessInfo.processInfo.systemUptime
}
doAuthenticate = false
canConnectCall = false
NtfManager.shared.setNtfBadgeCount(chatModel.totalUnreadCountForAllUsers())
case .active:
CallController.shared.shouldSuspendChat = false
let appState = appStateGroupDefault.get()
startChatAndActivate()
if appState.inactive && chatModel.chatRunning == true {
updateChats()
if !chatModel.showCallView && !CallController.shared.hasActiveCalls() {
updateCallInvitations()
let appState = AppChatState.shared.value
if appState != .stopped {
startChatAndActivate {
if appState.inactive && chatModel.chatRunning == true {
updateChats()
if !chatModel.showCallView && !CallController.shared.hasActiveCalls() {
updateCallInvitations()
}
}
}
}
doAuthenticate = authenticationExpired()
canConnectCall = !(doAuthenticate && prefPerformLA) || unlockedRecently()
default:
break
}
@@ -100,12 +107,12 @@ struct SimpleXApp: App {
if legacyDatabase, case .documents = dbContainerGroupDefault.get() {
dbContainerGroupDefault.set(.documents)
setMigrationState(.offer)
logger.debug("SimpleXApp init: using legacy DB in documents folder: \(getAppDatabasePath(), privacy: .public)*.db")
logger.debug("SimpleXApp init: using legacy DB in documents folder: \(getAppDatabasePath())*.db")
} else {
dbContainerGroupDefault.set(.group)
setMigrationState(.ready)
logger.debug("SimpleXApp init: using DB in app group container: \(getAppDatabasePath(), privacy: .public)*.db")
logger.debug("SimpleXApp init: legacy DB\(legacyDatabase ? "" : " not", privacy: .public) present")
logger.debug("SimpleXApp init: using DB in app group container: \(getAppDatabasePath())*.db")
logger.debug("SimpleXApp init: legacy DB\(legacyDatabase ? "" : " not") present")
}
}
@@ -115,34 +122,26 @@ struct SimpleXApp: App {
}
private func authenticationExpired() -> Bool {
if let enteredBackground = enteredBackground {
if let enteredBackgroundAuthenticated = enteredBackgroundAuthenticated {
let delay = Double(UserDefaults.standard.integer(forKey: DEFAULT_LA_LOCK_DELAY))
return ProcessInfo.processInfo.systemUptime - enteredBackground >= delay
return ProcessInfo.processInfo.systemUptime - enteredBackgroundAuthenticated >= delay
} else {
return true
}
}
private func unlockedRecently() -> Bool {
if let lastSuccessfulUnlock = lastSuccessfulUnlock {
return ProcessInfo.processInfo.systemUptime - lastSuccessfulUnlock < 2
} else {
return false
}
}
private func updateChats() {
do {
let chats = try apiGetChats()
chatModel.updateChats(with: chats)
if let id = chatModel.chatId,
let chat = chatModel.getChat(id) {
loadChat(chat: chat)
Task { await loadChat(chat: chat, clearItems: false) }
}
if let chatId = chatModel.ntfContactRequest {
if let ncr = chatModel.ntfContactRequest {
chatModel.ntfContactRequest = nil
if case let .contactRequest(contactRequest) = chatModel.getChat(chatId)?.chatInfo {
Task { await acceptContactRequest(contactRequest) }
if case let .contactRequest(contactRequest) = chatModel.getChat(ncr.chatId)?.chatInfo {
Task { await acceptContactRequest(incognito: ncr.incognito, contactRequest: contactRequest) }
}
}
} catch let error {
+199
View File
@@ -0,0 +1,199 @@
//
// Theme.swift
// SimpleX (iOS)
//
// Created by Avently on 14.06.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import Foundation
import SwiftUI
import SimpleXChat
var CurrentColors: ThemeManager.ActiveTheme = ThemeManager.currentColors(nil, nil, ChatModel.shared.currentUser?.uiThemes, themeOverridesDefault.get())
var MenuTextColor: Color { if isInDarkTheme() { AppTheme.shared.colors.onBackground.opacity(0.8) } else { Color.black } }
var NoteFolderIconColor: Color { AppTheme.shared.appColors.primaryVariant2 }
func isInDarkTheme() -> Bool { !CurrentColors.colors.isLight }
class AppTheme: ObservableObject, Equatable {
static let shared = AppTheme(name: CurrentColors.name, base: CurrentColors.base, colors: CurrentColors.colors, appColors: CurrentColors.appColors, wallpaper: CurrentColors.wallpaper)
var name: String
var base: DefaultTheme
@ObservedObject var colors: Colors
@ObservedObject var appColors: AppColors
@ObservedObject var wallpaper: AppWallpaper
init(name: String, base: DefaultTheme, colors: Colors, appColors: AppColors, wallpaper: AppWallpaper) {
self.name = name
self.base = base
self.colors = colors
self.appColors = appColors
self.wallpaper = wallpaper
}
static func == (lhs: AppTheme, rhs: AppTheme) -> Bool {
lhs.name == rhs.name &&
lhs.colors == rhs.colors &&
lhs.appColors == rhs.appColors &&
lhs.wallpaper == rhs.wallpaper
}
func updateFromCurrentColors() {
objectWillChange.send()
name = CurrentColors.name
base = CurrentColors.base
colors.updateColorsFrom(CurrentColors.colors)
appColors.updateColorsFrom(CurrentColors.appColors)
wallpaper.updateWallpaperFrom(CurrentColors.wallpaper)
}
}
struct ThemedBackground: ViewModifier {
@EnvironmentObject var theme: AppTheme
var grouped: Bool = false
func body(content: Content) -> some View {
content
.background(
theme.base == DefaultTheme.SIMPLEX
? LinearGradient(
colors: [
grouped
? theme.colors.background.lighter(0.4).asGroupedBackground(theme.base.mode)
: theme.colors.background.lighter(0.4),
grouped
? theme.colors.background.darker(0.4).asGroupedBackground(theme.base.mode)
: theme.colors.background.darker(0.4)
],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
: LinearGradient(
colors: [],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.background(
theme.base == DefaultTheme.SIMPLEX
? Color.clear
: grouped
? theme.colors.background.asGroupedBackground(theme.base.mode)
: theme.colors.background
)
}
}
var systemInDarkThemeCurrently: Bool {
return UITraitCollection.current.userInterfaceStyle == .dark
}
func reactOnDarkThemeChanges() {
if currentThemeDefault.get() == DefaultTheme.SYSTEM_THEME_NAME && CurrentColors.colors.isLight == systemInDarkThemeCurrently {
// Change active colors from light to dark and back based on system theme
ThemeManager.applyTheme(DefaultTheme.SYSTEM_THEME_NAME)
}
}
extension ThemeWallpaper {
public func importFromString() -> ThemeWallpaper {
if preset == nil, let image {
// Need to save image from string and to save its path
if let parsed = UIImage(base64Encoded: image),
let filename = saveWallpaperFile(image: parsed) {
var copy = self
copy.image = nil
copy.imageFile = filename
return copy
} else {
return ThemeWallpaper()
}
} else {
return self
}
}
func withFilledWallpaperBase64() -> ThemeWallpaper {
let aw = toAppWallpaper()
let type = aw.type
let preset: String? = if case let WallpaperType.preset(filename, _) = type { filename } else { nil }
let scale: Float? = if case let WallpaperType.preset(_, scale) = type { scale } else { if case let WallpaperType.image(_, scale, _) = type { scale } else { 1.0 } }
let scaleType: WallpaperScaleType? = if case let WallpaperType.image(_, _, scaleType) = type { scaleType } else { nil }
let image: String? = if case WallpaperType.image = type, let image = type.uiImage { resizeImageToStrSize(image, maxDataSize: 5_000_000) } else { nil }
return ThemeWallpaper (
preset: preset,
scale: scale,
scaleType: scaleType,
background: aw.background?.toReadableHex(),
tint: aw.tint?.toReadableHex(),
image: image,
imageFile: nil
)
}
}
extension ThemeModeOverride {
func removeSameColors(_ base: DefaultTheme, colorsToCompare tc: ThemeColors) -> ThemeModeOverride {
let wallpaperType = WallpaperType.from(wallpaper) ?? WallpaperType.empty
let w: ThemeWallpaper
switch wallpaperType {
case let WallpaperType.preset(filename, scale):
let p = PresetWallpaper.from(filename)
w = ThemeWallpaper(
preset: filename,
scale: scale ?? wallpaper?.scale,
scaleType: nil,
background: p?.background[base]?.toReadableHex(),
tint: p?.tint[base]?.toReadableHex(),
image: nil,
imageFile: nil
)
case WallpaperType.image:
w = ThemeWallpaper(
preset: nil,
scale: nil,
scaleType: WallpaperScaleType.fill,
background: Color.clear.toReadableHex(),
tint: Color.clear.toReadableHex(),
image: nil,
imageFile: nil
)
default:
w = ThemeWallpaper()
}
let wallpaper: ThemeWallpaper? = if let wallpaper {
ThemeWallpaper(
preset: wallpaper.preset,
scale: wallpaper.scale != w.scale ? wallpaper.scale : nil,
scaleType: wallpaper.scaleType != w.scaleType ? wallpaper.scaleType : nil,
background: wallpaper.background != w.background ? wallpaper.background : nil,
tint: wallpaper.tint != w.tint ? wallpaper.tint : nil,
image: wallpaper.image,
imageFile: wallpaper.imageFile
)
} else {
nil
}
return ThemeModeOverride(
mode: self.mode,
colors: ThemeColors(
primary: colors.primary != tc.primary ? colors.primary : nil,
primaryVariant: colors.primaryVariant != tc.primaryVariant ? colors.primaryVariant : nil,
secondary: colors.secondary != tc.secondary ? colors.secondary : nil,
secondaryVariant: colors.secondaryVariant != tc.secondaryVariant ? colors.secondaryVariant : nil,
background: colors.background != tc.background ? colors.background : nil,
surface: colors.surface != tc.surface ? colors.surface : nil,
title: colors.title != tc.title ? colors.title : nil,
primaryVariant2: colors.primaryVariant2 != tc.primaryVariant2 ? colors.primary : nil,
sentMessage: colors.sentMessage != tc.sentMessage ? colors.sentMessage : nil,
sentQuote: colors.sentQuote != tc.sentQuote ? colors.sentQuote : nil,
receivedMessage: colors.receivedMessage != tc.receivedMessage ? colors.receivedMessage : nil,
receivedQuote: colors.receivedQuote != tc.receivedQuote ? colors.receivedQuote : nil
),
wallpaper: wallpaper
)
}
}
+303
View File
@@ -0,0 +1,303 @@
//
// ThemeManager.swift
// SimpleX (iOS)
//
// Created by Avently on 03.06.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import Foundation
import SwiftUI
import SimpleXChat
class ThemeManager {
struct ActiveTheme: Equatable {
let name: String
let base: DefaultTheme
let colors: Colors
let appColors: AppColors
var wallpaper: AppWallpaper = AppWallpaper(background: nil, tint: nil, type: .empty)
func toAppTheme() -> AppTheme {
AppTheme(name: name, base: base, colors: colors, appColors: appColors, wallpaper: wallpaper)
}
}
private static func systemDarkThemeColors() -> (Colors, DefaultTheme) {
switch systemDarkThemeDefault.get() {
case DefaultTheme.DARK.themeName: (DarkColorPalette, DefaultTheme.DARK)
case DefaultTheme.SIMPLEX.themeName: (SimplexColorPalette, DefaultTheme.SIMPLEX)
case DefaultTheme.BLACK.themeName: (BlackColorPalette, DefaultTheme.BLACK)
default: (SimplexColorPalette, DefaultTheme.SIMPLEX)
}
}
private static func nonSystemThemeName() -> String {
let themeName = currentThemeDefault.get()
return if themeName != DefaultTheme.SYSTEM_THEME_NAME {
themeName
} else {
systemInDarkThemeCurrently ? systemDarkThemeDefault.get() : DefaultTheme.LIGHT.themeName
}
}
static func defaultActiveTheme(_ appSettingsTheme: [ThemeOverrides]) -> ThemeOverrides? {
let nonSystemThemeName = nonSystemThemeName()
let defaultThemeId = currentThemeIdsDefault.get()[nonSystemThemeName]
return appSettingsTheme.getTheme(defaultThemeId)
}
static func defaultActiveTheme(_ perUserTheme: ThemeModeOverrides?, _ appSettingsTheme: [ThemeOverrides]) -> ThemeModeOverride {
let perUserTheme = !CurrentColors.colors.isLight ? perUserTheme?.dark : perUserTheme?.light
if let perUserTheme {
return perUserTheme
}
let defaultTheme = defaultActiveTheme(appSettingsTheme)
return ThemeModeOverride(mode: CurrentColors.base.mode, colors: defaultTheme?.colors ?? ThemeColors(), wallpaper: defaultTheme?.wallpaper)
}
static func currentColors(_ themeOverridesForType: WallpaperType?, _ perChatTheme: ThemeModeOverride?, _ perUserTheme: ThemeModeOverrides?, _ appSettingsTheme: [ThemeOverrides]) -> ActiveTheme {
let themeName = currentThemeDefault.get()
let nonSystemThemeName = nonSystemThemeName()
let defaultTheme = defaultActiveTheme(appSettingsTheme)
let baseTheme = switch nonSystemThemeName {
case DefaultTheme.LIGHT.themeName: ActiveTheme(name: DefaultTheme.LIGHT.themeName, base: DefaultTheme.LIGHT, colors: LightColorPalette.clone(), appColors: LightColorPaletteApp.clone(), wallpaper: AppWallpaper(background: nil, tint: nil, type: PresetWallpaper.school.toType(DefaultTheme.LIGHT)))
case DefaultTheme.DARK.themeName: ActiveTheme(name: DefaultTheme.DARK.themeName, base: DefaultTheme.DARK, colors: DarkColorPalette.clone(), appColors: DarkColorPaletteApp.clone(), wallpaper: AppWallpaper(background: nil, tint: nil, type: PresetWallpaper.school.toType(DefaultTheme.DARK)))
case DefaultTheme.SIMPLEX.themeName: ActiveTheme(name: DefaultTheme.SIMPLEX.themeName, base: DefaultTheme.SIMPLEX, colors: SimplexColorPalette.clone(), appColors: SimplexColorPaletteApp.clone(), wallpaper: AppWallpaper(background: nil, tint: nil, type: PresetWallpaper.school.toType(DefaultTheme.SIMPLEX)))
case DefaultTheme.BLACK.themeName: ActiveTheme(name: DefaultTheme.BLACK.themeName, base: DefaultTheme.BLACK, colors: BlackColorPalette.clone(), appColors: BlackColorPaletteApp.clone(), wallpaper: AppWallpaper(background: nil, tint: nil, type: PresetWallpaper.school.toType(DefaultTheme.BLACK)))
default: ActiveTheme(name: DefaultTheme.LIGHT.themeName, base: DefaultTheme.LIGHT, colors: LightColorPalette.clone(), appColors: LightColorPaletteApp.clone(), wallpaper: AppWallpaper(background: nil, tint: nil, type: PresetWallpaper.school.toType(DefaultTheme.LIGHT)))
}
let perUserTheme = baseTheme.colors.isLight ? perUserTheme?.light : perUserTheme?.dark
let theme = appSettingsTheme.sameTheme(themeOverridesForType ?? perChatTheme?.type ?? perUserTheme?.type ?? defaultTheme?.wallpaper?.toAppWallpaper().type, nonSystemThemeName) ?? defaultTheme
if theme == nil && perUserTheme == nil && perChatTheme == nil && themeOverridesForType == nil {
return ActiveTheme(name: themeName, base: baseTheme.base, colors: baseTheme.colors, appColors: baseTheme.appColors, wallpaper: baseTheme.wallpaper)
}
let presetWallpaperTheme: ThemeColors? = if let themeOverridesForType, case let WallpaperType.preset(filename, _) = themeOverridesForType {
PresetWallpaper.from(filename)?.colors[baseTheme.base]
} else if let wallpaper = perChatTheme?.wallpaper {
if let preset = wallpaper.preset { PresetWallpaper.from(preset)?.colors[baseTheme.base] } else { nil }
} else if let wallpaper = perUserTheme?.wallpaper {
if let preset = wallpaper.preset { PresetWallpaper.from(preset)?.colors[baseTheme.base] } else { nil }
} else {
if let preset = theme?.wallpaper?.preset { PresetWallpaper.from(preset)?.colors[baseTheme.base] } else { nil }
}
let themeOrEmpty = theme ?? ThemeOverrides(base: baseTheme.base)
let colors = themeOrEmpty.toColors(themeOrEmpty.base, perChatTheme?.colors, perUserTheme?.colors, presetWallpaperTheme)
return ActiveTheme(
name: themeName,
base: baseTheme.base,
colors: colors,
appColors: themeOrEmpty.toAppColors(themeOrEmpty.base, perChatTheme?.colors, perChatTheme?.type, perUserTheme?.colors, perUserTheme?.type, presetWallpaperTheme),
wallpaper: themeOrEmpty.toAppWallpaper(themeOverridesForType, perChatTheme, perUserTheme, colors.background)
)
}
static func currentThemeOverridesForExport(_ themeOverridesForType: WallpaperType?, _ perChatTheme: ThemeModeOverride?, _ perUserTheme: ThemeModeOverrides?) -> ThemeOverrides {
let current = currentColors(themeOverridesForType, perChatTheme, perUserTheme, themeOverridesDefault.get())
let wType = current.wallpaper.type
let wBackground = current.wallpaper.background
let wTint = current.wallpaper.tint
let w: ThemeWallpaper? = if case WallpaperType.empty = wType {
nil
} else {
ThemeWallpaper.from(wType, wBackground?.toReadableHex(), wTint?.toReadableHex()).withFilledWallpaperBase64()
}
return ThemeOverrides(
themeId: "",
base: current.base,
colors: ThemeColors.from(current.colors, current.appColors),
wallpaper: w
)
}
static func applyTheme(_ theme: String) {
currentThemeDefault.set(theme)
CurrentColors = currentColors(nil, nil, ChatModel.shared.currentUser?.uiThemes, themeOverridesDefault.get())
AppTheme.shared.updateFromCurrentColors()
let tint = UIColor(CurrentColors.colors.primary)
if SceneDelegate.windowStatic?.tintColor != tint {
SceneDelegate.windowStatic?.tintColor = tint
}
// applyNavigationBarColors(CurrentColors.toAppTheme())
}
static func adjustWindowStyle() {
let style = switch currentThemeDefault.get() {
case DefaultTheme.LIGHT.themeName: UIUserInterfaceStyle.light
case DefaultTheme.SYSTEM_THEME_NAME: UIUserInterfaceStyle.unspecified
default: UIUserInterfaceStyle.dark
}
if SceneDelegate.windowStatic?.overrideUserInterfaceStyle != style {
SceneDelegate.windowStatic?.overrideUserInterfaceStyle = style
}
}
// static func applyNavigationBarColors(_ theme: AppTheme) {
// let baseColors = switch theme.base {
// case DefaultTheme.LIGHT: LightColorPaletteApp
// case DefaultTheme.DARK: DarkColorPaletteApp
// case DefaultTheme.SIMPLEX: SimplexColorPaletteApp
// case DefaultTheme.BLACK: BlackColorPaletteApp
// }
// let isDefaultColor = baseColors.title == theme.appColors.title
//
// let title = UIColor(theme.appColors.title)
// if !isDefaultColor && UINavigationBar.appearance().titleTextAttributes?.first as? UIColor != title {
// UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: title]
// UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: title]
// } else {
// UINavigationBar.appearance().titleTextAttributes = nil
// UINavigationBar.appearance().largeTitleTextAttributes = nil
// }
// }
static func changeDarkTheme(_ theme: String) {
systemDarkThemeDefault.set(theme)
CurrentColors = currentColors(nil, nil, ChatModel.shared.currentUser?.uiThemes, themeOverridesDefault.get())
AppTheme.shared.updateFromCurrentColors()
}
static func saveAndApplyThemeColor(_ baseTheme: DefaultTheme, _ name: ThemeColor, _ color: Color? = nil, _ pref: CodableDefault<[ThemeOverrides]>? = nil) {
let nonSystemThemeName = baseTheme.themeName
let pref = pref ?? themeOverridesDefault
let overrides = pref.get()
let themeId = currentThemeIdsDefault.get()[nonSystemThemeName]
let prevValue = overrides.getTheme(themeId) ?? ThemeOverrides(base: baseTheme)
pref.set(overrides.replace(prevValue.withUpdatedColor(name, color?.toReadableHex())))
var themeIds = currentThemeIdsDefault.get()
themeIds[nonSystemThemeName] = prevValue.themeId
currentThemeIdsDefault.set(themeIds)
applyTheme(currentThemeDefault.get())
}
static func applyThemeColor(name: ThemeColor, color: Color? = nil, pref: Binding<ThemeModeOverride>) {
pref.wrappedValue = pref.wrappedValue.withUpdatedColor(name, color?.toReadableHex())
}
static func saveAndApplyWallpaper(_ baseTheme: DefaultTheme, _ type: WallpaperType?, _ pref: CodableDefault<[ThemeOverrides]>?) {
let nonSystemThemeName = baseTheme.themeName
let pref = pref ?? themeOverridesDefault
let overrides = pref.get()
let theme = overrides.sameTheme(type, baseTheme.themeName)
var prevValue = theme ?? ThemeOverrides(base: baseTheme)
prevValue.wallpaper = if let type {
if case WallpaperType.empty = type {
nil as ThemeWallpaper?
} else {
ThemeWallpaper.from(type, prevValue.wallpaper?.background, prevValue.wallpaper?.tint)
}
} else {
nil
}
pref.set(overrides.replace(prevValue))
var themeIds = currentThemeIdsDefault.get()
themeIds[nonSystemThemeName] = prevValue.themeId
currentThemeIdsDefault.set(themeIds)
applyTheme(nonSystemThemeName)
}
static func copyFromSameThemeOverrides(_ type: WallpaperType?, _ lowerLevelOverride: ThemeModeOverride?, _ pref: Binding<ThemeModeOverride>) -> Bool {
let overrides = themeOverridesDefault.get()
let sameWallpaper: ThemeWallpaper? = if let wallpaper = lowerLevelOverride?.wallpaper, lowerLevelOverride?.type?.sameType(type) == true {
wallpaper
} else {
overrides.sameTheme(type, CurrentColors.base.themeName)?.wallpaper
}
guard let sameWallpaper else {
if let type {
var w: ThemeWallpaper = ThemeWallpaper.from(type, nil, nil)
w.scale = nil
w.scaleType = nil
w.background = nil
w.tint = nil
pref.wrappedValue = ThemeModeOverride(mode: CurrentColors.base.mode, wallpaper: w)
} else {
// Make an empty wallpaper to override any top level ones
pref.wrappedValue = ThemeModeOverride(mode: CurrentColors.base.mode, wallpaper: ThemeWallpaper())
}
return true
}
var type = sameWallpaper.toAppWallpaper().type
if case let WallpaperType.image(filename, scale, scaleType) = type, sameWallpaper.imageFile == filename {
// same image file. Needs to be copied first in order to be able to remove the file once it's not needed anymore without affecting main theme override
if let filename = saveWallpaperFile(url: getWallpaperFilePath(filename)) {
type = WallpaperType.image(filename, scale, scaleType)
} else {
logger.error("Error while copying wallpaper from global overrides to chat overrides")
return false
}
}
var prevValue = pref.wrappedValue
var w = ThemeWallpaper.from(type, nil, nil)
w.scale = nil
w.scaleType = nil
w.background = nil
w.tint = nil
prevValue.colors = ThemeColors()
prevValue.wallpaper = w
pref.wrappedValue = prevValue
return true
}
static func applyWallpaper(_ type: WallpaperType?, _ pref: Binding<ThemeModeOverride>) {
var prevValue = pref.wrappedValue
prevValue.wallpaper = if let type {
ThemeWallpaper.from(type, prevValue.wallpaper?.background, prevValue.wallpaper?.tint)
} else {
nil
}
pref.wrappedValue = prevValue
}
static func saveAndApplyThemeOverrides(_ theme: ThemeOverrides, _ pref: CodableDefault<[ThemeOverrides]>? = nil) {
let wallpaper = theme.wallpaper?.importFromString()
let nonSystemThemeName = theme.base.themeName
let pref: CodableDefault<[ThemeOverrides]> = pref ?? themeOverridesDefault
let overrides = pref.get()
var prevValue = overrides.getTheme(nil, wallpaper?.toAppWallpaper().type, theme.base) ?? ThemeOverrides(base: theme.base)
if let imageFile = prevValue.wallpaper?.imageFile {
try? FileManager.default.removeItem(at: getWallpaperFilePath(imageFile))
}
prevValue.base = theme.base
prevValue.colors = theme.colors
prevValue.wallpaper = wallpaper
pref.set(overrides.replace(prevValue))
currentThemeDefault.set(nonSystemThemeName)
var currentThemeIds = currentThemeIdsDefault.get()
currentThemeIds[nonSystemThemeName] = prevValue.themeId
currentThemeIdsDefault.set(currentThemeIds)
applyTheme(nonSystemThemeName)
}
static func resetAllThemeColors(_ pref: CodableDefault<[ThemeOverrides]>? = nil) {
let nonSystemThemeName = nonSystemThemeName()
let pref: CodableDefault<[ThemeOverrides]> = pref ?? themeOverridesDefault
let overrides = pref.get()
guard let themeId = currentThemeIdsDefault.get()[nonSystemThemeName],
var prevValue = overrides.getTheme(themeId)
else { return }
prevValue.colors = ThemeColors()
prevValue.wallpaper?.background = nil
prevValue.wallpaper?.tint = nil
pref.set(overrides.replace(prevValue))
applyTheme(currentThemeDefault.get())
}
static func resetAllThemeColors(_ pref: Binding<ThemeModeOverride>) {
var prevValue = pref.wrappedValue
prevValue.colors = ThemeColors()
prevValue.wallpaper?.background = nil
prevValue.wallpaper?.tint = nil
pref.wrappedValue = prevValue
}
static func removeTheme(_ themeId: String?) {
var themes = themeOverridesDefault.get().map { $0 }
themes.removeAll(where: { $0.themeId == themeId })
themeOverridesDefault.set(themes)
}
}
+175 -54
View File
@@ -9,68 +9,84 @@
import SwiftUI
import WebKit
import SimpleXChat
import AVFoundation
struct ActiveCallView: View {
@EnvironmentObject var m: ChatModel
@Environment(\.colorScheme) var colorScheme
@ObservedObject var call: Call
@Environment(\.scenePhase) var scenePhase
@State private var client: WebRTCClient? = nil
@State private var activeCall: WebRTCClient.Call? = nil
@State private var localRendererAspectRatio: CGFloat? = nil
@Binding var canConnectCall: Bool
@State var prevColorScheme: ColorScheme = .dark
@State var pipShown = false
@State var wasConnected = false
var body: some View {
ZStack(alignment: .bottom) {
if let client = client, [call.peerMedia, call.localMedia].contains(.video), activeCall != nil {
GeometryReader { g in
let width = g.size.width * 0.3
ZStack(alignment: .topTrailing) {
CallViewRemote(client: client, activeCall: $activeCall)
CallViewLocal(client: client, activeCall: $activeCall, localRendererAspectRatio: $localRendererAspectRatio)
.cornerRadius(10)
.frame(width: width, height: width / (localRendererAspectRatio ?? 1))
.padding([.top, .trailing], 17)
ZStack(alignment: .topLeading) {
ZStack(alignment: .bottom) {
if let client = client, [call.peerMedia, call.localMedia].contains(.video), activeCall != nil {
GeometryReader { g in
let width = g.size.width * 0.3
ZStack(alignment: .topTrailing) {
CallViewRemote(client: client, activeCall: $activeCall, activeCallViewIsCollapsed: $m.activeCallViewIsCollapsed, pipShown: $pipShown)
CallViewLocal(client: client, activeCall: $activeCall, localRendererAspectRatio: $localRendererAspectRatio, pipShown: $pipShown)
.cornerRadius(10)
.frame(width: width, height: width / (localRendererAspectRatio ?? 1))
.padding([.top, .trailing], 17)
ZStack(alignment: .center) {
// For some reason, when the view in GeometryReader and ZStack is visible, it steals clicks on a back button, so showing something on top like this with background color helps (.clear color doesn't work)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.primary.opacity(0.000001))
}
}
}
}
if let call = m.activeCall, let client = client {
ActiveCallOverlay(call: call, client: client)
if let call = m.activeCall, let client = client, (!pipShown || !call.supportsVideo) {
ActiveCallOverlay(call: call, client: client)
}
}
}
.allowsHitTesting(!m.activeCallViewIsCollapsed)
.opacity(m.activeCallViewIsCollapsed ? 0 : 1)
.onAppear {
logger.debug("ActiveCallView: appear client is nil \(client == nil), scenePhase \(String(describing: scenePhase), privacy: .public), canConnectCall \(canConnectCall)")
logger.debug("ActiveCallView: appear client is nil \(client == nil), scenePhase \(String(describing: scenePhase)), canConnectCall \(canConnectCall)")
AppDelegate.keepScreenOn(true)
createWebRTCClient()
dismissAllSheets()
hideKeyboard()
prevColorScheme = colorScheme
}
.onChange(of: canConnectCall) { _ in
logger.debug("ActiveCallView: canConnectCall changed to \(canConnectCall, privacy: .public)")
logger.debug("ActiveCallView: canConnectCall changed to \(canConnectCall)")
createWebRTCClient()
}
.onChange(of: m.activeCallViewIsCollapsed) { _ in
hideKeyboard()
}
.onDisappear {
logger.debug("ActiveCallView: disappear")
Task { await m.callCommand.setClient(nil) }
AppDelegate.keepScreenOn(false)
client?.endCall()
CallSoundsPlayer.shared.stop()
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient)
if (wasConnected) {
CallSoundsPlayer.shared.vibrate(long: true)
}
}
.onChange(of: m.callCommand) { _ in sendCommandToClient()}
.background(.black)
.preferredColorScheme(.dark)
.background(m.activeCallViewIsCollapsed ? .clear : .black)
// Quite a big delay when opening/closing the view when a scheme changes (globally) this way. It's not needed when CallKit is used since status bar is green with white text on it
.preferredColorScheme(m.activeCallViewIsCollapsed || CallController.useCallKit() ? prevColorScheme : .dark)
}
private func createWebRTCClient() {
if client == nil && canConnectCall {
client = WebRTCClient($activeCall, { msg in await MainActor.run { processRtcMessage(msg: msg) } }, $localRendererAspectRatio)
sendCommandToClient()
}
}
private func sendCommandToClient() {
if call == m.activeCall,
m.activeCall != nil,
let client = client,
let cmd = m.callCommand {
m.callCommand = nil
logger.debug("sendCallCommand: \(cmd.cmdType)")
Task {
await client.sendCallCommand(command: cmd)
await m.callCommand.setClient(client)
}
}
}
@@ -78,8 +94,8 @@ struct ActiveCallView: View {
@MainActor
private func processRtcMessage(msg: WVAPIMessage) {
if call == m.activeCall,
let call = m.activeCall,
let client = client {
let call = m.activeCall,
let client = client {
logger.debug("ActiveCallView: response \(msg.resp.respType)")
switch msg.resp {
case let .capabilities(capabilities):
@@ -94,12 +110,17 @@ struct ActiveCallView: View {
call.callState = .invitationSent
call.localCapabilities = capabilities
}
if call.supportsVideo && !AVAudioSession.sharedInstance().hasExternalAudioDevice() {
try? AVAudioSession.sharedInstance().setCategory(.playback, options: [.allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
}
CallSoundsPlayer.shared.startConnectingCallSound()
activeCallWaitDeliveryReceipt()
}
case let .offer(offer, iceCandidates, capabilities):
Task {
do {
try await apiSendCallOffer(call.contact, offer, iceCandidates,
media: call.localMedia, capabilities: capabilities)
media: call.localMedia, capabilities: capabilities)
} catch {
logger.error("apiSendCallOffer \(responseError(error))")
}
@@ -117,6 +138,7 @@ struct ActiveCallView: View {
}
await MainActor.run {
call.callState = .negotiated
CallSoundsPlayer.shared.stop()
}
}
case let .ice(iceCandidates):
@@ -131,13 +153,19 @@ struct ActiveCallView: View {
if let callStatus = WebRTCCallStatus.init(rawValue: state.connectionState),
case .connected = callStatus {
call.direction == .outgoing
? CallController.shared.reportOutgoingCall(call: call, connectedAt: nil)
: CallController.shared.reportIncomingCall(call: call, connectedAt: nil)
? CallController.shared.reportOutgoingCall(call: call, connectedAt: nil)
: CallController.shared.reportIncomingCall(call: call, connectedAt: nil)
call.callState = .connected
call.connectedAt = .now
if !wasConnected {
CallSoundsPlayer.shared.vibrate(long: false)
wasConnected = true
}
}
if state.connectionState == "closed" {
closeCallView(client)
m.activeCall = nil
m.activeCallViewIsCollapsed = false
}
Task {
do {
@@ -149,6 +177,11 @@ struct ActiveCallView: View {
case let .connected(connectionInfo):
call.callState = .connected
call.connectionInfo = connectionInfo
call.connectedAt = .now
if !wasConnected {
CallSoundsPlayer.shared.vibrate(long: false)
wasConnected = true
}
case .ended:
closeCallView(client)
call.callState = .ended
@@ -162,12 +195,31 @@ struct ActiveCallView: View {
case .end:
closeCallView(client)
m.activeCall = nil
m.activeCallViewIsCollapsed = false
default: ()
}
case let .error(message):
logger.debug("ActiveCallView: command error: \(message)")
AlertManager.shared.showAlert(Alert(title: Text("Error"), message: Text(message)))
case let .invalid(type):
logger.debug("ActiveCallView: invalid response: \(type)")
AlertManager.shared.showAlert(Alert(title: Text("Invalid response"), message: Text(type)))
}
}
}
private func activeCallWaitDeliveryReceipt() {
ChatReceiver.shared.messagesChannel = { msg in
guard let call = ChatModel.shared.activeCall, call.callState == .invitationSent else {
ChatReceiver.shared.messagesChannel = nil
return
}
if case let .chatItemStatusUpdated(_, msg) = msg,
msg.chatInfo.id == call.contact.id,
case .sndCall = msg.chatItem.content,
case .sndRcvd = msg.chatItem.meta.itemStatus {
CallSoundsPlayer.shared.startInCallSound()
ChatReceiver.shared.messagesChannel = nil
}
}
}
@@ -183,12 +235,13 @@ struct ActiveCallOverlay: View {
@EnvironmentObject var chatModel: ChatModel
@ObservedObject var call: Call
var client: WebRTCClient
@ObservedObject private var deviceManager = CallAudioDeviceManager.shared
var body: some View {
VStack {
switch call.localMedia {
case .video:
callInfoView(call, .leading)
videoCallInfoView(call)
.foregroundColor(.white)
.opacity(0.8)
.padding()
@@ -198,7 +251,16 @@ struct ActiveCallOverlay: View {
HStack {
toggleAudioButton()
Spacer()
Color.clear.frame(width: 40, height: 40)
if deviceManager.availableInputs.allSatisfy({ $0.portType == .builtInMic }) {
toggleSpeakerButton()
.frame(width: 40, height: 40)
} else if call.hasMedia {
AudioDevicePicker()
.scaleEffect(2)
.frame(maxWidth: 40, maxHeight: 40)
} else {
Color.clear.frame(width: 40, height: 40)
}
Spacer()
endCallButton()
Spacer()
@@ -215,16 +277,23 @@ struct ActiveCallOverlay: View {
.frame(maxWidth: .infinity, alignment: .center)
case .audio:
VStack {
ProfileImage(imageStr: call.contact.profile.image)
.scaledToFit()
.frame(width: 192, height: 192)
callInfoView(call, .center)
ZStack(alignment: .topLeading) {
Button {
chatModel.activeCallViewIsCollapsed = true
} label: {
Label("Back", systemImage: "chevron.left")
.padding()
.foregroundColor(.white.opacity(0.8))
}
VStack {
ProfileImage(imageStr: call.contact.profile.image, size: 192)
audioCallInfoView(call)
}
.foregroundColor(.white)
.opacity(0.8)
.padding()
.frame(maxHeight: .infinity)
}
.foregroundColor(.white)
.opacity(0.8)
.padding()
.frame(maxHeight: .infinity)
Spacer()
@@ -232,34 +301,81 @@ struct ActiveCallOverlay: View {
toggleAudioButton()
.frame(maxWidth: .infinity, alignment: .leading)
endCallButton()
toggleSpeakerButton()
.frame(maxWidth: .infinity, alignment: .trailing)
// Check if the only input is microphone. And in this case show toggle button,
// If there are more inputs, it probably means something like bluetooth headphones are available
// and in this case show iOS button for choosing different output.
// There is no way to get available outputs, only inputs
if deviceManager.availableInputs.allSatisfy({ $0.portType == .builtInMic }) {
toggleSpeakerButton()
.frame(maxWidth: .infinity, alignment: .trailing)
} else if call.hasMedia {
AudioDevicePicker()
.scaleEffect(2)
.frame(maxWidth: 50, maxHeight: 40)
.frame(maxWidth: .infinity, alignment: .trailing)
} else {
Color.clear.frame(width: 50, height: 40)
}
}
.padding(.bottom, 60)
.padding(.horizontal, 48)
}
}
.frame(maxWidth: .infinity)
.onAppear {
deviceManager.start()
}
.onDisappear {
deviceManager.stop()
}
}
private func callInfoView(_ call: Call, _ alignment: Alignment) -> some View {
private func audioCallInfoView(_ call: Call) -> some View {
VStack {
Text(call.contact.chatViewName)
.lineLimit(1)
.font(.title)
.frame(maxWidth: .infinity, alignment: alignment)
.frame(maxWidth: .infinity, alignment: .center)
Group {
Text(call.callState.text)
HStack {
Text(call.encryptionStatus)
if let connInfo = call.connectionInfo {
// Text("(") + Text(connInfo.text) + Text(", \(connInfo.protocolText))")
Text("(") + Text(connInfo.text) + Text(")")
}
}
}
.font(.subheadline)
.frame(maxWidth: .infinity, alignment: alignment)
.frame(maxWidth: .infinity, alignment: .center)
}
}
private func videoCallInfoView(_ call: Call) -> some View {
VStack {
Button {
chatModel.activeCallViewIsCollapsed = true
} label: {
HStack(alignment: .center, spacing: 16) {
Image(systemName: "chevron.left")
.resizable()
.frame(width: 10, height: 18)
Text(call.contact.chatViewName)
.lineLimit(1)
.font(.title)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
Group {
Text(call.callState.text)
HStack {
Text(call.encryptionStatus)
if let connInfo = call.connectionInfo {
Text("(") + Text(connInfo.text) + Text(")")
}
}
}
.font(.subheadline)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
@@ -289,12 +405,17 @@ struct ActiveCallOverlay: View {
private func toggleSpeakerButton() -> some View {
controlButton(call, call.speakerEnabled ? "speaker.wave.2.fill" : "speaker.wave.1.fill") {
Task {
client.setSpeakerEnabledAndConfigureSession(!call.speakerEnabled)
let speakerEnabled = AVAudioSession.sharedInstance().currentRoute.outputs.first?.portType == .builtInSpeaker
client.setSpeakerEnabledAndConfigureSession(!speakerEnabled)
DispatchQueue.main.async {
call.speakerEnabled = !call.speakerEnabled
call.speakerEnabled = !speakerEnabled
}
}
}
.onAppear {
deviceManager.call = call
//call.speakerEnabled = AVAudioSession.sharedInstance().currentRoute.outputs.first?.portType == .builtInSpeaker
}
}
private func toggleVideoButton() -> some View {
@@ -0,0 +1,25 @@
//
// MPVolumeView.swift
// SimpleX (iOS)
//
// Created by Avently on 24.04.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import Foundation
import SwiftUI
import UIKit
import AVKit
struct AudioDevicePicker: UIViewRepresentable {
func makeUIView(context: Context) -> some UIView {
let v = AVRoutePickerView(frame: .zero)
v.activeTintColor = .white
v.tintColor = .white
return v
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
}
@@ -0,0 +1,67 @@
//
// CallAudioDeviceManager.swift
// SimpleX (iOS)
//
// Created by Avently on 23.04.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import Foundation
import SwiftUI
import SimpleXChat
import AVKit
import WebRTC
class CallAudioDeviceManager: ObservableObject {
static let shared = CallAudioDeviceManager()
let audioSession: AVAudioSession
let nc = NotificationCenter.default
var call: Call?
var timer: Timer? = nil
// Actually, only one output
@Published var outputs: [AVAudioSessionPortDescription]
@Published var currentDevice: AVAudioSessionPortDescription? = nil
// All devices that can record audio (the ones that can play audio are not included)
@Published var availableInputs: [AVAudioSessionPortDescription] = []
init(_ audioSession: AVAudioSession? = nil) {
self.audioSession = audioSession ?? RTCAudioSession.sharedInstance().session
self.outputs = self.audioSession.currentRoute.outputs
self.availableInputs = self.audioSession.availableInputs ?? []
}
func reloadDevices() {
outputs = audioSession.currentRoute.outputs
currentDevice = audioSession.currentRoute.outputs.first
availableInputs = audioSession.availableInputs ?? []
call?.speakerEnabled = currentDevice?.portType == .builtInSpeaker
// Workaround situation:
// have bluetooth device connected, choosing speaker, disconnecting bluetooth device. In this case iOS will not post notification, so do it manually
timer?.invalidate()
if availableInputs.contains(where: { $0.portType != .builtInReceiver && $0.portType != .builtInSpeaker }) {
timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { t in
self.reloadDevices()
}
}
}
@objc func audioCallback(notification: Notification) {
reloadDevices()
logger.debug("Changes in devices, current audio devices: \(String(describing: self.availableInputs.map({ $0.portType.rawValue }))), output: \(String(describing: self.currentDevice?.portType.rawValue))")
}
func start() {
nc.addObserver(self, selector: #selector(audioCallback), name: AVAudioSession.routeChangeNotification, object: nil)
}
func stop() {
nc.removeObserver(self, name: AVAudioSession.routeChangeNotification, object: nil)
timer?.invalidate()
}
}
+45 -18
View File
@@ -103,12 +103,27 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
RTCAudioSession.sharedInstance().audioSessionDidActivate(audioSession)
RTCAudioSession.sharedInstance().isAudioEnabled = true
do {
try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: .mixWithOthers)
let supportsVideo = ChatModel.shared.activeCall?.supportsVideo == true
if supportsVideo {
try audioSession.setCategory(.playAndRecord, mode: .videoChat, options: [.defaultToSpeaker, .mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
} else {
try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: [.mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
}
// Without any delay sound is not playing from speaker or external device in incoming call
Task {
for i in 0 ... 3 {
try? await Task.sleep(nanoseconds: UInt64(i) * 300_000000)
if let preferred = audioSession.preferredInputDevice() {
await MainActor.run { try? audioSession.setPreferredInput(preferred) }
} else if supportsVideo {
await MainActor.run { try? audioSession.overrideOutputAudioPort(.speaker) }
}
}
}
logger.debug("audioSession category set")
try audioSession.setActive(true)
logger.debug("audioSession activated")
} catch {
print(error)
logger.error("failed activating audio session")
}
}
@@ -121,7 +136,6 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
try audioSession.setActive(false)
logger.debug("audioSession deactivated")
} catch {
print(error)
logger.error("failed deactivating audio session")
}
suspendOnEndCall()
@@ -132,7 +146,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
// The delay allows to accept the second call before suspending a chat
// see `.onChange(of: scenePhase)` in SimpleXApp
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in
logger.debug("CallController: shouldSuspendChat \(String(describing: self?.shouldSuspendChat), privacy: .public)")
logger.debug("CallController: shouldSuspendChat \(String(describing: self?.shouldSuspendChat))")
if ChatModel.shared.activeCall == nil && self?.shouldSuspendChat == true {
self?.shouldSuspendChat = false
suspendChat()
@@ -144,33 +158,46 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
@objc(pushRegistry:didUpdatePushCredentials:forType:)
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
logger.debug("CallController: didUpdate push credentials for type \(type.rawValue, privacy: .public)")
logger.debug("CallController: didUpdate push credentials for type \(type.rawValue)")
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
logger.debug("CallController: did receive push with type \(type.rawValue, privacy: .public)")
logger.debug("CallController: did receive push with type \(type.rawValue)")
if type != .voIP {
completion()
return
}
logger.debug("CallController: initializing chat")
if (!ChatModel.shared.chatInitialized) {
initChatAndMigrate(refreshInvitations: false)
if AppChatState.shared.value == .stopped {
self.reportExpiredCall(payload: payload, completion)
return
}
startChatAndActivate()
shouldSuspendChat = true
if (!ChatModel.shared.chatInitialized) {
logger.debug("CallController: initializing chat")
do {
try initializeChat(start: true, refreshInvitations: false)
} catch let error {
logger.error("CallController: initializing chat error: \(error)")
self.reportExpiredCall(payload: payload, completion)
return
}
}
logger.debug("CallController: initialized chat")
startChatForCall()
logger.debug("CallController: started chat")
self.shouldSuspendChat = true
// There are no invitations in the model, as it was processed by NSE
_ = try? justRefreshCallInvitations()
logger.debug("CallController: updated call invitations chat")
// logger.debug("CallController justRefreshCallInvitations: \(String(describing: m.callInvitations))")
// Extract the call information from the push notification payload
let m = ChatModel.shared
if let contactId = payload.dictionaryPayload["contactId"] as? String,
let invitation = m.callInvitations[contactId] {
let update = cxCallUpdate(invitation: invitation)
let update = self.cxCallUpdate(invitation: invitation)
if let uuid = invitation.callkitUUID {
logger.debug("CallController: report pushkit call via CallKit")
let update = cxCallUpdate(invitation: invitation)
provider.reportNewIncomingCall(with: uuid, update: update) { error in
let update = self.cxCallUpdate(invitation: invitation)
self.provider.reportNewIncomingCall(with: uuid, update: update) { error in
if error != nil {
m.callInvitations.removeValue(forKey: contactId)
}
@@ -178,10 +205,10 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
completion()
}
} else {
reportExpiredCall(update: update, completion)
self.reportExpiredCall(update: update, completion)
}
} else {
reportExpiredCall(payload: payload, completion)
self.reportExpiredCall(payload: payload, completion)
}
}
@@ -212,7 +239,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
}
func reportNewIncomingCall(invitation: RcvCallInvitation, completion: @escaping (Error?) -> Void) {
logger.debug("CallController.reportNewIncomingCall, UUID=\(String(describing: invitation.callkitUUID), privacy: .public)")
logger.debug("CallController.reportNewIncomingCall, UUID=\(String(describing: invitation.callkitUUID))")
if CallController.useCallKit(), let uuid = invitation.callkitUUID {
if invitation.callTs.timeIntervalSinceNow >= -180 {
let update = cxCallUpdate(invitation: invitation)
@@ -352,7 +379,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
private func requestTransaction(with action: CXAction, onSuccess: @escaping () -> Void = {}) {
controller.request(CXTransaction(action: action)) { error in
if let error = error {
logger.error("CallController.requestTransaction error requesting transaction: \(error.localizedDescription, privacy: .public)")
logger.error("CallController.requestTransaction error requesting transaction: \(error.localizedDescription)")
} else {
logger.debug("CallController.requestTransaction requested transaction successfully")
onSuccess()
+14 -8
View File
@@ -22,7 +22,7 @@ class CallManager {
let m = ChatModel.shared
if let call = m.activeCall, call.callkitUUID == callUUID {
m.showCallView = true
m.callCommand = .capabilities(media: call.localMedia)
Task { await m.callCommand.processCommand(.capabilities(media: call.localMedia)) }
return true
}
return false
@@ -57,19 +57,21 @@ class CallManager {
m.activeCall = call
m.showCallView = true
m.callCommand = .start(
Task {
await m.callCommand.processCommand(.start(
media: invitation.callType.media,
aesKey: invitation.sharedKey,
iceServers: iceServers,
relay: useRelay
)
))
}
}
}
func enableMedia(media: CallMediaType, enable: Bool, callUUID: UUID) -> Bool {
if let call = ChatModel.shared.activeCall, call.callkitUUID == callUUID {
let m = ChatModel.shared
m.callCommand = .media(media: media, enable: enable)
Task { await m.callCommand.processCommand(.media(media: media, enable: enable)) }
return true
}
return false
@@ -90,15 +92,19 @@ class CallManager {
if case .ended = call.callState {
logger.debug("CallManager.endCall: call ended")
m.activeCall = nil
m.activeCallViewIsCollapsed = false
m.showCallView = false
completed()
} else {
logger.debug("CallManager.endCall: ending call...")
m.callCommand = .end
m.activeCall = nil
m.showCallView = false
completed()
Task {
await m.callCommand.processCommand(.end)
await MainActor.run {
m.activeCall = nil
m.activeCallViewIsCollapsed = false
m.showCallView = false
completed()
}
do {
try await apiEndCall(call.contact)
} catch {
@@ -6,14 +6,20 @@
import SwiftUI
import WebRTC
import SimpleXChat
import AVKit
struct CallViewRemote: UIViewRepresentable {
var client: WebRTCClient
var activeCall: Binding<WebRTCClient.Call?>
@State var enablePip: (Bool) -> Void = {_ in }
@Binding var activeCallViewIsCollapsed: Bool
@Binding var pipShown: Bool
init(client: WebRTCClient, activeCall: Binding<WebRTCClient.Call?>) {
init(client: WebRTCClient, activeCall: Binding<WebRTCClient.Call?>, activeCallViewIsCollapsed: Binding<Bool>, pipShown: Binding<Bool>) {
self.client = client
self.activeCall = activeCall
self._activeCallViewIsCollapsed = activeCallViewIsCollapsed
self._pipShown = pipShown
}
func makeUIView(context: Context) -> UIView {
@@ -23,12 +29,120 @@ struct CallViewRemote: UIViewRepresentable {
remoteRenderer.videoContentMode = .scaleAspectFill
client.addRemoteRenderer(call, remoteRenderer)
addSubviewAndResize(remoteRenderer, into: view)
if AVPictureInPictureController.isPictureInPictureSupported() {
makeViewWithRTCRenderer(call, remoteRenderer, view, context)
}
}
return view
}
func makeViewWithRTCRenderer(_ call: WebRTCClient.Call, _ remoteRenderer: RTCMTLVideoView, _ view: UIView, _ context: Context) {
let pipRemoteRenderer = RTCMTLVideoView(frame: view.frame)
pipRemoteRenderer.videoContentMode = .scaleAspectFill
let pipVideoCallViewController = AVPictureInPictureVideoCallViewController()
pipVideoCallViewController.preferredContentSize = CGSize(width: 1080, height: 1920)
addSubviewAndResize(pipRemoteRenderer, into: pipVideoCallViewController.view)
let pipContentSource = AVPictureInPictureController.ContentSource(
activeVideoCallSourceView: view,
contentViewController: pipVideoCallViewController
)
let pipController = AVPictureInPictureController(contentSource: pipContentSource)
pipController.canStartPictureInPictureAutomaticallyFromInline = true
pipController.delegate = context.coordinator
context.coordinator.pipController = pipController
context.coordinator.willShowHide = { show in
if show {
client.addRemoteRenderer(call, pipRemoteRenderer)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
activeCallViewIsCollapsed = true
}
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
activeCallViewIsCollapsed = false
}
}
}
context.coordinator.didShowHide = { show in
if show {
remoteRenderer.isHidden = true
} else {
client.removeRemoteRenderer(call, pipRemoteRenderer)
remoteRenderer.isHidden = false
}
pipShown = show
}
DispatchQueue.main.async {
enablePip = { enable in
if enable != pipShown /* pipController.isPictureInPictureActive */ {
if enable {
pipController.startPictureInPicture()
} else {
pipController.stopPictureInPicture()
}
}
}
}
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
func updateUIView(_ view: UIView, context: Context) {
logger.debug("CallView.updateUIView remote")
DispatchQueue.main.async {
if activeCallViewIsCollapsed != pipShown {
enablePip(activeCallViewIsCollapsed)
}
}
}
// MARK: - Coordinator
class Coordinator: NSObject, AVPictureInPictureControllerDelegate {
var pipController: AVPictureInPictureController? = nil
var willShowHide: (Bool) -> Void = { _ in }
var didShowHide: (Bool) -> Void = { _ in }
func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
willShowHide(true)
}
func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
didShowHide(true)
}
func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
logger.error("PiP failed to start: \(error.localizedDescription)")
}
func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
willShowHide(false)
}
func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
didShowHide(false)
}
deinit {
pipController?.stopPictureInPicture()
pipController?.canStartPictureInPictureAutomaticallyFromInline = false
pipController?.contentSource = nil
pipController?.delegate = nil
pipController = nil
}
}
class SampleBufferVideoCallView: UIView {
override class var layerClass: AnyClass {
get { return AVSampleBufferDisplayLayer.self }
}
var sampleBufferDisplayLayer: AVSampleBufferDisplayLayer {
return layer as! AVSampleBufferDisplayLayer
}
}
}
@@ -36,11 +150,14 @@ struct CallViewLocal: UIViewRepresentable {
var client: WebRTCClient
var activeCall: Binding<WebRTCClient.Call?>
var localRendererAspectRatio: Binding<CGFloat?>
@State var pipStateChanged: (Bool) -> Void = {_ in }
@Binding var pipShown: Bool
init(client: WebRTCClient, activeCall: Binding<WebRTCClient.Call?>, localRendererAspectRatio: Binding<CGFloat?>) {
init(client: WebRTCClient, activeCall: Binding<WebRTCClient.Call?>, localRendererAspectRatio: Binding<CGFloat?>, pipShown: Binding<Bool>) {
self.client = client
self.activeCall = activeCall
self.localRendererAspectRatio = localRendererAspectRatio
self._pipShown = pipShown
}
func makeUIView(context: Context) -> UIView {
@@ -50,12 +167,18 @@ struct CallViewLocal: UIViewRepresentable {
client.addLocalRenderer(call, localRenderer)
client.startCaptureLocalVideo(call)
addSubviewAndResize(localRenderer, into: view)
DispatchQueue.main.async {
pipStateChanged = { shown in
localRenderer.isHidden = shown
}
}
}
return view
}
func updateUIView(_ view: UIView, context: Context) {
logger.debug("CallView.updateUIView local")
pipStateChanged(pipShown)
}
}
@@ -11,6 +11,7 @@ import SimpleXChat
struct IncomingCallView: View {
@EnvironmentObject var m: ChatModel
@EnvironmentObject var theme: AppTheme
@ObservedObject var cc = CallController.shared
var body: some View {
@@ -30,8 +31,7 @@ struct IncomingCallView: View {
VStack(alignment: .leading, spacing: 6) {
HStack {
if m.users.count > 1 {
ProfileImage(imageStr: invitation.user.image, color: .white)
.frame(width: 24, height: 24)
ProfileImage(imageStr: invitation.user.image, size: 24, color: .white)
}
Image(systemName: invitation.callType.media == .video ? "video.fill" : "phone.fill").foregroundColor(.green)
Text(invitation.callTypeText)
@@ -44,7 +44,7 @@ struct IncomingCallView: View {
cc.endCall(invitation: invitation)
}
callButton("Ignore", "multiply", .accentColor) {
callButton("Ignore", "multiply", .primary) {
cc.activeCallInvitation = nil
}
@@ -64,7 +64,7 @@ struct IncomingCallView: View {
.padding(.horizontal, 16)
.padding(.vertical, 12)
.frame(maxWidth: .infinity)
.background(Color(uiColor: .tertiarySystemGroupedBackground))
.modifier(ThemedBackground())
.onAppear { dismissAllSheets() }
}
@@ -77,7 +77,7 @@ struct IncomingCallView: View {
.frame(width: 24, height: 24)
Text(text)
.font(.caption)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
}
.frame(minWidth: 44)
})
@@ -8,6 +8,7 @@
import Foundation
import AVFoundation
import UIKit
class SoundPlayer {
static let shared = SoundPlayer()
@@ -43,3 +44,63 @@ class SoundPlayer {
audioPlayer = nil
}
}
class CallSoundsPlayer {
static let shared = CallSoundsPlayer()
private var audioPlayer: AVAudioPlayer?
private var playerTask: Task = Task {}
private func start(_ soundName: String, delayMs: Double) {
audioPlayer?.stop()
playerTask.cancel()
logger.debug("start \(soundName)")
guard let path = Bundle.main.path(forResource: soundName, ofType: "mp3", inDirectory: "sounds") else {
logger.debug("start: file not found")
return
}
do {
let player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
if player.prepareToPlay() {
audioPlayer = player
}
} catch {
logger.debug("start: AVAudioPlayer error \(error.localizedDescription)")
}
playerTask = Task {
while let player = audioPlayer {
player.play()
do {
try await Task.sleep(nanoseconds: UInt64((player.duration * 1_000_000_000) + delayMs * 1_000_000))
} catch {
break
}
}
}
}
func startConnectingCallSound() {
start("connecting_call", delayMs: 0)
}
func startInCallSound() {
// Taken from https://github.com/TelegramOrg/Telegram-Android
// https://github.com/TelegramOrg/Telegram-Android/blob/master/LICENSE
start("in_call", delayMs: 1000)
}
func stop() {
playerTask.cancel()
audioPlayer?.stop()
audioPlayer = nil
}
func vibrate(long: Bool) {
// iOS just don't want to vibrate more than once after a short period of time, and all 'styles' feel the same
if long {
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate)
} else {
UIImpactFeedbackGenerator(style: .heavy).impactOccurred()
}
}
}
+50 -17
View File
@@ -28,6 +28,7 @@ class Call: ObservableObject, Equatable {
@Published var speakerEnabled = false
@Published var videoEnabled: Bool
@Published var connectionInfo: ConnectionInfo?
@Published var connectedAt: Date? = nil
init(
direction: CallDirection,
@@ -59,6 +60,7 @@ class Call: ObservableObject, Equatable {
}
}
var hasMedia: Bool { get { callState == .offerSent || callState == .negotiated || callState == .connected } }
var supportsVideo: Bool { get { peerMedia == .video || localMedia == .video } }
}
enum CallDirection {
@@ -335,6 +337,50 @@ extension WCallResponse: Encodable {
}
}
actor WebRTCCommandProcessor {
private var client: WebRTCClient? = nil
private var commands: [WCallCommand] = []
private var running: Bool = false
func setClient(_ client: WebRTCClient?) async {
logger.debug("WebRTC: setClient, commands count \(self.commands.count)")
self.client = client
if client != nil {
await processAllCommands()
} else {
commands.removeAll()
}
}
func processCommand(_ c: WCallCommand) async {
// logger.debug("WebRTC: process command \(c.cmdType)")
commands.append(c)
if !running && client != nil {
await processAllCommands()
}
}
func processAllCommands() async {
logger.debug("WebRTC: process all commands, commands count \(self.commands.count), client == nil \(self.client == nil)")
if let client = client {
running = true
while let c = commands.first, shouldRunCommand(client, c) {
commands.remove(at: 0)
await client.sendCallCommand(command: c)
logger.debug("WebRTC: processed cmd \(c.cmdType)")
}
running = false
}
}
func shouldRunCommand(_ client: WebRTCClient, _ c: WCallCommand) -> Bool {
switch c {
case .capabilities, .start, .offer, .end: true
default: client.activeCall.wrappedValue != nil
}
}
}
struct ConnectionState: Codable, Equatable {
var connectionState: String
var iceConnectionState: String
@@ -358,26 +404,12 @@ struct ConnectionInfo: Codable, Equatable {
return "\(local?.rawValue ?? unknown) / \(remote?.rawValue ?? unknown)"
}
}
var protocolText: String {
let unknown = NSLocalizedString("unknown", comment: "connection info")
let local = localCandidate?.protocol?.uppercased() ?? unknown
let localRelay = localCandidate?.relayProtocol?.uppercased() ?? unknown
let remote = remoteCandidate?.protocol?.uppercased() ?? unknown
let localText = localRelay == local || localCandidate?.relayProtocol == nil
? local
: "\(local) (\(localRelay))"
return local == remote
? localText
: "\(localText) / \(remote)"
}
}
// https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate
struct RTCIceCandidate: Codable, Equatable {
var candidateType: RTCIceCandidateType?
var `protocol`: String?
var relayProtocol: String?
var sdpMid: String?
var sdpMLineIndex: Int?
var candidate: String
@@ -399,17 +431,18 @@ struct RTCIceServer: Codable, Equatable {
}
// the servers are expected in this format:
// stun:stun.simplex.im:443?transport=tcp
// turn:private:yleob6AVkiNI87hpR94Z@turn.simplex.im:443?transport=tcp
// stuns:stun.simplex.im:443?transport=tcp
// turns:private2:Hxuq2QxUjnhj96Zq2r4HjqHRj@turn.simplex.im:443?transport=tcp
func parseRTCIceServer(_ str: String) -> RTCIceServer? {
var s = replaceScheme(str, "stun:")
s = replaceScheme(s, "stuns:")
s = replaceScheme(s, "turn:")
s = replaceScheme(s, "turns:")
if let u: URL = URL(string: s),
let scheme = u.scheme,
let host = u.host,
let port = u.port,
u.path == "" && (scheme == "stun" || scheme == "turn" || scheme == "turns") {
u.path == "" && (scheme == "stun" || scheme == "stuns" || scheme == "turn" || scheme == "turns") {
let query = u.query == nil || u.query == "" ? "" : "?" + (u.query ?? "")
return RTCIceServer(
urls: ["\(scheme):\(host):\(port)\(query)"],
+153 -82
View File
@@ -18,10 +18,11 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
}()
private static let ivTagBytes: Int = 28
private static let enableEncryption: Bool = true
private var chat_ctrl = getChatCtrl()
struct Call {
var connection: RTCPeerConnection
var iceCandidates: [RTCIceCandidate]
var iceCandidates: IceCandidates
var localMedia: CallMediaType
var localCamera: RTCVideoCapturer?
var localVideoSource: RTCVideoSource?
@@ -33,10 +34,24 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
var frameDecryptor: RTCFrameDecryptor?
}
actor IceCandidates {
private var candidates: [RTCIceCandidate] = []
func getAndClear() async -> [RTCIceCandidate] {
let cs = candidates
candidates = []
return cs
}
func append(_ c: RTCIceCandidate) async {
candidates.append(c)
}
}
private let rtcAudioSession = RTCAudioSession.sharedInstance()
private let audioQueue = DispatchQueue(label: "audio")
private let audioQueue = DispatchQueue(label: "chat.simplex.app.audio")
private var sendCallResponse: (WVAPIMessage) async -> Void
private var activeCall: Binding<Call?>
var activeCall: Binding<Call?>
private var localRendererAspectRatio: Binding<CGFloat?>
@available(*, unavailable)
@@ -50,17 +65,17 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
self.localRendererAspectRatio = localRendererAspectRatio
rtcAudioSession.useManualAudio = CallController.useCallKit()
rtcAudioSession.isAudioEnabled = !CallController.useCallKit()
logger.debug("WebRTCClient: rtcAudioSession has manual audio \(self.rtcAudioSession.useManualAudio) and audio enabled \(self.rtcAudioSession.isAudioEnabled)}")
logger.debug("WebRTCClient: rtcAudioSession has manual audio \(self.rtcAudioSession.useManualAudio) and audio enabled \(self.rtcAudioSession.isAudioEnabled)")
super.init()
}
let defaultIceServers: [WebRTC.RTCIceServer] = [
WebRTC.RTCIceServer(urlStrings: ["stun:stun.simplex.im:443"]),
WebRTC.RTCIceServer(urlStrings: ["turn:turn.simplex.im:443?transport=udp"], username: "private", credential: "yleob6AVkiNI87hpR94Z"),
WebRTC.RTCIceServer(urlStrings: ["turn:turn.simplex.im:443?transport=tcp"], username: "private", credential: "yleob6AVkiNI87hpR94Z"),
WebRTC.RTCIceServer(urlStrings: ["stuns:stun.simplex.im:443"]),
//WebRTC.RTCIceServer(urlStrings: ["turns:turn.simplex.im:443?transport=udp"], username: "private2", credential: "Hxuq2QxUjnhj96Zq2r4HjqHRj"),
WebRTC.RTCIceServer(urlStrings: ["turns:turn.simplex.im:443?transport=tcp"], username: "private2", credential: "Hxuq2QxUjnhj96Zq2r4HjqHRj"),
]
func initializeCall(_ iceServers: [WebRTC.RTCIceServer]?, _ remoteIceCandidates: [RTCIceCandidate], _ mediaType: CallMediaType, _ aesKey: String?, _ relay: Bool?) -> Call {
func initializeCall(_ iceServers: [WebRTC.RTCIceServer]?, _ mediaType: CallMediaType, _ aesKey: String?, _ relay: Bool?) -> Call {
let connection = createPeerConnection(iceServers ?? getWebRTCIceServers() ?? defaultIceServers, relay)
connection.delegate = self
createAudioSender(connection)
@@ -87,7 +102,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
}
return Call(
connection: connection,
iceCandidates: remoteIceCandidates,
iceCandidates: IceCandidates(),
localMedia: mediaType,
localCamera: localCamera,
localVideoSource: localVideoSource,
@@ -144,26 +159,18 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
logger.debug("starting incoming call - create webrtc session")
if activeCall.wrappedValue != nil { endCall() }
let encryption = WebRTCClient.enableEncryption
let call = initializeCall(iceServers?.toWebRTCIceServers(), [], media, encryption ? aesKey : nil, relay)
let call = initializeCall(iceServers?.toWebRTCIceServers(), media, encryption ? aesKey : nil, relay)
activeCall.wrappedValue = call
call.connection.offer { answer in
Task {
let gotCandidates = await self.waitWithTimeout(10_000, stepMs: 1000, until: { self.activeCall.wrappedValue?.iceCandidates.count ?? 0 > 0 })
if gotCandidates {
await self.sendCallResponse(.init(
corrId: nil,
resp: .offer(
offer: compressToBase64(input: encodeJSON(CustomRTCSessionDescription(type: answer.type.toSdpType(), sdp: answer.sdp))),
iceCandidates: compressToBase64(input: encodeJSON(self.activeCall.wrappedValue?.iceCandidates ?? [])),
capabilities: CallCapabilities(encryption: encryption)
),
command: command)
)
} else {
self.endCall()
}
}
let (offer, error) = await call.connection.offer()
if let offer = offer {
resp = .offer(
offer: compressToBase64(input: encodeJSON(CustomRTCSessionDescription(type: offer.type.toSdpType(), sdp: offer.sdp))),
iceCandidates: compressToBase64(input: encodeJSON(await self.getInitialIceCandidates())),
capabilities: CallCapabilities(encryption: encryption)
)
self.waitForMoreIceCandidates()
} else {
resp = .error(message: "offer error: \(error?.localizedDescription ?? "unknown error")")
}
case let .offer(offer, iceCandidates, media, aesKey, iceServers, relay):
if activeCall.wrappedValue != nil {
@@ -172,26 +179,21 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
resp = .error(message: "accept: encryption is not supported")
} else if let offer: CustomRTCSessionDescription = decodeJSON(decompressFromBase64(input: offer)),
let remoteIceCandidates: [RTCIceCandidate] = decodeJSON(decompressFromBase64(input: iceCandidates)) {
let call = initializeCall(iceServers?.toWebRTCIceServers(), remoteIceCandidates, media, WebRTCClient.enableEncryption ? aesKey : nil, relay)
let call = initializeCall(iceServers?.toWebRTCIceServers(), media, WebRTCClient.enableEncryption ? aesKey : nil, relay)
activeCall.wrappedValue = call
let pc = call.connection
if let type = offer.type, let sdp = offer.sdp {
if (try? await pc.setRemoteDescription(RTCSessionDescription(type: type.toWebRTCSdpType(), sdp: sdp))) != nil {
pc.answer { answer in
let (answer, error) = await pc.answer()
if let answer = answer {
self.addIceCandidates(pc, remoteIceCandidates)
// Task {
// try? await Task.sleep(nanoseconds: 32_000 * 1000000)
Task {
await self.sendCallResponse(.init(
corrId: nil,
resp: .answer(
answer: compressToBase64(input: encodeJSON(CustomRTCSessionDescription(type: answer.type.toSdpType(), sdp: answer.sdp))),
iceCandidates: compressToBase64(input: encodeJSON(call.iceCandidates))
),
command: command)
)
}
// }
resp = .answer(
answer: compressToBase64(input: encodeJSON(CustomRTCSessionDescription(type: answer.type.toSdpType(), sdp: answer.sdp))),
iceCandidates: compressToBase64(input: encodeJSON(await self.getInitialIceCandidates()))
)
self.waitForMoreIceCandidates()
} else {
resp = .error(message: "answer error: \(error?.localizedDescription ?? "unknown error")")
}
} else {
resp = .error(message: "accept: remote description is not set")
@@ -234,6 +236,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
resp = .ok
}
case .end:
// TODO possibly, endCall should be called before returning .ok
await sendCallResponse(.init(corrId: nil, resp: .ok, command: command))
endCall()
}
@@ -242,6 +245,33 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
}
}
func getInitialIceCandidates() async -> [RTCIceCandidate] {
await untilIceComplete(timeoutMs: 750, stepMs: 150) {}
let candidates = await activeCall.wrappedValue?.iceCandidates.getAndClear() ?? []
logger.debug("WebRTCClient: sending initial ice candidates: \(candidates.count)")
return candidates
}
func waitForMoreIceCandidates() {
Task {
await untilIceComplete(timeoutMs: 12000, stepMs: 1500) {
let candidates = await self.activeCall.wrappedValue?.iceCandidates.getAndClear() ?? []
if candidates.count > 0 {
logger.debug("WebRTCClient: sending more ice candidates: \(candidates.count)")
await self.sendIceCandidates(candidates)
}
}
}
}
func sendIceCandidates(_ candidates: [RTCIceCandidate]) async {
await self.sendCallResponse(.init(
corrId: nil,
resp: .ice(iceCandidates: compressToBase64(input: encodeJSON(candidates))),
command: nil)
)
}
func enableMedia(_ media: CallMediaType, _ enable: Bool) {
logger.debug("WebRTCClient: enabling media \(media.rawValue) \(enable)")
media == .video ? setVideoEnabled(enable) : setAudioEnabled(enable)
@@ -279,7 +309,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
memcpy(pointer, (unencrypted as NSData).bytes, unencrypted.count)
let isKeyFrame = unencrypted[0] & 1 == 0
let clearTextBytesSize = mediaType.rawValue == 0 ? 1 : isKeyFrame ? 10 : 3
logCrypto("encrypt", chat_encrypt_media(&key, pointer.advanced(by: clearTextBytesSize), Int32(unencrypted.count + WebRTCClient.ivTagBytes - clearTextBytesSize)))
logCrypto("encrypt", chat_encrypt_media(chat_ctrl, &key, pointer.advanced(by: clearTextBytesSize), Int32(unencrypted.count + WebRTCClient.ivTagBytes - clearTextBytesSize)))
return Data(bytes: pointer, count: unencrypted.count + WebRTCClient.ivTagBytes)
} else {
return nil
@@ -301,6 +331,10 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
activeCall.remoteStream?.add(renderer)
}
func removeRemoteRenderer(_ activeCall: Call, _ renderer: RTCVideoRenderer) {
activeCall.remoteStream?.remove(renderer)
}
func startCaptureLocalVideo(_ activeCall: Call) {
#if targetEnvironment(simulator)
guard
@@ -380,6 +414,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
guard let call = activeCall.wrappedValue else { return }
logger.debug("WebRTCClient: ending the call")
activeCall.wrappedValue = nil
(call.localCamera as? RTCCameraVideoCapturer)?.stopCapture()
call.connection.close()
call.connection.delegate = nil
call.frameEncryptor?.delegate = nil
@@ -387,12 +422,13 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
audioSessionToDefaults()
}
func waitWithTimeout(_ timeoutMs: UInt64, stepMs: UInt64, until success: () -> Bool) async -> Bool {
let startedAt = DispatchTime.now()
while !success() && startedAt.uptimeNanoseconds + timeoutMs * 1000000 > DispatchTime.now().uptimeNanoseconds {
guard let _ = try? await Task.sleep(nanoseconds: stepMs * 1000000) else { break }
}
return success()
func untilIceComplete(timeoutMs: UInt64, stepMs: UInt64, action: @escaping () async -> Void) async {
var t: UInt64 = 0
repeat {
_ = try? await Task.sleep(nanoseconds: stepMs * 1000000)
t += stepMs
await action()
} while t < timeoutMs && activeCall.wrappedValue?.connection.iceGatheringState != .complete
}
}
@@ -405,25 +441,33 @@ extension WebRTC.RTCPeerConnection {
optionalConstraints: nil)
}
func offer(_ completion: @escaping (_ sdp: RTCSessionDescription) -> Void) {
offer(for: mediaConstraints()) { (sdp, error) in
guard let sdp = sdp else {
return
func offer() async -> (RTCSessionDescription?, Error?) {
await withCheckedContinuation { cont in
offer(for: mediaConstraints()) { (sdp, error) in
self.processSDP(cont, sdp, error)
}
self.setLocalDescription(sdp, completionHandler: { (error) in
completion(sdp)
})
}
}
func answer(_ completion: @escaping (_ sdp: RTCSessionDescription) -> Void) {
answer(for: mediaConstraints()) { (sdp, error) in
guard let sdp = sdp else {
return
func answer() async -> (RTCSessionDescription?, Error?) {
await withCheckedContinuation { cont in
answer(for: mediaConstraints()) { (sdp, error) in
self.processSDP(cont, sdp, error)
}
}
}
private func processSDP(_ cont: CheckedContinuation<(RTCSessionDescription?, Error?), Never>, _ sdp: RTCSessionDescription?, _ error: Error?) {
if let sdp = sdp {
self.setLocalDescription(sdp, completionHandler: { (error) in
completion(sdp)
if let error = error {
cont.resume(returning: (nil, error))
} else {
cont.resume(returning: (sdp, nil))
}
})
} else {
cont.resume(returning: (nil, error))
}
}
}
@@ -479,6 +523,7 @@ extension WebRTCClient: RTCPeerConnectionDelegate {
default: enableSpeaker = false
}
setSpeakerEnabledAndConfigureSession(enableSpeaker)
case .connected: sendConnectedEvent(connection)
case .disconnected, .failed: endCall()
default: do {}
}
@@ -491,7 +536,9 @@ extension WebRTCClient: RTCPeerConnectionDelegate {
func peerConnection(_ connection: RTCPeerConnection, didGenerate candidate: WebRTC.RTCIceCandidate) {
// logger.debug("Connection generated candidate \(candidate.debugDescription)")
activeCall.wrappedValue?.iceCandidates.append(candidate.toCandidate(nil, nil, nil))
Task {
await self.activeCall.wrappedValue?.iceCandidates.append(candidate.toCandidate(nil, nil))
}
}
func peerConnection(_ connection: RTCPeerConnection, didRemove candidates: [WebRTC.RTCIceCandidate]) {
@@ -506,10 +553,9 @@ extension WebRTCClient: RTCPeerConnectionDelegate {
lastReceivedMs lastDataReceivedMs: Int32,
changeReason reason: String) {
// logger.debug("Connection changed candidate \(reason) \(remote.debugDescription) \(remote.description)")
sendConnectedEvent(connection, local: local, remote: remote)
}
func sendConnectedEvent(_ connection: WebRTC.RTCPeerConnection, local: WebRTC.RTCIceCandidate, remote: WebRTC.RTCIceCandidate) {
func sendConnectedEvent(_ connection: WebRTC.RTCPeerConnection) {
connection.statistics { (stats: RTCStatisticsReport) in
stats.statistics.values.forEach { stat in
// logger.debug("Stat \(stat.debugDescription)")
@@ -517,24 +563,25 @@ extension WebRTCClient: RTCPeerConnectionDelegate {
let localId = stat.values["localCandidateId"] as? String,
let remoteId = stat.values["remoteCandidateId"] as? String,
let localStats = stats.statistics[localId],
let remoteStats = stats.statistics[remoteId],
local.sdp.contains("\((localStats.values["ip"] as? String ?? "--")) \((localStats.values["port"] as? String ?? "--"))") &&
remote.sdp.contains("\((remoteStats.values["ip"] as? String ?? "--")) \((remoteStats.values["port"] as? String ?? "--"))")
let remoteStats = stats.statistics[remoteId]
{
Task {
await self.sendCallResponse(.init(
corrId: nil,
resp: .connected(connectionInfo: ConnectionInfo(
localCandidate: local.toCandidate(
RTCIceCandidateType.init(rawValue: localStats.values["candidateType"] as! String),
localStats.values["protocol"] as? String,
localStats.values["relayProtocol"] as? String
localCandidate: RTCIceCandidate(
candidateType: RTCIceCandidateType.init(rawValue: localStats.values["candidateType"] as! String),
protocol: localStats.values["protocol"] as? String,
sdpMid: nil,
sdpMLineIndex: nil,
candidate: ""
),
remoteCandidate: remote.toCandidate(
RTCIceCandidateType.init(rawValue: remoteStats.values["candidateType"] as! String),
remoteStats.values["protocol"] as? String,
remoteStats.values["relayProtocol"] as? String
))),
remoteCandidate: RTCIceCandidate(
candidateType: RTCIceCandidateType.init(rawValue: remoteStats.values["candidateType"] as! String),
protocol: remoteStats.values["protocol"] as? String,
sdpMid: nil,
sdpMLineIndex: nil,
candidate: ""))),
command: nil)
)
}
@@ -558,9 +605,23 @@ extension WebRTCClient {
self.rtcAudioSession.unlockForConfiguration()
}
do {
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue)
try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)
try self.rtcAudioSession.overrideOutputAudioPort(enabled ? .speaker : .none)
let hasExternalAudioDevice = self.rtcAudioSession.session.hasExternalAudioDevice()
if enabled {
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue, with: [.defaultToSpeaker, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
try self.rtcAudioSession.setMode(AVAudioSession.Mode.videoChat.rawValue)
if hasExternalAudioDevice, let preferred = self.rtcAudioSession.session.preferredInputDevice() {
try self.rtcAudioSession.setPreferredInput(preferred)
} else {
try self.rtcAudioSession.overrideOutputAudioPort(.speaker)
}
} else {
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue, with: [.allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)
try self.rtcAudioSession.overrideOutputAudioPort(.none)
}
if hasExternalAudioDevice {
logger.debug("WebRTCClient: configuring session with external device available, skip configuring speaker")
}
try self.rtcAudioSession.setActive(true)
logger.debug("WebRTCClient: configuring session with speaker enabled \(enabled) success")
} catch let error {
@@ -611,6 +672,17 @@ extension WebRTCClient {
}
}
extension AVAudioSession {
func hasExternalAudioDevice() -> Bool {
availableInputs?.allSatisfy({ $0.portType == .builtInMic }) != true
}
func preferredInputDevice() -> AVAudioSessionPortDescription? {
// logger.debug("Preferred input device: \(String(describing: self.availableInputs?.filter({ $0.portType != .builtInMic })))")
return availableInputs?.filter({ $0.portType != .builtInMic }).last
}
}
struct CustomRTCSessionDescription: Codable {
public var type: RTCSdpType?
public var sdp: String?
@@ -634,11 +706,10 @@ extension RTCIceCandidate {
}
extension WebRTC.RTCIceCandidate {
func toCandidate(_ candidateType: RTCIceCandidateType?, _ protocol: String?, _ relayProtocol: String?) -> RTCIceCandidate {
func toCandidate(_ candidateType: RTCIceCandidateType?, _ protocol: String?) -> RTCIceCandidate {
RTCIceCandidate(
candidateType: candidateType,
protocol: `protocol`,
relayProtocol: relayProtocol,
sdpMid: sdpMid,
sdpMLineIndex: Int(sdpMLineIndex),
candidate: sdp
@@ -9,10 +9,9 @@
import SwiftUI
import SimpleXChat
let chatImageColorLight = Color(red: 0.9, green: 0.9, blue: 0.9)
let chatImageColorDark = Color(red: 0.2, green: 0.2, blue: 0.2)
struct ChatInfoToolbar: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var theme: AppTheme
@ObservedObject var chat: Chat
var imageSize: CGFloat = 32
@@ -25,30 +24,30 @@ struct ChatInfoToolbar: View {
}
ChatInfoImage(
chat: chat,
color: colorScheme == .dark
? chatImageColorDark
: chatImageColorLight
size: imageSize,
color: Color(uiColor: .tertiaryLabel)
)
.frame(width: imageSize, height: imageSize)
.padding(.trailing, 4)
VStack {
let t = Text(cInfo.displayName).font(.headline)
(cInfo.contact?.verified == true ? contactVerifiedShield + t : t)
.lineLimit(1)
if cInfo.fullName != "" && cInfo.displayName != cInfo.fullName {
Text(cInfo.fullName).font(.subheadline)
.lineLimit(1)
let t = Text(cInfo.displayName).font(.headline)
(cInfo.contact?.verified == true ? contactVerifiedShield + t : t)
.lineLimit(1)
.if (cInfo.fullName != "" && cInfo.displayName != cInfo.fullName) { v in
VStack(spacing: 0) {
v
Text(cInfo.fullName).font(.subheadline)
.lineLimit(1)
.padding(.top, -2)
}
}
}
}
.foregroundColor(.primary)
.foregroundColor(theme.colors.onBackground)
.frame(width: 220)
}
private var contactVerifiedShield: Text {
(Text(Image(systemName: "checkmark.shield")) + Text(" "))
.font(.caption)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
.baselineOffset(1)
.kerning(-2)
}
@@ -57,5 +56,6 @@ struct ChatInfoToolbar: View {
struct ChatInfoToolbar_Previews: PreviewProvider {
static var previews: some View {
ChatInfoToolbar(chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []))
.environmentObject(CurrentColors.toAppTheme())
}
}
File diff suppressed because it is too large Load Diff
@@ -9,6 +9,7 @@ import SwiftUI
class AnimatedImageView: UIView {
var image: UIImage? = nil
var imageView: UIImageView? = nil
var cMode: UIView.ContentMode = .scaleAspectFit
override init(frame: CGRect) {
super.init(frame: frame)
@@ -18,11 +19,12 @@ class AnimatedImageView: UIView {
fatalError("Not implemented")
}
convenience init(image: UIImage) {
convenience init(image: UIImage, contentMode: UIView.ContentMode) {
self.init()
self.image = image
self.cMode = contentMode
imageView = UIImageView(gifImage: image)
imageView!.contentMode = .scaleAspectFit
imageView!.contentMode = contentMode
self.addSubview(imageView!)
}
@@ -35,7 +37,7 @@ class AnimatedImageView: UIView {
if let subview = self.subviews.first as? UIImageView {
if image.imageData != subview.gifImage?.imageData {
imageView = UIImageView(gifImage: image)
imageView!.contentMode = .scaleAspectFit
imageView!.contentMode = contentMode
self.addSubview(imageView!)
subview.removeFromSuperview()
}
@@ -47,13 +49,15 @@ class AnimatedImageView: UIView {
struct SwiftyGif: UIViewRepresentable {
private let image: UIImage
private let contentMode: UIView.ContentMode
init(image: UIImage) {
init(image: UIImage, contentMode: UIView.ContentMode = .scaleAspectFit) {
self.image = image
self.contentMode = contentMode
}
func makeUIView(context: Context) -> AnimatedImageView {
AnimatedImageView(image: image)
AnimatedImageView(image: image, contentMode: contentMode)
}
func updateUIView(_ imageView: AnimatedImageView, context: Context) {
@@ -11,7 +11,8 @@ import SimpleXChat
struct CICallItemView: View {
@EnvironmentObject var m: ChatModel
var chatInfo: ChatInfo
@EnvironmentObject var theme: AppTheme
@ObservedObject var chat: Chat
var chatItem: ChatItem
var status: CICallStatus
var duration: Int
@@ -22,7 +23,7 @@ struct CICallItemView: View {
switch status {
case .pending:
if sent {
Image(systemName: "phone.arrow.up.right").foregroundColor(.secondary)
Image(systemName: "phone.arrow.up.right").foregroundColor(theme.colors.secondary)
} else {
acceptCallButton()
}
@@ -35,9 +36,7 @@ struct CICallItemView: View {
case .error: missedCallIcon(sent).foregroundColor(.orange)
}
chatItem.timestampText
.font(.caption)
.foregroundColor(.secondary)
CIMetaView(chat: chat, chatItem: chatItem, metaColor: theme.colors.secondary, showStatus: false, showEdited: false)
.padding(.bottom, 8)
.padding(.horizontal, 12)
}
@@ -54,13 +53,13 @@ struct CICallItemView: View {
@ViewBuilder private func endedCallIcon(_ sent: Bool) -> some View {
HStack {
Image(systemName: "phone.down")
Text(durationText(duration)).foregroundColor(.secondary)
Text(durationText(duration)).foregroundColor(theme.colors.secondary)
}
}
@ViewBuilder private func acceptCallButton() -> some View {
if case let .direct(contact) = chatInfo {
if case let .direct(contact) = chat.chatInfo {
Button {
if let invitation = m.callInvitations[contact.id] {
CallController.shared.answerCall(invitation: invitation)
@@ -72,7 +71,7 @@ struct CICallItemView: View {
Label("Answer call", systemImage: "phone.arrow.down.left")
}
} else {
Image(systemName: "phone.arrow.down.left").foregroundColor(.secondary)
Image(systemName: "phone.arrow.down.left").foregroundColor(theme.colors.secondary)
}
}
}
@@ -10,20 +10,95 @@ import SwiftUI
import SimpleXChat
struct CIChatFeatureView: View {
@EnvironmentObject var m: ChatModel
@ObservedObject var im = ItemsModel.shared
@ObservedObject var chat: Chat
@EnvironmentObject var theme: AppTheme
var chatItem: ChatItem
@Binding var revealed: Bool
var feature: Feature
var icon: String? = nil
var iconColor: Color
var body: some View {
if !revealed, let fs = mergedFeatures() {
HStack {
ForEach(fs, content: featureIconView)
}
.padding(.horizontal, 6)
.padding(.vertical, 6)
} else {
fullFeatureView
}
}
private struct FeatureInfo: Identifiable {
var icon: String
var scale: CGFloat
var color: Color
var param: String?
init(_ f: Feature, _ color: Color, _ param: Int?) {
self.icon = f.iconFilled
self.scale = f.iconScale
self.color = color
self.param = f.hasParam && param != nil ? timeText(param) : nil
}
var id: String {
"\(icon) \(color) \(param ?? "")"
}
}
private func mergedFeatures() -> [FeatureInfo]? {
var fs: [FeatureInfo] = []
var icons: Set<String> = []
if var i = m.getChatItemIndex(chatItem) {
while i < im.reversedChatItems.count,
let f = featureInfo(im.reversedChatItems[i]) {
if !icons.contains(f.icon) {
fs.insert(f, at: 0)
icons.insert(f.icon)
}
i += 1
}
}
return fs.count > 1 ? fs : nil
}
private func featureInfo(_ ci: ChatItem) -> FeatureInfo? {
switch ci.content {
case let .rcvChatFeature(feature, enabled, param): FeatureInfo(feature, enabled.iconColor(theme.colors.secondary), param)
case let .sndChatFeature(feature, enabled, param): FeatureInfo(feature, enabled.iconColor(theme.colors.secondary), param)
case let .rcvGroupFeature(feature, preference, param, role): FeatureInfo(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor(theme.colors.secondary), param)
case let .sndGroupFeature(feature, preference, param, role): FeatureInfo(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor(theme.colors.secondary), param)
default: nil
}
}
@ViewBuilder private func featureIconView(_ f: FeatureInfo) -> some View {
let i = Image(systemName: f.icon)
.foregroundColor(f.color)
.scaleEffect(f.scale)
if let param = f.param {
HStack {
i
chatEventText(Text(param), theme.colors.secondary).lineLimit(1)
}
} else {
i
}
}
private var fullFeatureView: some View {
HStack(alignment: .bottom, spacing: 4) {
Image(systemName: icon ?? feature.iconFilled)
.foregroundColor(iconColor)
.scaleEffect(feature.iconScale)
chatEventText(chatItem)
chatEventText(chatItem, theme.colors.secondary)
}
.padding(.leading, 6)
.padding(.bottom, 6)
.padding(.horizontal, 6)
.padding(.vertical, 4)
.textSelection(.disabled)
}
}
@@ -31,6 +106,6 @@ struct CIChatFeatureView: View {
struct CIChatFeatureView_Previews: PreviewProvider {
static var previews: some View {
let enabled = FeatureEnabled(forUser: false, forContact: false)
CIChatFeatureView(chatItem: ChatItem.getChatFeatureSample(.fullDelete, enabled), feature: ChatFeature.fullDelete, iconColor: enabled.iconColor)
CIChatFeatureView(chat: Chat.sampleData, chatItem: ChatItem.getChatFeatureSample(.fullDelete, enabled), revealed: Binding.constant(true), feature: ChatFeature.fullDelete, iconColor: enabled.iconColor(.secondary))
}
}
@@ -10,41 +10,19 @@ import SwiftUI
import SimpleXChat
struct CIEventView: View {
var chatItem: ChatItem
var eventText: Text
var body: some View {
HStack(alignment: .bottom, spacing: 0) {
if let member = chatItem.memberDisplayName {
Text(member)
.font(.caption)
.foregroundColor(.secondary)
.fontWeight(.light)
+ Text(" ")
+ chatEventText(chatItem)
} else {
chatEventText(chatItem)
}
}
.padding(.leading, 6)
.padding(.bottom, 6)
eventText
.padding(.horizontal, 6)
.padding(.vertical, 4)
.textSelection(.disabled)
.lineLimit(4)
}
}
func chatEventText(_ ci: ChatItem) -> Text {
Text(ci.content.text)
.font(.caption)
.foregroundColor(.secondary)
.fontWeight(.light)
+ Text(" ")
+ ci.timestampText
.font(.caption)
.foregroundColor(Color.secondary)
.fontWeight(.light)
}
struct CIEventView_Previews: PreviewProvider {
static var previews: some View {
CIEventView(chatItem: ChatItem.getGroupEventSample())
CIEventView(eventText: Text("event happened"))
}
}
@@ -10,7 +10,8 @@ import SwiftUI
import SimpleXChat
struct CIFeaturePreferenceView: View {
@EnvironmentObject var chat: Chat
@ObservedObject var chat: Chat
@EnvironmentObject var theme: AppTheme
var chatItem: ChatItem
var feature: ChatFeature
var allowed: FeatureAllowed
@@ -19,7 +20,7 @@ struct CIFeaturePreferenceView: View {
var body: some View {
HStack(alignment: .center, spacing: 4) {
Image(systemName: feature.icon)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
.scaleEffect(feature.iconScale)
if let ct = chat.chatInfo.contact,
allowed != .no && ct.allowsFeature(feature) && !ct.userAllowsFeature(feature) {
@@ -40,17 +41,17 @@ struct CIFeaturePreferenceView: View {
private func featurePreferenceView(acceptText: LocalizedStringKey? = nil) -> some View {
var r = Text(CIContent.preferenceText(feature, allowed, param) + " ")
.fontWeight(.light)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
if let acceptText {
r = r
+ Text(acceptText)
.fontWeight(.medium)
.foregroundColor(.accentColor)
.foregroundColor(theme.colors.primary)
+ Text(" ")
}
r = r + chatItem.timestampText
.fontWeight(.light)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
return r.font(.caption)
}
}
@@ -80,7 +81,6 @@ struct CIFeaturePreferenceView_Previews: PreviewProvider {
quotedItem: nil,
file: nil
)
CIFeaturePreferenceView(chatItem: chatItem, feature: ChatFeature.timedMessages, allowed: .yes, param: 30)
.environmentObject(Chat.sampleData)
CIFeaturePreferenceView(chat: Chat.sampleData, chatItem: chatItem, feature: ChatFeature.timedMessages, allowed: .yes, param: 30)
}
}
@@ -10,80 +10,83 @@ import SwiftUI
import SimpleXChat
struct CIFileView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var m: ChatModel
@EnvironmentObject var theme: AppTheme
let file: CIFile?
let edited: Bool
var smallViewSize: CGFloat?
var body: some View {
let metaReserve = edited
? " "
: " "
Button(action: fileAction) {
HStack(alignment: .bottom, spacing: 6) {
fileIndicator()
.padding(.top, 5)
.padding(.bottom, 3)
if let file = file {
let prettyFileSize = ByteCountFormatter.string(fromByteCount: file.fileSize, countStyle: .binary)
VStack(alignment: .leading, spacing: 2) {
Text(file.fileName)
.lineLimit(1)
.multilineTextAlignment(.leading)
.foregroundColor(.primary)
Text(prettyFileSize + metaReserve)
.font(.caption)
.lineLimit(1)
.multilineTextAlignment(.leading)
.foregroundColor(.secondary)
if smallViewSize != nil {
fileIndicator()
.onTapGesture(perform: fileAction)
} else {
let metaReserve = edited
? " "
: " "
Button(action: fileAction) {
HStack(alignment: .bottom, spacing: 6) {
fileIndicator()
.padding(.top, 5)
.padding(.bottom, 3)
if let file = file {
let prettyFileSize = ByteCountFormatter.string(fromByteCount: file.fileSize, countStyle: .binary)
VStack(alignment: .leading, spacing: 2) {
Text(file.fileName)
.lineLimit(1)
.multilineTextAlignment(.leading)
.foregroundColor(theme.colors.onBackground)
Text(prettyFileSize + metaReserve)
.font(.caption)
.lineLimit(1)
.multilineTextAlignment(.leading)
.foregroundColor(theme.colors.secondary)
}
} else {
Text(metaReserve)
}
} else {
Text(metaReserve)
}
.padding(.top, 4)
.padding(.bottom, 6)
.padding(.leading, 10)
.padding(.trailing, 12)
}
.padding(.top, 4)
.padding(.bottom, 6)
.padding(.leading, 10)
.padding(.trailing, 12)
.disabled(!itemInteractive)
}
.disabled(!itemInteractive)
}
private var itemInteractive: Bool {
if let file = file {
switch (file.fileStatus) {
case .sndStored: return false
case .sndStored: return file.fileProtocol == .local
case .sndTransfer: return false
case .sndComplete: return false
case .sndComplete: return true
case .sndCancelled: return false
case .sndError: return false
case .sndError: return true
case .sndWarning: return true
case .rcvInvitation: return true
case .rcvAccepted: return true
case .rcvTransfer: return false
case .rcvAborted: return true
case .rcvComplete: return true
case .rcvCancelled: return false
case .rcvError: return false
case .rcvError: return true
case .rcvWarning: return true
case .invalid: return false
}
}
return false
}
private func fileSizeValid() -> Bool {
if let file = file {
return file.fileSize <= getMaxFileSize(file.fileProtocol)
}
return false
}
private func fileAction() {
logger.debug("CIFileView fileAction")
if let file = file {
switch (file.fileStatus) {
case .rcvInvitation:
if fileSizeValid() {
case .rcvInvitation, .rcvAborted:
if fileSizeValid(file) {
Task {
logger.debug("CIFileView fileAction - in .rcvInvitation, in Task")
if let user = ChatModel.shared.currentUser {
logger.debug("CIFileView fileAction - in .rcvInvitation, .rcvAborted, in Task")
if let user = m.currentUser {
await receiveFile(user: user, fileId: file.fileId)
}
}
@@ -106,13 +109,47 @@ struct CIFileView: View {
title: "Waiting for file",
message: "File will be received when your contact is online, please wait or check later!"
)
case .local: ()
}
case .rcvComplete:
logger.debug("CIFileView fileAction - in .rcvComplete")
if let filePath = getLoadedFilePath(file) {
let url = URL(fileURLWithPath: filePath)
showShareSheet(items: [url])
if let fileSource = getLoadedFileSource(file) {
saveCryptoFile(fileSource)
}
case let .rcvError(rcvFileError):
logger.debug("CIFileView fileAction - in .rcvError")
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(rcvFileError.errorInfo)
))
case let .rcvWarning(rcvFileError):
logger.debug("CIFileView fileAction - in .rcvWarning")
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(rcvFileError.errorInfo)
))
case .sndStored:
logger.debug("CIFileView fileAction - in .sndStored")
if file.fileProtocol == .local, let fileSource = getLoadedFileSource(file) {
saveCryptoFile(fileSource)
}
case .sndComplete:
logger.debug("CIFileView fileAction - in .sndComplete")
if let fileSource = getLoadedFileSource(file) {
saveCryptoFile(fileSource)
}
case let .sndError(sndFileError):
logger.debug("CIFileView fileAction - in .sndError")
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(sndFileError.errorInfo)
))
case let .sndWarning(sndFileError):
logger.debug("CIFileView fileAction - in .sndWarning")
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(sndFileError.errorInfo)
))
default: break
}
}
@@ -125,18 +162,21 @@ struct CIFileView: View {
switch file.fileProtocol {
case .xftp: progressView()
case .smp: fileIcon("doc.fill")
case .local: fileIcon("doc.fill")
}
case let .sndTransfer(sndProgress, sndTotal):
switch file.fileProtocol {
case .xftp: progressCircle(sndProgress, sndTotal)
case .smp: progressView()
case .local: EmptyView()
}
case .sndComplete: fileIcon("doc.fill", innerIcon: "checkmark", innerIconSize: 10)
case .sndCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .sndError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .sndWarning: fileIcon("doc.fill", innerIcon: "exclamationmark.triangle.fill", innerIconSize: 10)
case .rcvInvitation:
if fileSizeValid() {
fileIcon("arrow.down.doc.fill", color: .accentColor)
if fileSizeValid(file) {
fileIcon("arrow.down.doc.fill", color: theme.colors.primary)
} else {
fileIcon("doc.fill", color: .orange, innerIcon: "exclamationmark", innerIconSize: 12)
}
@@ -147,9 +187,12 @@ struct CIFileView: View {
} else {
progressView()
}
case .rcvAborted:
fileIcon("doc.fill", color: theme.colors.primary, innerIcon: "exclamationmark.arrow.circlepath", innerIconSize: 12)
case .rcvComplete: fileIcon("doc.fill")
case .rcvCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .rcvError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .rcvWarning: fileIcon("doc.fill", innerIcon: "exclamationmark.triangle.fill", innerIconSize: 10)
case .invalid: fileIcon("doc.fill", innerIcon: "questionmark", innerIconSize: 10)
}
} else {
@@ -158,21 +201,22 @@ struct CIFileView: View {
}
private func fileIcon(_ icon: String, color: Color = Color(uiColor: .tertiaryLabel), innerIcon: String? = nil, innerIconSize: CGFloat? = nil) -> some View {
ZStack(alignment: .center) {
let size = smallViewSize ?? 30
return ZStack(alignment: .center) {
Image(systemName: icon)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30)
.frame(width: size, height: size)
.foregroundColor(color)
if let innerIcon = innerIcon,
let innerIconSize = innerIconSize {
let innerIconSize = innerIconSize, (smallViewSize == nil || file?.showStatusIconInSmallView == true) {
Image(systemName: innerIcon)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxHeight: 16)
.frame(width: innerIconSize, height: innerIconSize)
.foregroundColor(.white)
.padding(.top, 12)
.padding(.top, size / 2.5)
}
}
}
@@ -193,11 +237,42 @@ struct CIFileView: View {
}
}
func fileSizeValid(_ file: CIFile?) -> Bool {
if let file = file {
return file.fileSize <= getMaxFileSize(file.fileProtocol)
}
return false
}
func saveCryptoFile(_ fileSource: CryptoFile) {
if let cfArgs = fileSource.cryptoArgs {
let url = getAppFilePath(fileSource.filePath)
let tempUrl = getTempFilesDirectory().appendingPathComponent(fileSource.filePath)
Task {
do {
try decryptCryptoFile(fromPath: url.path, cryptoArgs: cfArgs, toPath: tempUrl.path)
await MainActor.run {
showShareSheet(items: [tempUrl]) {
removeFile(tempUrl)
}
}
} catch {
await MainActor.run {
AlertManager.shared.showAlertMsg(title: "Error decrypting file", message: "Error: \(error.localizedDescription)")
}
}
}
} else {
let url = getAppFilePath(fileSource.filePath)
showShareSheet(items: [url])
}
}
struct CIFileView_Previews: PreviewProvider {
static var previews: some View {
let sentFile: ChatItem = ChatItem(
chatDir: .directSnd,
meta: CIMeta.getSample(1, .now, "", .sndSent, itemEdited: true),
meta: CIMeta.getSample(1, .now, "", .sndSent(sndProgress: .complete), itemEdited: true),
content: .sndMsgContent(msgContent: .file("")),
quotedItem: nil,
file: CIFile.getSample(fileStatus: .sndComplete)
@@ -210,18 +285,17 @@ struct CIFileView_Previews: PreviewProvider {
file: nil
)
Group {
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: sentFile, revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getFileMsgContentSample(), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getFileMsgContentSample(fileName: "some_long_file_name_here", fileStatus: .rcvInvitation), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvAccepted), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvCancelled), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getFileMsgContentSample(fileSize: 1_000_000_000, fileStatus: .rcvInvitation), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getFileMsgContentSample(text: "Hello there", fileStatus: .rcvInvitation), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, 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), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: fileChatItemWtFile, revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: sentFile, revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileName: "some_long_file_name_here", fileStatus: .rcvInvitation), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvAccepted), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileStatus: .rcvCancelled), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(fileSize: 1_000_000_000, fileStatus: .rcvInvitation), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getFileMsgContentSample(text: "Hello there", fileStatus: .rcvInvitation), revealed: Binding.constant(false))
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), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: fileChatItemWtFile, revealed: Binding.constant(false))
}
.previewLayout(.fixed(width: 360, height: 360))
.environmentObject(Chat.sampleData)
}
}
@@ -11,55 +11,85 @@ import SimpleXChat
struct CIGroupInvitationView: View {
@EnvironmentObject var chatModel: ChatModel
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var theme: AppTheme
@ObservedObject var chat: Chat
var chatItem: ChatItem
var groupInvitation: CIGroupInvitation
var memberRole: GroupMemberRole
var chatIncognito: Bool = false
@State private var frameWidth: CGFloat = 0
@State private var inProgress = false
@State private var progressByTimeout = false
@AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = false
var body: some View {
let action = !chatItem.chatDir.sent && groupInvitation.status == .pending
let v = ZStack(alignment: .bottomTrailing) {
VStack(alignment: .leading) {
groupInfoView(action)
.padding(.horizontal, 2)
.padding(.top, 8)
.padding(.bottom, 6)
.overlay(DetermineWidth())
ZStack {
VStack(alignment: .leading) {
groupInfoView(action)
.padding(.horizontal, 2)
.padding(.top, 8)
.padding(.bottom, 6)
.overlay(DetermineWidth())
Divider().frame(width: frameWidth)
Divider().frame(width: frameWidth)
if action {
groupInvitationText()
.overlay(DetermineWidth())
Text(chatIncognito ? "Tap to join incognito" : "Tap to join")
.foregroundColor(chatIncognito ? .indigo : .accentColor)
.font(.callout)
.padding(.trailing, 60)
.overlay(DetermineWidth())
} else {
groupInvitationText()
.padding(.trailing, 60)
if action {
VStack(alignment: .leading, spacing: 2) {
groupInvitationText()
.overlay(DetermineWidth())
(
Text(chatIncognito ? "Tap to join incognito" : "Tap to join")
.foregroundColor(inProgress ? theme.colors.secondary : chatIncognito ? .indigo : theme.colors.primary)
.font(.callout)
+ Text(" ")
+ ciMetaText(chatItem.meta, chatTTL: nil, encrypted: nil, transparent: true, showStatus: false, showEdited: false, showViaProxy: showSentViaProxy)
)
.overlay(DetermineWidth())
}
} else {
(
groupInvitationText()
+ Text(" ")
+ ciMetaText(chatItem.meta, chatTTL: nil, encrypted: nil, transparent: true, showStatus: false, showEdited: false, showViaProxy: showSentViaProxy)
)
.overlay(DetermineWidth())
}
}
.padding(.bottom, 2)
if progressByTimeout {
ProgressView().scaleEffect(2)
}
}
.padding(.bottom, 2)
chatItem.timestampText
.font(.caption)
.foregroundColor(.secondary)
CIMetaView(chat: chat, chatItem: chatItem, metaColor: theme.colors.secondary, showStatus: false, showEdited: false)
}
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(chatItemFrameColor(chatItem, colorScheme))
.cornerRadius(18)
.background(chatItemFrameColor(chatItem, theme))
.textSelection(.disabled)
.onPreferenceChange(DetermineWidth.Key.self) { frameWidth = $0 }
.onChange(of: inProgress) { inProgress in
if inProgress {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
progressByTimeout = inProgress
}
} else {
progressByTimeout = false
}
}
if action {
v.onTapGesture {
joinGroup(groupInvitation.groupId)
inProgress = true
joinGroup(groupInvitation.groupId) {
await MainActor.run { inProgress = false }
}
}
.disabled(inProgress)
} else {
v
}
@@ -67,8 +97,8 @@ struct CIGroupInvitationView: View {
private func groupInfoView(_ action: Bool) -> some View {
var color: Color
if action {
color = chatIncognito ? .indigo : .accentColor
if action && !inProgress {
color = chatIncognito ? .indigo : theme.colors.primary
} else {
color = Color(uiColor: .tertiaryLabel)
}
@@ -76,9 +106,9 @@ struct CIGroupInvitationView: View {
ProfileImage(
imageStr: groupInvitation.groupProfile.image,
iconName: "person.2.circle.fill",
size: 44,
color: color
)
.frame(width: 44, height: 44)
.padding(.trailing, 4)
VStack(alignment: .leading) {
let p = groupInvitation.groupProfile
@@ -91,7 +121,7 @@ struct CIGroupInvitationView: View {
}
}
private func groupInvitationText() -> some View {
private func groupInvitationText() -> Text {
Text(groupInvitationStr())
.font(.callout)
}
@@ -113,8 +143,8 @@ struct CIGroupInvitationView: View {
struct CIGroupInvitationView_Previews: PreviewProvider {
static var previews: some View {
Group {
CIGroupInvitationView(chatItem: ChatItem.getGroupInvitationSample(), groupInvitation: CIGroupInvitation.getSample(groupProfile: GroupProfile(displayName: "team", fullName: "team")), memberRole: .admin)
CIGroupInvitationView(chatItem: ChatItem.getGroupInvitationSample(), groupInvitation: CIGroupInvitation.getSample(status: .accepted), memberRole: .admin)
CIGroupInvitationView(chat: Chat.sampleData, chatItem: ChatItem.getGroupInvitationSample(), groupInvitation: CIGroupInvitation.getSample(groupProfile: GroupProfile(displayName: "team", fullName: "team")), memberRole: .admin)
CIGroupInvitationView(chat: Chat.sampleData, chatItem: ChatItem.getGroupInvitationSample(), groupInvitation: CIGroupInvitation.getSample(status: .accepted), memberRole: .admin)
}
}
}
@@ -10,35 +10,46 @@ import SwiftUI
import SimpleXChat
struct CIImageView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var m: ChatModel
let chatItem: ChatItem
let image: String
var preview: UIImage?
let maxWidth: CGFloat
@Binding var imgWidth: CGFloat?
@State var scrollProxy: ScrollViewProxy?
@State private var showFullScreenImage = false
var imgWidth: CGFloat?
var smallView: Bool = false
@Binding var showFullScreenImage: Bool
@State private var blurred: Bool = UserDefaults.standard.integer(forKey: DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS) > 0
var body: some View {
let file = chatItem.file
VStack(alignment: .center, spacing: 6) {
if let uiImage = getLoadedImage(file) {
imageView(uiImage)
Group { if smallView { smallViewImageView(uiImage) } else { imageView(uiImage) } }
.fullScreenCover(isPresented: $showFullScreenImage) {
FullScreenMediaView(chatItem: chatItem, image: uiImage, showView: $showFullScreenImage, scrollProxy: scrollProxy)
FullScreenMediaView(chatItem: chatItem, image: uiImage, showView: $showFullScreenImage)
}
.if(!smallView) { view in
view.modifier(PrivacyBlur(blurred: $blurred))
}
.onTapGesture { showFullScreenImage = true }
} else if let data = Data(base64Encoded: dropImagePrefix(image)),
let uiImage = UIImage(data: data) {
imageView(uiImage)
.onChange(of: m.activeCallViewIsCollapsed) { _ in
showFullScreenImage = false
}
} else if let preview {
Group {
if smallView {
smallViewImageView(preview)
} else {
imageView(preview).modifier(PrivacyBlur(blurred: $blurred))
}
}
.onTapGesture {
if let file = file {
switch file.fileStatus {
case .rcvInvitation:
case .rcvInvitation, .rcvAborted:
Task {
if let user = ChatModel.shared.currentUser {
if let user = m.currentUser {
await receiveFile(user: user, fileId: file.fileId)
}
// TODO image accepted alert?
}
case .rcvAccepted:
switch file.fileProtocol {
@@ -52,33 +63,75 @@ struct CIImageView: View {
title: "Waiting for image",
message: "Image will be received when your contact is online, please wait or check later!"
)
case .local: ()
}
case .rcvTransfer: () // ?
case .rcvComplete: () // ?
case .rcvCancelled: () // TODO
case let .rcvError(rcvFileError):
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(rcvFileError.errorInfo)
))
case let .rcvWarning(rcvFileError):
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(rcvFileError.errorInfo)
))
case let .sndError(sndFileError):
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(sndFileError.errorInfo)
))
case let .sndWarning(sndFileError):
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(sndFileError.errorInfo)
))
default: ()
}
}
}
}
}
.onDisappear {
showFullScreenImage = false
}
}
private func imageView(_ img: UIImage) -> some View {
let w = img.size.width <= img.size.height ? maxWidth * 0.75 : img.imageData == nil ? .infinity : maxWidth
DispatchQueue.main.async { imgWidth = w }
let w = img.size.width <= img.size.height ? maxWidth * 0.75 : maxWidth
return ZStack(alignment: .topTrailing) {
if img.imageData == nil {
Image(uiImage: img)
.resizable()
.scaledToFit()
.frame(maxWidth: w)
.frame(width: w)
} else {
SwiftyGif(image: img)
.frame(width: w, height: w * img.size.height / img.size.width)
.scaledToFit()
}
loadingIndicator()
if !blurred || !showDownloadButton(chatItem.file?.fileStatus) {
loadingIndicator()
}
}
}
private func smallViewImageView(_ img: UIImage) -> some View {
ZStack(alignment: .topTrailing) {
if img.imageData == nil {
Image(uiImage: img)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: maxWidth, height: maxWidth)
} else {
SwiftyGif(image: img, contentMode: .scaleAspectFill)
.frame(width: maxWidth, height: maxWidth)
}
if chatItem.file?.showStatusIconInSmallView == true {
loadingIndicator()
}
}
}
@@ -89,18 +142,22 @@ struct CIImageView: View {
switch file.fileProtocol {
case .xftp: progressView()
case .smp: EmptyView()
case .local: EmptyView()
}
case .sndTransfer: progressView()
case .sndComplete: fileIcon("checkmark", 10, 13)
case .sndCancelled: fileIcon("xmark", 10, 13)
case .sndError: fileIcon("xmark", 10, 13)
case .sndWarning: fileIcon("exclamationmark.triangle.fill", 10, 13)
case .rcvInvitation: fileIcon("arrow.down", 10, 13)
case .rcvAccepted: fileIcon("ellipsis", 14, 11)
case .rcvTransfer: progressView()
case .rcvAborted: fileIcon("exclamationmark.arrow.circlepath", 14, 11)
case .rcvComplete: EmptyView()
case .rcvCancelled: fileIcon("xmark", 10, 13)
case .rcvError: fileIcon("xmark", 10, 13)
case .rcvWarning: fileIcon("exclamationmark.triangle.fill", 10, 13)
case .invalid: fileIcon("questionmark", 10, 13)
default: EmptyView()
}
}
}
@@ -121,4 +178,12 @@ struct CIImageView: View {
.tint(.white)
.padding(8)
}
private func showDownloadButton(_ fileStatus: CIFileStatus?) -> Bool {
switch fileStatus {
case .rcvInvitation: true
case .rcvAborted: true
default: false
}
}
}
@@ -9,6 +9,7 @@
import SwiftUI
struct CIInvalidJSONView: View {
@EnvironmentObject var theme: AppTheme
var json: String
@State private var showJSON = false
@@ -21,10 +22,9 @@ struct CIInvalidJSONView: View {
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(Color(uiColor: .tertiarySystemGroupedBackground))
.cornerRadius(18)
.textSelection(.disabled)
.onTapGesture { showJSON = true }
.sheet(isPresented: $showJSON) {
.appSheet(isPresented: $showJSON) {
invalidJSONView(json)
}
}
@@ -44,6 +44,7 @@ func invalidJSONView(_ json: String) -> some View {
}
.frame(maxHeight: .infinity)
.padding()
.modifier(ThemedBackground())
}
struct CIInvalidJSONView_Previews: PreviewProvider {
@@ -10,16 +10,17 @@ import SwiftUI
import SimpleXChat
struct CILinkView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var theme: AppTheme
let linkPreview: LinkPreview
@State private var blurred: Bool = UserDefaults.standard.integer(forKey: DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS) > 0
var body: some View {
VStack(alignment: .center, spacing: 6) {
if let data = Data(base64Encoded: dropImagePrefix(linkPreview.image)),
let uiImage = UIImage(data: data) {
if let uiImage = UIImage(base64Encoded: linkPreview.image) {
Image(uiImage: uiImage)
.resizable()
.scaledToFit()
.modifier(PrivacyBlur(blurred: $blurred))
}
VStack(alignment: .leading, spacing: 6) {
Text(linkPreview.title)
@@ -32,7 +33,7 @@ struct CILinkView: View {
Text(linkPreview.uri.absoluteString)
.font(.caption)
.lineLimit(1)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
}
.padding(.horizontal, 12)
.frame(maxWidth: .infinity, alignment: .leading)
@@ -0,0 +1,81 @@
//
// CIMemberCreatedContactView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 19.09.2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct CIMemberCreatedContactView: View {
@EnvironmentObject var m: ChatModel
@EnvironmentObject var theme: AppTheme
var chatItem: ChatItem
var body: some View {
HStack(alignment: .bottom, spacing: 0) {
switch chatItem.chatDir {
case let .groupRcv(groupMember):
if let contactId = groupMember.memberContactId {
memberCreatedContactView(openText: "Open")
.onTapGesture {
dismissAllSheets(animated: true)
DispatchQueue.main.async {
m.chatId = "@\(contactId)"
}
}
} else {
memberCreatedContactView()
}
default:
EmptyView()
}
}
.padding(.leading, 6)
.padding(.bottom, 6)
.textSelection(.disabled)
}
private func memberCreatedContactView(openText: LocalizedStringKey? = nil) -> some View {
var r = eventText()
if let openText {
r = r
+ Text(openText)
.fontWeight(.medium)
.foregroundColor(theme.colors.primary)
+ Text(" ")
}
r = r + chatItem.timestampText
.fontWeight(.light)
.foregroundColor(theme.colors.secondary)
return r.font(.caption)
}
private func eventText() -> Text {
if let member = chatItem.memberDisplayName {
return Text(member + " " + chatItem.content.text + " ")
.fontWeight(.light)
.foregroundColor(theme.colors.secondary)
} else {
return Text(chatItem.content.text + " ")
.fontWeight(.light)
.foregroundColor(theme.colors.secondary)
}
}
}
struct CIMemberCreatedContactView_Previews: PreviewProvider {
static var previews: some View {
let content = CIContent.rcvGroupEvent(rcvGroupEvent: .memberCreatedContact)
let chatItem = ChatItem(
chatDir: .groupRcv(groupMember: GroupMember.sampleData),
meta: CIMeta.getSample(1, .now, content.text, .rcvRead),
content: content,
quotedItem: nil,
file: nil
)
CIMemberCreatedContactView(chatItem: chatItem)
}
}
@@ -10,9 +10,15 @@ import SwiftUI
import SimpleXChat
struct CIMetaView: View {
@EnvironmentObject var chat: Chat
@ObservedObject var chat: Chat
@EnvironmentObject var theme: AppTheme
var chatItem: ChatItem
var metaColor = Color.secondary
var metaColor: Color
var paleMetaColor = Color(UIColor.tertiaryLabel)
var showStatus = true
var showEdited = true
@AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = false
var body: some View {
if chatItem.isDeletedContent {
@@ -20,16 +26,28 @@ struct CIMetaView: View {
} else {
let meta = chatItem.meta
let ttl = chat.chatInfo.timedMessagesTTL
let encrypted = chatItem.encryptedFile
switch meta.itemStatus {
case .sndSent:
ciMetaText(meta, chatTTL: ttl, color: metaColor, sent: .sent)
case .sndRcvd:
ZStack {
ciMetaText(meta, chatTTL: ttl, color: metaColor, sent: .rcvd1)
ciMetaText(meta, chatTTL: ttl, color: metaColor, sent: .rcvd2)
case let .sndSent(sndProgress):
switch sndProgress {
case .complete: ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .sent, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
case .partial: ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .sent, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
}
case let .sndRcvd(_, sndProgress):
switch sndProgress {
case .complete:
ZStack {
ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .rcvd1, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .rcvd2, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
}
case .partial:
ZStack {
ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .rcvd1, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .rcvd2, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
}
}
default:
ciMetaText(meta, chatTTL: ttl, color: metaColor)
ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
}
}
}
@@ -41,9 +59,20 @@ enum SentCheckmark {
case rcvd2
}
func ciMetaText(_ meta: CIMeta, chatTTL: Int?, color: Color = .clear, transparent: Bool = false, sent: SentCheckmark? = nil) -> Text {
func ciMetaText(
_ meta: CIMeta,
chatTTL: Int?,
encrypted: Bool?,
color: Color = .clear,
primaryColor: Color = .accentColor,
transparent: Bool = false,
sent: SentCheckmark? = nil,
showStatus: Bool = true,
showEdited: Bool = true,
showViaProxy: Bool
) -> Text {
var r = Text("")
if meta.itemEdited {
if showEdited, meta.itemEdited {
r = r + statusIconText("pencil", color)
}
if meta.disappearing {
@@ -54,21 +83,30 @@ func ciMetaText(_ meta: CIMeta, chatTTL: Int?, color: Color = .clear, transparen
}
r = r + Text(" ")
}
if let (icon, statusColor) = meta.statusIcon(color) {
let t = Text(Image(systemName: icon)).font(.caption2)
let gap = Text(" ").kerning(-1.25)
let t1 = t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67))
switch sent {
case nil: r = r + t1
case .sent: r = r + t1 + gap
case .rcvd1: r = r + t.foregroundColor(transparent ? .clear : color.opacity(0.67)) + gap
case .rcvd2: r = r + gap + t1
}
r = r + Text(" ")
} else if !meta.disappearing {
r = r + statusIconText("circlebadge.fill", .clear) + Text(" ")
if showViaProxy, meta.sentViaProxy == true {
r = r + statusIconText("arrow.forward", color.opacity(0.67)).font(.caption2)
}
return (r + meta.timestampText.foregroundColor(color)).font(.caption)
if showStatus {
if let (icon, statusColor) = meta.statusIcon(color, primaryColor) {
let t = Text(Image(systemName: icon)).font(.caption2)
let gap = Text(" ").kerning(-1.25)
let t1 = t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67))
switch sent {
case nil: r = r + t1
case .sent: r = r + t1 + gap
case .rcvd1: r = r + t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67)) + gap
case .rcvd2: r = r + gap + t1
}
r = r + Text(" ")
} else if !meta.disappearing {
r = r + statusIconText("circlebadge.fill", .clear) + Text(" ")
}
}
if let enc = encrypted {
r = r + statusIconText(enc ? "lock" : "lock.open", color) + Text(" ")
}
r = r + meta.timestampText.foregroundColor(color)
return r.font(.caption)
}
private func statusIconText(_ icon: String, _ color: Color) -> Text {
@@ -76,13 +114,17 @@ private func statusIconText(_ icon: String, _ color: Color) -> Text {
}
struct CIMetaView_Previews: PreviewProvider {
static let metaColor = Color.secondary
static var previews: some View {
Group {
CIMetaView(chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndSent))
CIMetaView(chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndSent, itemEdited: true))
CIMetaView(chatItem: ChatItem.getDeletedContentSample())
CIMetaView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndSent(sndProgress: .complete)), metaColor: metaColor)
CIMetaView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndSent(sndProgress: .partial)), metaColor: metaColor)
CIMetaView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndRcvd(msgRcptStatus: .ok, sndProgress: .complete)), metaColor: metaColor)
CIMetaView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndRcvd(msgRcptStatus: .ok, sndProgress: .partial)), metaColor: metaColor)
CIMetaView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndRcvd(msgRcptStatus: .badMsgHash, sndProgress: .complete)), metaColor: metaColor)
CIMetaView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndSent(sndProgress: .complete), itemEdited: true), metaColor: metaColor)
CIMetaView(chat: Chat.sampleData, chatItem: ChatItem.getDeletedContentSample(), metaColor: metaColor)
}
.previewLayout(.fixed(width: 360, height: 100))
.environmentObject(Chat.sampleData)
}
}
@@ -12,19 +12,22 @@ import SimpleXChat
let decryptErrorReason: LocalizedStringKey = "It can happen when you or your connection used the old database backup."
struct CIRcvDecryptionError: View {
@EnvironmentObject var chat: Chat
@EnvironmentObject var m: ChatModel
@EnvironmentObject var theme: AppTheme
@ObservedObject var chat: Chat
var msgDecryptError: MsgDecryptError
var msgCount: UInt32
var chatItem: ChatItem
var showMember = false
@State private var alert: CIRcvDecryptionErrorAlert?
@AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = false
enum CIRcvDecryptionErrorAlert: Identifiable {
case syncAllowedAlert(_ syncConnection: () -> Void)
case syncNotSupportedContactAlert
case syncNotSupportedMemberAlert
case decryptionErrorAlert
case error(title: LocalizedStringKey, error: LocalizedStringKey)
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -46,7 +49,7 @@ struct CIRcvDecryptionError: View {
do {
let (member, stats) = try apiGroupMemberInfo(groupInfo.apiId, groupMember.groupMemberId)
if let s = stats {
ChatModel.shared.updateGroupMemberConnectionStats(groupInfo, member, s)
m.updateGroupMemberConnectionStats(groupInfo, member, s)
}
} catch let error {
logger.error("apiGroupMemberInfo error: \(responseError(error))")
@@ -59,14 +62,14 @@ struct CIRcvDecryptionError: View {
case .syncNotSupportedContactAlert: return Alert(title: Text("Fix not supported by contact"), message: message())
case .syncNotSupportedMemberAlert: return Alert(title: Text("Fix not supported by group member"), message: message())
case .decryptionErrorAlert: return Alert(title: Text("Decryption error"), message: message())
case let .error(title, error): return Alert(title: Text(title), message: Text(error))
case let .error(title, error): return mkAlert(title: title, message: error)
}
}
}
@ViewBuilder private func viewBody() -> some View {
if case let .direct(contact) = chat.chatInfo,
let contactStats = contact.activeConn.connectionStats {
let contactStats = contact.activeConn?.connectionStats {
if contactStats.ratchetSyncAllowed {
decryptionErrorItemFixButton(syncSupported: true) {
alert = .syncAllowedAlert { syncContactConnection(contact) }
@@ -80,8 +83,8 @@ struct CIRcvDecryptionError: View {
}
} else if case let .group(groupInfo) = chat.chatInfo,
case let .groupRcv(groupMember) = chatItem.chatDir,
let modelMember = ChatModel.shared.groupMembers.first(where: { $0.id == groupMember.id }),
let memberStats = modelMember.activeConn?.connectionStats {
let mem = m.getGroupMember(groupMember.groupMemberId),
let memberStats = mem.wrapped.activeConn?.connectionStats {
if memberStats.ratchetSyncAllowed {
decryptionErrorItemFixButton(syncSupported: true) {
alert = .syncAllowedAlert { syncMemberConnection(groupInfo, groupMember) }
@@ -106,60 +109,48 @@ struct CIRcvDecryptionError: View {
ZStack(alignment: .bottomTrailing) {
VStack(alignment: .leading, spacing: 2) {
HStack {
if showMember, let member = chatItem.memberDisplayName {
Text(member).fontWeight(.medium) + Text(": ")
}
Text(chatItem.content.text)
.foregroundColor(.red)
.italic()
}
(
Text(Image(systemName: "exclamationmark.arrow.triangle.2.circlepath"))
.foregroundColor(syncSupported ? .accentColor : .secondary)
.foregroundColor(syncSupported ? theme.colors.primary : theme.colors.secondary)
.font(.callout)
+ Text(" ")
+ Text("Fix connection")
.foregroundColor(syncSupported ? .accentColor : .secondary)
.foregroundColor(syncSupported ? theme.colors.primary : theme.colors.secondary)
.font(.callout)
+ Text(" ")
+ ciMetaText(chatItem.meta, chatTTL: nil, transparent: true)
+ ciMetaText(chatItem.meta, chatTTL: nil, encrypted: nil, transparent: true, showViaProxy: showSentViaProxy)
)
}
.padding(.horizontal, 12)
CIMetaView(chatItem: chatItem)
CIMetaView(chat: chat, chatItem: chatItem, metaColor: theme.colors.secondary)
.padding(.horizontal, 12)
}
.onTapGesture(perform: { onClick() })
.padding(.vertical, 6)
.background(Color(uiColor: .tertiarySystemGroupedBackground))
.cornerRadius(18)
.textSelection(.disabled)
}
private func decryptionErrorItem(_ onClick: @escaping (() -> Void)) -> some View {
func text() -> Text {
Text(chatItem.content.text)
.foregroundColor(.red)
.italic()
+ Text(" ")
+ ciMetaText(chatItem.meta, chatTTL: nil, transparent: true)
}
return ZStack(alignment: .bottomTrailing) {
HStack {
if showMember, let member = chatItem.memberDisplayName {
Text(member).fontWeight(.medium) + Text(": ") + text()
} else {
text()
}
Text(chatItem.content.text)
.foregroundColor(.red)
.italic()
+ Text(" ")
+ ciMetaText(chatItem.meta, chatTTL: nil, encrypted: nil, transparent: true, showViaProxy: showSentViaProxy)
}
.padding(.horizontal, 12)
CIMetaView(chatItem: chatItem)
CIMetaView(chat: chat, chatItem: chatItem, metaColor: theme.colors.secondary)
.padding(.horizontal, 12)
}
.onTapGesture(perform: { onClick() })
.padding(.vertical, 6)
.background(Color(uiColor: .tertiarySystemGroupedBackground))
.cornerRadius(18)
.textSelection(.disabled)
}
@@ -175,6 +166,8 @@ struct CIRcvDecryptionError: View {
message = Text("\(msgCount) messages failed to decrypt.") + Text("\n") + why
case .other:
message = Text("\(msgCount) messages failed to decrypt.") + Text("\n") + why
case .ratchetSync:
message = Text("Encryption re-negotiation failed.")
}
return message
}
@@ -184,7 +177,7 @@ struct CIRcvDecryptionError: View {
do {
let (mem, stats) = try apiSyncGroupMemberRatchet(groupInfo.apiId, member.groupMemberId, false)
await MainActor.run {
ChatModel.shared.updateGroupMemberConnectionStats(groupInfo, mem, stats)
m.updateGroupMemberConnectionStats(groupInfo, mem, stats)
}
} catch let error {
logger.error("syncMemberConnection apiSyncGroupMemberRatchet error: \(responseError(error))")
@@ -201,7 +194,7 @@ struct CIRcvDecryptionError: View {
do {
let stats = try apiSyncContactRatchet(contact.apiId, false)
await MainActor.run {
ChatModel.shared.updateContactConnectionStats(contact, stats)
m.updateContactConnectionStats(contact, stats)
}
} catch let error {
logger.error("syncContactConnection apiSyncContactRatchet error: \(responseError(error))")
@@ -9,54 +9,57 @@
import SwiftUI
import AVKit
import SimpleXChat
import Combine
struct CIVideoView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var m: ChatModel
private let chatItem: ChatItem
private let image: String
private let preview: UIImage?
@State private var duration: Int
@State private var progress: Int = 0
@State private var videoPlaying: Bool = false
private let maxWidth: CGFloat
@Binding private var videoWidth: CGFloat?
@State private var scrollProxy: ScrollViewProxy?
@State private var preview: UIImage? = nil
private var videoWidth: CGFloat?
private let smallView: Bool
@State private var player: AVPlayer?
@State private var fullPlayer: AVPlayer?
@State private var url: URL?
@State private var showFullScreenPlayer = false
@State private var urlDecrypted: URL?
@State private var decryptionInProgress: Bool = false
@Binding private var showFullScreenPlayer: Bool
@State private var timeObserver: Any? = nil
@State private var fullScreenTimeObserver: Any? = nil
@State private var publisher: AnyCancellable? = nil
private var sizeMultiplier: CGFloat { smallView ? 0.38 : 1 }
@State private var blurred: Bool = UserDefaults.standard.integer(forKey: DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS) > 0
init(chatItem: ChatItem, image: String, duration: Int, maxWidth: CGFloat, videoWidth: Binding<CGFloat?>, scrollProxy: ScrollViewProxy?) {
init(chatItem: ChatItem, preview: UIImage?, duration: Int, maxWidth: CGFloat, videoWidth: CGFloat?, smallView: Bool = false, showFullscreenPlayer: Binding<Bool>) {
self.chatItem = chatItem
self.image = image
self.preview = preview
self._duration = State(initialValue: duration)
self.maxWidth = maxWidth
self._videoWidth = videoWidth
self.scrollProxy = scrollProxy
if let url = getLoadedVideo(chatItem.file) {
self._player = State(initialValue: VideoPlayerView.getOrCreatePlayer(url, false))
self._url = State(initialValue: url)
}
if let data = Data(base64Encoded: dropImagePrefix(image)),
let uiImage = UIImage(data: data) {
self._preview = State(initialValue: uiImage)
}
self.videoWidth = videoWidth
self.smallView = smallView
self._showFullScreenPlayer = showFullscreenPlayer
}
var body: some View {
let file = chatItem.file
ZStack {
ZStack(alignment: smallView ? .topLeading : .center) {
ZStack(alignment: .topLeading) {
if let file = file, let preview = preview, let player = player, let url = url {
videoView(player, url, file, preview, duration)
} else if let data = Data(base64Encoded: dropImagePrefix(image)),
let uiImage = UIImage(data: data) {
imageView(uiImage)
.onTapGesture {
if let file = file {
if let file = file, let preview = preview, let decrypted = urlDecrypted, smallView {
smallVideoView(decrypted, file, preview)
} else if let file = file, let preview = preview, let player = player, let decrypted = urlDecrypted {
videoView(player, decrypted, file, preview, duration)
} else if let file = file, let defaultPreview = preview, file.loaded && urlDecrypted == nil, smallView {
smallVideoViewEncrypted(file, defaultPreview)
} else if let file = file, let defaultPreview = preview, file.loaded && urlDecrypted == nil {
videoViewEncrypted(file, defaultPreview, duration)
} else if let preview, let file {
Group { if smallView { smallViewImageView(preview, file) } else { imageView(preview) } }
.onTapGesture {
switch file.fileStatus {
case .rcvInvitation:
case .rcvInvitation, .rcvAborted:
receiveFileIfValidSize(file: file, receiveFile: receiveFile)
case .rcvAccepted:
switch file.fileProtocol {
@@ -70,6 +73,7 @@ struct CIVideoView: View {
title: "Waiting for video",
message: "Video will be received when your contact is online, please wait or check later!"
)
case .local: ()
}
case .rcvTransfer: () // ?
case .rcvComplete: () // ?
@@ -77,15 +81,100 @@ struct CIVideoView: View {
default: ()
}
}
}
if !smallView {
durationProgress()
}
}
if !blurred, let file, showDownloadButton(file.fileStatus) {
if !smallView {
Button {
receiveFileIfValidSize(file: file, receiveFile: receiveFile)
} label: {
playPauseIcon("play.fill")
}
} else if !file.showStatusIconInSmallView {
playPauseIcon("play.fill")
.onTapGesture {
receiveFileIfValidSize(file: file, receiveFile: receiveFile)
}
}
}
}
.fullScreenCover(isPresented: $showFullScreenPlayer) {
if let decrypted = urlDecrypted {
fullScreenPlayer(decrypted)
}
}
.onAppear {
setupPlayer(chatItem.file)
}
.onChange(of: chatItem.file) { file in
// ChatItem can be changed in small view on chat list screen
setupPlayer(file)
}
.onDisappear {
showFullScreenPlayer = false
}
}
private func setupPlayer(_ file: CIFile?) {
let newUrl = getLoadedVideo(file)
if newUrl == url {
return
}
url = nil
urlDecrypted = nil
player = nil
fullPlayer = nil
if let newUrl {
let decrypted = file?.fileSource?.cryptoArgs == nil ? newUrl : file?.fileSource?.decryptedGet()
urlDecrypted = decrypted
if let decrypted = decrypted {
player = VideoPlayerView.getOrCreatePlayer(decrypted, false)
fullPlayer = AVPlayer(url: decrypted)
}
url = newUrl
}
}
private func showDownloadButton(_ fileStatus: CIFileStatus?) -> Bool {
switch fileStatus {
case .rcvInvitation: true
case .rcvAborted: true
default: false
}
}
private func videoViewEncrypted(_ file: CIFile, _ defaultPreview: UIImage, _ duration: Int) -> some View {
return ZStack(alignment: .topTrailing) {
ZStack(alignment: .center) {
let canBePlayed = !chatItem.chatDir.sent || file.fileStatus == CIFileStatus.sndComplete || (file.fileStatus == .sndStored && file.fileProtocol == .local)
imageView(defaultPreview)
.onTapGesture {
decrypt(file: file) {
showFullScreenPlayer = urlDecrypted != nil
}
}
durationProgress()
}
if let file = file, case .rcvInvitation = file.fileStatus {
Button {
receiveFileIfValidSize(file: file, receiveFile: receiveFile)
} label: {
playPauseIcon("play.fill")
.onChange(of: m.activeCallViewIsCollapsed) { _ in
showFullScreenPlayer = false
}
if !blurred {
if !decryptionInProgress {
Button {
decrypt(file: file) {
if urlDecrypted != nil {
videoPlaying = true
player?.play()
}
}
} label: {
playPauseIcon(canBePlayed ? "play.fill" : "play.slash")
}
.disabled(!canBePlayed)
} else {
videoDecryptionProgress()
}
}
}
}
@@ -93,40 +182,44 @@ struct CIVideoView: View {
private func videoView(_ player: AVPlayer, _ url: URL, _ file: CIFile, _ preview: UIImage, _ duration: Int) -> some View {
let w = preview.size.width <= preview.size.height ? maxWidth * 0.75 : maxWidth
DispatchQueue.main.async { videoWidth = w }
return ZStack(alignment: .topTrailing) {
ZStack(alignment: .center) {
let canBePlayed = !chatItem.chatDir.sent || file.fileStatus == CIFileStatus.sndComplete || (file.fileStatus == .sndStored && file.fileProtocol == .local)
VideoPlayerView(player: player, url: url, showControls: false)
.frame(width: w, height: w * preview.size.height / preview.size.width)
.onChange(of: ChatModel.shared.stopPreviousRecPlay) { playingUrl in
.onChange(of: m.stopPreviousRecPlay) { playingUrl in
if playingUrl != url {
player.pause()
videoPlaying = false
}
}
.fullScreenCover(isPresented: $showFullScreenPlayer) {
fullScreenPlayer(url)
}
.modifier(PrivacyBlur(enabled: !videoPlaying, blurred: $blurred))
.onTapGesture {
switch player.timeControlStatus {
case .playing:
player.pause()
videoPlaying = false
case .paused:
showFullScreenPlayer = true
if canBePlayed {
showFullScreenPlayer = true
}
default: ()
}
}
if !videoPlaying {
.onChange(of: m.activeCallViewIsCollapsed) { _ in
showFullScreenPlayer = false
}
if !videoPlaying && !blurred {
Button {
ChatModel.shared.stopPreviousRecPlay = url
m.stopPreviousRecPlay = url
player.play()
} label: {
playPauseIcon("play.fill")
playPauseIcon(canBePlayed ? "play.fill" : "play.slash")
}
.disabled(!canBePlayed)
}
}
loadingIndicator()
fileStatusIcon()
}
.onAppear {
addObserver(player, url)
@@ -138,18 +231,67 @@ struct CIVideoView: View {
}
}
private func smallVideoViewEncrypted(_ file: CIFile, _ preview: UIImage) -> some View {
return ZStack(alignment: .topLeading) {
let canBePlayed = !chatItem.chatDir.sent || file.fileStatus == CIFileStatus.sndComplete || (file.fileStatus == .sndStored && file.fileProtocol == .local)
smallViewImageView(preview, file)
.onTapGesture {
decrypt(file: file) {
showFullScreenPlayer = urlDecrypted != nil
}
}
.onChange(of: m.activeCallViewIsCollapsed) { _ in
showFullScreenPlayer = false
}
if file.showStatusIconInSmallView {
// Show nothing
} else if !decryptionInProgress {
playPauseIcon(canBePlayed ? "play.fill" : "play.slash")
} else {
videoDecryptionProgress()
}
}
}
private func smallVideoView(_ url: URL, _ file: CIFile, _ preview: UIImage) -> some View {
return ZStack(alignment: .topLeading) {
smallViewImageView(preview, file)
.onTapGesture {
showFullScreenPlayer = true
}
.onChange(of: m.activeCallViewIsCollapsed) { _ in
showFullScreenPlayer = false
}
if !file.showStatusIconInSmallView {
playPauseIcon("play.fill")
}
}
}
private func playPauseIcon(_ image: String, _ color: Color = .white) -> some View {
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 12, height: 12)
.frame(width: smallView ? 12 * sizeMultiplier * 1.6 : 12, height: smallView ? 12 * sizeMultiplier * 1.6 : 12)
.foregroundColor(color)
.padding(.leading, 4)
.frame(width: 40, height: 40)
.padding(.leading, smallView ? 0 : 4)
.frame(width: 40 * sizeMultiplier, height: 40 * sizeMultiplier)
.background(Color.black.opacity(0.35))
.clipShape(Circle())
}
private func videoDecryptionProgress(_ color: Color = .white) -> some View {
ProgressView()
.progressViewStyle(.circular)
.frame(width: smallView ? 12 * sizeMultiplier : 12, height: smallView ? 12 * sizeMultiplier : 12)
.tint(color)
.frame(width: smallView ? 40 * sizeMultiplier * 0.9 : 40, height: smallView ? 40 * sizeMultiplier * 0.9 : 40)
.background(Color.black.opacity(0.35))
.clipShape(Circle())
}
private func durationProgress() -> some View {
HStack {
Text("\(durationText(videoPlaying ? progress : duration))")
@@ -175,33 +317,65 @@ struct CIVideoView: View {
}
private func imageView(_ img: UIImage) -> some View {
let w = img.size.width <= img.size.height ? maxWidth * 0.75 : .infinity
DispatchQueue.main.async { videoWidth = w }
let w = img.size.width <= img.size.height ? maxWidth * 0.75 : maxWidth
return ZStack(alignment: .topTrailing) {
Image(uiImage: img)
.resizable()
.scaledToFit()
.frame(maxWidth: w)
loadingIndicator()
.frame(width: w)
.modifier(PrivacyBlur(blurred: $blurred))
if !blurred || !showDownloadButton(chatItem.file?.fileStatus) {
fileStatusIcon()
}
}
}
@ViewBuilder private func loadingIndicator() -> some View {
private func smallViewImageView(_ img: UIImage, _ file: CIFile) -> some View {
ZStack(alignment: .center) {
Image(uiImage: img)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: maxWidth, height: maxWidth)
if file.showStatusIconInSmallView {
fileStatusIcon()
.allowsHitTesting(false)
}
}
}
@ViewBuilder private func fileStatusIcon() -> some View {
if let file = chatItem.file {
switch file.fileStatus {
case .sndStored:
switch file.fileProtocol {
case .xftp: progressView()
case .smp: EmptyView()
case .local: EmptyView()
}
case let .sndTransfer(sndProgress, sndTotal):
switch file.fileProtocol {
case .xftp: progressCircle(sndProgress, sndTotal)
case .smp: progressView()
case .local: EmptyView()
}
case .sndComplete: fileIcon("checkmark", 10, 13)
case .sndCancelled: fileIcon("xmark", 10, 13)
case .sndError: fileIcon("xmark", 10, 13)
case let .sndError(sndFileError):
fileIcon("xmark", 10, 13)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(sndFileError.errorInfo)
))
}
case let .sndWarning(sndFileError):
fileIcon("exclamationmark.triangle.fill", 10, 13)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(sndFileError.errorInfo)
))
}
case .rcvInvitation: fileIcon("arrow.down", 10, 13)
case .rcvAccepted: fileIcon("ellipsis", 14, 11)
case let .rcvTransfer(rcvProgress, rcvTotal):
@@ -210,10 +384,26 @@ struct CIVideoView: View {
} else {
progressView()
}
case .rcvAborted: fileIcon("exclamationmark.arrow.circlepath", 14, 11)
case .rcvComplete: EmptyView()
case .rcvCancelled: fileIcon("xmark", 10, 13)
case .rcvError: fileIcon("xmark", 10, 13)
case let .rcvError(rcvFileError):
fileIcon("xmark", 10, 13)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(rcvFileError.errorInfo)
))
}
case let .rcvWarning(rcvFileError):
fileIcon("exclamationmark.triangle.fill", 10, 13)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(rcvFileError.errorInfo)
))
}
case .invalid: fileIcon("questionmark", 10, 13)
default: EmptyView()
}
}
}
@@ -224,7 +414,7 @@ struct CIVideoView: View {
.aspectRatio(contentMode: .fit)
.frame(width: size, height: size)
.foregroundColor(.white)
.padding(padding)
.padding(smallView ? 0 : padding)
}
private func progressView() -> some View {
@@ -232,7 +422,7 @@ struct CIVideoView: View {
.progressViewStyle(.circular)
.frame(width: 16, height: 16)
.tint(.white)
.padding(11)
.padding(smallView ? 0 : 11)
}
private func progressCircle(_ progress: Int64, _ total: Int64) -> some View {
@@ -244,13 +434,14 @@ struct CIVideoView: View {
)
.rotationEffect(.degrees(-90))
.frame(width: 16, height: 16)
.padding([.trailing, .top], 11)
.padding([.trailing, .top], smallView ? 0 : 11)
}
private func receiveFileIfValidSize(file: CIFile, receiveFile: @escaping (User, Int64) async -> Void) {
// TODO encrypt: where file size is checked?
private func receiveFileIfValidSize(file: CIFile, receiveFile: @escaping (User, Int64, Bool, Bool) async -> Void) {
Task {
if let user = ChatModel.shared.currentUser {
await receiveFile(user, file.fileId)
if let user = m.currentUser {
await receiveFile(user, file.fileId, false, false)
}
}
}
@@ -258,8 +449,7 @@ struct CIVideoView: View {
private func fullScreenPlayer(_ url: URL) -> some View {
ZStack {
Color.black.edgesIgnoringSafeArea(.all)
VideoPlayer(player: createFullScreenPlayerAndPlay(url)) {
}
VideoPlayer(player: fullPlayer)
.overlay(alignment: .topLeading, content: {
Button(action: { showFullScreenPlayer = false },
label: {
@@ -282,26 +472,55 @@ struct CIVideoView: View {
}
}
)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now()) {
// Prevent feedback loop - setting `ChatModel`s property causes `onAppear` to be called on iOS17+
if m.stopPreviousRecPlay != url { m.stopPreviousRecPlay = url }
if let player = fullPlayer {
player.play()
var played = false
publisher = player.publisher(for: \.timeControlStatus).sink { status in
if played || status == .playing {
AppDelegate.keepScreenOn(status == .playing)
AudioPlayer.changeAudioSession(status == .playing)
}
played = status == .playing
}
fullScreenTimeObserver = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: .main) { _ in
player.seek(to: CMTime.zero)
player.play()
}
}
}
}
.onDisappear {
if let fullScreenTimeObserver = fullScreenTimeObserver {
NotificationCenter.default.removeObserver(fullScreenTimeObserver)
}
fullScreenTimeObserver = nil
fullPlayer?.pause()
fullPlayer?.seek(to: CMTime.zero)
publisher?.cancel()
}
}
}
private func createFullScreenPlayerAndPlay(_ url: URL) -> AVPlayer {
let player = AVPlayer(url: url)
DispatchQueue.main.asyncAfter(deadline: .now()) {
ChatModel.shared.stopPreviousRecPlay = url
player.play()
fullScreenTimeObserver = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: .main) { _ in
player.seek(to: CMTime.zero)
player.play()
private func decrypt(file: CIFile, completed: (() -> Void)? = nil) {
if decryptionInProgress { return }
decryptionInProgress = true
Task {
urlDecrypted = await file.fileSource?.decryptedGetOrCreate(&ChatModel.shared.filesToDelete)
await MainActor.run {
if let decrypted = urlDecrypted {
if !smallView {
player = VideoPlayerView.getOrCreatePlayer(decrypted, false)
}
fullPlayer = AVPlayer(url: decrypted)
}
decryptionInProgress = false
completed?()
}
}
return player
}
private func addObserver(_ player: AVPlayer, _ url: URL) {
@@ -10,18 +10,31 @@ import SwiftUI
import SimpleXChat
struct CIVoiceView: View {
@ObservedObject var chat: Chat
@EnvironmentObject var theme: AppTheme
var chatItem: ChatItem
let recordingFile: CIFile?
let duration: Int
@Binding var audioPlayer: AudioPlayer?
@Binding var playbackState: VoiceMessagePlaybackState
@Binding var playbackTime: TimeInterval?
@State var audioPlayer: AudioPlayer? = nil
@State var playbackState: VoiceMessagePlaybackState = .noPlayback
@State var playbackTime: TimeInterval? = nil
@Binding var allowMenu: Bool
var smallViewSize: CGFloat?
@State private var seek: (TimeInterval) -> Void = { _ in }
var body: some View {
Group {
if chatItem.chatDir.sent {
if smallViewSize != nil {
HStack(spacing: 10) {
player()
playerTime()
.allowsHitTesting(false)
if .playing == playbackState || (playbackTime ?? 0) > 0 || !allowMenu {
playbackSlider()
}
}
} else if chatItem.chatDir.sent {
VStack (alignment: .trailing, spacing: 6) {
HStack {
if .playing == playbackState || (playbackTime ?? 0) > 0 || !allowMenu {
@@ -52,7 +65,13 @@ struct CIVoiceView: View {
}
private func player() -> some View {
VoiceMessagePlayer(
let sizeMultiplier: CGFloat = if let sz = smallViewSize {
voiceMessageSizeBasedOnSquareSize(sz) / 56
} else {
1
}
return VoiceMessagePlayer(
chat: chat,
chatItem: chatItem,
recordingFile: recordingFile,
recordingTime: TimeInterval(duration),
@@ -61,7 +80,8 @@ struct CIVoiceView: View {
audioPlayer: $audioPlayer,
playbackState: $playbackState,
playbackTime: $playbackTime,
allowMenu: $allowMenu
allowMenu: $allowMenu,
sizeMultiplier: sizeMultiplier
)
}
@@ -71,7 +91,7 @@ struct CIVoiceView: View {
playbackState: $playbackState,
playbackTime: $playbackTime
)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
}
private func playbackSlider() -> some View {
@@ -88,10 +108,11 @@ struct CIVoiceView: View {
allowMenu = true
}
}
.tint(theme.colors.primary)
}
private func metaView() -> some View {
CIMetaView(chatItem: chatItem)
CIMetaView(chat: chat, chatItem: chatItem, metaColor: theme.colors.secondary)
}
}
@@ -116,8 +137,9 @@ struct VoiceMessagePlayerTime: View {
}
struct VoiceMessagePlayer: View {
@ObservedObject var chat: Chat
@EnvironmentObject var chatModel: ChatModel
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var theme: AppTheme
var chatItem: ChatItem
var recordingFile: CIFile?
var recordingTime: TimeInterval
@@ -127,23 +149,61 @@ struct VoiceMessagePlayer: View {
@Binding var audioPlayer: AudioPlayer?
@Binding var playbackState: VoiceMessagePlaybackState
@Binding var playbackTime: TimeInterval?
@Binding var allowMenu: Bool
var sizeMultiplier: CGFloat
var body: some View {
ZStack {
if let recordingFile = recordingFile {
switch recordingFile.fileStatus {
case .sndStored: playbackButton()
case .sndTransfer: playbackButton()
case .sndStored:
if recordingFile.fileProtocol == .local {
playbackButton()
} else {
loadingIcon()
}
case .sndTransfer: loadingIcon()
case .sndComplete: playbackButton()
case .sndCancelled: playbackButton()
case .sndError: playbackButton()
case .rcvInvitation: downloadButton(recordingFile)
case let .sndError(sndFileError):
fileStatusIcon("multiply", 14)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(sndFileError.errorInfo)
))
}
case let .sndWarning(sndFileError):
fileStatusIcon("exclamationmark.triangle.fill", 16)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(sndFileError.errorInfo)
))
}
case .rcvInvitation: downloadButton(recordingFile, "play.fill")
case .rcvAccepted: loadingIcon()
case .rcvTransfer: loadingIcon()
case .rcvAborted: downloadButton(recordingFile, "exclamationmark.arrow.circlepath")
case .rcvComplete: playbackButton()
case .rcvCancelled: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
case .rcvError: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
case let .rcvError(rcvFileError):
fileStatusIcon("multiply", 14)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(rcvFileError.errorInfo)
))
}
case let .rcvWarning(rcvFileError):
fileStatusIcon("exclamationmark.triangle.fill", 16)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(rcvFileError.errorInfo)
))
}
case .invalid: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
}
} else {
@@ -151,83 +211,170 @@ struct VoiceMessagePlayer: View {
}
}
.onAppear {
if audioPlayer == nil {
let small = sizeMultiplier != 1
audioPlayer = small ? VoiceItemState.smallView[VoiceItemState.id(chat, chatItem)]?.audioPlayer : VoiceItemState.chatView[VoiceItemState.id(chat, chatItem)]?.audioPlayer
playbackState = (small ? VoiceItemState.smallView[VoiceItemState.id(chat, chatItem)]?.playbackState : VoiceItemState.chatView[VoiceItemState.id(chat, chatItem)]?.playbackState) ?? .noPlayback
playbackTime = small ? VoiceItemState.smallView[VoiceItemState.id(chat, chatItem)]?.playbackTime : VoiceItemState.chatView[VoiceItemState.id(chat, chatItem)]?.playbackTime
}
seek = { to in audioPlayer?.seek(to) }
audioPlayer?.onTimer = { playbackTime = $0 }
let audioPath: URL? = if let recordingSource = getLoadedFileSource(recordingFile) {
getAppFilePath(recordingSource.filePath)
} else {
nil
}
let chatId = chatModel.chatId
let userId = chatModel.currentUser?.userId
audioPlayer?.onTimer = {
playbackTime = $0
notifyStateChange()
// Manual check here is needed because when this view is not visible, SwiftUI don't react on stopPreviousRecPlay, chatId and current user changes and audio keeps playing when it should stop
if (audioPath != nil && chatModel.stopPreviousRecPlay != audioPath) || chatModel.chatId != chatId || chatModel.currentUser?.userId != userId {
stopPlayback()
}
}
audioPlayer?.onFinishPlayback = {
playbackState = .noPlayback
playbackTime = TimeInterval(0)
notifyStateChange()
}
// One voice message was paused, then scrolled far from it, started to play another one, drop to stopped state
if let audioPath, chatModel.stopPreviousRecPlay != audioPath {
stopPlayback()
}
}
.onChange(of: chatModel.stopPreviousRecPlay) { it in
if let recordingFileName = getLoadedFileName(recordingFile), chatModel.stopPreviousRecPlay != getAppFilePath(recordingFileName) {
audioPlayer?.stop()
playbackState = .noPlayback
playbackTime = TimeInterval(0)
if let recordingFileName = getLoadedFileSource(recordingFile)?.filePath,
chatModel.stopPreviousRecPlay != getAppFilePath(recordingFileName) {
stopPlayback()
}
}
.onChange(of: playbackState) { state in
allowMenu = state == .paused || state == .noPlayback
// Notify activeContentPreview in ChatPreviewView that playback is finished
if state == .noPlayback, let recordingFileName = getLoadedFileSource(recordingFile)?.filePath,
chatModel.stopPreviousRecPlay == getAppFilePath(recordingFileName) {
chatModel.stopPreviousRecPlay = nil
}
}
.onChange(of: chatModel.chatId) { _ in
stopPlayback()
}
.onDisappear {
if sizeMultiplier == 1 && chatModel.chatId == nil {
stopPlayback()
}
}
}
@ViewBuilder private func playbackButton() -> some View {
switch playbackState {
case .noPlayback:
Button {
if let recordingFileName = getLoadedFileName(recordingFile) {
startPlayback(recordingFileName)
if sizeMultiplier != 1 {
switch playbackState {
case .noPlayback:
playPauseIcon("play.fill", theme.colors.primary)
.onTapGesture {
if let recordingSource = getLoadedFileSource(recordingFile) {
startPlayback(recordingSource)
}
}
case .playing:
playPauseIcon("pause.fill", theme.colors.primary)
.onTapGesture {
audioPlayer?.pause()
playbackState = .paused
notifyStateChange()
}
case .paused:
playPauseIcon("play.fill", theme.colors.primary)
.onTapGesture {
audioPlayer?.play()
playbackState = .playing
notifyStateChange()
}
}
} else {
switch playbackState {
case .noPlayback:
Button {
if let recordingSource = getLoadedFileSource(recordingFile) {
startPlayback(recordingSource)
}
} label: {
playPauseIcon("play.fill", theme.colors.primary)
}
case .playing:
Button {
audioPlayer?.pause()
playbackState = .paused
notifyStateChange()
} label: {
playPauseIcon("pause.fill", theme.colors.primary)
}
case .paused:
Button {
audioPlayer?.play()
playbackState = .playing
notifyStateChange()
} label: {
playPauseIcon("play.fill", theme.colors.primary)
}
} label: {
playPauseIcon("play.fill")
}
case .playing:
Button {
audioPlayer?.pause()
playbackState = .paused
} label: {
playPauseIcon("pause.fill")
}
case .paused:
Button {
audioPlayer?.play()
playbackState = .playing
} label: {
playPauseIcon("play.fill")
}
}
}
private func playPauseIcon(_ image: String, _ color: Color = .accentColor) -> some View {
private func playPauseIcon(_ image: String, _ color: Color/* = .accentColor*/) -> some View {
ZStack {
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)
.frame(width: 20 * sizeMultiplier, height: 20 * sizeMultiplier)
.foregroundColor(color)
.padding(.leading, image == "play.fill" ? 4 : 0)
.frame(width: 56, height: 56)
.background(showBackground ? chatItemFrameColor(chatItem, colorScheme) : .clear)
.frame(width: 56 * sizeMultiplier, height: 56 * sizeMultiplier)
.background(showBackground ? chatItemFrameColor(chatItem, theme) : .clear)
.clipShape(Circle())
if recordingTime > 0 {
ProgressCircle(length: recordingTime, progress: $playbackTime)
.frame(width: 53, height: 53) // this + ProgressCircle lineWidth = background circle diameter
.frame(width: 53 * sizeMultiplier, height: 53 * sizeMultiplier) // this + ProgressCircle lineWidth = background circle diameter
}
}
}
private func downloadButton(_ recordingFile: CIFile) -> some View {
Button {
Task {
if let user = ChatModel.shared.currentUser {
await receiveFile(user: user, fileId: recordingFile.fileId)
private func downloadButton(_ recordingFile: CIFile, _ icon: String) -> some View {
Group {
if sizeMultiplier != 1 {
playPauseIcon(icon, theme.colors.primary)
.onTapGesture {
Task {
if let user = chatModel.currentUser {
await receiveFile(user: user, fileId: recordingFile.fileId)
}
}
}
} else {
Button {
Task {
if let user = chatModel.currentUser {
await receiveFile(user: user, fileId: recordingFile.fileId)
}
}
} label: {
playPauseIcon(icon, theme.colors.primary)
}
}
} label: {
playPauseIcon("play.fill")
}
}
func notifyStateChange() {
if sizeMultiplier != 1 {
VoiceItemState.smallView[VoiceItemState.id(chat, chatItem)] = VoiceItemState(audioPlayer: audioPlayer, playbackState: playbackState, playbackTime: playbackTime)
} else {
VoiceItemState.chatView[VoiceItemState.id(chat, chatItem)] = VoiceItemState(audioPlayer: audioPlayer, playbackState: playbackState, playbackTime: playbackTime)
}
}
private struct ProgressCircle: View {
@EnvironmentObject var theme: AppTheme
var length: TimeInterval
@Binding var progress: TimeInterval?
@@ -235,7 +382,7 @@ struct VoiceMessagePlayer: View {
Circle()
.trim(from: 0, to: ((progress ?? TimeInterval(0)) / length))
.stroke(
Color.accentColor,
theme.colors.primary,
style: StrokeStyle(lineWidth: 3)
)
.rotationEffect(.degrees(-90))
@@ -243,33 +390,107 @@ struct VoiceMessagePlayer: View {
}
}
private func loadingIcon() -> some View {
ProgressView()
.frame(width: 30, height: 30)
.frame(width: 56, height: 56)
.background(showBackground ? chatItemFrameColor(chatItem, colorScheme) : .clear)
private func fileStatusIcon(_ image: String, _ size: CGFloat) -> some View {
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: size * sizeMultiplier, height: size * sizeMultiplier)
.foregroundColor(Color(uiColor: .tertiaryLabel))
.frame(width: 56 * sizeMultiplier, height: 56 * sizeMultiplier)
.background(showBackground ? chatItemFrameColor(chatItem, theme) : .clear)
.clipShape(Circle())
}
private func startPlayback(_ recordingFileName: String) {
chatModel.stopPreviousRecPlay = getAppFilePath(recordingFileName)
private func loadingIcon() -> some View {
ProgressView()
.frame(width: 30 * sizeMultiplier, height: 30 * sizeMultiplier)
.frame(width: 56 * sizeMultiplier, height: 56 * sizeMultiplier)
.background(showBackground ? chatItemFrameColor(chatItem, theme) : .clear)
.clipShape(Circle())
}
private func startPlayback(_ recordingSource: CryptoFile) {
let audioPath = getAppFilePath(recordingSource.filePath)
let chatId = chatModel.chatId
let userId = chatModel.currentUser?.userId
chatModel.stopPreviousRecPlay = audioPath
audioPlayer = AudioPlayer(
onTimer: { playbackTime = $0 },
onTimer: {
playbackTime = $0
notifyStateChange()
// Manual check here is needed because when this view is not visible, SwiftUI don't react on stopPreviousRecPlay, chatId and current user changes and audio keeps playing when it should stop
if chatModel.stopPreviousRecPlay != audioPath || chatModel.chatId != chatId || chatModel.currentUser?.userId != userId {
stopPlayback()
}
},
onFinishPlayback: {
playbackState = .noPlayback
playbackTime = TimeInterval(0)
notifyStateChange()
}
)
audioPlayer?.start(fileName: recordingFileName, at: playbackTime)
audioPlayer?.start(fileSource: recordingSource, at: playbackTime)
playbackState = .playing
notifyStateChange()
}
private func stopPlayback() {
audioPlayer?.stop()
playbackState = .noPlayback
playbackTime = TimeInterval(0)
notifyStateChange()
}
}
func voiceMessageSizeBasedOnSquareSize(_ squareSize: CGFloat) -> CGFloat {
let squareToCircleRatio = 0.935
return squareSize + squareSize * (1 - squareToCircleRatio)
}
class VoiceItemState {
var audioPlayer: AudioPlayer?
var playbackState: VoiceMessagePlaybackState
var playbackTime: TimeInterval?
init(audioPlayer: AudioPlayer? = nil, playbackState: VoiceMessagePlaybackState, playbackTime: TimeInterval? = nil) {
self.audioPlayer = audioPlayer
self.playbackState = playbackState
self.playbackTime = playbackTime
}
static func id(_ chat: Chat, _ chatItem: ChatItem) -> String {
"\(chat.id) \(chatItem.id)"
}
static func id(_ chatInfo: ChatInfo, _ chatItem: ChatItem) -> String {
"\(chatInfo.id) \(chatItem.id)"
}
static func stopVoiceInSmallView(_ chatInfo: ChatInfo, _ chatItem: ChatItem) {
let id = id(chatInfo, chatItem)
if let item = smallView[id] {
item.audioPlayer?.stop()
ChatModel.shared.stopPreviousRecPlay = nil
}
}
static func stopVoiceInChatView(_ chatInfo: ChatInfo, _ chatItem: ChatItem) {
let id = id(chatInfo, chatItem)
if let item = chatView[id] {
item.audioPlayer?.stop()
ChatModel.shared.stopPreviousRecPlay = nil
}
}
static var smallView: [String: VoiceItemState] = [:]
static var chatView: [String: VoiceItemState] = [:]
}
struct CIVoiceView_Previews: PreviewProvider {
static var previews: some View {
let sentVoiceMessage: ChatItem = ChatItem(
chatDir: .directSnd,
meta: CIMeta.getSample(1, .now, "", .sndSent, itemEdited: true),
meta: CIMeta.getSample(1, .now, "", .sndSent(sndProgress: .complete), itemEdited: true),
content: .sndMsgContent(msgContent: .voice(text: "", duration: 30)),
quotedItem: nil,
file: CIFile.getSample(fileStatus: .sndComplete)
@@ -283,20 +504,17 @@ struct CIVoiceView_Previews: PreviewProvider {
)
Group {
CIVoiceView(
chat: Chat.sampleData,
chatItem: ChatItem.getVoiceMsgContentSample(),
recordingFile: CIFile.getSample(fileName: "voice.m4a", fileSize: 65536, fileStatus: .rcvComplete),
duration: 30,
audioPlayer: .constant(nil),
playbackState: .constant(.playing),
playbackTime: .constant(TimeInterval(20)),
allowMenu: Binding.constant(true)
)
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: sentVoiceMessage, revealed: Binding.constant(false), allowMenu: .constant(true), playbackState: .constant(.noPlayback), playbackTime: .constant(nil))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getVoiceMsgContentSample(), revealed: Binding.constant(false), allowMenu: .constant(true), playbackState: .constant(.noPlayback), playbackTime: .constant(nil))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getVoiceMsgContentSample(fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), revealed: Binding.constant(false), allowMenu: .constant(true), playbackState: .constant(.noPlayback), playbackTime: .constant(nil))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: voiceMessageWtFile, revealed: Binding.constant(false), allowMenu: .constant(true), playbackState: .constant(.noPlayback), playbackTime: .constant(nil))
ChatItemView(chat: Chat.sampleData, chatItem: sentVoiceMessage, revealed: Binding.constant(false), allowMenu: .constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(), revealed: Binding.constant(false), allowMenu: .constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), revealed: Binding.constant(false), allowMenu: .constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: voiceMessageWtFile, revealed: Binding.constant(false), allowMenu: .constant(true))
}
.previewLayout(.fixed(width: 360, height: 360))
.environmentObject(Chat.sampleData)
}
}
@@ -10,25 +10,21 @@ import SwiftUI
import SimpleXChat
struct DeletedItemView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var theme: AppTheme
@ObservedObject var chat: Chat
var chatItem: ChatItem
var showMember = false
var body: some View {
HStack(alignment: .bottom, spacing: 0) {
if showMember, let member = chatItem.memberDisplayName {
Text(member).fontWeight(.medium) + Text(": ")
}
Text(chatItem.content.text)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
.italic()
CIMetaView(chatItem: chatItem)
CIMetaView(chat: chat, chatItem: chatItem, metaColor: theme.colors.secondary)
.padding(.horizontal, 12)
}
.padding(.leading, 12)
.padding(.vertical, 6)
.background(chatItemFrameColor(chatItem, colorScheme))
.cornerRadius(18)
.background(chatItemFrameColor(chatItem, theme))
.textSelection(.disabled)
}
}
@@ -36,11 +32,8 @@ struct DeletedItemView: View {
struct DeletedItemView_Previews: PreviewProvider {
static var previews: some View {
Group {
DeletedItemView(chatItem: ChatItem.getDeletedContentSample())
DeletedItemView(
chatItem: ChatItem.getDeletedContentSample(dir: .groupRcv(groupMember: GroupMember.sampleData)),
showMember: true
)
DeletedItemView(chat: Chat.sampleData, chatItem: ChatItem.getDeletedContentSample())
DeletedItemView(chat: Chat.sampleData, chatItem: ChatItem.getDeletedContentSample(dir: .groupRcv(groupMember: GroupMember.sampleData)))
}
.previewLayout(.fixed(width: 360, height: 200))
}
@@ -10,6 +10,8 @@ import SwiftUI
import SimpleXChat
struct EmojiItemView: View {
@ObservedObject var chat: Chat
@EnvironmentObject var theme: AppTheme
var chatItem: ChatItem
var body: some View {
@@ -17,7 +19,7 @@ struct EmojiItemView: View {
emojiText(chatItem.content.text)
.padding(.top, 8)
.padding(.horizontal, 6)
CIMetaView(chatItem: chatItem)
CIMetaView(chat: chat, chatItem: chatItem, metaColor: theme.colors.secondary)
.padding(.bottom, 8)
.padding(.horizontal, 12)
}
@@ -32,8 +34,8 @@ func emojiText(_ text: String) -> Text {
struct EmojiItemView_Previews: PreviewProvider {
static var previews: some View {
Group{
EmojiItemView(chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂", .sndSent))
EmojiItemView(chatItem: ChatItem.getSample(2, .directRcv, .now, "👍"))
EmojiItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂", .sndSent(sndProgress: .complete)))
EmojiItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directRcv, .now, "👍"))
}
.previewLayout(.fixed(width: 360, height: 70))
}
@@ -12,21 +12,24 @@ import SwiftUI
import SimpleXChat
struct FramedCIVoiceView: View {
@EnvironmentObject var theme: AppTheme
@ObservedObject var chat: Chat
var chatItem: ChatItem
let recordingFile: CIFile?
let duration: Int
@State var audioPlayer: AudioPlayer? = nil
@State var playbackState: VoiceMessagePlaybackState = .noPlayback
@State var playbackTime: TimeInterval? = nil
@Binding var allowMenu: Bool
@Binding var audioPlayer: AudioPlayer?
@Binding var playbackState: VoiceMessagePlaybackState
@Binding var playbackTime: TimeInterval?
@State private var seek: (TimeInterval) -> Void = { _ in }
var body: some View {
HStack {
VoiceMessagePlayer(
chat: chat,
chatItem: chatItem,
recordingFile: recordingFile,
recordingTime: TimeInterval(duration),
@@ -35,14 +38,15 @@ struct FramedCIVoiceView: View {
audioPlayer: $audioPlayer,
playbackState: $playbackState,
playbackTime: $playbackTime,
allowMenu: $allowMenu
allowMenu: $allowMenu,
sizeMultiplier: 1
)
VoiceMessagePlayerTime(
recordingTime: TimeInterval(duration),
playbackState: $playbackState,
playbackTime: $playbackTime
)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
.frame(width: 50, alignment: .leading)
if .playing == playbackState || (playbackTime ?? 0) > 0 || !allowMenu {
playbackSlider()
@@ -75,26 +79,25 @@ struct FramedCIVoiceView_Previews: PreviewProvider {
static var previews: some View {
let sentVoiceMessage: ChatItem = ChatItem(
chatDir: .directSnd,
meta: CIMeta.getSample(1, .now, "", .sndSent, itemEdited: true),
meta: CIMeta.getSample(1, .now, "", .sndSent(sndProgress: .complete), itemEdited: true),
content: .sndMsgContent(msgContent: .voice(text: "Hello there", duration: 30)),
quotedItem: nil,
file: CIFile.getSample(fileStatus: .sndComplete)
)
let voiceMessageWithQuote: ChatItem = ChatItem(
chatDir: .directSnd,
meta: CIMeta.getSample(1, .now, "", .sndSent, itemEdited: true),
meta: CIMeta.getSample(1, .now, "", .sndSent(sndProgress: .complete), itemEdited: true),
content: .sndMsgContent(msgContent: .voice(text: "", duration: 30)),
quotedItem: CIQuote.getSample(1, .now, "Hi", chatDir: .directRcv),
file: CIFile.getSample(fileStatus: .sndComplete)
)
Group {
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: sentVoiceMessage, revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getVoiceMsgContentSample(text: "Hello there"), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getVoiceMsgContentSample(text: "Hello there", fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, 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."), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: voiceMessageWithQuote, revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: sentVoiceMessage, revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(text: "Hello there"), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(text: "Hello there", fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), revealed: Binding.constant(false))
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."), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: voiceMessageWithQuote, revealed: Binding.constant(false))
}
.previewLayout(.fixed(width: 360, height: 360))
.environmentObject(Chat.sampleData)
}
}
File diff suppressed because one or more lines are too long
@@ -13,12 +13,12 @@ import AVKit
struct FullScreenMediaView: View {
@EnvironmentObject var m: ChatModel
@EnvironmentObject var scrollModel: ReverseListScrollModel<ChatItem>
@State var chatItem: ChatItem
@State var image: UIImage?
@State var player: AVPlayer? = nil
@State var url: URL? = nil
@Binding var showView: Bool
@State var scrollProxy: ScrollViewProxy?
@State private var showNext = false
@State private var nextImage: UIImage?
@State private var nextPlayer: AVPlayer?
@@ -71,9 +71,7 @@ struct FullScreenMediaView: View {
let w = abs(t.width)
if t.height > 60 && t.height > w * 2 {
showView = false
if let proxy = scrollProxy {
proxy.scrollTo(chatItem.viewId)
}
scrollModel.scrollToItem(id: chatItem.id)
} else if w > 60 && w > abs(t.height) * 2 && !scrolling {
let previous = t.width > 0
scrolling = true
@@ -150,7 +148,7 @@ struct FullScreenMediaView: View {
private func startPlayerAndNotify() {
if let player = player {
ChatModel.shared.stopPreviousRecPlay = url
m.stopPreviousRecPlay = url
player.play()
}
}
@@ -10,12 +10,13 @@ import SwiftUI
import SimpleXChat
struct IntegrityErrorItemView: View {
@ObservedObject var chat: Chat
@EnvironmentObject var theme: AppTheme
var msgError: MsgErrorType
var chatItem: ChatItem
var showMember = false
var body: some View {
CIMsgError(chatItem: chatItem, showMember: showMember) {
CIMsgError(chat: chat, chatItem: chatItem) {
switch msgError {
case .msgSkipped:
AlertManager.shared.showAlertMsg(
@@ -53,25 +54,22 @@ struct IntegrityErrorItemView: View {
}
struct CIMsgError: View {
@ObservedObject var chat: Chat
@EnvironmentObject var theme: AppTheme
var chatItem: ChatItem
var showMember = false
var onTap: () -> Void
var body: some View {
HStack(alignment: .bottom, spacing: 0) {
if showMember, let member = chatItem.memberDisplayName {
Text(member).fontWeight(.medium) + Text(": ")
}
Text(chatItem.content.text)
.foregroundColor(.red)
.italic()
CIMetaView(chatItem: chatItem)
CIMetaView(chat: chat, chatItem: chatItem, metaColor: theme.colors.secondary)
.padding(.horizontal, 12)
}
.padding(.leading, 12)
.padding(.vertical, 6)
.background(Color(uiColor: .tertiarySystemGroupedBackground))
.cornerRadius(18)
.textSelection(.disabled)
.onTapGesture(perform: onTap)
}
@@ -79,6 +77,6 @@ struct CIMsgError: View {
struct IntegrityErrorItemView_Previews: PreviewProvider {
static var previews: some View {
IntegrityErrorItemView(msgError: .msgBadHash, chatItem: ChatItem.getIntegrityErrorSample())
IntegrityErrorItemView(chat: Chat.sampleData, msgError: .msgBadHash, chatItem: ChatItem.getIntegrityErrorSample())
}
}
@@ -10,43 +10,76 @@ import SwiftUI
import SimpleXChat
struct MarkedDeletedItemView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var m: ChatModel
@EnvironmentObject var theme: AppTheme
@ObservedObject var chat: Chat
var chatItem: ChatItem
var showMember = false
@Binding var revealed: Bool
var body: some View {
HStack(alignment: .bottom, spacing: 0) {
if showMember, let member = chatItem.memberDisplayName {
Text(member).font(.caption).fontWeight(.medium) + Text(": ").font(.caption)
}
if case let .moderated(_, byGroupMember) = chatItem.meta.itemDeleted {
markedDeletedText("moderated by \(byGroupMember.chatViewName)")
} else {
markedDeletedText("marked deleted")
}
CIMetaView(chatItem: chatItem)
.padding(.horizontal, 12)
}
.padding(.leading, 12)
(Text(mergedMarkedDeletedText).italic() + Text(" ") + chatItem.timestampText)
.font(.caption)
.foregroundColor(theme.colors.secondary)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(chatItemFrameColor(chatItem, colorScheme))
.cornerRadius(18)
.background(chatItemFrameColor(chatItem, theme))
.textSelection(.disabled)
}
func markedDeletedText(_ s: LocalizedStringKey) -> some View {
Text(s)
.font(.caption)
.foregroundColor(.secondary)
.italic()
.lineLimit(1)
var mergedMarkedDeletedText: LocalizedStringKey {
if !revealed,
let ciCategory = chatItem.mergeCategory,
var i = m.getChatItemIndex(chatItem) {
var moderated = 0
var blocked = 0
var blockedByAdmin = 0
var deleted = 0
var moderatedBy: Set<String> = []
while i < ItemsModel.shared.reversedChatItems.count,
let ci = .some(ItemsModel.shared.reversedChatItems[i]),
ci.mergeCategory == ciCategory,
let itemDeleted = ci.meta.itemDeleted {
switch itemDeleted {
case let .moderated(_, byGroupMember):
moderated += 1
moderatedBy.insert(byGroupMember.displayName)
case .blocked: blocked += 1
case .blockedByAdmin: blockedByAdmin += 1
case .deleted: deleted += 1
}
i += 1
}
let total = moderated + blocked + blockedByAdmin + deleted
return total <= 1
? markedDeletedText
: total == moderated
? "\(total) messages moderated by \(moderatedBy.joined(separator: ", "))"
: total == blockedByAdmin
? "\(total) messages blocked by admin"
: total == blocked + blockedByAdmin
? "\(total) messages blocked"
: "\(total) messages marked deleted"
} else {
return markedDeletedText
}
}
// same texts are in markedDeletedText in ChatPreviewView, but it returns String;
// can be refactored into a single function if functions calling these are changed to return same type
var markedDeletedText: LocalizedStringKey {
switch chatItem.meta.itemDeleted {
case let .moderated(_, byGroupMember): "moderated by \(byGroupMember.displayName)"
case .blocked: "blocked"
case .blockedByAdmin: "blocked by admin"
case .deleted, nil: "marked deleted"
}
}
}
struct MarkedDeletedItemView_Previews: PreviewProvider {
static var previews: some View {
Group {
MarkedDeletedItemView(chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, itemDeleted: .deleted(deletedTs: .now)))
MarkedDeletedItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete), itemDeleted: .deleted(deletedTs: .now)), revealed: Binding.constant(true))
}
.previewLayout(.fixed(width: 360, height: 200))
}
@@ -9,7 +9,7 @@
import SwiftUI
import SimpleXChat
private let uiLinkColor = UIColor(red: 0, green: 0.533, blue: 1, alpha: 1)
let uiLinkColor = UIColor(red: 0, green: 0.533, blue: 1, alpha: 1)
private let noTyping = Text(" ")
@@ -25,15 +25,19 @@ private func typing(_ w: Font.Weight = .light) -> Text {
}
struct MsgContentView: View {
@EnvironmentObject var chat: Chat
@ObservedObject var chat: Chat
@EnvironmentObject var theme: AppTheme
var text: String
var formattedText: [FormattedText]? = nil
var sender: String? = nil
var meta: CIMeta? = nil
var rightToLeft = false
var showSecrets: Bool
@State private var typingIdx = 0
@State private var timer: Timer?
@AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = false
var body: some View {
if meta?.isLive == true {
msgContentView()
@@ -62,7 +66,7 @@ struct MsgContentView: View {
}
private func msgContentView() -> Text {
var v = messageText(text, formattedText, sender)
var v = messageText(text, formattedText, sender, showSecrets: showSecrets, secondaryColor: theme.colors.secondary)
if let mt = meta {
if mt.isLive {
v = v + typingIndicator(mt.recent)
@@ -76,22 +80,22 @@ struct MsgContentView: View {
return (recent ? typingIndicators[typingIdx] : noTyping)
.font(.body.monospaced())
.kerning(-2)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
}
private func reserveSpaceForMeta(_ mt: CIMeta) -> Text {
(rightToLeft ? Text("\n") : Text(" ")) + ciMetaText(mt, chatTTL: chat.chatInfo.timedMessagesTTL, transparent: true)
(rightToLeft ? Text("\n") : Text(" ")) + ciMetaText(mt, chatTTL: chat.chatInfo.timedMessagesTTL, encrypted: nil, transparent: true, showViaProxy: showSentViaProxy)
}
}
func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: String?, icon: String? = nil, preview: Bool = false) -> Text {
func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: String?, icon: String? = nil, preview: Bool = false, showSecrets: Bool, secondaryColor: Color) -> Text {
let s = text
var res: Text
if let ft = formattedText, ft.count > 0 && ft.count <= 200 {
res = formatText(ft[0], preview)
res = formatText(ft[0], preview, showSecret: showSecrets)
var i = 1
while i < ft.count {
res = res + formatText(ft[i], preview)
res = res + formatText(ft[i], preview, showSecret: showSecrets)
i = i + 1
}
} else {
@@ -99,7 +103,7 @@ func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: St
}
if let i = icon {
res = Text(Image(systemName: i)).foregroundColor(Color(uiColor: .tertiaryLabel)) + Text(" ") + res
res = Text(Image(systemName: i)).foregroundColor(secondaryColor) + Text(" ") + res
}
if let s = sender {
@@ -110,7 +114,7 @@ func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: St
}
}
private func formatText(_ ft: FormattedText, _ preview: Bool) -> Text {
private func formatText(_ ft: FormattedText, _ preview: Bool, showSecret: Bool) -> Text {
let t = ft.text
if let f = ft.format {
switch (f) {
@@ -118,16 +122,20 @@ private func formatText(_ ft: FormattedText, _ preview: Bool) -> Text {
case .italic: return Text(t).italic()
case .strikeThrough: return Text(t).strikethrough()
case .snippet: return Text(t).font(.body.monospaced())
case .secret: return Text(t).foregroundColor(.clear).underline(color: .primary)
case .secret: return
showSecret
? Text(t)
: Text(AttributedString(t, attributes: AttributeContainer([
.foregroundColor: UIColor.clear as Any,
.backgroundColor: UIColor.secondarySystemFill as Any
])))
case let .colored(color): return Text(t).foregroundColor(color.uiColor)
case .uri: return linkText(t, t, preview, prefix: "")
case let .simplexLink(linkType, simplexUri, trustedUri, smpHosts):
case let .simplexLink(linkType, simplexUri, smpHosts):
switch privacySimplexLinkModeDefault.get() {
case .description: return linkText(simplexLinkText(linkType, smpHosts), simplexUri, preview, prefix: "")
case .full: return linkText(t, simplexUri, preview, prefix: "")
case .browser: return trustedUri
? linkText(t, t, preview, prefix: "")
: linkText(t, t, preview, prefix: "", color: .red, uiColor: .red)
case .browser: return linkText(t, simplexUri, preview, prefix: "")
}
case .email: return linkText(t, t, preview, prefix: "mailto:")
case .phone: return linkText(t, t.replacingOccurrences(of: " ", with: ""), preview, prefix: "tel:")
@@ -146,7 +154,7 @@ private func linkText(_ s: String, _ link: String, _ preview: Bool, prefix: Stri
]))).underline()
}
private func simplexLinkText(_ linkType: SimplexLinkType, _ smpHosts: [String]) -> String {
func simplexLinkText(_ linkType: SimplexLinkType, _ smpHosts: [String]) -> String {
linkType.description + " " + "(via \(smpHosts.first ?? "?"))"
}
@@ -154,10 +162,12 @@ struct MsgContentView_Previews: PreviewProvider {
static var previews: some View {
let chatItem = ChatItem.getSample(1, .directSnd, .now, "hello")
return MsgContentView(
chat: Chat.sampleData,
text: chatItem.text,
formattedText: chatItem.formattedText,
sender: chatItem.memberDisplayName,
meta: chatItem.meta
meta: chatItem.meta,
showSecrets: false
)
.environmentObject(Chat.sampleData)
}
@@ -0,0 +1,131 @@
//
// ChatItemForwardingView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 12.04.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct ChatItemForwardingView: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@Environment(\.dismiss) var dismiss
var ci: ChatItem
var fromChatInfo: ChatInfo
@Binding var composeState: ComposeState
@State private var searchText: String = ""
@FocusState private var searchFocused
@State private var alert: SomeAlert?
private let chatsToForwardTo = filterChatsToForwardTo(chats: ChatModel.shared.chats)
var body: some View {
NavigationView {
forwardListView()
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Cancel") {
dismiss()
}
}
ToolbarItem(placement: .principal) {
Text("Forward")
.bold()
}
}
}
.modifier(ThemedBackground())
.alert(item: $alert) { $0.alert }
}
@ViewBuilder private func forwardListView() -> some View {
VStack(alignment: .leading) {
if !chatsToForwardTo.isEmpty {
List {
searchFieldView(text: $searchText, focussed: $searchFocused, theme.colors.onBackground, theme.colors.secondary)
.padding(.leading, 2)
let s = searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
let chats = s == "" ? chatsToForwardTo : chatsToForwardTo.filter { foundChat($0, s) }
ForEach(chats) { chat in
forwardListChatView(chat)
.disabled(chatModel.deletedChats.contains(chat.chatInfo.id))
}
}
.modifier(ThemedBackground(grouped: true))
} else {
ZStack {
emptyList()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.modifier(ThemedBackground())
}
}
}
private func emptyList() -> some View {
Text("No filtered chats")
.foregroundColor(theme.colors.secondary)
.frame(maxWidth: .infinity)
}
@ViewBuilder private func forwardListChatView(_ chat: Chat) -> some View {
let prohibited = chat.prohibitedByPref(
hasSimplexLink: hasSimplexLink(ci.content.msgContent?.text),
isMediaOrFileAttachment: ci.content.msgContent?.isMediaOrFileAttachment ?? false,
isVoice: ci.content.msgContent?.isVoice ?? false
)
Button {
if prohibited {
alert = SomeAlert(
alert: mkAlert(
title: "Cannot forward message",
message: "Selected chat preferences prohibit this message."
),
id: "forward prohibited by preferences"
)
} else {
dismiss()
if chat.id == fromChatInfo.id {
composeState = ComposeState(
message: composeState.message,
preview: composeState.linkPreview != nil ? composeState.preview : .noPreview,
contextItem: .forwardingItem(chatItem: ci, fromChatInfo: fromChatInfo)
)
} else {
composeState = ComposeState.init(forwardingItem: ci, fromChatInfo: fromChatInfo)
ItemsModel.shared.loadOpenChat(chat.id)
}
}
} label: {
HStack {
ChatInfoImage(chat: chat, size: 30)
.padding(.trailing, 2)
Text(chat.chatInfo.chatViewName)
.foregroundColor(prohibited ? theme.colors.secondary : theme.colors.onBackground)
.lineLimit(1)
if chat.chatInfo.incognito {
Spacer()
Image(systemName: "theatermasks")
.resizable()
.scaledToFit()
.frame(width: 22, height: 22)
.foregroundColor(theme.colors.secondary)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}
#Preview {
ChatItemForwardingView(
ci: ChatItem.getSample(1, .directSnd, .now, "hello"),
fromChatInfo: .direct(contact: Contact.sampleData),
composeState: Binding.constant(ComposeState(message: "hello"))
).environmentObject(CurrentColors.toAppTheme())
}
+294 -26
View File
@@ -10,15 +10,32 @@ import SwiftUI
import SimpleXChat
struct ChatItemInfoView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var chatModel: ChatModel
@Environment(\.dismiss) var dismiss
@EnvironmentObject var theme: AppTheme
var ci: ChatItem
@Binding var chatItemInfo: ChatItemInfo?
@State private var selection: CIInfoTab = .history
@State private var alert: CIInfoViewAlert? = nil
@State private var messageStatusLimited: Bool = true
@State private var fileStatusLimited: Bool = true
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
enum CIInfoTab {
case history
case quote
case forwarded
case delivery
}
enum CIInfoViewAlert: Identifiable {
case alert(title: String, text: String)
var id: String {
switch self {
case let .alert(title, text): return "alert \(title) \(text)"
}
}
}
var body: some View {
@@ -31,31 +48,85 @@ struct ChatItemInfoView: View {
}
}
}
.alert(item: $alert) { a in
switch(a) {
case let .alert(title, text): return Alert(title: Text(title), message: Text(text))
}
}
}
}
private var title: String {
ci.chatDir.sent
ci.localNote
? NSLocalizedString("Saved message", comment: "message info title")
: ci.chatDir.sent
? NSLocalizedString("Sent message", comment: "message info title")
: NSLocalizedString("Received message", comment: "message info title")
}
private var numTabs: Int {
var numTabs = 1
if chatItemInfo?.memberDeliveryStatuses != nil {
numTabs += 1
}
if ci.quotedItem != nil {
numTabs += 1
}
if chatItemInfo?.forwardedFromChatItem != nil {
numTabs += 1
}
return numTabs
}
private var local: Bool {
switch ci.chatDir {
case .localSnd: true
case .localRcv: true
default: false
}
}
@ViewBuilder private func itemInfoView() -> some View {
if let qi = ci.quotedItem {
if numTabs > 1 {
TabView(selection: $selection) {
if let mdss = chatItemInfo?.memberDeliveryStatuses {
deliveryTab(mdss)
.tabItem {
Label("Delivery", systemImage: "checkmark.message")
}
.tag(CIInfoTab.delivery)
}
historyTab()
.tabItem {
Label("History", systemImage: "clock")
}
.tag(CIInfoTab.history)
quoteTab(qi)
.tabItem {
Label("In reply to", systemImage: "arrowshape.turn.up.left")
}
.tag(CIInfoTab.quote)
.modifier(ThemedBackground())
if let qi = ci.quotedItem {
quoteTab(qi)
.tabItem {
Label("In reply to", systemImage: "arrowshape.turn.up.left")
}
.tag(CIInfoTab.quote)
.modifier(ThemedBackground())
}
if let forwardedFromItem = chatItemInfo?.forwardedFromChatItem {
forwardedFromTab(forwardedFromItem)
.tabItem {
Label(local ? "Saved" : "Forwarded", systemImage: "arrowshape.turn.up.forward")
}
.tag(CIInfoTab.forwarded)
.modifier(ThemedBackground())
}
}
.onAppear {
if chatItemInfo?.memberDeliveryStatuses != nil {
selection = .delivery
}
}
} else {
historyTab()
.modifier(ThemedBackground())
}
}
@@ -67,7 +138,11 @@ struct ChatItemInfoView: View {
.bold()
.padding(.bottom)
infoRow("Sent at", localTimestamp(meta.itemTs))
if ci.localNote {
infoRow("Created at", localTimestamp(meta.itemTs))
} else {
infoRow("Sent at", localTimestamp(meta.itemTs))
}
if !ci.chatDir.sent {
infoRow("Received at", localTimestamp(meta.createdAt))
}
@@ -88,6 +163,35 @@ struct ChatItemInfoView: View {
if developerTools {
infoRow("Database ID", "\(meta.itemId)")
infoRow("Record updated at", localTimestamp(meta.updatedAt))
let msv = infoRow("Message status", ci.meta.itemStatus.id)
Group {
if messageStatusLimited {
msv.lineLimit(1)
} else {
msv
}
}
.onTapGesture {
withAnimation {
messageStatusLimited.toggle()
}
}
if let file = ci.file {
let fsv = infoRow("File status", file.fileStatus.id)
Group {
if fileStatusLimited {
fsv.lineLimit(1)
} else {
fsv
}
}
.onTapGesture {
withAnimation {
fileStatusLimited.toggle()
}
}
}
}
}
}
@@ -112,7 +216,7 @@ struct ChatItemInfoView: View {
}
else {
Text("No history")
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
.frame(maxWidth: .infinity)
}
}
@@ -125,11 +229,10 @@ struct ChatItemInfoView: View {
@ViewBuilder private func itemVersionView(_ itemVersion: ChatItemVersion, _ maxWidth: CGFloat, current: Bool) -> some View {
VStack(alignment: .leading, spacing: 4) {
textBubble(itemVersion.msgContent.text, itemVersion.formattedText, nil)
.allowsHitTesting(false)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(chatItemFrameColor(ci, colorScheme))
.cornerRadius(18)
.background(chatItemFrameColor(ci, theme))
.modifier(ChatItemClipped())
.contextMenu {
if itemVersion.msgContent.text != "" {
Button {
@@ -155,11 +258,23 @@ struct ChatItemInfoView: View {
@ViewBuilder private func textBubble(_ text: String, _ formattedText: [FormattedText]?, _ sender: String? = nil) -> some View {
if text != "" {
messageText(text, formattedText, sender)
TextBubble(text: text, formattedText: formattedText, sender: sender)
} else {
Text("no text")
.italic()
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
}
}
private struct TextBubble: View {
@EnvironmentObject var theme: AppTheme
var text: String
var formattedText: [FormattedText]?
var sender: String? = nil
@State private var showSecrets = false
var body: some View {
toggleSecrets(formattedText, $showSecrets, messageText(text, formattedText, sender, showSecrets: showSecrets, secondaryColor: theme.colors.secondary))
}
}
@@ -184,11 +299,10 @@ struct ChatItemInfoView: View {
@ViewBuilder private func quotedMsgView(_ qi: CIQuote, _ maxWidth: CGFloat) -> some View {
VStack(alignment: .leading, spacing: 4) {
textBubble(qi.text, qi.formattedText, qi.getSender(nil))
.allowsHitTesting(false)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(quotedMsgFrameColor(qi, colorScheme))
.cornerRadius(18)
.background(quotedMsgFrameColor(qi, theme))
.modifier(ChatItemClipped())
.contextMenu {
if qi.text != "" {
Button {
@@ -211,16 +325,166 @@ struct ChatItemInfoView: View {
.frame(maxWidth: maxWidth, alignment: .leading)
}
func quotedMsgFrameColor(_ qi: CIQuote, _ colorScheme: ColorScheme) -> Color {
func quotedMsgFrameColor(_ qi: CIQuote, _ theme: AppTheme) -> Color {
(qi.chatDir?.sent ?? false)
? (colorScheme == .light ? sentColorLight : sentColorDark)
: Color(uiColor: .tertiarySystemGroupedBackground)
? theme.appColors.sentMessage
: theme.appColors.receivedMessage
}
@ViewBuilder private func forwardedFromTab(_ forwardedFromItem: AChatItem) -> some View {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
details()
Divider().padding(.vertical)
Text(local ? "Saved from" : "Forwarded from")
.font(.title2)
.padding(.bottom, 4)
forwardedFromView(forwardedFromItem)
}
.padding()
}
.frame(maxHeight: .infinity, alignment: .top)
}
private func forwardedFromView(_ forwardedFromItem: AChatItem) -> some View {
VStack(alignment: .leading, spacing: 8) {
Button {
Task {
await MainActor.run {
ItemsModel.shared.loadOpenChat(forwardedFromItem.chatInfo.id)
dismiss()
}
}
} label: {
forwardedFromSender(forwardedFromItem)
}
if !local {
Divider().padding(.top, 32)
Text("Recipient(s) can't see who this message is from.")
.font(.caption)
.foregroundColor(theme.colors.secondary)
}
}
}
@ViewBuilder private func forwardedFromSender(_ forwardedFromItem: AChatItem) -> some View {
HStack {
ChatInfoImage(chat: Chat(chatInfo: forwardedFromItem.chatInfo), size: 48)
.padding(.trailing, 6)
if forwardedFromItem.chatItem.chatDir.sent {
VStack(alignment: .leading) {
Text("you")
.italic()
.foregroundColor(theme.colors.onBackground)
Text(forwardedFromItem.chatInfo.chatViewName)
.foregroundColor(theme.colors.secondary)
.lineLimit(1)
}
} else if case let .groupRcv(groupMember) = forwardedFromItem.chatItem.chatDir {
VStack(alignment: .leading) {
Text(groupMember.chatViewName)
.foregroundColor(theme.colors.onBackground)
.lineLimit(1)
Text(forwardedFromItem.chatInfo.chatViewName)
.foregroundColor(theme.colors.secondary)
.lineLimit(1)
}
} else {
Text(forwardedFromItem.chatInfo.chatViewName)
.foregroundColor(theme.colors.onBackground)
.lineLimit(1)
}
}
}
@ViewBuilder private func deliveryTab(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
details()
Divider().padding(.vertical)
Text("Delivery")
.font(.title2)
.padding(.bottom, 4)
memberDeliveryStatusesView(memberDeliveryStatuses)
}
.padding()
}
.frame(maxHeight: .infinity, alignment: .top)
}
@ViewBuilder private func memberDeliveryStatusesView(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View {
LazyVStack(alignment: .leading, spacing: 12) {
let mss = membersStatuses(memberDeliveryStatuses)
if !mss.isEmpty {
ForEach(mss, id: \.0.groupMemberId) { memberStatus in
memberDeliveryStatusView(memberStatus.0, memberStatus.1, memberStatus.2)
}
} else {
Text("No delivery information")
.foregroundColor(theme.colors.secondary)
}
}
}
private func membersStatuses(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> [(GroupMember, GroupSndStatus, Bool?)] {
memberDeliveryStatuses.compactMap({ mds in
if let mem = chatModel.getGroupMember(mds.groupMemberId) {
return (mem.wrapped, mds.memberDeliveryStatus, mds.sentViaProxy)
} else {
return nil
}
})
}
private func memberDeliveryStatusView(_ member: GroupMember, _ status: GroupSndStatus, _ sentViaProxy: Bool?) -> some View {
HStack{
MemberProfileImage(member, size: 30)
.padding(.trailing, 2)
Text(member.chatViewName)
.lineLimit(1)
Spacer()
if sentViaProxy == true {
Image(systemName: "arrow.forward")
.foregroundColor(theme.colors.secondary).opacity(0.67)
}
let v = Group {
let (icon, statusColor) = status.statusIcon(theme.colors.secondary, theme.colors.primary)
switch status {
case .rcvd:
ZStack(alignment: .trailing) {
Image(systemName: icon)
.foregroundColor(statusColor.opacity(0.67))
.padding(.trailing, 6)
Image(systemName: icon)
.foregroundColor(statusColor.opacity(0.67))
}
default:
Image(systemName: icon)
.foregroundColor(statusColor)
}
}
if let (title, text) = status.statusInfo {
v.onTapGesture {
alert = .alert(title: title, text: text)
}
} else {
v
}
}
}
private func itemInfoShareText() -> String {
let meta = ci.meta
var shareText: [String] = [title, ""]
shareText += [String.localizedStringWithFormat(NSLocalizedString("Sent at: %@", comment: "copied message info"), localTimestamp(meta.itemTs))]
var shareText: [String] = [String.localizedStringWithFormat(NSLocalizedString("# %@", comment: "copied message info title, # <title>"), title), ""]
shareText += [String.localizedStringWithFormat(
ci.localNote
? NSLocalizedString("Created at: %@", comment: "copied message info")
: NSLocalizedString("Sent at: %@", comment: "copied message info"),
localTimestamp(meta.itemTs))
]
if !ci.chatDir.sent {
shareText += [String.localizedStringWithFormat(NSLocalizedString("Received at: %@", comment: "copied message info"), localTimestamp(meta.createdAt))]
}
@@ -241,11 +505,15 @@ struct ChatItemInfoView: View {
if developerTools {
shareText += [
String.localizedStringWithFormat(NSLocalizedString("Database ID: %d", comment: "copied message info"), meta.itemId),
String.localizedStringWithFormat(NSLocalizedString("Record updated at: %@", comment: "copied message info"), localTimestamp(meta.updatedAt))
String.localizedStringWithFormat(NSLocalizedString("Record updated at: %@", comment: "copied message info"), localTimestamp(meta.updatedAt)),
String.localizedStringWithFormat(NSLocalizedString("Message status: %@", comment: "copied message info"), meta.itemStatus.id)
]
if let file = ci.file {
shareText += [String.localizedStringWithFormat(NSLocalizedString("File status: %@", comment: "copied message info"), file.fileStatus.id)]
}
}
if let qi = ci.quotedItem {
shareText += ["", NSLocalizedString("In reply to", comment: "copied message info")]
shareText += ["", NSLocalizedString("## In reply to", comment: "copied message info")]
let t = qi.text
shareText += [""]
if let sender = qi.getSender(nil) {
@@ -264,7 +532,7 @@ struct ChatItemInfoView: View {
}
if let chatItemInfo = chatItemInfo,
!chatItemInfo.itemVersions.isEmpty {
shareText += ["", NSLocalizedString("History", comment: "copied message info")]
shareText += ["", NSLocalizedString("## History", comment: "copied message info")]
for (index, itemVersion) in chatItemInfo.itemVersions.enumerated() {
let t = itemVersion.msgContent.text
shareText += [
+156 -49
View File
@@ -10,40 +10,39 @@ import SwiftUI
import SimpleXChat
struct ChatItemView: View {
var chatInfo: ChatInfo
@ObservedObject var chat: Chat
@EnvironmentObject var theme: AppTheme
var chatItem: ChatItem
var showMember = false
var maxWidth: CGFloat = .infinity
@State var scrollProxy: ScrollViewProxy? = nil
@Binding var revealed: Bool
@Binding var allowMenu: Bool
@Binding var audioPlayer: AudioPlayer?
@Binding var playbackState: VoiceMessagePlaybackState
@Binding var playbackTime: TimeInterval?
init(chatInfo: ChatInfo, chatItem: ChatItem, showMember: Bool = false, maxWidth: CGFloat = .infinity, scrollProxy: ScrollViewProxy? = nil, revealed: Binding<Bool>, allowMenu: Binding<Bool> = .constant(false), audioPlayer: Binding<AudioPlayer?> = .constant(nil), playbackState: Binding<VoiceMessagePlaybackState> = .constant(.noPlayback), playbackTime: Binding<TimeInterval?> = .constant(nil)) {
self.chatInfo = chatInfo
init(
chat: Chat,
chatItem: ChatItem,
showMember: Bool = false,
maxWidth: CGFloat = .infinity,
revealed: Binding<Bool>,
allowMenu: Binding<Bool> = .constant(false)
) {
self.chat = chat
self.chatItem = chatItem
self.showMember = showMember
self.maxWidth = maxWidth
_scrollProxy = .init(initialValue: scrollProxy)
_revealed = revealed
_allowMenu = allowMenu
_audioPlayer = audioPlayer
_playbackState = playbackState
_playbackTime = playbackTime
}
var body: some View {
let ci = chatItem
if chatItem.meta.itemDeleted != nil && !revealed {
MarkedDeletedItemView(chatItem: chatItem, showMember: showMember)
} else if ci.quotedItem == nil && ci.meta.itemDeleted == nil && !ci.meta.isLive {
if chatItem.meta.itemDeleted != nil && (!revealed || chatItem.isDeletedContent) {
MarkedDeletedItemView(chat: chat, chatItem: chatItem, revealed: $revealed)
} else if ci.quotedItem == nil && ci.meta.itemForwarded == nil && ci.meta.itemDeleted == nil && !ci.meta.isLive {
if let mc = ci.content.msgContent, mc.isText && isShortEmoji(ci.content.text) {
EmojiItemView(chatItem: ci)
EmojiItemView(chat: chat, chatItem: ci)
} else if ci.content.text.isEmpty, case let .voice(_, duration) = ci.content.msgContent {
CIVoiceView(chatItem: ci, recordingFile: ci.file, duration: duration, audioPlayer: $audioPlayer, playbackState: $playbackState, playbackTime: $playbackTime, allowMenu: $allowMenu)
CIVoiceView(chat: chat, chatItem: ci, recordingFile: ci.file, duration: duration, allowMenu: $allowMenu)
} else if ci.content.msgContent == nil {
ChatItemContentView(chatInfo: chatInfo, chatItem: chatItem, showMember: showMember, msgContentView: { Text(ci.text) }) // msgContent is unreachable branch in this case
ChatItemContentView(chat: chat, chatItem: chatItem, revealed: $revealed, msgContentView: { Text(ci.text) }) // msgContent is unreachable branch in this case
} else {
framedItemView()
}
@@ -53,15 +52,43 @@ struct ChatItemView: View {
}
private func framedItemView() -> some View {
FramedItemView(chatInfo: chatInfo, chatItem: chatItem, showMember: showMember, maxWidth: maxWidth, scrollProxy: scrollProxy, allowMenu: $allowMenu, audioPlayer: $audioPlayer, playbackState: $playbackState, playbackTime: $playbackTime)
let preview = chatItem.content.msgContent
.flatMap {
switch $0 {
case let .image(_, image): image
case let .video(_, image, _): image
default: nil
}
}
.flatMap { UIImage(base64Encoded: $0) }
let adjustedMaxWidth = {
if let preview, preview.size.width <= preview.size.height {
maxWidth * 0.75
} else {
maxWidth
}
}()
return FramedItemView(
chat: chat,
chatItem: chatItem,
preview: preview,
revealed: $revealed,
maxWidth: maxWidth,
imgWidth: adjustedMaxWidth,
videoWidth: adjustedMaxWidth,
allowMenu: $allowMenu
)
}
}
struct ChatItemContentView<Content: View>: View {
var chatInfo: ChatInfo
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@ObservedObject var chat: Chat
var chatItem: ChatItem
var showMember: Bool
@Binding var revealed: Bool
var msgContentView: () -> Content
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
var body: some View {
switch chatItem.content {
@@ -71,63 +98,143 @@ struct ChatItemContentView<Content: View>: View {
case .rcvDeleted: deletedItemView()
case let .sndCall(status, duration): callItemView(status, duration)
case let .rcvCall(status, duration): callItemView(status, duration)
case let .rcvIntegrityError(msgError): IntegrityErrorItemView(msgError: msgError, chatItem: chatItem, showMember: showMember)
case let .rcvDecryptionError(msgDecryptError, msgCount): CIRcvDecryptionError(msgDecryptError: msgDecryptError, msgCount: msgCount, chatItem: chatItem, showMember: showMember)
case let .rcvIntegrityError(msgError):
if developerTools {
IntegrityErrorItemView(chat: chat, msgError: msgError, chatItem: chatItem)
} else {
ZStack {}
}
case let .rcvDecryptionError(msgDecryptError, msgCount): CIRcvDecryptionError(chat: chat, msgDecryptError: msgDecryptError, msgCount: msgCount, chatItem: chatItem)
case let .rcvGroupInvitation(groupInvitation, memberRole): groupInvitationItemView(groupInvitation, memberRole)
case let .sndGroupInvitation(groupInvitation, memberRole): groupInvitationItemView(groupInvitation, memberRole)
case .rcvDirectEvent: eventItemView()
case .rcvGroupEvent(.memberCreatedContact): CIMemberCreatedContactView(chatItem: chatItem)
case .rcvGroupEvent: eventItemView()
case .sndGroupEvent: eventItemView()
case .rcvConnEvent: eventItemView()
case .sndConnEvent: eventItemView()
case let .rcvChatFeature(feature, enabled, _): chatFeatureView(feature, enabled.iconColor)
case let .sndChatFeature(feature, enabled, _): chatFeatureView(feature, enabled.iconColor)
case let .rcvChatFeature(feature, enabled, _): chatFeatureView(feature, enabled.iconColor(theme.colors.secondary))
case let .sndChatFeature(feature, enabled, _): chatFeatureView(feature, enabled.iconColor(theme.colors.secondary))
case let .rcvChatPreference(feature, allowed, param):
CIFeaturePreferenceView(chatItem: chatItem, feature: feature, allowed: allowed, param: param)
CIFeaturePreferenceView(chat: chat, chatItem: chatItem, feature: feature, allowed: allowed, param: param)
case let .sndChatPreference(feature, _, _):
CIChatFeatureView(chatItem: chatItem, feature: feature, icon: feature.icon, iconColor: .secondary)
case let .rcvGroupFeature(feature, preference, _): chatFeatureView(feature, preference.enable.iconColor)
case let .sndGroupFeature(feature, preference, _): chatFeatureView(feature, preference.enable.iconColor)
CIChatFeatureView(chat: chat, chatItem: chatItem, revealed: $revealed, feature: feature, icon: feature.icon, iconColor: theme.colors.secondary)
case let .rcvGroupFeature(feature, preference, _, role): chatFeatureView(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor(theme.colors.secondary))
case let .sndGroupFeature(feature, preference, _, role): chatFeatureView(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor(theme.colors.secondary))
case let .rcvChatFeatureRejected(feature): chatFeatureView(feature, .red)
case let .rcvGroupFeatureRejected(feature): chatFeatureView(feature, .red)
case .sndModerated: deletedItemView()
case .rcvModerated: deletedItemView()
case .rcvBlocked: deletedItemView()
case let .sndDirectE2EEInfo(e2eeInfo): CIEventView(eventText: directE2EEInfoText(e2eeInfo))
case let .rcvDirectE2EEInfo(e2eeInfo): CIEventView(eventText: directE2EEInfoText(e2eeInfo))
case .sndGroupE2EEInfo: CIEventView(eventText: e2eeInfoNoPQText())
case .rcvGroupE2EEInfo: CIEventView(eventText: e2eeInfoNoPQText())
case let .invalidJSON(json): CIInvalidJSONView(json: json)
}
}
private func deletedItemView() -> some View {
DeletedItemView(chatItem: chatItem, showMember: showMember)
DeletedItemView(chat: chat, chatItem: chatItem)
}
private func callItemView(_ status: CICallStatus, _ duration: Int) -> some View {
CICallItemView(chatInfo: chatInfo, chatItem: chatItem, status: status, duration: duration)
CICallItemView(chat: chat, chatItem: chatItem, status: status, duration: duration)
}
private func groupInvitationItemView(_ groupInvitation: CIGroupInvitation, _ memberRole: GroupMemberRole) -> some View {
CIGroupInvitationView(chatItem: chatItem, groupInvitation: groupInvitation, memberRole: memberRole, chatIncognito: chatInfo.incognito)
CIGroupInvitationView(chat: chat, chatItem: chatItem, groupInvitation: groupInvitation, memberRole: memberRole, chatIncognito: chat.chatInfo.incognito)
}
private func eventItemView() -> some View {
CIEventView(chatItem: chatItem)
CIEventView(eventText: eventItemViewText(theme.colors.secondary))
}
private func eventItemViewText(_ secondaryColor: Color) -> Text {
if !revealed, let t = mergedGroupEventText {
return chatEventText(t + Text(" ") + chatItem.timestampText, secondaryColor)
} else if let member = chatItem.memberDisplayName {
return Text(member + " ")
.font(.caption)
.foregroundColor(secondaryColor)
.fontWeight(.light)
+ chatEventText(chatItem, secondaryColor)
} else {
return chatEventText(chatItem, secondaryColor)
}
}
private func chatFeatureView(_ feature: Feature, _ iconColor: Color) -> some View {
CIChatFeatureView(chatItem: chatItem, feature: feature, iconColor: iconColor)
CIChatFeatureView(chat: chat, chatItem: chatItem, revealed: $revealed, feature: feature, iconColor: iconColor)
}
private var mergedGroupEventText: Text? {
let (count, ns) = chatModel.getConnectedMemberNames(chatItem)
let members: LocalizedStringKey =
switch ns.count {
case 1: "\(ns[0]) connected"
case 2: "\(ns[0]) and \(ns[1]) connected"
case 3: "\(ns[0] + ", " + ns[1]) and \(ns[2]) connected"
default:
ns.count > 3
? "\(ns[0]), \(ns[1]) and \(ns.count - 2) other members connected"
: ""
}
return if count <= 1 {
nil
} else if ns.count == 0 {
Text("\(count) group events")
} else if count > ns.count {
Text(members) + Text(" ") + Text("and \(count - ns.count) other events")
} else {
Text(members)
}
}
private func directE2EEInfoText(_ info: E2EEInfo) -> Text {
info.pqEnabled
? Text("Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.")
.font(.caption)
.foregroundColor(theme.colors.secondary)
.fontWeight(.light)
: e2eeInfoNoPQText()
}
private func e2eeInfoNoPQText() -> Text {
Text("Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.")
.font(.caption)
.foregroundColor(theme.colors.secondary)
.fontWeight(.light)
}
}
func chatEventText(_ text: Text, _ secondaryColor: Color) -> Text {
text
.font(.caption)
.foregroundColor(secondaryColor)
.fontWeight(.light)
}
func chatEventText(_ eventText: LocalizedStringKey, _ ts: Text, _ secondaryColor: Color) -> Text {
chatEventText(Text(eventText) + Text(" ") + ts, secondaryColor)
}
func chatEventText(_ ci: ChatItem, _ secondaryColor: Color) -> Text {
chatEventText("\(ci.content.text)", ci.timestampText, secondaryColor)
}
struct ChatItemView_Previews: PreviewProvider {
static var previews: some View {
Group{
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello"), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(2, .directRcv, .now, "hello there too"), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂"), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂"), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂🙂"), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getDeletedContentSample(), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, itemDeleted: .deleted(deletedTs: .now)), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂", .sndSent, itemLive: true), revealed: Binding.constant(true))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, itemLive: true), revealed: Binding.constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello"), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directRcv, .now, "hello there too"), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂"), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂"), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂🙂"), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getDeletedContentSample(), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete), itemDeleted: .deleted(deletedTs: .now)), revealed: Binding.constant(false))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂", .sndSent(sndProgress: .complete), itemLive: true), revealed: Binding.constant(true))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete), itemLive: true), revealed: Binding.constant(true))
}
.previewLayout(.fixed(width: 360, height: 70))
.environmentObject(Chat.sampleData)
@@ -139,7 +246,7 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
let ciFeatureContent = CIContent.rcvChatFeature(feature: .fullDelete, enabled: FeatureEnabled(forUser: false, forContact: false), param: nil)
Group{
ChatItemView(
chatInfo: ChatInfo.sampleData.direct,
chat: Chat.sampleData,
chatItem: ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "1 skipped message", .rcvRead, itemDeleted: .deleted(deletedTs: .now)),
@@ -150,7 +257,7 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
revealed: Binding.constant(true)
)
ChatItemView(
chatInfo: ChatInfo.sampleData.direct,
chat: Chat.sampleData,
chatItem: ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "1 skipped message", .rcvRead),
@@ -161,7 +268,7 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
revealed: Binding.constant(true)
)
ChatItemView(
chatInfo: ChatInfo.sampleData.direct,
chat: Chat.sampleData,
chatItem: ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "received invitation to join group team as admin", .rcvRead, itemDeleted: .deleted(deletedTs: .now)),
@@ -172,7 +279,7 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
revealed: Binding.constant(true)
)
ChatItemView(
chatInfo: ChatInfo.sampleData.direct,
chat: Chat.sampleData,
chatItem: ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "group event text", .rcvRead, itemDeleted: .deleted(deletedTs: .now)),
@@ -183,7 +290,7 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
revealed: Binding.constant(true)
)
ChatItemView(
chatInfo: ChatInfo.sampleData.direct,
chat: Chat.sampleData,
chatItem: ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, ciFeatureContent.text, .rcvRead, itemDeleted: .deleted(deletedTs: .now)),
File diff suppressed because it is too large Load Diff
@@ -9,7 +9,7 @@
import SwiftUI
struct ComposeFileView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var theme: AppTheme
let fileName: String
let cancelFile: (() -> Void)
let cancelEnabled: Bool
@@ -32,9 +32,8 @@ struct ComposeFileView: View {
}
.padding(.vertical, 1)
.padding(.trailing, 12)
.frame(height: 50)
.background(colorScheme == .light ? sentColorLight : sentColorDark)
.frame(height: 54)
.background(theme.appColors.sentMessage)
.frame(maxWidth: .infinity)
.padding(.top, 8)
}
}
@@ -10,7 +10,7 @@ import SwiftUI
import SimpleXChat
struct ComposeImageView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var theme: AppTheme
let images: [String]
let cancelImage: (() -> Void)
let cancelEnabled: Bool
@@ -18,10 +18,7 @@ struct ComposeImageView: View {
var body: some View {
HStack(alignment: .center, spacing: 8) {
let imgs: [UIImage] = images.compactMap { image in
if let data = Data(base64Encoded: dropImagePrefix(image)) {
return UIImage(data: data)
}
return nil
UIImage(base64Encoded: image)
}
if imgs.count == 0 {
ProgressView()
@@ -48,9 +45,9 @@ struct ComposeImageView: View {
}
.padding(.vertical, 1)
.padding(.trailing, 12)
.background(colorScheme == .light ? sentColorLight : sentColorDark)
.background(theme.appColors.sentMessage)
.frame(minHeight: 54)
.frame(maxWidth: .infinity)
.padding(.top, 8)
}
}
@@ -10,37 +10,8 @@ import SwiftUI
import LinkPresentation
import SimpleXChat
func getLinkPreview(url: URL, cb: @escaping (LinkPreview?) -> Void) {
logger.debug("getLinkMetadata: fetching URL preview")
LPMetadataProvider().startFetchingMetadata(for: url){ metadata, error in
if let e = error {
logger.error("Error retrieving link metadata: \(e.localizedDescription)")
}
if let metadata = metadata,
let imageProvider = metadata.imageProvider,
imageProvider.canLoadObject(ofClass: UIImage.self) {
imageProvider.loadObject(ofClass: UIImage.self){ object, error in
var linkPreview: LinkPreview? = nil
if let error = error {
logger.error("Couldn't load image preview from link metadata with error: \(error.localizedDescription)")
} else {
if let image = object as? UIImage,
let resized = resizeImageToStrSize(image, maxDataSize: 14000),
let title = metadata.title,
let uri = metadata.originalURL {
linkPreview = LinkPreview(uri: uri, title: title, image: resized)
}
}
cb(linkPreview)
}
} else {
cb(nil)
}
}
}
struct ComposeLinkView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var theme: AppTheme
let linkPreview: LinkPreview?
var cancelPreview: (() -> Void)? = nil
let cancelEnabled: Bool
@@ -62,15 +33,14 @@ struct ComposeLinkView: View {
}
.padding(.vertical, 1)
.padding(.trailing, 12)
.background(colorScheme == .light ? sentColorLight : sentColorDark)
.background(theme.appColors.sentMessage)
.frame(minHeight: 54)
.frame(maxWidth: .infinity)
.padding(.top, 8)
}
private func linkPreviewView(_ linkPreview: LinkPreview) -> some View {
HStack(alignment: .center, spacing: 8) {
if let data = Data(base64Encoded: dropImagePrefix(linkPreview.image)),
let uiImage = UIImage(data: data) {
if let uiImage = UIImage(base64Encoded: linkPreview.image) {
Image(uiImage: uiImage)
.resizable()
.aspectRatio(contentMode: .fit)
@@ -82,10 +52,10 @@ struct ComposeLinkView: View {
Text(linkPreview.uri.absoluteString)
.font(.caption)
.lineLimit(1)
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
}
.padding(.vertical, 5)
.frame(maxWidth: .infinity, minHeight: 60, maxHeight: 60)
.frame(maxWidth: .infinity, minHeight: 60)
}
}
}
@@ -23,6 +23,7 @@ enum ComposeContextItem {
case noContextItem
case quotedItem(chatItem: ChatItem)
case editingItem(chatItem: ChatItem)
case forwardingItem(chatItem: ChatItem, fromChatInfo: ChatInfo)
}
enum VoiceMessageRecordingState {
@@ -44,7 +45,6 @@ struct ComposeState {
var contextItem: ComposeContextItem
var voiceMessageRecordingState: VoiceMessageRecordingState
var inProgress = false
var disabled = false
var useLinkPreviews: Bool = UserDefaults.standard.bool(forKey: DEFAULT_PRIVACY_LINK_PREVIEWS)
init(
@@ -73,6 +73,13 @@ struct ComposeState {
}
}
init(forwardingItem: ChatItem, fromChatInfo: ChatInfo) {
self.message = ""
self.preview = .noPreview
self.contextItem = .forwardingItem(chatItem: forwardingItem, fromChatInfo: fromChatInfo)
self.voiceMessageRecordingState = .noRecording
}
func copy(
message: String? = nil,
liveMessage: LiveMessage? = nil,
@@ -103,12 +110,19 @@ struct ComposeState {
}
}
var forwarding: Bool {
switch contextItem {
case .forwardingItem: return true
default: return false
}
}
var sendEnabled: Bool {
switch preview {
case .mediaPreviews: return true
case let .mediaPreviews(media): return !media.isEmpty
case .voicePreview: return voiceMessageRecordingState == .finished
case .filePreview: return true
default: return !message.isEmpty || liveMessage != nil
default: return !message.isEmpty || forwarding || liveMessage != nil
}
}
@@ -154,7 +168,7 @@ struct ComposeState {
}
var attachmentDisabled: Bool {
if editing || liveMessage != nil || inProgress { return true }
if editing || forwarding || liveMessage != nil || inProgress { return true }
switch preview {
case .noPreview: return false
case .linkPreview: return false
@@ -162,31 +176,39 @@ struct ComposeState {
}
}
var attachmentPreview: Bool {
switch preview {
case .noPreview: false
case .linkPreview: false
case let .mediaPreviews(mediaPreviews): !mediaPreviews.isEmpty
case .voicePreview: false
case .filePreview: true
}
}
var empty: Bool {
message == "" && noPreview
}
}
func chatItemPreview(chatItem: ChatItem) -> ComposePreview {
let chatItemPreview: ComposePreview
switch chatItem.content.msgContent {
case .text:
chatItemPreview = .noPreview
return .noPreview
case let .link(_, preview: preview):
chatItemPreview = .linkPreview(linkPreview: preview)
return .linkPreview(linkPreview: preview)
case let .image(_, image):
chatItemPreview = .mediaPreviews(mediaPreviews: [(image, nil)])
return .mediaPreviews(mediaPreviews: [(image, nil)])
case let .video(_, image, _):
chatItemPreview = .mediaPreviews(mediaPreviews: [(image, nil)])
return .mediaPreviews(mediaPreviews: [(image, nil)])
case let .voice(_, duration):
chatItemPreview = .voicePreview(recordingFileName: chatItem.file?.fileName ?? "", duration: duration)
return .voicePreview(recordingFileName: chatItem.file?.fileName ?? "", duration: duration)
case .file:
let fileName = chatItem.file?.fileName ?? ""
chatItemPreview = .filePreview(fileName: fileName, file: getAppFilePath(fileName))
return .filePreview(fileName: fileName, file: getAppFilePath(fileName))
default:
chatItemPreview = .noPreview
return .noPreview
}
return chatItemPreview
}
enum UploadContent: Equatable {
@@ -232,15 +254,18 @@ enum UploadContent: Equatable {
struct ComposeView: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@ObservedObject var chat: Chat
@Binding var composeState: ComposeState
@Binding var keyboardVisible: Bool
@State var linkUrl: URL? = nil
@State var hasSimplexLink: Bool = false
@State var prevLinkUrl: URL? = nil
@State var pendingLinkUrl: URL? = nil
@State var cancelledLinks: Set<String> = []
@Environment(\.colorScheme) private var colorScheme
@State private var showChooseSource = false
@State private var showMediaPicker = false
@State private var showTakePhoto = false
@@ -255,8 +280,30 @@ struct ComposeView: View {
// this is a workaround to fire an explicit event in certain cases
@State private var stopPlayback: Bool = false
@AppStorage(DEFAULT_PRIVACY_SAVE_LAST_DRAFT) private var saveLastDraft = true
@AppStorage(DEFAULT_TOOLBAR_MATERIAL) private var toolbarMaterial = ToolbarMaterial.defaultMaterial
var body: some View {
VStack(spacing: 0) {
Divider()
if chat.chatInfo.contact?.nextSendGrpInv ?? false {
ContextInvitingContactMemberView()
Divider()
}
// preference checks should match checks in forwarding list
let simplexLinkProhibited = hasSimplexLink && !chat.groupFeatureEnabled(.simplexLinks)
let fileProhibited = composeState.attachmentPreview && !chat.groupFeatureEnabled(.files)
let voiceProhibited = composeState.voicePreview && !chat.chatInfo.featureEnabled(.voice)
if simplexLinkProhibited {
msgNotAllowedView("SimpleX links not allowed", icon: "link")
Divider()
} else if fileProhibited {
msgNotAllowedView("Files and media not allowed", icon: "doc")
Divider()
} else if voiceProhibited {
msgNotAllowedView("Voice messages not allowed", icon: "mic")
Divider()
}
contextItemView()
switch (composeState.editing, composeState.preview) {
case (true, .filePreview): EmptyView()
@@ -270,12 +317,13 @@ struct ComposeView: View {
Image(systemName: "paperclip")
.resizable()
}
.disabled(composeState.attachmentDisabled || !chat.userCanSend)
.disabled(composeState.attachmentDisabled || !chat.userCanSend || (chat.chatInfo.contact?.nextSendGrpInv ?? false))
.frame(width: 25, height: 25)
.padding(.bottom, 12)
.padding(.leading, 12)
.tint(theme.colors.primary)
if case let .group(g) = chat.chatInfo,
!g.fullGroupPreferences.files.on {
!g.fullGroupPreferences.files.on(for: g.membership) {
b.disabled(true).onTapGesture {
AlertManager.shared.showAlertMsg(
title: "Files and media prohibited!",
@@ -292,13 +340,15 @@ struct ComposeView: View {
sendMessage(ttl: ttl)
resetLinkPreview()
},
sendLiveMessage: sendLiveMessage,
sendLiveMessage: chat.chatInfo.chatType != .local ? sendLiveMessage : nil,
updateLiveMessage: updateLiveMessage,
cancelLiveMessage: {
composeState.liveMessage = nil
chatModel.removeLiveDummy()
},
nextSendGrpInv: chat.chatInfo.contact?.nextSendGrpInv ?? false,
voiceMessageAllowed: chat.chatInfo.featureEnabled(.voice),
disableSendButton: simplexLinkProhibited || fileProhibited || voiceProhibited,
showEnableVoiceMessagesAlert: chat.chatInfo.showEnableVoiceMessagesAlert,
startVoiceMessageRecording: {
Task {
@@ -309,16 +359,18 @@ struct ComposeView: View {
allowVoiceMessagesToContact: allowVoiceMessagesToContact,
timedMessageAllowed: chat.chatInfo.featureEnabled(.timedMessages),
onMediaAdded: { media in if !media.isEmpty { chosenMedia = media }},
keyboardVisible: $keyboardVisible
keyboardVisible: $keyboardVisible,
sendButtonColor: chat.chatInfo.incognito
? .indigo.opacity(colorScheme == .dark ? 1 : 0.7)
: theme.colors.primary
)
.padding(.trailing, 12)
.background(.background)
.disabled(!chat.userCanSend)
if chat.userIsObserver {
Text("you are observer")
.italic()
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
.padding(.horizontal, 12)
.onTapGesture {
AlertManager.shared.showAlertMsg(
@@ -330,13 +382,23 @@ struct ComposeView: View {
}
}
}
.onChange(of: composeState.message) { _ in
.background {
Color.clear
.overlay(ToolbarMaterial.material(toolbarMaterial))
.ignoresSafeArea(.all, edges: .bottom)
}
.onChange(of: composeState.message) { msg in
if composeState.linkPreviewAllowed {
if composeState.message.count > 0 {
showLinkPreview(composeState.message)
if msg.count > 0 {
showLinkPreview(msg)
} else {
resetLinkPreview()
hasSimplexLink = false
}
} else if msg.count > 0 && !chat.groupFeatureEnabled(.simplexLinks) {
(_, hasSimplexLink) = parseMessage(msg)
} else {
hasSimplexLink = false
}
}
.onChange(of: chat.userCanSend) { canSend in
@@ -377,10 +439,10 @@ struct ComposeView: View {
}
}
.sheet(isPresented: $showMediaPicker) {
LibraryMediaListPicker(media: $chosenMedia, selectionLimit: 10) { itemsSelected in
showMediaPicker = false
if itemsSelected {
DispatchQueue.main.async {
LibraryMediaListPicker(addMedia: addMediaContent, selectionLimit: 10, finishedPreprocessing: finishedPreprocessingMediaContent) { itemsSelected in
await MainActor.run {
showMediaPicker = false
if itemsSelected {
composeState = composeState.copy(preview: .mediaPreviews(mediaPreviews: []))
}
}
@@ -442,7 +504,15 @@ struct ComposeView: View {
} else if (composeState.inProgress) {
clearCurrentDraft()
} else if !composeState.empty {
saveCurrentDraft()
if case .recording = composeState.voiceMessageRecordingState {
finishVoiceMessageRecording()
if let fileName = composeState.voiceMessageRecordingFileName {
chatModel.filesToDelete.insert(getAppFilePath(fileName))
}
}
if saveLastDraft {
saveCurrentDraft()
}
} else {
cancelCurrentVoiceRecording()
clearCurrentDraft()
@@ -473,6 +543,30 @@ struct ComposeView: View {
}
}
private func addMediaContent(_ content: UploadContent) async {
if let img = resizeImageToStrSize(content.uiImage, maxDataSize: 14000) {
var newMedia: [(String, UploadContent?)] = []
if case var .mediaPreviews(media) = composeState.preview {
media.append((img, content))
newMedia = media
} else {
newMedia = [(img, content)]
}
await MainActor.run {
composeState = composeState.copy(preview: .mediaPreviews(mediaPreviews: newMedia))
}
}
}
// When error occurs while converting video, remove media preview
private func finishedPreprocessingMediaContent() {
if case let .mediaPreviews(media) = composeState.preview, media.isEmpty {
DispatchQueue.main.async {
composeState = composeState.copy(preview: .noPreview)
}
}
}
private var maxFileSize: Int64 {
getMaxFileSize(.xftp)
}
@@ -541,6 +635,7 @@ struct ComposeView: View {
cancelPreview: cancelLinkPreview,
cancelEnabled: !composeState.inProgress
)
Divider()
case let .mediaPreviews(mediaPreviews: media):
ComposeImageView(
images: media.map { (img, _) in img },
@@ -549,6 +644,7 @@ struct ComposeView: View {
chosenMedia = []
},
cancelEnabled: !composeState.editing && !composeState.inProgress)
Divider()
case let .voicePreview(recordingFileName, _):
ComposeVoiceView(
recordingFileName: recordingFileName,
@@ -561,6 +657,7 @@ struct ComposeView: View {
cancelEnabled: !composeState.editing && !composeState.inProgress,
stopPlayback: $stopPlayback
)
Divider()
case let .filePreview(fileName, _):
ComposeFileView(
fileName: fileName,
@@ -568,25 +665,50 @@ struct ComposeView: View {
composeState = composeState.copy(preview: .noPreview)
},
cancelEnabled: !composeState.editing && !composeState.inProgress)
Divider()
}
}
private func msgNotAllowedView(_ reason: LocalizedStringKey, icon: String) -> some View {
HStack {
Image(systemName: icon).foregroundColor(theme.colors.secondary)
Text(reason).italic()
}
.padding(12)
.frame(minHeight: 54)
.frame(maxWidth: .infinity, alignment: .leading)
.background(.thinMaterial)
}
@ViewBuilder private func contextItemView() -> some View {
switch composeState.contextItem {
case .noContextItem:
EmptyView()
case let .quotedItem(chatItem: quotedItem):
ContextItemView(
chat: chat,
contextItem: quotedItem,
contextIcon: "arrowshape.turn.up.left",
cancelContextItem: { composeState = composeState.copy(contextItem: .noContextItem) }
)
Divider()
case let .editingItem(chatItem: editingItem):
ContextItemView(
chat: chat,
contextItem: editingItem,
contextIcon: "pencil",
cancelContextItem: { clearState() }
)
Divider()
case let .forwardingItem(chatItem: forwardedItem, _):
ContextItemView(
chat: chat,
contextItem: forwardedItem,
contextIcon: "arrowshape.turn.up.forward",
cancelContextItem: { composeState = composeState.copy(contextItem: .noContextItem) },
showSender: false
)
Divider()
}
}
@@ -606,7 +728,14 @@ struct ComposeView: View {
if liveMessage != nil { composeState = composeState.copy(liveMessage: nil) }
await sending()
}
if case let .editingItem(ci) = composeState.contextItem {
if chat.chatInfo.contact?.nextSendGrpInv ?? false {
await sendMemberContactInvitation()
} else if case let .forwardingItem(ci, fromChatInfo) = composeState.contextItem {
sent = await forwardItem(ci, fromChatInfo, ttl)
if !composeState.message.isEmpty {
sent = await send(checkLinkPreview(), quoted: sent?.id, live: false, ttl: ttl)
}
} else if case let .editingItem(ci) = composeState.contextItem {
sent = await updateMessage(ci, live: live)
} else if let liveMessage = liveMessage, liveMessage.sentMsg != nil {
sent = await updateMessage(liveMessage.chatItem, live: live)
@@ -643,21 +772,39 @@ struct ComposeView: View {
}
case let .voicePreview(recordingFileName, duration):
stopPlayback.toggle()
chatModel.filesToDelete.remove(getAppFilePath(recordingFileName))
sent = await send(.voice(text: msgText, duration: duration), quoted: quoted, file: recordingFileName, ttl: ttl)
let file = voiceCryptoFile(recordingFileName)
sent = await send(.voice(text: msgText, duration: duration), quoted: quoted, file: file, ttl: ttl)
case let .filePreview(_, file):
if let savedFile = saveFileFromURL(file) {
sent = await send(.file(msgText), quoted: quoted, file: savedFile, live: live, ttl: ttl)
}
}
}
await MainActor.run { clearState(live: live) }
await MainActor.run {
let wasForwarding = composeState.forwarding
clearState(live: live)
if wasForwarding,
chatModel.draftChatId == chat.chatInfo.id,
let draft = chatModel.draft {
composeState = draft
}
}
return sent
func sending() async {
await MainActor.run { composeState.disabled = true }
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if composeState.disabled { composeState.inProgress = true }
await MainActor.run { composeState.inProgress = true }
}
func sendMemberContactInvitation() async {
do {
let mc = checkLinkPreview()
let contact = try await apiSendMemberContactInvitation(chat.chatInfo.apiId, mc)
await MainActor.run {
self.chatModel.updateContact(contact)
}
} catch {
logger.error("ChatView.sendMemberContactInvitation error: \(error.localizedDescription)")
AlertManager.shared.showAlertMsg(title: "Error sending member contact invitation", message: "Error: \(responseError(error))")
}
}
@@ -717,22 +864,40 @@ struct ComposeView: View {
func sendVideo(_ imageData: (String, UploadContent?), text: String = "", quoted: Int64? = nil, live: Bool = false, ttl: Int?) async -> ChatItem? {
let (image, data) = imageData
if case let .video(_, url, duration) = data, let savedFile = saveFileFromURLWithoutLoad(url) {
if case let .video(_, url, duration) = data, let savedFile = moveTempFileFromURL(url) {
ChatModel.shared.filesToDelete.remove(url)
return await send(.video(text: text, image: image, duration: duration), quoted: quoted, file: savedFile, live: live, ttl: ttl)
}
return nil
}
func send(_ mc: MsgContent, quoted: Int64?, file: String? = nil, live: Bool = false, ttl: Int?) async -> ChatItem? {
if let chatItem = await apiSendMessage(
type: chat.chatInfo.chatType,
id: chat.chatInfo.apiId,
file: file,
quotedItemId: quoted,
msg: mc,
live: live,
ttl: ttl
) {
func voiceCryptoFile(_ fileName: String) -> CryptoFile? {
if !privacyEncryptLocalFilesGroupDefault.get() {
return CryptoFile.plain(fileName)
}
let url = getAppFilePath(fileName)
let toFile = generateNewFileName("voice", "m4a")
let toUrl = getAppFilePath(toFile)
if let cfArgs = try? encryptCryptoFile(fromPath: url.path, toPath: toUrl.path) {
removeFile(url)
return CryptoFile(filePath: toFile, cryptoArgs: cfArgs)
} else {
return nil
}
}
func send(_ mc: MsgContent, quoted: Int64?, file: CryptoFile? = nil, live: Bool = false, ttl: Int?) async -> ChatItem? {
if let chatItem = chat.chatInfo.chatType == .local
? await apiCreateChatItem(noteFolderId: chat.chatInfo.apiId, file: file, msg: mc)
: await apiSendMessage(
type: chat.chatInfo.chatType,
id: chat.chatInfo.apiId,
file: file,
quotedItemId: quoted,
msg: mc,
live: live,
ttl: ttl
) {
await MainActor.run {
chatModel.removeLiveDummy(animated: false)
chatModel.addChatItem(chat.chatInfo, chatItem)
@@ -740,7 +905,24 @@ struct ComposeView: View {
return chatItem
}
if let file = file {
removeFile(file)
removeFile(file.filePath)
}
return nil
}
func forwardItem(_ forwardedItem: ChatItem, _ fromChatInfo: ChatInfo, _ ttl: Int?) async -> ChatItem? {
if let chatItem = await apiForwardChatItem(
toChatType: chat.chatInfo.chatType,
toChatId: chat.chatInfo.apiId,
fromChatType: fromChatInfo.chatType,
fromChatId: fromChatInfo.apiId,
itemId: forwardedItem.id,
ttl: ttl
) {
await MainActor.run {
chatModel.addChatItem(chat.chatInfo, chatItem)
}
return chatItem
}
return nil
}
@@ -748,7 +930,7 @@ struct ComposeView: View {
func checkLinkPreview() -> MsgContent {
switch (composeState.preview) {
case let .linkPreview(linkPreview: linkPreview):
if let url = parseMessage(msgText),
if let url = parseMessage(msgText).url,
let linkPreview = linkPreview,
url == linkPreview.uri {
return .link(text: msgText, preview: linkPreview)
@@ -760,7 +942,7 @@ struct ComposeView: View {
}
}
func saveAnyImage(_ img: UploadContent) -> String? {
func saveAnyImage(_ img: UploadContent) -> CryptoFile? {
switch img {
case let .simpleImage(image): return saveImage(image)
case let .animatedImage(image): return saveAnimImage(image)
@@ -852,7 +1034,6 @@ struct ComposeView: View {
private func clearState(live: Bool = false) {
if live {
composeState.disabled = false
composeState.inProgress = false
} else {
composeState = ComposeState()
@@ -865,12 +1046,6 @@ struct ComposeView: View {
}
private func saveCurrentDraft() {
if case .recording = composeState.voiceMessageRecordingState {
finishVoiceMessageRecording()
if let fileName = composeState.voiceMessageRecordingFileName {
chatModel.filesToDelete.insert(getAppFilePath(fileName))
}
}
chatModel.draft = composeState
chatModel.draftChatId = chat.id
}
@@ -884,7 +1059,7 @@ struct ComposeView: View {
private func showLinkPreview(_ s: String) {
prevLinkUrl = linkUrl
linkUrl = parseMessage(s)
(linkUrl, hasSimplexLink) = parseMessage(s)
if let url = linkUrl {
if url != composeState.linkPreview?.uri && url != pendingLinkUrl {
pendingLinkUrl = url
@@ -901,13 +1076,17 @@ struct ComposeView: View {
}
}
private func parseMessage(_ msg: String) -> URL? {
let parsedMsg = parseSimpleXMarkdown(msg)
let uri = parsedMsg?.first(where: { ft in
private func parseMessage(_ msg: String) -> (url: URL?, hasSimplexLink: Bool) {
guard let parsedMsg = parseSimpleXMarkdown(msg) else { return (nil, false) }
let url: URL? = if let uri = parsedMsg.first(where: { ft in
ft.format == .uri && !cancelledLinks.contains(ft.text) && !isSimplexLink(ft.text)
})
if let uri = uri { return URL(string: uri.text) }
else { return nil }
}) {
URL(string: uri.text)
} else {
nil
}
let simplexLink = parsedMsgHasSimplexLink(parsedMsg)
return (url, simplexLink)
}
private func isSimplexLink(_ link: String) -> Bool {
@@ -915,6 +1094,9 @@ struct ComposeView: View {
}
private func cancelLinkPreview() {
if let pendingLink = pendingLinkUrl?.absoluteString {
cancelledLinks.insert(pendingLink)
}
if let uri = composeState.linkPreview?.uri.absoluteString {
cancelledLinks.insert(uri)
}
@@ -25,7 +25,7 @@ func voiceMessageTime_(_ time: TimeInterval?) -> String {
struct ComposeVoiceView: View {
@EnvironmentObject var chatModel: ChatModel
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var theme: AppTheme
var recordingFileName: String
@Binding var recordingTime: TimeInterval?
@Binding var recordingState: VoiceMessageRecordingState
@@ -50,9 +50,9 @@ struct ComposeVoiceView: View {
}
.padding(.vertical, 1)
.frame(height: ComposeVoiceView.previewHeight)
.background(colorScheme == .light ? sentColorLight : sentColorDark)
.background(theme.appColors.sentMessage)
.frame(minHeight: 54)
.frame(maxWidth: .infinity)
.padding(.top, 8)
}
private func recordingMode() -> some View {
@@ -80,7 +80,7 @@ struct ComposeVoiceView: View {
Button {
startPlayback()
} label: {
playPauseIcon("play.fill")
playPauseIcon("play.fill", theme.colors.primary)
}
Text(voiceMessageTime_(recordingTime))
case .playing:
@@ -88,7 +88,7 @@ struct ComposeVoiceView: View {
audioPlayer?.pause()
playbackState = .paused
} label: {
playPauseIcon("pause.fill")
playPauseIcon("pause.fill", theme.colors.primary)
}
Text(voiceMessageTime_(playbackTime))
case .paused:
@@ -96,7 +96,7 @@ struct ComposeVoiceView: View {
audioPlayer?.play()
playbackState = .playing
} label: {
playPauseIcon("play.fill")
playPauseIcon("play.fill", theme.colors.primary)
}
Text(voiceMessageTime_(playbackTime))
}
@@ -131,7 +131,7 @@ struct ComposeVoiceView: View {
}
}
private func playPauseIcon(_ image: String, _ color: Color = .accentColor) -> some View {
private func playPauseIcon(_ image: String, _ color: Color) -> some View {
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fit)
@@ -147,9 +147,11 @@ struct ComposeVoiceView: View {
} label: {
Image(systemName: "multiply")
}
.tint(theme.colors.primary)
}
struct SliderBar: View {
@EnvironmentObject var theme: AppTheme
var length: TimeInterval
@Binding var progress: TimeInterval?
var seek: (TimeInterval) -> Void
@@ -158,10 +160,12 @@ struct ComposeVoiceView: View {
Slider(value: Binding(get: { progress ?? TimeInterval(0) }, set: { seek($0) }), in: 0 ... length)
.frame(maxWidth: .infinity)
.frame(height: 4)
.tint(theme.colors.primary)
}
}
private struct ProgressBar: View {
@EnvironmentObject var theme: AppTheme
var length: TimeInterval
@Binding var progress: TimeInterval?
@@ -169,7 +173,7 @@ struct ComposeVoiceView: View {
GeometryReader { geometry in
ZStack {
Rectangle()
.fill(Color.accentColor)
.fill(theme.colors.primary)
.frame(width: min(CGFloat((progress ?? TimeInterval(0)) / length) * geometry.size.width, geometry.size.width), height: 4)
.animation(.linear, value: progress)
}
@@ -188,7 +192,7 @@ struct ComposeVoiceView: View {
playbackTime = recordingTime // animate progress bar to the end
}
)
audioPlayer?.start(fileName: recordingFileName, at: playbackTime)
audioPlayer?.start(fileSource: CryptoFile.plain(recordingFileName), at: playbackTime)
playbackState = .playing
}
}
@@ -0,0 +1,31 @@
//
// ContextInvitingContactMemberView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 18.09.2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import SwiftUI
struct ContextInvitingContactMemberView: View {
@EnvironmentObject var theme: AppTheme
var body: some View {
HStack {
Image(systemName: "message")
.foregroundColor(theme.colors.secondary)
Text("Send direct message to connect")
}
.padding(12)
.frame(minHeight: 54)
.frame(maxWidth: .infinity, alignment: .leading)
.background(.thinMaterial)
}
}
struct ContextInvitingContactMemberView_Previews: PreviewProvider {
static var previews: some View {
ContextInvitingContactMemberView()
}
}
@@ -10,10 +10,12 @@ import SwiftUI
import SimpleXChat
struct ContextItemView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var theme: AppTheme
@ObservedObject var chat: Chat
let contextItem: ChatItem
let contextIcon: String
let cancelContextItem: () -> Void
var showSender: Bool = true
var body: some View {
HStack {
@@ -21,14 +23,15 @@ struct ContextItemView: View {
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 16, height: 16)
.foregroundColor(.secondary)
MsgContentView(
text: contextItem.text,
formattedText: contextItem.formattedText,
sender: contextItem.memberDisplayName
)
.multilineTextAlignment(isRightToLeft(contextItem.text) ? .trailing : .leading)
.lineLimit(3)
.foregroundColor(theme.colors.secondary)
if showSender, let sender = contextItem.memberDisplayName {
VStack(alignment: .leading, spacing: 4) {
Text(sender).font(.caption).foregroundColor(theme.colors.secondary)
msgContentView(lines: 2)
}
} else {
msgContentView(lines: 3)
}
Spacer()
Button {
withAnimation {
@@ -37,18 +40,41 @@ struct ContextItemView: View {
} label: {
Image(systemName: "multiply")
}
.tint(theme.colors.primary)
}
.padding(12)
.frame(minHeight: 50)
.frame(minHeight: 54)
.frame(maxWidth: .infinity)
.background(chatItemFrameColor(contextItem, colorScheme))
.padding(.top, 8)
.background(chatItemFrameColor(contextItem, theme))
}
private func msgContentView(lines: Int) -> some View {
contextMsgPreview()
.multilineTextAlignment(isRightToLeft(contextItem.text) ? .trailing : .leading)
.lineLimit(lines)
}
private func contextMsgPreview() -> Text {
return attachment() + messageText(contextItem.text, contextItem.formattedText, nil, preview: true, showSecrets: false, secondaryColor: theme.colors.secondary)
func attachment() -> Text {
switch contextItem.content.msgContent {
case .file: return image("doc.fill")
case .image: return image("photo")
case .voice: return image("play.fill")
default: return Text("")
}
}
func image(_ s: String) -> Text {
Text(Image(systemName: s)).foregroundColor(Color(uiColor: .tertiaryLabel)) + Text(" ")
}
}
}
struct ContextItemView_Previews: PreviewProvider {
static var previews: some View {
let contextItem: ChatItem = ChatItem.getSample(1, .directSnd, .now, "hello")
return ContextItemView(contextItem: contextItem, contextIcon: "pencil.circle", cancelContextItem: {})
return ContextItemView(chat: Chat.sampleData, contextItem: contextItem, contextIcon: "pencil.circle", cancelContextItem: {})
}
}
@@ -14,21 +14,32 @@ import PhotosUI
struct NativeTextEditor: UIViewRepresentable {
@Binding var text: String
@Binding var disableEditing: Bool
let height: CGFloat
let font: UIFont
@Binding var height: CGFloat
@Binding var focused: Bool
let alignment: TextAlignment
let onImagesAdded: ([UploadContent]) -> Void
private let minHeight: CGFloat = 37
private let defaultHeight: CGFloat = {
let field = CustomUITextField(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 {
let field = CustomUITextField()
let field = CustomUITextField(height: _height)
field.backgroundColor = .clear
field.text = text
field.font = font
field.textAlignment = alignment == .leading ? .left : .right
field.textAlignment = alignment(text)
field.autocapitalizationType = .sentences
field.setOnTextChangedListener { newText, images in
if !disableEditing {
text = newText
field.textAlignment = alignment(text)
updateFont(field)
// Speed up the process of updating layout, reduce jumping content on screen
updateHeight(field)
self.height = field.frame.size.height
} else {
field.text = text
}
@@ -39,24 +50,81 @@ struct NativeTextEditor: UIViewRepresentable {
field.setOnFocusChangedListener { focused = $0 }
field.delegate = field
field.textContainerInset = UIEdgeInsets(top: 8, left: 5, bottom: 6, right: 4)
updateFont(field)
updateHeight(field)
return field
}
func updateUIView(_ field: UITextView, context: Context) {
field.text = text
field.font = font
field.textAlignment = alignment == .leading ? .left : .right
if field.markedTextRange == nil && field.text != text {
field.text = text
field.textAlignment = alignment(text)
updateFont(field)
updateHeight(field)
}
}
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 {
var height: Binding<CGFloat>
var newHeight: CGFloat = 0
var onTextChanged: (String, [UploadContent]) -> Void = { newText, image in }
var onFocusChanged: (Bool) -> Void = { focused in }
init(height: Binding<CGFloat>) {
self.height = height
super.init(frame: .zero, textContainer: nil)
}
required init?(coder: NSCoder) {
fatalError("Not implemented")
}
// This func here needed because using frame.size.height in intrinsicContentSize while loading a screen with text (for example. when you have a draft),
// produces incorrect height because at that point intrinsicContentSize has old value of frame.size.height even if it was set to new value right before the call
// (who knows why...)
func invalidateIntrinsicContentHeight(_ newHeight: CGFloat) {
self.newHeight = newHeight
invalidateIntrinsicContentSize()
}
override var intrinsicContentSize: CGSize {
if height.wrappedValue != newHeight {
DispatchQueue.main.asyncAfter(deadline: .now(), execute: { self.height.wrappedValue = self.newHeight })
}
return CGSizeMake(0, newHeight)
}
func setOnTextChangedListener(onTextChanged: @escaping (String, [UploadContent]) -> Void) {
self.onTextChanged = onTextChanged
}
func setOnFocusChangedListener(onFocusChanged: @escaping (Bool) -> Void) {
self.onFocusChanged = onFocusChanged
}
@@ -144,14 +212,13 @@ private class CustomUITextField: UITextView, UITextViewDelegate {
struct NativeTextEditor_Previews: PreviewProvider{
static var previews: some View {
return NativeTextEditor(
NativeTextEditor(
text: Binding.constant("Hello, world!"),
disableEditing: Binding.constant(false),
height: 100,
font: UIFont.preferredFont(forTextStyle: .body),
height: Binding.constant(100),
focused: Binding.constant(false),
alignment: TextAlignment.leading,
onImagesAdded: { _ in }
)
.fixedSize(horizontal: false, vertical: true)
}
}
@@ -13,12 +13,15 @@ private let liveMsgInterval: UInt64 = 3000_000000
struct SendMessageView: View {
@Binding var composeState: ComposeState
@EnvironmentObject var theme: AppTheme
var sendMessage: (Int?) -> Void
var sendLiveMessage: (() async -> Void)? = nil
var updateLiveMessage: (() async -> Void)? = nil
var cancelLiveMessage: (() -> Void)? = nil
var nextSendGrpInv: Bool = false
var showVoiceMessageButton: Bool = true
var voiceMessageAllowed: Bool = true
var disableSendButton = false
var showEnableVoiceMessagesAlert: ChatInfo.ShowEnableVoiceMessagesAlert = .other
var startVoiceMessageRecording: (() -> Void)? = nil
var finishVoiceMessageRecording: (() -> Void)? = nil
@@ -28,60 +31,43 @@ struct SendMessageView: View {
@State private var holdingVMR = false
@Namespace var namespace
@Binding var keyboardVisible: Bool
var sendButtonColor = Color.accentColor
@State private var teHeight: CGFloat = 42
@State private var teFont: Font = .body
@State private var teUiFont: UIFont = UIFont.preferredFont(forTextStyle: .body)
@State private var sendButtonSize: CGFloat = 29
@State private var sendButtonOpacity: CGFloat = 1
@State private var showCustomDisappearingMessageDialogue = false
@State private var showCustomTimePicker = false
@State private var selectedDisappearingMessageTime: Int? = customDisappearingMessageTimeDefault.get()
var maxHeight: CGFloat = 360
var minHeight: CGFloat = 37
@State private var progressByTimeout = false
@AppStorage(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(.secondary)
.foregroundColor(theme.colors.secondary)
.padding(.horizontal, 10)
.padding(.vertical, 8)
.frame(maxWidth: .infinity)
} else {
let alignment: TextAlignment = isRightToLeft(composeState.message) ? .trailing : .leading
Text(composeState.message)
.lineLimit(10)
.font(teFont)
.multilineTextAlignment(alignment)
// put text on top (after NativeTextEditor) and set color to precisely align it on changes
// .foregroundColor(.red)
.foregroundColor(.clear)
.padding(.horizontal, 10)
.padding(.top, 8)
.padding(.bottom, 6)
.matchedGeometryEffect(id: "te", in: namespace)
.background(GeometryReader(content: updateHeight))
NativeTextEditor(
text: $composeState.message,
disableEditing: $composeState.inProgress,
height: teHeight,
font: teUiFont,
height: $teHeight,
focused: $keyboardVisible,
alignment: alignment,
onImagesAdded: onMediaAdded
)
.allowsTightening(false)
.frame(height: teHeight)
.fixedSize(horizontal: false, vertical: true)
}
}
if composeState.inProgress {
if progressByTimeout {
ProgressView()
.scaleEffect(1.4)
.frame(width: 31, height: 31, alignment: .center)
@@ -97,19 +83,32 @@ struct SendMessageView: View {
.frame(height: teHeight, alignment: .bottom)
}
}
RoundedRectangle(cornerSize: CGSize(width: 20, height: 20))
.strokeBorder(.secondary, lineWidth: 0.3, antialiased: true)
.frame(height: teHeight)
.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 {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
progressByTimeout = composeState.inProgress
}
} else {
progressByTimeout = false
}
}
.padding(.vertical, 8)
}
@ViewBuilder private func composeActionButtons() -> some View {
let vmrs = composeState.voiceMessageRecordingState
if showVoiceMessageButton
if nextSendGrpInv {
inviteMemberContactButton()
} else if showVoiceMessageButton
&& composeState.message.isEmpty
&& !composeState.editing
&& !composeState.forwarding
&& composeState.liveMessage == nil
&& ((composeState.noPreview && vmrs == .noRecording)
|| (vmrs == .recording && holdingVMR)) {
@@ -119,7 +118,7 @@ struct SendMessageView: View {
startVoiceMessageRecording: startVoiceMessageRecording,
finishVoiceMessageRecording: finishVoiceMessageRecording,
holdingVMR: $holdingVMR,
disabled: composeState.disabled
disabled: composeState.inProgress
)
} else {
voiceMessageNotAllowedButton()
@@ -151,6 +150,24 @@ struct SendMessageView: View {
.padding([.top, .trailing], 4)
}
private func inviteMemberContactButton() -> some View {
Button {
sendMessage(nil)
} label: {
Image(systemName: "arrow.up.circle.fill")
.resizable()
.foregroundColor(sendButtonColor)
.frame(width: sendButtonSize, height: sendButtonSize)
.opacity(sendButtonOpacity)
}
.disabled(
!composeState.sendEnabled ||
composeState.inProgress
)
.frame(width: 29, height: 29)
.padding([.bottom, .trailing], 4)
}
private func sendMessageButton() -> some View {
Button {
sendMessage(nil)
@@ -159,15 +176,16 @@ struct SendMessageView: View {
? "checkmark.circle.fill"
: "arrow.up.circle.fill")
.resizable()
.foregroundColor(.accentColor)
.foregroundColor(sendButtonColor)
.frame(width: sendButtonSize, height: sendButtonSize)
.opacity(sendButtonOpacity)
}
.disabled(
!composeState.sendEnabled ||
composeState.disabled ||
composeState.inProgress ||
(!voiceMessageAllowed && composeState.voicePreview) ||
composeState.endLiveDisabled
composeState.endLiveDisabled ||
disableSendButton
)
.frame(width: 29, height: 29)
.contextMenu{
@@ -229,6 +247,7 @@ struct SendMessageView: View {
}
private struct RecordVoiceMessageButton: View {
@EnvironmentObject var theme: AppTheme
var startVoiceMessageRecording: (() -> Void)?
var finishVoiceMessageRecording: (() -> Void)?
@Binding var holdingVMR: Bool
@@ -238,7 +257,10 @@ struct SendMessageView: View {
var body: some View {
Button(action: {}) {
Image(systemName: "mic.fill")
.foregroundColor(.accentColor)
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundColor(theme.colors.primary)
}
.disabled(disabled)
.frame(width: 29, height: 29)
@@ -291,9 +313,12 @@ struct SendMessageView: View {
}
} label: {
Image(systemName: "mic")
.foregroundColor(.secondary)
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundColor(theme.colors.secondary)
}
.disabled(composeState.disabled)
.disabled(composeState.inProgress)
.frame(width: 29, height: 29)
.padding([.bottom, .trailing], 4)
}
@@ -305,7 +330,7 @@ struct SendMessageView: View {
Image(systemName: "multiply")
.resizable()
.scaledToFit()
.foregroundColor(.accentColor)
.foregroundColor(theme.colors.primary)
.frame(width: 15, height: 15)
}
.frame(width: 29, height: 29)
@@ -322,7 +347,7 @@ struct SendMessageView: View {
Image(systemName: "bolt.fill")
.resizable()
.scaledToFit()
.foregroundColor(.accentColor)
.foregroundColor(theme.colors.primary)
.frame(width: 20, height: 20)
}
.frame(width: 29, height: 29)
@@ -365,7 +390,7 @@ struct SendMessageView: View {
}
Task {
_ = try? await Task.sleep(nanoseconds: liveMsgInterval)
while composeState.liveMessage != nil {
while await composeState.liveMessage != nil {
await update()
_ = try? await Task.sleep(nanoseconds: liveMsgInterval)
}
@@ -376,23 +401,19 @@ struct SendMessageView: View {
private func finishVoiceMessageRecordingButton() -> some View {
Button(action: { finishVoiceMessageRecording?() }) {
Image(systemName: "stop.fill")
.foregroundColor(.accentColor)
.foregroundColor(theme.colors.primary)
}
.disabled(composeState.disabled)
.disabled(composeState.inProgress)
.frame(width: 29, height: 29)
.padding([.bottom, .trailing], 4)
}
private func updateHeight(_ g: GeometryProxy) -> Color {
private func updateFont(_ text: String) {
DispatchQueue.main.async {
teHeight = min(max(g.frame(in: .local).size.height, minHeight), maxHeight)
(teFont, teUiFont) = isShortEmoji(composeState.message)
? composeState.message.count < 4
? (largeEmojiFont, largeEmojiUIFont)
: (mediumEmojiFont, mediumEmojiUIFont)
: (.body, UIFont.preferredFont(forTextStyle: .body))
teFont = isShortEmoji(text)
? (text.count < 4 ? largeEmojiFont : mediumEmojiFont)
: .body
}
return Color.clear
}
}
@@ -12,6 +12,7 @@ import SimpleXChat
struct ContactPreferencesView: View {
@Environment(\.dismiss) var dismiss: DismissAction
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@Binding var contact: Contact
@State var featuresAllowed: ContactFeaturesAllowed
@State var currentFeaturesAllowed: ContactFeaturesAllowed
@@ -35,7 +36,7 @@ struct ContactPreferencesView: View {
.disabled(currentFeaturesAllowed == featuresAllowed)
}
}
.modifier(BackButton {
.modifier(BackButton(disabled: Binding.constant(false)) {
if currentFeaturesAllowed == featuresAllowed {
dismiss()
} else {
@@ -66,8 +67,8 @@ struct ContactPreferencesView: View {
.frame(height: 36)
infoRow("Contact allows", pref.contactPreference.allow.text)
}
header: { featureHeader(feature, enabled) }
footer: { featureFooter(feature, enabled) }
header: { featureHeader(feature, enabled).foregroundColor(theme.colors.secondary) }
footer: { featureFooter(feature, enabled).foregroundColor(theme.colors.secondary) }
}
private func timedMessagesFeatureSection() -> some View {
@@ -102,8 +103,8 @@ struct ContactPreferencesView: View {
infoRow("Delete after", timeText(pref.contactPreference.ttl))
}
}
header: { featureHeader(.timedMessages, enabled) }
footer: { featureFooter(.timedMessages, enabled) }
header: { featureHeader(.timedMessages, enabled).foregroundColor(theme.colors.secondary) }
footer: { featureFooter(.timedMessages, enabled).foregroundColor(theme.colors.secondary) }
}
private func featureHeader(_ feature: ChatFeature, _ enabled: FeatureEnabled) -> some View {
@@ -116,7 +117,6 @@ struct ContactPreferencesView: View {
private func featureFooter(_ feature: ChatFeature, _ enabled: FeatureEnabled) -> some View {
Text(feature.enabledDescription(enabled))
.frame(height: 36, alignment: .topLeading)
}
private func savePreferences() {
@@ -21,6 +21,7 @@ struct AddGroupMembersView: View {
struct AddGroupMembersViewCommon: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
var chat: Chat
@State var groupInfo: GroupInfo
var creatingGroup: Bool = false
@@ -34,7 +35,7 @@ struct AddGroupMembersViewCommon: View {
private enum AddGroupMembersAlert: Identifiable {
case prohibitedToInviteIncognito
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -46,14 +47,13 @@ struct AddGroupMembersViewCommon: View {
var body: some View {
if creatingGroup {
NavigationView {
addGroupMembersView()
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button ("Skip") { addedMembersCb(selectedContacts) }
}
addGroupMembersView()
.navigationBarBackButtonHidden()
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button ("Skip") { addedMembersCb(selectedContacts) }
}
}
}
} else {
addGroupMembersView()
}
@@ -70,7 +70,7 @@ struct AddGroupMembersViewCommon: View {
if (membersToAdd.isEmpty) {
Text("No contacts to add")
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
.padding()
.frame(maxWidth: .infinity, alignment: .center)
.listRowBackground(Color.clear)
@@ -90,16 +90,18 @@ struct AddGroupMembersViewCommon: View {
Button { selectedContacts.removeAll() } label: { Text("Clear").font(.caption) }
Spacer()
Text("\(count) contact(s) selected")
.foregroundColor(theme.colors.secondary)
}
} else {
Text("No contacts selected")
.frame(maxWidth: .infinity, alignment: .trailing)
.foregroundColor(theme.colors.secondary)
}
}
}
Section {
searchFieldView(text: $searchText, focussed: $searchFocussed)
searchFieldView(text: $searchText, focussed: $searchFocussed, theme.colors.primary, theme.colors.secondary)
.padding(.leading, 2)
let s = searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
let members = s == "" ? membersToAdd : membersToAdd.filter { $0.chatViewName.localizedLowercase.contains(s) }
@@ -119,12 +121,13 @@ struct AddGroupMembersViewCommon: View {
message: Text("You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile")
)
case let .error(title, error):
return Alert(title: Text(title), message: Text(error))
return mkAlert(title: title, message: error)
}
}
.onChange(of: selectedContacts) { _ in
searchFocussed = false
}
.modifier(ThemedBackground(grouped: true))
}
private func inviteMembersButton() -> some View {
@@ -144,7 +147,7 @@ struct AddGroupMembersViewCommon: View {
do {
for contactId in selectedContacts {
let member = try await apiAddMember(groupInfo.groupId, contactId, selectedRole)
await MainActor.run { _ = ChatModel.shared.upsertGroupMember(groupInfo, member) }
await MainActor.run { _ = chatModel.upsertGroupMember(groupInfo, member) }
}
addedMembersCb(selectedContacts)
} catch {
@@ -157,7 +160,7 @@ struct AddGroupMembersViewCommon: View {
private func rolePicker() -> some View {
Picker("New member role", selection: $selectedRole) {
ForEach(GroupMemberRole.allCases) { role in
if role <= groupInfo.membership.memberRole {
if role <= groupInfo.membership.memberRole && role != .author {
Text(role.text)
}
}
@@ -172,14 +175,14 @@ struct AddGroupMembersViewCommon: View {
var iconColor: Color
if prohibitedToInviteIncognito {
icon = "theatermasks.circle.fill"
iconColor = Color(uiColor: .tertiaryLabel)
iconColor = Color(uiColor: .tertiaryLabel).asAnotherColorFromSecondary(theme)
} else {
if checked {
icon = "checkmark.circle.fill"
iconColor = .accentColor
iconColor = theme.colors.primary
} else {
icon = "circle"
iconColor = Color(uiColor: .tertiaryLabel)
iconColor = Color(uiColor: .tertiaryLabel).asAnotherColorFromSecondary(theme)
}
}
return Button {
@@ -194,11 +197,10 @@ struct AddGroupMembersViewCommon: View {
}
} label: {
HStack{
ProfileImage(imageStr: contact.image)
.frame(width: 30, height: 30)
ProfileImage(imageStr: contact.image, size: 30)
.padding(.trailing, 2)
Text(ChatInfo.direct(contact: contact).chatViewName)
.foregroundColor(prohibitedToInviteIncognito ? .secondary : .primary)
.foregroundColor(prohibitedToInviteIncognito ? theme.colors.secondary : theme.colors.onBackground)
.lineLimit(1)
Spacer()
Image(systemName: icon)
@@ -208,7 +210,7 @@ struct AddGroupMembersViewCommon: View {
}
}
func searchFieldView(text: Binding<String>, focussed: FocusState<Bool>.Binding) -> some View {
func searchFieldView(text: Binding<String>, focussed: FocusState<Bool>.Binding, _ onBackgroundColor: Color, _ secondaryColor: Color) -> some View {
HStack {
Image(systemName: "magnifyingglass")
.resizable()
@@ -217,7 +219,7 @@ func searchFieldView(text: Binding<String>, focussed: FocusState<Bool>.Binding)
.padding(.trailing, 10)
TextField("Search", text: text)
.focused(focussed)
.foregroundColor(.primary)
.foregroundColor(onBackgroundColor)
.frame(maxWidth: .infinity)
Image(systemName: "xmark.circle.fill")
.resizable()
@@ -229,7 +231,7 @@ func searchFieldView(text: Binding<String>, focussed: FocusState<Bool>.Binding)
focussed.wrappedValue = false
}
}
.foregroundColor(.secondary)
.foregroundColor(secondaryColor)
.frame(height: 36)
}
@@ -9,18 +9,24 @@
import SwiftUI
import SimpleXChat
let SMALL_GROUPS_RCPS_MEM_LIMIT: Int = 20
struct GroupChatInfoView: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@Environment(\.dismiss) var dismiss: DismissAction
@ObservedObject var chat: Chat
@State var groupInfo: GroupInfo
@ObservedObject private var alertManager = AlertManager.shared
@Binding var groupInfo: GroupInfo
var onSearch: () -> Void
@State private var alert: GroupChatInfoViewAlert? = nil
@State private var groupLink: String?
@State private var groupLinkMemberRole: GroupMemberRole = .member
@State private var showAddMembersSheet: Bool = false
@State private var groupLinkNavLinkActive: Bool = false
@State private var addMembersNavLinkActive: Bool = false
@State private var connectionStats: ConnectionStats?
@State private var connectionCode: String?
@State private var sendReceipts = SendReceipts.userDefault(true)
@State private var sendReceiptsUserDefault = true
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@State private var searchText: String = ""
@FocusState private var searchFocussed
@@ -30,19 +36,49 @@ struct GroupChatInfoView: View {
case clearChatAlert
case leaveGroupAlert
case cantInviteIncognitoAlert
case largeGroupReceiptsDisabled
case blockMemberAlert(mem: GroupMember)
case unblockMemberAlert(mem: GroupMember)
case blockForAllAlert(mem: GroupMember)
case unblockForAllAlert(mem: GroupMember)
case removeMemberAlert(mem: GroupMember)
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: GroupChatInfoViewAlert { get { self } }
var id: String {
switch self {
case .deleteGroupAlert: return "deleteGroupAlert"
case .clearChatAlert: return "clearChatAlert"
case .leaveGroupAlert: return "leaveGroupAlert"
case .cantInviteIncognitoAlert: return "cantInviteIncognitoAlert"
case .largeGroupReceiptsDisabled: return "largeGroupReceiptsDisabled"
case let .blockMemberAlert(mem): return "blockMemberAlert \(mem.groupMemberId)"
case let .unblockMemberAlert(mem): return "unblockMemberAlert \(mem.groupMemberId)"
case let .blockForAllAlert(mem): return "blockForAllAlert \(mem.groupMemberId)"
case let .unblockForAllAlert(mem): return "unblockForAllAlert \(mem.groupMemberId)"
case let .removeMemberAlert(mem): return "removeMemberAlert \(mem.groupMemberId)"
case let .error(title, _): return "error \(title)"
}
}
}
var body: some View {
NavigationView {
let members = chatModel.groupMembers
.filter { $0.memberStatus != .memLeft && $0.memberStatus != .memRemoved }
.sorted { $0.displayName.lowercased() < $1.displayName.lowercased() }
.filter { m in let status = m.wrapped.memberStatus; return status != .memLeft && status != .memRemoved }
.sorted { $0.wrapped.memberRole > $1.wrapped.memberRole }
List {
groupInfoHeader()
.listRowBackground(Color.clear)
.padding(.bottom, 18)
infoActionButtons()
.padding(.horizontal)
.frame(maxWidth: .infinity)
.frame(height: infoViewActionButtonHeight)
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
Section {
if groupInfo.canEdit {
@@ -52,13 +88,24 @@ struct GroupChatInfoView: View {
addOrEditWelcomeMessage()
}
groupPreferencesButton($groupInfo)
if members.filter({ $0.wrapped.memberCurrent }).count <= SMALL_GROUPS_RCPS_MEM_LIMIT {
sendReceiptsOption()
} else {
sendReceiptsOptionDisabled()
}
NavigationLink {
ChatWallpaperEditorSheet(chat: chat)
} label: {
Label("Chat theme", systemImage: "photo")
}
} header: {
Text("")
} footer: {
Text("Only group owners can change group preferences.")
.foregroundColor(theme.colors.secondary)
}
Section("\(members.count + 1) members") {
Section(header: Text("\(members.count + 1) members").foregroundColor(theme.colors.secondary)) {
if groupInfo.canAddMembers {
groupLinkButton()
if (chat.chatInfo.incognito) {
@@ -70,21 +117,21 @@ struct GroupChatInfoView: View {
}
}
if members.count > 8 {
searchFieldView(text: $searchText, focussed: $searchFocussed)
searchFieldView(text: $searchText, focussed: $searchFocussed, theme.colors.onBackground, theme.colors.secondary)
.padding(.leading, 8)
}
let s = searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
let filteredMembers = s == "" ? members : members.filter { $0.chatViewName.localizedLowercase.contains(s) }
memberView(groupInfo.membership, user: true)
let filteredMembers = s == "" ? members : members.filter { $0.wrapped.chatViewName.localizedLowercase.contains(s) }
MemberRowView(groupInfo: groupInfo, groupMember: GMember(groupInfo.membership), user: true, alert: $alert)
ForEach(filteredMembers) { member in
ZStack {
NavigationLink {
memberInfoView(member.groupMemberId)
memberInfoView(member)
} label: {
EmptyView()
}
.opacity(0)
memberView(member)
MemberRowView(groupInfo: groupInfo, groupMember: member, alert: $alert)
}
}
}
@@ -100,12 +147,13 @@ struct GroupChatInfoView: View {
}
if developerTools {
Section(header: Text("For console")) {
Section(header: Text("For console").foregroundColor(theme.colors.secondary)) {
infoRow("Local name", chat.chatInfo.localDisplayName)
infoRow("Database ID", "\(chat.chatInfo.apiId)")
}
}
}
.modifier(ThemedBackground(grouped: true))
.navigationBarHidden(true)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
@@ -115,9 +163,20 @@ struct GroupChatInfoView: View {
case .clearChatAlert: return clearChatAlert()
case .leaveGroupAlert: return leaveGroupAlert()
case .cantInviteIncognitoAlert: return cantInviteIncognitoAlert()
case .largeGroupReceiptsDisabled: return largeGroupReceiptsDisabledAlert()
case let .blockMemberAlert(mem): return blockMemberAlert(groupInfo, mem)
case let .unblockMemberAlert(mem): return unblockMemberAlert(groupInfo, mem)
case let .blockForAllAlert(mem): return blockForAllAlert(groupInfo, mem)
case let .unblockForAllAlert(mem): return unblockForAllAlert(groupInfo, mem)
case let .removeMemberAlert(mem): return removeMemberAlert(mem)
case let .error(title, error): return mkAlert(title: title, message: error)
}
}
.onAppear {
if let currentUser = chatModel.currentUser {
sendReceiptsUserDefault = currentUser.sendRcptsSmallGroups
}
sendReceipts = SendReceipts.fromBool(groupInfo.chatSettings.sendRcpts, userDefault: sendReceiptsUserDefault)
do {
if let link = try apiGetGroupLink(groupInfo.groupId) {
(groupLink, groupLinkMemberRole) = link
@@ -126,14 +185,12 @@ struct GroupChatInfoView: View {
logger.error("GroupChatInfoView apiGetGroupLink: \(responseError(error))")
}
}
.keyboardPadding()
}
private func groupInfoHeader() -> some View {
VStack {
let cInfo = chat.chatInfo
ChatInfoImage(chat: chat, color: Color(uiColor: .tertiarySystemFill))
.frame(width: 192, height: 192)
ChatInfoImage(chat: chat, size: 192, color: Color(uiColor: .tertiarySystemFill))
.padding(.top, 12)
.padding()
Text(cInfo.displayName)
@@ -151,68 +208,232 @@ struct GroupChatInfoView: View {
.frame(maxWidth: .infinity, alignment: .center)
}
func infoActionButtons() -> some View {
GeometryReader { g in
let buttonWidth = g.size.width / 4
HStack(alignment: .center, spacing: 8) {
searchButton(width: buttonWidth)
if groupInfo.canAddMembers {
addMembersActionButton(width: buttonWidth)
}
muteButton(width: buttonWidth)
}
.frame(maxWidth: .infinity, alignment: .center)
}
}
private func searchButton(width: CGFloat) -> some View {
InfoViewButton(image: "magnifyingglass", title: "search", width: width) {
dismiss()
onSearch()
}
.disabled(!groupInfo.ready || chat.chatItems.isEmpty)
}
@ViewBuilder private func addMembersActionButton(width: CGFloat) -> some View {
if chat.chatInfo.incognito {
ZStack {
InfoViewButton(image: "link.badge.plus", title: "invite", width: width) {
groupLinkNavLinkActive = true
}
NavigationLink(isActive: $groupLinkNavLinkActive) {
groupLinkDestinationView()
} label: {
EmptyView()
}
.frame(width: 1, height: 1)
.hidden()
}
.disabled(!groupInfo.ready)
} else {
ZStack {
InfoViewButton(image: "person.fill.badge.plus", title: "invite", width: width) {
addMembersNavLinkActive = true
}
NavigationLink(isActive: $addMembersNavLinkActive) {
addMembersDestinationView()
} label: {
EmptyView()
}
.frame(width: 1, height: 1)
.hidden()
}
.disabled(!groupInfo.ready)
}
}
private func muteButton(width: CGFloat) -> some View {
InfoViewButton(
image: chat.chatInfo.ntfsEnabled ? "speaker.slash.fill" : "speaker.wave.2.fill",
title: chat.chatInfo.ntfsEnabled ? "mute" : "unmute",
width: width
) {
toggleNotifications(chat, enableNtfs: !chat.chatInfo.ntfsEnabled)
}
.disabled(!groupInfo.ready)
}
private func addMembersButton() -> some View {
NavigationLink {
AddGroupMembersView(chat: chat, groupInfo: groupInfo)
.onAppear {
searchFocussed = false
Task {
let groupMembers = await apiListMembers(groupInfo.groupId)
await MainActor.run {
ChatModel.shared.groupMembers = groupMembers
}
}
}
addMembersDestinationView()
} label: {
Label("Invite members", systemImage: "plus")
}
}
private func memberView(_ member: GroupMember, user: Bool = false) -> some View {
HStack{
ProfileImage(imageStr: member.image)
.frame(width: 38, height: 38)
.padding(.trailing, 2)
// TODO server connection status
VStack(alignment: .leading) {
let t = Text(member.chatViewName).foregroundColor(member.memberIncognito ? .indigo : .primary)
(member.verified ? memberVerifiedShield + t : t)
.lineLimit(1)
let s = Text(member.memberStatus.shortText)
(user ? Text ("you: ") + s : s)
.lineLimit(1)
.font(.caption)
.foregroundColor(.secondary)
private func addMembersDestinationView() -> some View {
AddGroupMembersView(chat: chat, groupInfo: groupInfo)
.onAppear {
searchFocussed = false
Task {
let groupMembers = await apiListMembers(groupInfo.groupId)
await MainActor.run {
chatModel.groupMembers = groupMembers.map { GMember.init($0) }
chatModel.populateGroupMembersIndexes()
}
}
}
Spacer()
let role = member.memberRole
if role == .owner || role == .admin {
Text(member.memberRole.text)
.foregroundColor(.secondary)
}
private struct MemberRowView: View {
var groupInfo: GroupInfo
@ObservedObject var groupMember: GMember
@EnvironmentObject var theme: AppTheme
var user: Bool = false
@Binding var alert: GroupChatInfoViewAlert?
var body: some View {
let member = groupMember.wrapped
let v = HStack{
MemberProfileImage(member, size: 38)
.padding(.trailing, 2)
// TODO server connection status
VStack(alignment: .leading) {
let t = Text(member.chatViewName).foregroundColor(member.memberIncognito ? .indigo : theme.colors.onBackground)
(member.verified ? memberVerifiedShield + t : t)
.lineLimit(1)
(user ? Text ("you: ") + Text(member.memberStatus.shortText) : Text(memberConnStatus(member)))
.lineLimit(1)
.font(.caption)
.foregroundColor(theme.colors.secondary)
}
Spacer()
memberInfo(member)
}
if user {
v
} else if groupInfo.membership.memberRole >= .admin {
// TODO if there are more actions, refactor with lists of swipeActions
let canBlockForAll = member.canBlockForAll(groupInfo: groupInfo)
let canRemove = member.canBeRemoved(groupInfo: groupInfo)
if canBlockForAll && canRemove {
removeSwipe(member, blockForAllSwipe(member, v))
} else if canBlockForAll {
blockForAllSwipe(member, v)
} else if canRemove {
removeSwipe(member, v)
} else {
v
}
} else {
if !member.blockedByAdmin {
blockSwipe(member, v)
} else {
v
}
}
}
private func memberConnStatus(_ member: GroupMember) -> LocalizedStringKey {
if member.activeConn?.connDisabled ?? false {
return "disabled"
} else if member.activeConn?.connInactive ?? false {
return "inactive"
} else {
return member.memberStatus.shortText
}
}
@ViewBuilder private func memberInfo(_ member: GroupMember) -> some View {
if member.blocked {
Text("blocked")
.foregroundColor(theme.colors.secondary)
} else {
let role = member.memberRole
if [.owner, .admin, .observer].contains(role) {
Text(member.memberRole.text)
.foregroundColor(theme.colors.secondary)
}
}
}
private func blockSwipe<V: View>(_ member: GroupMember, _ v: V) -> some View {
v.swipeActions(edge: .leading) {
if member.memberSettings.showMessages {
Button {
alert = .blockMemberAlert(mem: member)
} label: {
Label("Block member", systemImage: "hand.raised").foregroundColor(theme.colors.secondary)
}
} else {
Button {
alert = .unblockMemberAlert(mem: member)
} label: {
Label("Unblock member", systemImage: "hand.raised.slash").foregroundColor(theme.colors.primary)
}
}
}
}
private func blockForAllSwipe<V: View>(_ member: GroupMember, _ v: V) -> some View {
v.swipeActions(edge: .leading) {
if member.blockedByAdmin {
Button {
alert = .unblockForAllAlert(mem: member)
} label: {
Label("Unblock for all", systemImage: "hand.raised.slash").foregroundColor(theme.colors.primary)
}
} else {
Button {
alert = .blockForAllAlert(mem: member)
} label: {
Label("Block for all", systemImage: "hand.raised").foregroundColor(theme.colors.secondary)
}
}
}
}
private func removeSwipe<V: View>(_ member: GroupMember, _ v: V) -> some View {
v.swipeActions(edge: .trailing) {
Button(role: .destructive) {
alert = .removeMemberAlert(mem: member)
} label: {
Label("Remove member", systemImage: "trash")
.foregroundColor(Color.red)
}
}
}
private var memberVerifiedShield: Text {
(Text(Image(systemName: "checkmark.shield")) + Text(" "))
.font(.caption)
.baselineOffset(2)
.kerning(-2)
.foregroundColor(theme.colors.secondary)
}
}
private var memberVerifiedShield: Text {
(Text(Image(systemName: "checkmark.shield")) + Text(" "))
.font(.caption)
.baselineOffset(2)
.kerning(-2)
.foregroundColor(.secondary)
}
@ViewBuilder private func memberInfoView(_ groupMemberId: Int64?) -> some View {
if let mId = groupMemberId, let member = chatModel.groupMembers.first(where: { $0.groupMemberId == mId }) {
GroupMemberInfoView(groupInfo: groupInfo, member: member)
.navigationBarHidden(false)
}
private func memberInfoView(_ groupMember: GMember) -> some View {
GroupMemberInfoView(groupInfo: groupInfo, groupMember: groupMember)
.navigationBarHidden(false)
}
private func groupLinkButton() -> some View {
NavigationLink {
GroupLinkView(groupId: groupInfo.groupId, groupLink: $groupLink, groupLinkMemberRole: $groupLinkMemberRole)
.navigationBarTitle("Group link")
.navigationBarTitleDisplayMode(.large)
groupLinkDestinationView()
} label: {
if groupLink == nil {
Label("Create group link", systemImage: "link.badge.plus")
@@ -222,6 +443,19 @@ struct GroupChatInfoView: View {
}
}
private func groupLinkDestinationView() -> some View {
GroupLinkView(
groupId: groupInfo.groupId,
groupLink: $groupLink,
groupLinkMemberRole: $groupLinkMemberRole,
showTitle: false,
creatingGroup: false
)
.navigationBarTitle("Group link")
.modifier(ThemedBackground(grouped: true))
.navigationBarTitleDisplayMode(.large)
}
private func editGroupButton() -> some View {
NavigationLink {
GroupProfileView(
@@ -229,6 +463,7 @@ struct GroupChatInfoView: View {
groupProfile: groupInfo.groupProfile
)
.navigationBarTitle("Group profile")
.modifier(ThemedBackground())
.navigationBarTitleDisplayMode(.large)
} label: {
Label("Edit group profile", systemImage: "pencil")
@@ -237,8 +472,13 @@ struct GroupChatInfoView: View {
private func addOrEditWelcomeMessage() -> some View {
NavigationLink {
GroupWelcomeView(groupId: groupInfo.groupId, groupInfo: $groupInfo)
GroupWelcomeView(
groupInfo: $groupInfo,
groupProfile: groupInfo.groupProfile,
welcomeText: groupInfo.groupProfile.description ?? ""
)
.navigationTitle("Welcome message")
.modifier(ThemedBackground(grouped: true))
.navigationBarTitleDisplayMode(.large)
} label: {
groupInfo.groupProfile.description == nil
@@ -284,9 +524,9 @@ struct GroupChatInfoView: View {
do {
try await apiDeleteChat(type: chat.chatInfo.chatType, id: chat.chatInfo.apiId)
await MainActor.run {
chatModel.removeChat(chat.chatInfo.id)
chatModel.chatId = nil
dismiss()
chatModel.chatId = nil
chatModel.removeChat(chat.chatInfo.id)
}
} catch let error {
logger.error("deleteGroupAlert apiDeleteChat error: \(error.localizedDescription)")
@@ -328,6 +568,60 @@ struct GroupChatInfoView: View {
secondaryButton: .cancel()
)
}
private func sendReceiptsOption() -> some View {
Picker(selection: $sendReceipts) {
ForEach([.yes, .no, .userDefault(sendReceiptsUserDefault)]) { (opt: SendReceipts) in
Text(opt.text)
}
} label: {
Label("Send receipts", systemImage: "checkmark.message")
}
.frame(height: 36)
.onChange(of: sendReceipts) { _ in
setSendReceipts()
}
}
private func setSendReceipts() {
var chatSettings = chat.chatInfo.chatSettings ?? ChatSettings.defaults
chatSettings.sendRcpts = sendReceipts.bool()
updateChatSettings(chat, chatSettings: chatSettings)
}
private func sendReceiptsOptionDisabled() -> some View {
HStack {
Label("Send receipts", systemImage: "checkmark.message")
Spacer()
Text("disabled")
.foregroundStyle(.secondary)
}
.onTapGesture {
alert = .largeGroupReceiptsDisabled
}
}
private func removeMemberAlert(_ mem: GroupMember) -> Alert {
Alert(
title: Text("Remove member?"),
message: Text("Member will be removed from group - this cannot be undone!"),
primaryButton: .destructive(Text("Remove")) {
Task {
do {
let updatedMember = try await apiRemoveMember(groupInfo.groupId, mem.groupMemberId)
await MainActor.run {
_ = chatModel.upsertGroupMember(groupInfo, updatedMember)
}
} catch let error {
logger.error("apiRemoveMember error: \(responseError(error))")
let a = getErrorAlert(error, "Error removing member")
alert = .error(title: a.title, error: a.message)
}
}
},
secondaryButton: .cancel()
)
}
}
func groupPreferencesButton(_ groupInfo: Binding<GroupInfo>, _ creatingGroup: Bool = false) -> some View {
@@ -339,6 +633,7 @@ func groupPreferencesButton(_ groupInfo: Binding<GroupInfo>, _ creatingGroup: Bo
creatingGroup: creatingGroup
)
.navigationBarTitle("Group preferences")
.modifier(ThemedBackground(grouped: true))
.navigationBarTitleDisplayMode(.large)
} label: {
if creatingGroup {
@@ -356,8 +651,19 @@ func cantInviteIncognitoAlert() -> Alert {
)
}
func largeGroupReceiptsDisabledAlert() -> Alert {
Alert(
title: Text("Receipts are disabled"),
message: Text("This group has over \(SMALL_GROUPS_RCPS_MEM_LIMIT) members, delivery receipts are not sent.")
)
}
struct GroupChatInfoView_Previews: PreviewProvider {
static var previews: some View {
GroupChatInfoView(chat: Chat(chatInfo: ChatInfo.sampleData.group, chatItems: []), groupInfo: GroupInfo.sampleData)
GroupChatInfoView(
chat: Chat(chatInfo: ChatInfo.sampleData.group, chatItems: []),
groupInfo: Binding.constant(GroupInfo.sampleData),
onSearch: {}
)
}
}
@@ -13,12 +13,16 @@ struct GroupLinkView: View {
var groupId: Int64
@Binding var groupLink: String?
@Binding var groupLinkMemberRole: GroupMemberRole
var showTitle: Bool = false
var creatingGroup: Bool = false
var linkCreatedCb: (() -> Void)? = nil
@State private var creatingLink = false
@State private var alert: GroupLinkAlert?
@State private var shouldCreate = true
private enum GroupLinkAlert: Identifiable {
case deleteLink
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -29,10 +33,34 @@ struct GroupLinkView: View {
}
var body: some View {
if creatingGroup {
groupLinkView()
.navigationBarBackButtonHidden()
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button ("Continue") { linkCreatedCb?() }
}
}
} else {
groupLinkView()
}
}
private func groupLinkView() -> some View {
List {
Text("You can share a link or a QR code - anybody will be able to join the group. You won't lose members of the group if you later delete it.")
.listRowBackground(Color.clear)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
Group {
if showTitle {
Text("Group link")
.font(.largeTitle)
.bold()
.fixedSize(horizontal: false, vertical: true)
}
Text("You can share a link or a QR code - anybody will be able to join the group. You won't lose members of the group if you later delete it.")
}
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
Section {
if let groupLink = groupLink {
Picker("Initial role", selection: $groupLinkMemberRole) {
@@ -41,15 +69,18 @@ struct GroupLinkView: View {
}
}
.frame(height: 36)
QRCode(uri: groupLink)
SimpleXLinkQRCode(uri: groupLink)
.id("simplex-qrcode-view-for-\(groupLink)")
Button {
showShareSheet(items: [groupLink])
showShareSheet(items: [simplexChatLink(groupLink)])
} label: {
Label("Share link", systemImage: "square.and.arrow.up")
}
Button(role: .destructive) { alert = .deleteLink } label: {
Label("Delete link", systemImage: "trash")
if !creatingGroup {
Button(role: .destructive) { alert = .deleteLink } label: {
Label("Delete link", systemImage: "trash")
}
}
} else {
Button(action: createGroupLink) {
@@ -81,7 +112,7 @@ struct GroupLinkView: View {
}, secondaryButton: .cancel()
)
case let .error(title, error):
return Alert(title: Text(title), message: Text(error))
return mkAlert(title: title, message: error)
}
}
.onChange(of: groupLinkMemberRole) { _ in
@@ -95,11 +126,13 @@ struct GroupLinkView: View {
}
}
.onAppear {
if groupLink == nil && !creatingLink {
if groupLink == nil && !creatingLink && shouldCreate {
createGroupLink()
}
shouldCreate = false
}
}
.modifier(ThemedBackground(grouped: true))
}
private func createGroupLink() {
@@ -11,37 +11,50 @@ import SimpleXChat
struct GroupMemberInfoView: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@Environment(\.dismiss) var dismiss: DismissAction
var groupInfo: GroupInfo
@State var member: GroupMember
@State var groupInfo: GroupInfo
@ObservedObject var groupMember: GMember
var navigation: Bool = false
@State private var connectionStats: ConnectionStats? = nil
@State private var connectionCode: String? = nil
@State private var newRole: GroupMemberRole = .member
@State private var alert: GroupMemberInfoViewAlert?
@State private var sheet: PlanAndConnectActionSheet?
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@State private var justOpened = true
@State private var progressIndicator = false
enum GroupMemberInfoViewAlert: Identifiable {
case blockMemberAlert(mem: GroupMember)
case unblockMemberAlert(mem: GroupMember)
case blockForAllAlert(mem: GroupMember)
case unblockForAllAlert(mem: GroupMember)
case removeMemberAlert(mem: GroupMember)
case changeMemberRoleAlert(mem: GroupMember, role: GroupMemberRole)
case switchAddressAlert
case abortSwitchAddressAlert
case syncConnectionForceAlert
case connRequestSentAlert(type: ConnReqType)
case error(title: LocalizedStringKey, error: LocalizedStringKey)
case other(alert: Alert)
case planAndConnectAlert(alert: PlanAndConnectAlert)
case queueInfo(info: String)
case someAlert(alert: SomeAlert)
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
case .removeMemberAlert: return "removeMemberAlert"
case let .changeMemberRoleAlert(_, role): return "changeMemberRoleAlert \(role.rawValue)"
case let .blockMemberAlert(mem): return "blockMemberAlert \(mem.groupMemberId)"
case let .unblockMemberAlert(mem): return "unblockMemberAlert \(mem.groupMemberId)"
case let .blockForAllAlert(mem): return "blockForAllAlert \(mem.groupMemberId)"
case let .unblockForAllAlert(mem): return "unblockForAllAlert \(mem.groupMemberId)"
case let .removeMemberAlert(mem): return "removeMemberAlert \(mem.groupMemberId)"
case let .changeMemberRoleAlert(mem, role): return "changeMemberRoleAlert \(mem.groupMemberId) \(role.rawValue)"
case .switchAddressAlert: return "switchAddressAlert"
case .abortSwitchAddressAlert: return "abortSwitchAddressAlert"
case .connRequestSentAlert: return "connRequestSentAlert"
case .syncConnectionForceAlert: return "syncConnectionForceAlert"
case let .planAndConnectAlert(alert): return "planAndConnectAlert \(alert.id)"
case let .queueInfo(info): return "queueInfo \(info)"
case let .someAlert(alert): return "someAlert \(alert.id)"
case let .error(title, _): return "error \(title)"
case let .other(alert): return "other \(alert)"
}
}
}
@@ -54,51 +67,56 @@ struct GroupMemberInfoView: View {
}
}
private func knownDirectChat(_ contactId: Int64) -> Chat? {
private func knownDirectChat(_ contactId: Int64) -> (Chat, Contact)? {
if let chat = chatModel.getContactChat(contactId),
chat.chatInfo.contact?.directOrUsed == true {
return chat
let contact = chat.chatInfo.contact,
contact.directOrUsed == true {
return (chat, contact)
} else {
return nil
}
}
private func groupMemberInfoView() -> some View {
VStack {
ZStack {
let member = groupMember.wrapped
List {
groupMemberInfoHeader(member)
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
.padding(.bottom, 18)
infoActionButtons(member)
.padding(.horizontal)
.frame(maxWidth: .infinity)
.frame(height: infoViewActionButtonHeight)
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
if member.memberActive {
Section {
if let contactId = member.memberContactId {
if let chat = knownDirectChat(contactId) {
knownDirectChatButton(chat)
} else if groupInfo.fullGroupPreferences.directMessages.on {
newDirectChatButton(contactId)
}
}
if let code = connectionCode { verifyCodeButton(code) }
if let connStats = connectionStats,
connStats.ratchetSyncAllowed {
connStats.ratchetSyncAllowed {
synchronizeConnectionButton()
}
// } else if developerTools {
// synchronizeConnectionButtonForce()
// }
// } else if developerTools {
// synchronizeConnectionButtonForce()
// }
}
}
if let contactLink = member.contactLink {
Section {
QRCode(uri: contactLink)
SimpleXLinkQRCode(uri: contactLink)
Button {
showShareSheet(items: [contactLink])
showShareSheet(items: [simplexChatLink(contactLink)])
} label: {
Label("Share address", systemImage: "square.and.arrow.up")
}
if let contactId = member.memberContactId {
if knownDirectChat(contactId) == nil && !groupInfo.fullGroupPreferences.directMessages.on {
if knownDirectChat(contactId) == nil && !groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
connectViaAddressButton(contactLink)
}
} else {
@@ -106,12 +124,14 @@ struct GroupMemberInfoView: View {
}
} header: {
Text("Address")
.foregroundColor(theme.colors.secondary)
} footer: {
Text("You can share this address with your contacts to let them connect with **\(member.displayName)**.")
.foregroundColor(theme.colors.secondary)
}
}
Section("Member") {
Section(header: Text("Member").foregroundColor(theme.colors.secondary)) {
infoRow("Group", groupInfo.displayName)
if let roles = member.canChangeRoleTo(groupInfo: groupInfo) {
@@ -124,16 +144,10 @@ struct GroupMemberInfoView: View {
} else {
infoRow("Role", member.memberRole.text)
}
// TODO invited by - need to get contact by contact id
if let conn = member.activeConn {
let connLevelDesc = conn.connLevel == 0 ? NSLocalizedString("direct", comment: "connection level description") : String.localizedStringWithFormat(NSLocalizedString("indirect (%d)", comment: "connection level description"), conn.connLevel)
infoRow("Connection", connLevelDesc)
}
}
if let connStats = connectionStats {
Section("Servers") {
Section(header: Text("Servers").foregroundColor(theme.colors.secondary)) {
// TODO network connection status
Button("Change receiving address") {
alert = .switchAddressAlert
@@ -142,7 +156,7 @@ struct GroupMemberInfoView: View {
connStats.rcvQueuesInfo.contains { $0.rcvSwitchStatus != nil }
|| connStats.ratchetSyncSendProhibited
)
if connStats.rcvQueuesInfo.contains { $0.rcvSwitchStatus != nil } {
if connStats.rcvQueuesInfo.contains(where: { $0.rcvSwitchStatus != nil }) {
Button("Abort changing address") {
alert = .abortSwitchAddressAlert
}
@@ -151,21 +165,37 @@ struct GroupMemberInfoView: View {
|| connStats.ratchetSyncSendProhibited
)
}
smpServers("Receiving via", connStats.rcvQueuesInfo.map { $0.rcvServer })
smpServers("Sending via", connStats.sndQueuesInfo.map { $0.sndServer })
smpServers("Receiving via", connStats.rcvQueuesInfo.map { $0.rcvServer }, theme.colors.secondary)
smpServers("Sending via", connStats.sndQueuesInfo.map { $0.sndServer }, theme.colors.secondary)
}
}
if member.canBeRemoved(groupInfo: groupInfo) {
Section {
removeMemberButton(member)
}
if groupInfo.membership.memberRole >= .admin {
adminDestructiveSection(member)
} else {
nonAdminBlockSection(member)
}
if developerTools {
Section("For console") {
Section(header: Text("For console").foregroundColor(theme.colors.secondary)) {
infoRow("Local name", member.localDisplayName)
infoRow("Database ID", "\(member.groupMemberId)")
if let conn = member.activeConn {
let connLevelDesc = conn.connLevel == 0 ? NSLocalizedString("direct", comment: "connection level description") : String.localizedStringWithFormat(NSLocalizedString("indirect (%d)", comment: "connection level description"), conn.connLevel)
infoRow("Connection", connLevelDesc)
}
Button ("Debug delivery") {
Task {
do {
let info = queueInfoText(try await apiGroupMemberQueueInfo(groupInfo.apiId, member.groupMemberId))
await MainActor.run { alert = .queueInfo(info: info) }
} catch let e {
logger.error("apiContactQueueInfo error: \(responseError(e))")
let a = getErrorAlert(e, "Error")
await MainActor.run { alert = .error(title: a.title, error: a.message) }
}
}
}
}
}
}
@@ -175,96 +205,179 @@ struct GroupMemberInfoView: View {
// this condition prevents re-setting picker
if !justOpened { return }
}
newRole = member.memberRole
do {
let (_, stats) = try apiGroupMemberInfo(groupInfo.apiId, member.groupMemberId)
let (mem, code) = member.memberActive ? try apiGetGroupMemberCode(groupInfo.apiId, member.groupMemberId) : (member, nil)
member = mem
connectionStats = stats
connectionCode = code
} catch let error {
logger.error("apiGroupMemberInfo or apiGetGroupMemberCode error: \(responseError(error))")
}
justOpened = false
DispatchQueue.main.async {
newRole = member.memberRole
do {
let (_, stats) = try apiGroupMemberInfo(groupInfo.apiId, member.groupMemberId)
let (mem, code) = member.memberActive ? try apiGetGroupMemberCode(groupInfo.apiId, member.groupMemberId) : (member, nil)
_ = chatModel.upsertGroupMember(groupInfo, mem)
connectionStats = stats
connectionCode = code
} catch let error {
logger.error("apiGroupMemberInfo or apiGetGroupMemberCode error: \(responseError(error))")
}
}
}
.onChange(of: newRole) { _ in
.onChange(of: newRole) { newRole in
if newRole != member.memberRole {
alert = .changeMemberRoleAlert(mem: member, role: newRole)
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.alert(item: $alert) { alertItem in
switch(alertItem) {
case let .removeMemberAlert(mem): return removeMemberAlert(mem)
case let .changeMemberRoleAlert(mem, _): return changeMemberRoleAlert(mem)
case .switchAddressAlert: return switchAddressAlert(switchMemberAddress)
case .abortSwitchAddressAlert: return abortSwitchAddressAlert(abortSwitchMemberAddress)
case .syncConnectionForceAlert: return syncConnectionForceAlert({ syncMemberConnection(force: true) })
case let .connRequestSentAlert(type): return connReqSentAlert(type)
case let .error(title, error): return Alert(title: Text(title), message: Text(error))
case let .other(alert): return alert
.onChange(of: member.memberRole) { role in
newRole = role
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.alert(item: $alert) { alertItem in
switch(alertItem) {
case let .blockMemberAlert(mem): return blockMemberAlert(groupInfo, mem)
case let .unblockMemberAlert(mem): return unblockMemberAlert(groupInfo, mem)
case let .blockForAllAlert(mem): return blockForAllAlert(groupInfo, mem)
case let .unblockForAllAlert(mem): return unblockForAllAlert(groupInfo, mem)
case let .removeMemberAlert(mem): return removeMemberAlert(mem)
case let .changeMemberRoleAlert(mem, _): return changeMemberRoleAlert(mem)
case .switchAddressAlert: return switchAddressAlert(switchMemberAddress)
case .abortSwitchAddressAlert: return abortSwitchAddressAlert(abortSwitchMemberAddress)
case .syncConnectionForceAlert: return syncConnectionForceAlert({ syncMemberConnection(force: true) })
case let .planAndConnectAlert(alert): return planAndConnectAlert(alert, dismiss: true)
case let .queueInfo(info): return queueInfoAlert(info)
case let .someAlert(a): return a.alert
case let .error(title, error): return mkAlert(title: title, message: error)
}
}
.actionSheet(item: $sheet) { s in planAndConnectActionSheet(s, dismiss: true) }
if progressIndicator {
ProgressView().scaleEffect(2)
}
}
.modifier(ThemedBackground(grouped: true))
}
func infoActionButtons(_ member: GroupMember) -> some View {
GeometryReader { g in
let buttonWidth = g.size.width / 4
HStack(alignment: .center, spacing: 8) {
if let contactId = member.memberContactId, let (chat, contact) = knownDirectChat(contactId) {
knownDirectChatButton(chat, width: buttonWidth)
AudioCallButton(chat: chat, contact: contact, width: buttonWidth) { alert = .someAlert(alert: $0) }
VideoButton(chat: chat, contact: contact, width: buttonWidth) { alert = .someAlert(alert: $0) }
} else if groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
if let contactId = member.memberContactId {
newDirectChatButton(contactId, width: buttonWidth)
} else if member.activeConn?.peerChatVRange.isCompatibleRange(CREATE_MEMBER_CONTACT_VRANGE) ?? false {
createMemberContactButton(width: buttonWidth)
}
InfoViewButton(image: "phone.fill", title: "call", disabledLook: true, width: buttonWidth) { showSendMessageToEnableCallsAlert()
}
InfoViewButton(image: "video.fill", title: "video", disabledLook: true, width: buttonWidth) { showSendMessageToEnableCallsAlert()
}
} else { // no known contact chat && directMessages are off
InfoViewButton(image: "message.fill", title: "message", disabledLook: true, width: buttonWidth) { showDirectMessagesProhibitedAlert("Can't message member")
}
InfoViewButton(image: "phone.fill", title: "call", disabledLook: true, width: buttonWidth) { showDirectMessagesProhibitedAlert("Can't call member")
}
InfoViewButton(image: "video.fill", title: "video", disabledLook: true, width: buttonWidth) { showDirectMessagesProhibitedAlert("Can't call member")
}
}
}
.frame(maxWidth: .infinity, alignment: .center)
}
}
func showSendMessageToEnableCallsAlert() {
alert = .someAlert(alert: SomeAlert(
alert: mkAlert(
title: "Can't call member",
message: "Send message to enable calls."
),
id: "can't call member, send message"
))
}
func showDirectMessagesProhibitedAlert(_ title: LocalizedStringKey) {
alert = .someAlert(alert: SomeAlert(
alert: mkAlert(
title: title,
message: "Direct messages between members are prohibited in this group."
),
id: "can't message member, direct messages prohibited"
))
}
func connectViaAddressButton(_ contactLink: String) -> some View {
Button {
connectViaAddress(contactLink)
planAndConnect(
contactLink,
showAlert: { alert = .planAndConnectAlert(alert: $0) },
showActionSheet: { sheet = $0 },
dismiss: true,
incognito: nil
)
} label: {
Label("Connect", systemImage: "link")
}
}
func connectViaAddress(_ contactLink: String) {
Task {
let (connReqType, connectAlert) = await apiConnect_(connReq: contactLink)
if let connReqType = connReqType {
alert = .connRequestSentAlert(type: connReqType)
} else if let connectAlert = connectAlert {
alert = .other(alert: connectAlert)
}
}
}
func knownDirectChatButton(_ chat: Chat) -> some View {
Button {
dismissAllSheets(animated: true)
DispatchQueue.main.async {
chatModel.chatId = chat.id
}
} label: {
Label("Send direct message", systemImage: "message")
}
}
func newDirectChatButton(_ contactId: Int64) -> some View {
Button {
do {
let chat = try apiGetChat(type: .direct, id: contactId)
chatModel.addChat(chat)
func knownDirectChatButton(_ chat: Chat, width: CGFloat) -> some View {
InfoViewButton(image: "message.fill", title: "message", width: width) {
ItemsModel.shared.loadOpenChat(chat.id) {
dismissAllSheets(animated: true)
DispatchQueue.main.async {
chatModel.chatId = chat.id
}
} catch let error {
logger.error("openDirectChatButton apiGetChat error: \(responseError(error))")
}
} label: {
Label("Send direct message", systemImage: "message")
}
}
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))")
}
}
}
}
func createMemberContactButton(width: CGFloat) -> some View {
InfoViewButton(image: "message.fill", title: "message", width: width) {
progressIndicator = true
Task {
do {
let memberContact = try await apiCreateMemberContact(groupInfo.apiId, groupMember.groupMemberId)
await MainActor.run {
progressIndicator = false
chatModel.addChat(Chat(chatInfo: .direct(contact: memberContact)))
ItemsModel.shared.loadOpenChat(memberContact.id) {
dismissAllSheets(animated: true)
}
NetworkModel.shared.setContactNetworkStatus(memberContact, .connected)
}
} catch let error {
logger.error("createMemberContactButton apiCreateMemberContact error: \(responseError(error))")
let a = getErrorAlert(error, "Error creating member contact")
await MainActor.run {
progressIndicator = false
alert = .error(title: a.title, error: a.message)
}
}
}
}
}
private func groupMemberInfoHeader(_ mem: GroupMember) -> some View {
VStack {
ProfileImage(imageStr: mem.image, color: Color(uiColor: .tertiarySystemFill))
.frame(width: 192, height: 192)
MemberProfileImage(mem, size: 192, color: Color(uiColor: .tertiarySystemFill))
.padding(.top, 12)
.padding()
if mem.verified {
(
Text(Image(systemName: "checkmark.shield"))
.foregroundColor(.secondary)
.foregroundColor(theme.colors.secondary)
.font(.title2)
+ Text(" ")
+ Text(mem.displayName)
@@ -291,20 +404,20 @@ struct GroupMemberInfoView: View {
}
private func verifyCodeButton(_ code: String) -> some View {
NavigationLink {
let member = groupMember.wrapped
return NavigationLink {
VerifyCodeView(
displayName: member.displayName,
connectionCode: code,
connectionVerified: member.verified,
verify: { code in
var member = groupMember.wrapped
if let r = apiVerifyGroupMember(member.groupId, member.groupMemberId, connectionCode: code) {
let (verified, existingCode) = r
let connCode = verified ? SecurityCode(securityCode: existingCode, verifiedAt: .now) : nil
connectionCode = existingCode
member.activeConn?.connectionCode = connCode
if let i = chatModel.groupMembers.firstIndex(where: { $0.groupMemberId == member.groupMemberId }) {
chatModel.groupMembers[i].activeConn?.connectionCode = connCode
}
_ = chatModel.upsertGroupMember(groupInfo, member)
return r
}
return nil
@@ -312,6 +425,7 @@ struct GroupMemberInfoView: View {
)
.navigationBarTitleDisplayMode(.inline)
.navigationTitle("Security code")
.modifier(ThemedBackground())
} label: {
Label(
member.verified ? "View security code" : "Verify security code",
@@ -338,12 +452,78 @@ struct GroupMemberInfoView: View {
}
}
@ViewBuilder private func adminDestructiveSection(_ mem: GroupMember) -> some View {
let canBlockForAll = mem.canBlockForAll(groupInfo: groupInfo)
let canRemove = mem.canBeRemoved(groupInfo: groupInfo)
if canBlockForAll || canRemove {
Section {
if canBlockForAll {
if mem.blockedByAdmin {
unblockForAllButton(mem)
} else {
blockForAllButton(mem)
}
}
if canRemove {
removeMemberButton(mem)
}
}
}
}
private func nonAdminBlockSection(_ mem: GroupMember) -> some View {
Section {
if mem.blockedByAdmin {
Label("Blocked by admin", systemImage: "hand.raised")
.foregroundColor(theme.colors.secondary)
} else if mem.memberSettings.showMessages {
blockMemberButton(mem)
} else {
unblockMemberButton(mem)
}
}
}
private func blockForAllButton(_ mem: GroupMember) -> some View {
Button(role: .destructive) {
alert = .blockForAllAlert(mem: mem)
} label: {
Label("Block for all", systemImage: "hand.raised")
.foregroundColor(.red)
}
}
private func unblockForAllButton(_ mem: GroupMember) -> some View {
Button {
alert = .unblockForAllAlert(mem: mem)
} label: {
Label("Unblock for all", systemImage: "hand.raised.slash")
}
}
private func blockMemberButton(_ mem: GroupMember) -> some View {
Button(role: .destructive) {
alert = .blockMemberAlert(mem: mem)
} label: {
Label("Block member", systemImage: "hand.raised")
.foregroundColor(.red)
}
}
private func unblockMemberButton(_ mem: GroupMember) -> some View {
Button {
alert = .unblockMemberAlert(mem: mem)
} label: {
Label("Unblock member", systemImage: "hand.raised.slash")
}
}
private func removeMemberButton(_ mem: GroupMember) -> some View {
Button(role: .destructive) {
alert = .removeMemberAlert(mem: mem)
} label: {
Label("Remove member", systemImage: "trash")
.foregroundColor(Color.red)
.foregroundColor(.red)
}
}
@@ -379,7 +559,6 @@ struct GroupMemberInfoView: View {
do {
let updatedMember = try await apiMemberRole(groupInfo.groupId, mem.groupMemberId, newRole)
await MainActor.run {
member = updatedMember
_ = chatModel.upsertGroupMember(groupInfo, updatedMember)
}
@@ -400,10 +579,10 @@ struct GroupMemberInfoView: View {
private func switchMemberAddress() {
Task {
do {
let stats = try apiSwitchGroupMember(groupInfo.apiId, member.groupMemberId)
let stats = try apiSwitchGroupMember(groupInfo.apiId, groupMember.groupMemberId)
connectionStats = stats
await MainActor.run {
chatModel.updateGroupMemberConnectionStats(groupInfo, member, stats)
chatModel.updateGroupMemberConnectionStats(groupInfo, groupMember.wrapped, stats)
dismiss()
}
} catch let error {
@@ -419,10 +598,10 @@ struct GroupMemberInfoView: View {
private func abortSwitchMemberAddress() {
Task {
do {
let stats = try apiAbortSwitchGroupMember(groupInfo.apiId, member.groupMemberId)
let stats = try apiAbortSwitchGroupMember(groupInfo.apiId, groupMember.groupMemberId)
connectionStats = stats
await MainActor.run {
chatModel.updateGroupMemberConnectionStats(groupInfo, member, stats)
chatModel.updateGroupMemberConnectionStats(groupInfo, groupMember.wrapped, stats)
}
} catch let error {
logger.error("abortSwitchMemberAddress apiAbortSwitchGroupMember error: \(responseError(error))")
@@ -437,7 +616,7 @@ struct GroupMemberInfoView: View {
private func syncMemberConnection(force: Bool) {
Task {
do {
let (mem, stats) = try apiSyncGroupMemberRatchet(groupInfo.apiId, member.groupMemberId, force)
let (mem, stats) = try apiSyncGroupMemberRatchet(groupInfo.apiId, groupMember.groupMemberId, force)
connectionStats = stats
await MainActor.run {
chatModel.updateGroupMemberConnectionStats(groupInfo, mem, stats)
@@ -454,11 +633,104 @@ struct GroupMemberInfoView: View {
}
}
func MemberProfileImage(
_ mem: GroupMember,
size: CGFloat,
color: Color = Color(uiColor: .tertiarySystemGroupedBackground),
backgroundColor: Color? = nil
) -> some View {
ProfileImage(
imageStr: mem.image,
size: size,
color: color,
backgroundColor: backgroundColor,
blurred: mem.blocked
)
}
func blockMemberAlert(_ gInfo: GroupInfo, _ mem: GroupMember) -> Alert {
Alert(
title: Text("Block member?"),
message: Text("All new messages from \(mem.chatViewName) will be hidden!"),
primaryButton: .destructive(Text("Block")) {
toggleShowMemberMessages(gInfo, mem, false)
},
secondaryButton: .cancel()
)
}
func unblockMemberAlert(_ gInfo: GroupInfo, _ mem: GroupMember) -> Alert {
Alert(
title: Text("Unblock member?"),
message: Text("Messages from \(mem.chatViewName) will be shown!"),
primaryButton: .default(Text("Unblock")) {
toggleShowMemberMessages(gInfo, mem, true)
},
secondaryButton: .cancel()
)
}
func toggleShowMemberMessages(_ gInfo: GroupInfo, _ member: GroupMember, _ showMessages: Bool) {
var memberSettings = member.memberSettings
memberSettings.showMessages = showMessages
updateMemberSettings(gInfo, member, memberSettings)
}
func updateMemberSettings(_ gInfo: GroupInfo, _ member: GroupMember, _ memberSettings: GroupMemberSettings) {
Task {
do {
try await apiSetMemberSettings(gInfo.groupId, member.groupMemberId, memberSettings)
await MainActor.run {
var mem = member
mem.memberSettings = memberSettings
_ = ChatModel.shared.upsertGroupMember(gInfo, mem)
}
} catch let error {
logger.error("apiSetMemberSettings error \(responseError(error))")
}
}
}
func blockForAllAlert(_ gInfo: GroupInfo, _ mem: GroupMember) -> Alert {
Alert(
title: Text("Block member for all?"),
message: Text("All new messages from \(mem.chatViewName) will be hidden!"),
primaryButton: .destructive(Text("Block for all")) {
blockMemberForAll(gInfo, mem, true)
},
secondaryButton: .cancel()
)
}
func unblockForAllAlert(_ gInfo: GroupInfo, _ mem: GroupMember) -> Alert {
Alert(
title: Text("Unblock member for all?"),
message: Text("Messages from \(mem.chatViewName) will be shown!"),
primaryButton: .default(Text("Unblock for all")) {
blockMemberForAll(gInfo, mem, false)
},
secondaryButton: .cancel()
)
}
func blockMemberForAll(_ gInfo: GroupInfo, _ member: GroupMember, _ blocked: Bool) {
Task {
do {
let updatedMember = try await apiBlockMemberForAll(gInfo.groupId, member.groupMemberId, blocked)
await MainActor.run {
_ = ChatModel.shared.upsertGroupMember(gInfo, updatedMember)
}
} catch let error {
logger.error("apiBlockMemberForAll error: \(responseError(error))")
}
}
}
struct GroupMemberInfoView_Previews: PreviewProvider {
static var previews: some View {
GroupMemberInfoView(
groupInfo: GroupInfo.sampleData,
member: GroupMember.sampleData
groupMember: GMember.sampleData
)
}
}
@@ -9,9 +9,16 @@
import SwiftUI
import SimpleXChat
private let featureRoles: [(role: GroupMemberRole?, text: LocalizedStringKey)] = [
(nil, "all members"),
(.admin, "admins"),
(.owner, "owners")
]
struct GroupPreferencesView: View {
@Environment(\.dismiss) var dismiss: DismissAction
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@Binding var groupInfo: GroupInfo
@State var preferences: FullGroupPreferences
@State var currentPreferences: FullGroupPreferences
@@ -24,11 +31,12 @@ struct GroupPreferencesView: View {
List {
featureSection(.timedMessages, $preferences.timedMessages.enable)
featureSection(.fullDelete, $preferences.fullDelete.enable)
featureSection(.directMessages, $preferences.directMessages.enable)
featureSection(.directMessages, $preferences.directMessages.enable, $preferences.directMessages.role)
featureSection(.reactions, $preferences.reactions.enable)
featureSection(.voice, $preferences.voice.enable)
// TODO uncomment in 5.3
// featureSection(.files, $preferences.files.enable)
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(.history, $preferences.history.enable)
if groupInfo.canEdit {
Section {
@@ -48,7 +56,7 @@ struct GroupPreferencesView: View {
preferences.timedMessages.ttl = currentPreferences.timedMessages.ttl
}
}
.modifier(BackButton {
.modifier(BackButton(disabled: Binding.constant(false)) {
if currentPreferences == preferences {
dismiss()
} else {
@@ -64,9 +72,9 @@ struct GroupPreferencesView: View {
}
}
private func featureSection(_ feature: GroupFeature, _ enableFeature: Binding<GroupFeatureEnabled>) -> some View {
private func featureSection(_ feature: GroupFeature, _ enableFeature: Binding<GroupFeatureEnabled>, _ enableForRole: Binding<GroupMemberRole?>? = nil) -> some View {
Section {
let color: Color = enableFeature.wrappedValue == .on ? .green : .secondary
let color: Color = enableFeature.wrappedValue == .on ? .green : theme.colors.secondary
let icon = enableFeature.wrappedValue == .on ? feature.iconFilled : feature.icon
let timedOn = feature == .timedMessages && enableFeature.wrappedValue == .on
if groupInfo.canEdit {
@@ -87,6 +95,14 @@ struct GroupPreferencesView: View {
)
.frame(height: 36)
}
if enableFeature.wrappedValue == .on, let enableForRole {
Picker("Enabled for", selection: enableForRole) {
ForEach(featureRoles, id: \.role) { fr in
Text(fr.text)
}
}
.frame(height: 36)
}
} else {
settingsRow(icon, color: color) {
infoRow(Text(feature.text), enableFeature.wrappedValue.text)
@@ -94,10 +110,26 @@ struct GroupPreferencesView: View {
if timedOn {
infoRow("Delete after", timeText(preferences.timedMessages.ttl))
}
if enableFeature.wrappedValue == .on, let enableForRole {
HStack {
Text("Enabled for").foregroundColor(theme.colors.secondary)
Spacer()
Text(
featureRoles.first(where: { fr in fr.role == enableForRole.wrappedValue })?.text
?? "all members"
)
.foregroundColor(theme.colors.secondary)
}
}
}
} footer: {
Text(feature.enableDescription(enableFeature.wrappedValue, groupInfo.canEdit))
.frame(height: 36, alignment: .topLeading)
.foregroundColor(theme.colors.secondary)
}
.onChange(of: enableFeature.wrappedValue) { enabled in
if case .off = enabled {
enableForRole?.wrappedValue = nil
}
}
}
@@ -9,6 +9,18 @@
import SwiftUI
import SimpleXChat
enum GroupProfileAlert: Identifiable {
case saveError(err: String)
case invalidName(validName: String)
var id: String {
switch self {
case let .saveError(err): return "saveError \(err)"
case let .invalidName(validName): return "invalidName \(validName)"
}
}
}
struct GroupProfileView: View {
@EnvironmentObject var chatModel: ChatModel
@Environment(\.dismiss) var dismiss: DismissAction
@@ -18,8 +30,7 @@ struct GroupProfileView: View {
@State private var showImagePicker = false
@State private var showTakePhoto = false
@State private var chosenImage: UIImage? = nil
@State private var showSaveErrorAlert = false
@State private var saveGroupError: String? = nil
@State private var alert: GroupProfileAlert?
@FocusState private var focusDisplayName
var body: some View {
@@ -47,20 +58,29 @@ struct GroupProfileView: View {
.frame(maxWidth: .infinity, alignment: .center)
VStack(alignment: .leading) {
ZStack(alignment: .leading) {
if !validDisplayName(groupProfile.displayName) {
Image(systemName: "exclamationmark.circle")
.foregroundColor(.red)
.padding(.bottom, 10)
ZStack(alignment: .topLeading) {
if !validNewProfileName() {
Button {
alert = .invalidName(validName: mkValidName(groupProfile.displayName))
} label: {
Image(systemName: "exclamationmark.circle").foregroundColor(.red)
}
} else {
Image(systemName: "exclamationmark.circle").foregroundColor(.clear)
}
profileNameTextEdit("Group display name", $groupProfile.displayName)
.focused($focusDisplayName)
}
profileNameTextEdit("Group full name (optional)", $groupProfile.fullName)
.padding(.bottom)
let fullName = groupInfo.groupProfile.fullName
if fullName != "" && fullName != groupProfile.displayName {
profileNameTextEdit("Group full name (optional)", $groupProfile.fullName)
.padding(.bottom)
}
HStack(spacing: 20) {
Button("Cancel") { dismiss() }
Button("Save group profile") { saveProfile() }
.disabled(groupProfile.displayName == "" || !validDisplayName(groupProfile.displayName))
.disabled(!canUpdateProfile())
}
}
.frame(maxWidth: .infinity, minHeight: 120, alignment: .leading)
@@ -83,8 +103,10 @@ struct GroupProfileView: View {
}
}
.sheet(isPresented: $showImagePicker) {
LibraryImagePicker(image: $chosenImage) {
didSelectItem in showImagePicker = false
LibraryImagePicker(image: $chosenImage) { _ in
await MainActor.run {
showImagePicker = false
}
}
}
.onChange(of: chosenImage) { image in
@@ -99,27 +121,39 @@ struct GroupProfileView: View {
focusDisplayName = true
}
}
.alert(isPresented: $showSaveErrorAlert) {
Alert(
title: Text("Error saving group profile"),
message: Text("\(saveGroupError ?? "Unexpected error")")
)
.alert(item: $alert) { a in
switch a {
case let .saveError(err):
return Alert(
title: Text("Error saving group profile"),
message: Text(err)
)
case let .invalidName(name):
return createInvalidNameAlert(name, $groupProfile.displayName)
}
}
.contentShape(Rectangle())
.onTapGesture { hideKeyboard() }
}
private func canUpdateProfile() -> Bool {
groupProfile.displayName.trimmingCharacters(in: .whitespaces) != "" && validNewProfileName()
}
private func validNewProfileName() -> Bool {
groupProfile.displayName == groupInfo.groupProfile.displayName
|| validDisplayName(groupProfile.displayName.trimmingCharacters(in: .whitespaces))
}
func profileNameTextEdit(_ label: LocalizedStringKey, _ name: Binding<String>) -> some View {
TextField(label, text: name)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
.padding(.bottom)
.padding(.leading, 28)
.padding(.leading, 32)
}
func saveProfile() {
Task {
do {
groupProfile.displayName = groupProfile.displayName.trimmingCharacters(in: .whitespaces)
let gInfo = try await apiUpdateGroup(groupInfo.groupId, groupProfile)
await MainActor.run {
groupInfo = gInfo
@@ -128,9 +162,8 @@ struct GroupProfileView: View {
}
} catch let error {
let err = responseError(error)
saveGroupError = err
showSaveErrorAlert = true
logger.error("UserProfile apiUpdateProfile error: \(err)")
alert = .saveError(err: err)
logger.error("GroupProfile apiUpdateGroup error: \(err)")
}
}
}

Some files were not shown because too many files have changed in this diff Show More