Compare commits

...

53 Commits

Author SHA1 Message Date
Evgeny Poberezkin ceecaf6592 simplexmq 2024-07-29 19:36:51 +01:00
Evgeny Poberezkin fb831439e9 ios: load chats and refresh call invitations before chat is started 2024-07-29 19:35:48 +01:00
Evgeny Poberezkin 018d9a1064 core: allow getting call invitations and notificationn token when chat is stopped 2024-07-29 19:17:44 +01:00
Evgeny Poberezkin 4b382841a1 check chat is running 2024-07-29 18:51:01 +01:00
Evgeny Poberezkin 6834138270 fix race in the tests 2024-07-29 18:19:01 +01:00
Evgeny Poberezkin bf83ba40a3 simplexmq 2024-07-29 17:39:49 +01:00
Evgeny Poberezkin ca166d7f96 use priority database access 2024-07-29 15:12:18 +01:00
Evgeny Poberezkin 42669454b0 multiplatform: load chat data before starting chat 2024-07-29 11:37:32 +01:00
Evgeny Poberezkin 243f3a7516 revert some 2024-07-29 10:57:40 +01:00
spaced4ndy aadba41e66 core: move db actions out of synchronous execution on chat start 2024-07-29 13:33:31 +04: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
175 changed files with 7751 additions and 2336 deletions
+5 -1
View File
@@ -354,6 +354,9 @@ 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
}
@@ -420,6 +423,7 @@ final class ChatModel: ObservableObject {
}
}
}
VoiceItemState.stopVoiceInChatView(cInfo, cItem)
}
func nextChatItemData<T>(_ chatItemId: Int64, previous: Bool, map: @escaping (ChatItem) -> T?) -> T? {
@@ -774,7 +778,7 @@ struct UnreadChatItemCounts: Equatable {
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
+48 -55
View File
@@ -217,7 +217,7 @@ func apiDeleteUser(_ userId: Int64, _ delSMPQueues: Bool, viewPwd: String?) asyn
}
func apiStartChat(ctrl: chat_ctrl? = nil) throws -> Bool {
let r = chatSendCmdSync(.startChat(mainApp: true), ctrl)
let r = chatSendCmdSync(.startChat(mainApp: true, enableSndFiles: true), ctrl)
switch r {
case .chatStarted: return true
case .chatRunning: return false
@@ -225,6 +225,15 @@ func apiStartChat(ctrl: chat_ctrl? = nil) throws -> Bool {
}
}
func apiCheckChatRunning() throws -> Bool {
let r = chatSendCmdSync(.checkChatRunning)
switch r {
case .chatRunning: return true
case .chatStopped: return false
default: throw r
}
}
func apiStopChat() async throws {
let r = await chatSendCmd(.apiStopChat)
switch r {
@@ -397,7 +406,7 @@ private func sendMessageErrorAlert(_ r: ChatResponse) {
logger.error("send message error: \(String(describing: r))")
AlertManager.shared.showAlertMsg(
title: "Error sending message",
message: "Error: \(String(describing: r))"
message: "Error: \(responseError(r))"
)
}
@@ -405,7 +414,7 @@ private func createChatItemErrorAlert(_ r: ChatResponse) {
logger.error("apiCreateChatItem error: \(String(describing: r))")
AlertManager.shared.showAlertMsg(
title: "Error creating message",
message: "Error: \(String(describing: r))"
message: "Error: \(responseError(r))"
)
}
@@ -699,7 +708,7 @@ func apiConnect_(incognito: Bool, connReq: String) async -> ((ConnReqType, Pendi
message: "Please check that you used the correct link or ask your contact to send you another one."
)
return (nil, alert)
case .chatCmdError(_, .errorAgent(.SMP(.AUTH))):
case .chatCmdError(_, .errorAgent(.SMP(_, .AUTH))):
let alert = mkAlert(
title: "Connection error (AUTH)",
message: "Unless your contact deleted the connection or this link was already used, it might be a bug - please report it.\nTo connect, please ask your contact to create another connection link and check that you have a stable network connection."
@@ -732,7 +741,7 @@ private func connectionErrorAlert(_ r: ChatResponse) -> Alert {
} else {
return mkAlert(
title: "Connection error",
message: "Error: \(String(describing: r))"
message: "Error: \(responseError(r))"
)
}
}
@@ -898,7 +907,7 @@ func apiAcceptContactRequest(incognito: Bool, contactReqId: Int64) async -> Cont
let am = AlertManager.shared
if case let .acceptingContactRequest(_, contact) = r { return contact }
if case .chatCmdError(_, .errorAgent(.SMP(.AUTH))) = r {
if case .chatCmdError(_, .errorAgent(.SMP(_, .AUTH))) = r {
am.showAlertMsg(
title: "Connection error (AUTH)",
message: "Sender may have deleted the connection request."
@@ -909,7 +918,7 @@ func apiAcceptContactRequest(incognito: Bool, contactReqId: Int64) async -> Cont
logger.error("apiAcceptContactRequest error: \(String(describing: r))")
am.showAlertMsg(
title: "Error accepting contact request",
message: "Error: \(String(describing: r))"
message: "Error: \(responseError(r))"
)
}
return nil
@@ -935,7 +944,7 @@ func uploadStandaloneFile(user: any UserLike, file: CryptoFile, ctrl: chat_ctrl?
return (fileTransferMeta, nil)
} else {
logger.error("uploadStandaloneFile error: \(String(describing: r))")
return (nil, String(describing: r))
return (nil, responseError(r))
}
}
@@ -945,7 +954,7 @@ func downloadStandaloneFile(user: any UserLike, url: String, file: CryptoFile, c
return (rcvFileTransfer, nil)
} else {
logger.error("downloadStandaloneFile error: \(String(describing: r))")
return (nil, String(describing: r))
return (nil, responseError(r))
}
}
@@ -1025,7 +1034,7 @@ func apiReceiveFile(fileId: Int64, userApprovedRelays: Bool, encrypted: Bool, in
if !auto {
am.showAlertMsg(
title: "Error receiving file",
message: "Error: \(String(describing: r))"
message: "Error: \(responseError(r))"
)
}
}
@@ -1091,47 +1100,6 @@ func deleteRemoteCtrl(_ rcId: Int64) async throws {
try await sendCommandOkResp(.deleteRemoteCtrl(remoteCtrlId: rcId))
}
struct ErrorAlert {
var title: LocalizedStringKey
var message: LocalizedStringKey
}
func getNetworkErrorAlert(_ r: ChatResponse) -> ErrorAlert? {
switch r {
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TIMEOUT))):
return ErrorAlert(title: "Connection timeout", message: "Please check your network connection with \(serverHostname(addr)) and try again.")
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .NETWORK))):
return ErrorAlert(title: "Connection error", message: "Please check your network connection with \(serverHostname(addr)) and try again.")
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .HOST))):
return ErrorAlert(title: "Connection error", message: "Server address is incompatible with network settings: \(serverHostname(addr)).")
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TRANSPORT(.version)))):
return ErrorAlert(title: "Connection error", message: "Server version is incompatible with your app: \(serverHostname(addr)).")
case let .chatCmdError(_, .errorAgent(.SMP(.PROXY(proxyErr)))):
return proxyErrorAlert(proxyErr)
case let .chatCmdError(_, .errorAgent(.PROXY(_, _, .protocolError(.PROXY(proxyErr))))):
return proxyErrorAlert(proxyErr)
default:
return nil
}
}
private func proxyErrorAlert(_ proxyErr: ProxyError) -> ErrorAlert? {
switch proxyErr {
case .BROKER(brokerErr: .TIMEOUT):
return ErrorAlert(title: "Private routing error", message: "Please try later.")
case .BROKER(brokerErr: .NETWORK):
return ErrorAlert(title: "Private routing error", message: "Please try later.")
case .NO_SESSION:
return ErrorAlert(title: "Private routing error", message: "Please try later.")
case .BROKER(brokerErr: .HOST):
return ErrorAlert(title: "Private routing error", message: "Server address is incompatible with network settings.")
case .BROKER(brokerErr: .TRANSPORT(.version)):
return ErrorAlert(title: "Private routing error", message: "Server version is incompatible with network settings.")
default:
return nil
}
}
func networkErrorAlert(_ r: ChatResponse) -> Alert? {
if let alert = getNetworkErrorAlert(r) {
return mkAlert(title: alert.title, message: alert.message)
@@ -1143,7 +1111,10 @@ func networkErrorAlert(_ r: ChatResponse) -> Alert? {
func acceptContactRequest(incognito: Bool, contactRequest: UserContactRequest) async {
if let contact = await apiAcceptContactRequest(incognito: incognito, contactReqId: contactRequest.apiId) {
let chat = Chat(chatInfo: ChatInfo.direct(contact: contact), chatItems: [])
DispatchQueue.main.async { ChatModel.shared.replaceChat(contactRequest.id, chat) }
DispatchQueue.main.async {
ChatModel.shared.replaceChat(contactRequest.id, chat)
ChatModel.shared.setContactNetworkStatus(contact, .connected)
}
}
}
@@ -1280,7 +1251,7 @@ func apiJoinGroup(_ groupId: Int64) async throws -> JoinGroupResult {
let r = await chatSendCmd(.apiJoinGroup(groupId: groupId))
switch r {
case let .userAcceptedGroupSent(_, groupInfo, _): return .joined(groupInfo: groupInfo)
case .chatCmdError(_, .errorAgent(.SMP(.AUTH))): return .invitationRemoved
case .chatCmdError(_, .errorAgent(.SMP(_, .AUTH))): return .invitationRemoved
case .chatCmdError(_, .errorStore(.groupNotFound)): return .groupNotFound
default: throw r
}
@@ -1386,6 +1357,14 @@ func apiGetVersion() throws -> CoreVersionInfo {
throw r
}
func getAgentSubsTotal() throws -> (SMPServerSubs, Bool) {
let userId = try currentUserId("getAgentSubsTotal")
let r = chatSendCmdSync(.getAgentSubsTotal(userId: userId), log: false)
if case let .agentSubsTotal(_, subsTotal, hasSession) = r { return (subsTotal, hasSession) }
logger.error("getAgentSubsTotal error: \(String(describing: r))")
throw r
}
func getAgentServersSummary() throws -> PresentedServersSummary {
let userId = try currentUserId("getAgentServersSummary")
let r = chatSendCmdSync(.getAgentServersSummary(userId: userId), log: false)
@@ -1469,15 +1448,16 @@ func startChat(refreshInvitations: Bool = true) throws {
logger.debug("startChat")
let m = ChatModel.shared
try setNetworkConfig(getNetCfg())
let justStarted = try apiStartChat()
let chatRunning = try apiCheckChatRunning()
m.users = try listUsers()
if justStarted {
if !chatRunning {
try getUserChatData()
NtfManager.shared.setNtfBadgeCount(m.totalUnreadCountForAllUsers())
if (refreshInvitations) {
try refreshCallInvitations()
}
(m.savedToken, m.tokenStatus, m.notificationMode, m.notificationServer) = apiGetNtfToken()
_ = try apiStartChat()
// deviceToken is set when AppDelegate.application(didRegisterForRemoteNotificationsWithDeviceToken:) is called,
// when it is called before startChat
if let token = m.deviceToken {
@@ -1649,6 +1629,19 @@ func processReceivedMsg(_ res: ChatResponse) async {
}
}
}
case let .contactSndReady(user, contact):
if active(user) && contact.directOrUsed {
await MainActor.run {
m.updateContact(contact)
if let conn = contact.activeConn {
m.dismissConnReqView(conn.id)
m.removeChat(conn.id)
}
}
}
await MainActor.run {
m.setContactNetworkStatus(contact, .connected)
}
case let .receivedContactRequest(user, contactRequest):
if active(user) {
let cInfo = ChatInfo.contactRequest(contactRequest: contactRequest)
+12
View File
@@ -36,6 +36,18 @@ private func _suspendChat(timeout: Int) {
}
}
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 {
_suspendChat(timeout: appSuspendTimeout)
@@ -28,15 +28,17 @@ struct ChatInfoToolbar: View {
color: Color(uiColor: .tertiaryLabel)
)
.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(theme.colors.onBackground)
.frame(width: 220)
+14 -12
View File
@@ -112,7 +112,7 @@ struct ChatInfoView: View {
case abortSwitchAddressAlert
case syncConnectionForceAlert
case queueInfo(info: String)
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -155,23 +155,25 @@ struct ChatInfoView: View {
}
Section {
if let code = connectionCode { verifyCodeButton(code) }
contactPreferencesButton()
sendReceiptsOption()
if let connStats = connectionStats,
connStats.ratchetSyncAllowed {
synchronizeConnectionButton()
Group {
if let code = connectionCode { verifyCodeButton(code) }
contactPreferencesButton()
sendReceiptsOption()
if let connStats = connectionStats,
connStats.ratchetSyncAllowed {
synchronizeConnectionButton()
}
// } else if developerTools {
// synchronizeConnectionButtonForce()
// }
}
.disabled(!contact.ready || !contact.active)
NavigationLink {
ChatWallpaperEditorSheet(chat: chat)
} label: {
Label("Chat theme", systemImage: "photo")
}
// } else if developerTools {
// synchronizeConnectionButtonForce()
// }
}
.disabled(!contact.ready || !contact.active)
if let conn = contact.activeConn {
Section {
@@ -271,7 +273,7 @@ struct ChatInfoView: View {
}
}
.actionSheet(isPresented: $showDeleteContactActionSheet) {
if contact.ready && contact.active {
if contact.sndReady && contact.active {
return ActionSheet(
title: Text("Delete contact?\nThis cannot be undone!"),
buttons: [
@@ -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) {
@@ -14,39 +14,45 @@ struct CIFileView: View {
@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(theme.colors.onBackground)
Text(prettyFileSize + metaReserve)
.font(.caption)
.lineLimit(1)
.multilineTextAlignment(.leading)
.foregroundColor(theme.colors.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 {
@@ -195,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)
}
}
}
@@ -15,22 +15,33 @@ struct CIImageView: View {
var preview: UIImage?
let maxWidth: CGFloat
var imgWidth: CGFloat?
@State private var showFullScreenImage = false
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)
}
.if(!smallView) { view in
view.modifier(PrivacyBlur(blurred: $blurred))
}
.onTapGesture { showFullScreenImage = true }
.onChange(of: m.activeCallViewIsCollapsed) { _ in
showFullScreenImage = false
}
} else if let preview {
imageView(preview)
Group {
if smallView {
smallViewImageView(preview)
} else {
imageView(preview).modifier(PrivacyBlur(blurred: $blurred))
}
}
.onTapGesture {
if let file = file {
switch file.fileStatus {
@@ -83,6 +94,9 @@ struct CIImageView: View {
}
}
}
.onDisappear {
showFullScreenImage = false
}
}
private func imageView(_ img: UIImage) -> some View {
@@ -98,7 +112,26 @@ struct CIImageView: View {
.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()
}
}
}
@@ -145,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
}
}
}
@@ -12,6 +12,7 @@ import SimpleXChat
struct CILinkView: View {
@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) {
@@ -19,6 +20,7 @@ struct CILinkView: View {
Image(uiImage: uiImage)
.resizable()
.scaledToFit()
.modifier(PrivacyBlur(blurred: $blurred))
}
VStack(alignment: .leading, spacing: 6) {
Text(linkPreview.title)
@@ -27,7 +27,7 @@ struct CIRcvDecryptionError: View {
case syncNotSupportedContactAlert
case syncNotSupportedMemberAlert
case decryptionErrorAlert
case error(title: LocalizedStringKey, error: LocalizedStringKey)
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -62,7 +62,7 @@ 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)
}
}
}
@@ -20,45 +20,44 @@ struct CIVideoView: View {
@State private var videoPlaying: Bool = false
private let maxWidth: CGFloat
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 urlDecrypted: URL?
@State private var decryptionInProgress: Bool = false
@State private var showFullScreenPlayer = 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, preview: UIImage?, duration: Int, maxWidth: CGFloat, videoWidth: CGFloat?) {
init(chatItem: ChatItem, preview: UIImage?, duration: Int, maxWidth: CGFloat, videoWidth: CGFloat?, smallView: Bool = false, showFullscreenPlayer: Binding<Bool>) {
self.chatItem = chatItem
self.preview = preview
self._duration = State(initialValue: duration)
self.maxWidth = maxWidth
self.videoWidth = videoWidth
if let url = getLoadedVideo(chatItem.file) {
let decrypted = chatItem.file?.fileSource?.cryptoArgs == nil ? url : chatItem.file?.fileSource?.decryptedGet()
self._urlDecrypted = State(initialValue: decrypted)
if let decrypted = decrypted {
self._player = State(initialValue: VideoPlayerView.getOrCreatePlayer(decrypted, false))
self._fullPlayer = State(initialValue: AVPlayer(url: decrypted))
}
self._url = State(initialValue: url)
}
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 decrypted = urlDecrypted {
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 {
imageView(preview)
.onTapGesture {
if let file = file {
} else if let preview, let file {
Group { if smallView { smallViewImageView(preview, file) } else { imageView(preview) } }
.onTapGesture {
switch file.fileStatus {
case .rcvInvitation, .rcvAborted:
receiveFileIfValidSize(file: file, receiveFile: receiveFile)
@@ -82,21 +81,64 @@ struct CIVideoView: View {
default: ()
}
}
}
}
durationProgress()
if !smallView {
durationProgress()
}
}
if let file = file, showDownloadButton(file.fileStatus) {
Button {
receiveFileIfValidSize(file: file, receiveFile: receiveFile)
} label: {
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 showDownloadButton(_ fileStatus: CIFileStatus) -> Bool {
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
@@ -109,11 +151,6 @@ struct CIVideoView: View {
ZStack(alignment: .center) {
let canBePlayed = !chatItem.chatDir.sent || file.fileStatus == CIFileStatus.sndComplete || (file.fileStatus == .sndStored && file.fileProtocol == .local)
imageView(defaultPreview)
.fullScreenCover(isPresented: $showFullScreenPlayer) {
if let decrypted = urlDecrypted {
fullScreenPlayer(decrypted)
}
}
.onTapGesture {
decrypt(file: file) {
showFullScreenPlayer = urlDecrypted != nil
@@ -122,20 +159,22 @@ struct CIVideoView: View {
.onChange(of: m.activeCallViewIsCollapsed) { _ in
showFullScreenPlayer = false
}
if !decryptionInProgress {
Button {
decrypt(file: file) {
if urlDecrypted != nil {
videoPlaying = true
player?.play()
if !blurred {
if !decryptionInProgress {
Button {
decrypt(file: file) {
if urlDecrypted != nil {
videoPlaying = true
player?.play()
}
}
} label: {
playPauseIcon(canBePlayed ? "play.fill" : "play.slash")
}
} label: {
playPauseIcon(canBePlayed ? "play.fill" : "play.slash")
.disabled(!canBePlayed)
} else {
videoDecryptionProgress()
}
.disabled(!canBePlayed)
} else {
videoDecryptionProgress()
}
}
}
@@ -154,9 +193,7 @@ struct CIVideoView: View {
videoPlaying = false
}
}
.fullScreenCover(isPresented: $showFullScreenPlayer) {
fullScreenPlayer(url)
}
.modifier(PrivacyBlur(enabled: !videoPlaying, blurred: $blurred))
.onTapGesture {
switch player.timeControlStatus {
case .playing:
@@ -172,7 +209,7 @@ struct CIVideoView: View {
.onChange(of: m.activeCallViewIsCollapsed) { _ in
showFullScreenPlayer = false
}
if !videoPlaying {
if !videoPlaying && !blurred {
Button {
m.stopPreviousRecPlay = url
player.play()
@@ -194,14 +231,53 @@ 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())
}
@@ -209,9 +285,9 @@ struct CIVideoView: View {
private func videoDecryptionProgress(_ color: Color = .white) -> some View {
ProgressView()
.progressViewStyle(.circular)
.frame(width: 12, height: 12)
.frame(width: smallView ? 12 * sizeMultiplier : 12, height: smallView ? 12 * sizeMultiplier : 12)
.tint(color)
.frame(width: 40, height: 40)
.frame(width: smallView ? 40 * sizeMultiplier * 0.9 : 40, height: smallView ? 40 * sizeMultiplier * 0.9 : 40)
.background(Color.black.opacity(0.35))
.clipShape(Circle())
}
@@ -247,7 +323,23 @@ struct CIVideoView: View {
.resizable()
.scaledToFit()
.frame(width: w)
fileStatusIcon()
.modifier(PrivacyBlur(blurred: $blurred))
if !blurred || !showDownloadButton(chatItem.file?.fileStatus) {
fileStatusIcon()
}
}
}
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)
}
}
}
@@ -322,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 {
@@ -330,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 {
@@ -342,7 +434,7 @@ struct CIVideoView: View {
)
.rotationEffect(.degrees(-90))
.frame(width: 16, height: 16)
.padding([.trailing, .top], 11)
.padding([.trailing, .top], smallView ? 0 : 11)
}
// TODO encrypt: where file size is checked?
@@ -382,7 +474,8 @@ struct CIVideoView: View {
)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now()) {
m.stopPreviousRecPlay = url
// 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
@@ -419,10 +512,12 @@ struct CIVideoView: View {
urlDecrypted = await file.fileSource?.decryptedGetOrCreate(&ChatModel.shared.filesToDelete)
await MainActor.run {
if let decrypted = urlDecrypted {
player = VideoPlayerView.getOrCreatePlayer(decrypted, false)
if !smallView {
player = VideoPlayerView.getOrCreatePlayer(decrypted, false)
}
fullPlayer = AVPlayer(url: decrypted)
}
decryptionInProgress = true
decryptionInProgress = false
completed?()
}
}
@@ -15,15 +15,26 @@ struct CIVoiceView: View {
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 {
@@ -54,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),
@@ -63,7 +80,8 @@ struct CIVoiceView: View {
audioPlayer: $audioPlayer,
playbackState: $playbackState,
playbackTime: $playbackTime,
allowMenu: $allowMenu
allowMenu: $allowMenu,
sizeMultiplier: sizeMultiplier
)
}
@@ -119,6 +137,7 @@ struct VoiceMessagePlayerTime: View {
}
struct VoiceMessagePlayer: View {
@ObservedObject var chat: Chat
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
var chatItem: ChatItem
@@ -130,7 +149,9 @@ 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 {
@@ -190,49 +211,113 @@ 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 = getLoadedFileSource(recordingFile)?.filePath,
chatModel.stopPreviousRecPlay != getAppFilePath(recordingFileName) {
audioPlayer?.stop()
playbackState = .noPlayback
playbackTime = TimeInterval(0)
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 recordingSource = getLoadedFileSource(recordingFile) {
startPlayback(recordingSource)
}
} label: {
if sizeMultiplier != 1 {
switch playbackState {
case .noPlayback:
playPauseIcon("play.fill", theme.colors.primary)
}
case .playing:
Button {
audioPlayer?.pause()
playbackState = .paused
} label: {
.onTapGesture {
if let recordingSource = getLoadedFileSource(recordingFile) {
startPlayback(recordingSource)
}
}
case .playing:
playPauseIcon("pause.fill", theme.colors.primary)
}
case .paused:
Button {
audioPlayer?.play()
playbackState = .playing
} label: {
.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)
}
}
}
}
@@ -242,28 +327,49 @@ struct VoiceMessagePlayer: View {
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)
.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, _ icon: String) -> some View {
Button {
Task {
if let user = chatModel.currentUser {
await receiveFile(user: user, fileId: recordingFile.fileId)
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(icon, theme.colors.primary)
}
}
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)
}
}
@@ -288,33 +394,96 @@ struct VoiceMessagePlayer: View {
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: size, height: size)
.frame(width: size * sizeMultiplier, height: size * sizeMultiplier)
.foregroundColor(Color(uiColor: .tertiaryLabel))
.frame(width: 56, height: 56)
.frame(width: 56 * sizeMultiplier, height: 56 * sizeMultiplier)
.background(showBackground ? chatItemFrameColor(chatItem, theme) : .clear)
.clipShape(Circle())
}
private func loadingIcon() -> some View {
ProgressView()
.frame(width: 30, height: 30)
.frame(width: 56, height: 56)
.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) {
chatModel.stopPreviousRecPlay = getAppFilePath(recordingSource.filePath)
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(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 {
@@ -339,15 +508,12 @@ struct CIVoiceView_Previews: PreviewProvider {
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(chat: Chat.sampleData, chatItem: sentVoiceMessage, revealed: Binding.constant(false), allowMenu: .constant(true), playbackState: .constant(.noPlayback), playbackTime: .constant(nil))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(), revealed: Binding.constant(false), allowMenu: .constant(true), playbackState: .constant(.noPlayback), playbackTime: .constant(nil))
ChatItemView(chat: Chat.sampleData, chatItem: ChatItem.getVoiceMsgContentSample(fileStatus: .rcvTransfer(rcvProgress: 7, rcvTotal: 10)), revealed: Binding.constant(false), allowMenu: .constant(true), playbackState: .constant(.noPlayback), playbackTime: .constant(nil))
ChatItemView(chat: Chat.sampleData, 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))
}
@@ -13,21 +13,23 @@ 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),
@@ -36,7 +38,8 @@ struct FramedCIVoiceView: View {
audioPlayer: $audioPlayer,
playbackState: $playbackState,
playbackTime: $playbackTime,
allowMenu: $allowMenu
allowMenu: $allowMenu,
sizeMultiplier: 1
)
VoiceMessagePlayerTime(
recordingTime: TimeInterval(duration),
File diff suppressed because one or more lines are too long
@@ -22,7 +22,7 @@ struct ChatItemForwardingView: View {
@FocusState private var searchFocused
@State private var alert: SomeAlert?
@State private var hasSimplexLink_: Bool?
private let chatsToForwardTo = filterChatsToForwardTo()
private let chatsToForwardTo = filterChatsToForwardTo(chats: ChatModel.shared.chats)
var body: some View {
NavigationView {
@@ -67,22 +67,6 @@ struct ChatItemForwardingView: View {
}
}
private func foundChat(_ chat: Chat, _ searchStr: String) -> Bool {
let cInfo = chat.chatInfo
return switch cInfo {
case let .direct(contact):
viewNameContains(cInfo, searchStr) ||
contact.profile.displayName.localizedLowercase.contains(searchStr) ||
contact.fullName.localizedLowercase.contains(searchStr)
default:
viewNameContains(cInfo, searchStr)
}
func viewNameContains(_ cInfo: ChatInfo, _ s: String) -> Bool {
cInfo.chatViewName.localizedLowercase.contains(s)
}
}
private func prohibitedByPref(_ chat: Chat) -> Bool {
// preference checks should match checks in compose view
let simplexLinkProhibited = hasSimplexLink && !chat.groupFeatureEnabled(.simplexLinks)
@@ -162,27 +146,6 @@ struct ChatItemForwardingView: View {
}
}
private func filterChatsToForwardTo() -> [Chat] {
var filteredChats = ChatModel.shared.chats.filter { c in
c.chatInfo.chatType != .local && canForwardToChat(c)
}
if let privateNotes = ChatModel.shared.chats.first(where: { $0.chatInfo.chatType == .local }) {
filteredChats.insert(privateNotes, at: 0)
}
return filteredChats
}
private func canForwardToChat(_ chat: Chat) -> Bool {
switch chat.chatInfo {
case let .direct(contact): contact.sendMsgEnabled && !contact.nextSendGrpInv
case let .group(groupInfo): groupInfo.sendMsgEnabled
case let .local(noteFolder): noteFolder.sendMsgEnabled
case .contactRequest: false
case .contactConnection: false
case .invalidJSON: false
}
}
#Preview {
ChatItemForwardingView(
ci: ChatItem.getSample(1, .directSnd, .now, "hello"),
@@ -190,3 +153,4 @@ private func canForwardToChat(_ chat: Chat) -> Bool {
composeState: Binding.constant(ComposeState(message: "hello"))
).environmentObject(CurrentColors.toAppTheme())
}
+4 -15
View File
@@ -16,28 +16,20 @@ struct ChatItemView: View {
var maxWidth: CGFloat = .infinity
@Binding var revealed: Bool
@Binding var allowMenu: Bool
@Binding var audioPlayer: AudioPlayer?
@Binding var playbackState: VoiceMessagePlaybackState
@Binding var playbackTime: TimeInterval?
init(
chat: Chat,
chatItem: ChatItem,
showMember: Bool = false,
maxWidth: CGFloat = .infinity,
revealed: Binding<Bool>,
allowMenu: Binding<Bool> = .constant(false),
audioPlayer: Binding<AudioPlayer?> = .constant(nil),
playbackState: Binding<VoiceMessagePlaybackState> = .constant(.noPlayback),
playbackTime: Binding<TimeInterval?> = .constant(nil)
allowMenu: Binding<Bool> = .constant(false)
) {
self.chat = chat
self.chatItem = chatItem
self.maxWidth = maxWidth
_revealed = revealed
_allowMenu = allowMenu
_audioPlayer = audioPlayer
_playbackState = playbackState
_playbackTime = playbackTime
}
var body: some View {
@@ -48,7 +40,7 @@ struct ChatItemView: View {
if let mc = ci.content.msgContent, mc.isText && isShortEmoji(ci.content.text) {
EmojiItemView(chat: chat, chatItem: ci)
} else if ci.content.text.isEmpty, case let .voice(_, duration) = ci.content.msgContent {
CIVoiceView(chat: chat, 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(chat: chat, chatItem: chatItem, revealed: $revealed, msgContentView: { Text(ci.text) }) // msgContent is unreachable branch in this case
} else {
@@ -84,10 +76,7 @@ struct ChatItemView: View {
maxWidth: maxWidth,
imgWidth: adjustedMaxWidth,
videoWidth: adjustedMaxWidth,
allowMenu: $allowMenu,
audioPlayer: $audioPlayer,
playbackState: $playbackState,
playbackTime: $playbackTime
allowMenu: $allowMenu
)
}
}
+56 -39
View File
@@ -45,9 +45,14 @@ struct ChatView: View {
var body: some View {
if #available(iOS 16.0, *) {
viewBody
let v = viewBody
.scrollDismissesKeyboard(.immediately)
.keyboardPadding()
if (searchMode) {
v.toolbarBackground(.thinMaterial, for: .navigationBar)
} else {
v.toolbarBackground(.visible, for: .navigationBar)
}
} else {
viewBody
}
@@ -81,7 +86,6 @@ struct ChatView: View {
)
.disabled(!cInfo.sendMsgEnabled)
}
.padding(.top, 1)
.navigationTitle(cInfo.chatViewName)
.background(theme.colors.background)
.navigationBarTitleDisplayMode(.inline)
@@ -92,6 +96,7 @@ struct ChatView: View {
}
.onChange(of: chatModel.chatId) { cId in
showChatInfoSheet = false
stopAudioPlayer()
if let cId {
if let c = chatModel.getChat(cId) {
chat = c
@@ -113,6 +118,7 @@ struct ChatView: View {
.environmentObject(scrollModel)
.onDisappear {
VideoPlayerView.players.removeAll()
stopAudioPlayer()
if chatModel.chatId == cInfo.id && !presentationMode.wrappedValue.isPresented {
chatModel.chatId = nil
DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
@@ -310,8 +316,9 @@ struct ChatView: View {
}
.padding(.horizontal)
.padding(.vertical, 8)
.background(.thinMaterial)
}
private func voiceWithoutFrame(_ ci: ChatItem) -> Bool {
ci.content.msgContent?.isVoice == true && ci.content.text.count == 0 && ci.quotedItem == nil && ci.meta.itemForwarded == nil
}
@@ -373,7 +380,7 @@ struct ChatView: View {
@ViewBuilder private func connectingText() -> some View {
if case let .direct(contact) = chat.chatInfo,
!contact.ready,
!contact.sndReady,
contact.active,
!contact.nextSendGrpInv {
Text("connecting…")
@@ -584,6 +591,11 @@ struct ChatView: View {
}
}
func stopAudioPlayer() {
VoiceItemState.chatView.values.forEach { $0.audioPlayer?.stop() }
VoiceItemState.chatView = [:]
}
@ViewBuilder private func chatItemView(_ ci: ChatItem, _ maxWidth: CGFloat) -> some View {
ChatItemWithMenu(
chat: chat,
@@ -615,10 +627,6 @@ struct ChatView: View {
@State private var allowMenu: Bool = true
@State private var audioPlayer: AudioPlayer?
@State private var playbackState: VoiceMessagePlaybackState = .noPlayback
@State private var playbackTime: TimeInterval?
var revealed: Bool { chatItem == revealedChatItem }
var body: some View {
@@ -638,23 +646,38 @@ struct ChatView: View {
}
}
.onAppear {
markRead(
chatItems: range.flatMap { m.reversedChatItems[$0] }
?? [chatItem]
)
}
}
private func markRead(chatItems: Array<ChatItem>.SubSequence) {
let unreadItems = chatItems.filter { $0.isRcvNew }
if unreadItems.isEmpty { return }
DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) {
if m.chatId == chat.chatInfo.id {
Task {
for unreadItem in unreadItems {
await apiMarkChatItemRead(chat.chatInfo, unreadItem)
if let range {
if let items = unreadItems(range) {
waitToMarkRead {
for ci in items {
await apiMarkChatItemRead(chat.chatInfo, ci)
}
}
}
} else if chatItem.isRcvNew {
waitToMarkRead {
await apiMarkChatItemRead(chat.chatInfo, chatItem)
}
}
}
}
private func unreadItems(_ range: ClosedRange<Int>) -> [ChatItem]? {
let items = range.compactMap { i in
if i >= 0 && i < m.reversedChatItems.count {
let ci = m.reversedChatItems[i]
return if ci.isRcvNew { ci } else { nil }
} else {
return nil
}
}
return if items.isEmpty { nil } else { items }
}
private func waitToMarkRead(_ op: @Sendable @escaping () async -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) {
if m.chatId == chat.chatInfo.id {
Task(operation: op)
}
}
}
@@ -671,7 +694,12 @@ struct ChatView: View {
if prevItem == nil || showMemberImage(member, prevItem) || prevMember != nil {
VStack(alignment: .leading, spacing: 4) {
if ci.content.showMemberName {
Text(memberNames(member, prevMember, memCount))
let t = if memCount == 1 && member.memberRole > .member {
Text(member.memberRole.text + " ").fontWeight(.semibold) + Text(member.displayName)
} else {
Text(memberNames(member, prevMember, memCount))
}
t
.font(.caption)
.foregroundStyle(.secondary)
.lineLimit(2)
@@ -697,19 +725,19 @@ struct ChatView: View {
chatItemWithMenu(ci, range, maxWidth)
}
}
.padding(.top, 5)
.padding(.bottom, 5)
.padding(.trailing)
.padding(.leading, 12)
} else {
chatItemWithMenu(ci, range, maxWidth)
.padding(.top, 5)
.padding(.bottom, 5)
.padding(.trailing)
.padding(.leading, memberImageSize + 8 + 12)
}
} else {
chatItemWithMenu(ci, range, maxWidth)
.padding(.horizontal)
.padding(.top, 5)
.padding(.bottom, 5)
}
}
@@ -732,10 +760,7 @@ struct ChatView: View {
chatItem: ci,
maxWidth: maxWidth,
revealed: .constant(revealed),
allowMenu: $allowMenu,
audioPlayer: $audioPlayer,
playbackState: $playbackState,
playbackTime: $playbackTime
allowMenu: $allowMenu
)
.modifier(ChatItemClipped(ci))
.contextMenu { menu(ci, range, live: composeState.liveMessage != nil) }
@@ -762,14 +787,6 @@ struct ChatView: View {
}
.frame(maxWidth: maxWidth, maxHeight: .infinity, alignment: alignment)
.frame(minWidth: 0, maxWidth: .infinity, alignment: alignment)
.onDisappear {
if ci.content.msgContent?.isVoice == true {
allowMenu = true
audioPlayer?.stop()
playbackState = .noPlayback
playbackTime = TimeInterval(0)
}
}
.sheet(isPresented: $showChatItemInfoSheet, onDismiss: {
chatItemInfo = nil
}) {
@@ -32,9 +32,8 @@ struct ComposeFileView: View {
}
.padding(.vertical, 1)
.padding(.trailing, 12)
.frame(height: 50)
.frame(height: 54)
.background(theme.appColors.sentMessage)
.frame(maxWidth: .infinity)
.padding(.top, 8)
}
}
@@ -46,8 +46,8 @@ struct ComposeImageView: View {
.padding(.vertical, 1)
.padding(.trailing, 12)
.background(theme.appColors.sentMessage)
.frame(minHeight: 54)
.frame(maxWidth: .infinity)
.padding(.top, 8)
}
}
@@ -10,35 +10,6 @@ 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 {
@EnvironmentObject var theme: AppTheme
let linkPreview: LinkPreview?
@@ -63,8 +34,8 @@ struct ComposeLinkView: View {
.padding(.vertical, 1)
.padding(.trailing, 12)
.background(theme.appColors.sentMessage)
.frame(minHeight: 54)
.frame(maxWidth: .infinity)
.padding(.top, 8)
}
private func linkPreviewView(_ linkPreview: LinkPreview) -> some View {
@@ -284,8 +284,10 @@ struct ComposeView: View {
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)
@@ -293,10 +295,13 @@ struct ComposeView: View {
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) {
@@ -359,7 +364,6 @@ struct ComposeView: View {
: theme.colors.primary
)
.padding(.trailing, 12)
.background(theme.colors.background)
.disabled(!chat.userCanSend)
if chat.userIsObserver {
@@ -377,6 +381,7 @@ struct ComposeView: View {
}
}
}
.background(.thinMaterial)
.onChange(of: composeState.message) { msg in
if composeState.linkPreviewAllowed {
if msg.count > 0 {
@@ -625,6 +630,7 @@ struct ComposeView: View {
cancelPreview: cancelLinkPreview,
cancelEnabled: !composeState.inProgress
)
Divider()
case let .mediaPreviews(mediaPreviews: media):
ComposeImageView(
images: media.map { (img, _) in img },
@@ -633,6 +639,7 @@ struct ComposeView: View {
chosenMedia = []
},
cancelEnabled: !composeState.editing && !composeState.inProgress)
Divider()
case let .voicePreview(recordingFileName, _):
ComposeVoiceView(
recordingFileName: recordingFileName,
@@ -645,6 +652,7 @@ struct ComposeView: View {
cancelEnabled: !composeState.editing && !composeState.inProgress,
stopPlayback: $stopPlayback
)
Divider()
case let .filePreview(fileName, _):
ComposeFileView(
fileName: fileName,
@@ -652,6 +660,7 @@ struct ComposeView: View {
composeState = composeState.copy(preview: .noPreview)
},
cancelEnabled: !composeState.editing && !composeState.inProgress)
Divider()
}
}
@@ -661,10 +670,9 @@ struct ComposeView: View {
Text(reason).italic()
}
.padding(12)
.frame(minHeight: 50)
.frame(minHeight: 54)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(uiColor: .tertiarySystemGroupedBackground))
.padding(.top, 8)
.background(.thinMaterial)
}
@ViewBuilder private func contextItemView() -> some View {
@@ -678,6 +686,7 @@ struct ComposeView: View {
contextIcon: "arrowshape.turn.up.left",
cancelContextItem: { composeState = composeState.copy(contextItem: .noContextItem) }
)
Divider()
case let .editingItem(chatItem: editingItem):
ContextItemView(
chat: chat,
@@ -685,6 +694,7 @@ struct ComposeView: View {
contextIcon: "pencil",
cancelContextItem: { clearState() }
)
Divider()
case let .forwardingItem(chatItem: forwardedItem, _):
ContextItemView(
chat: chat,
@@ -693,6 +703,7 @@ struct ComposeView: View {
cancelContextItem: { composeState = composeState.copy(contextItem: .noContextItem) },
showSender: false
)
Divider()
}
}
@@ -51,8 +51,8 @@ struct ComposeVoiceView: View {
.padding(.vertical, 1)
.frame(height: ComposeVoiceView.previewHeight)
.background(theme.appColors.sentMessage)
.frame(minHeight: 54)
.frame(maxWidth: .infinity)
.padding(.top, 8)
}
private func recordingMode() -> some View {
@@ -18,10 +18,9 @@ struct ContextInvitingContactMemberView: View {
Text("Send direct message to connect")
}
.padding(12)
.frame(minHeight: 50)
.frame(minHeight: 54)
.frame(maxWidth: .infinity, alignment: .leading)
.background(theme.appColors.sentMessage)
.padding(.top, 8)
.background(.thinMaterial)
}
}
@@ -43,10 +43,9 @@ struct ContextItemView: View {
.tint(theme.colors.primary)
}
.padding(12)
.frame(minHeight: 50)
.frame(minHeight: 54)
.frame(maxWidth: .infinity)
.background(chatItemFrameColor(contextItem, theme))
.padding(.top, 8)
}
private func msgContentView(lines: Int) -> some View {
@@ -44,6 +44,7 @@ struct SendMessageView: View {
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 {
@@ -66,7 +67,6 @@ struct SendMessageView: View {
.fixedSize(horizontal: false, vertical: true)
}
}
if progressByTimeout {
ProgressView()
.scaleEffect(1.4)
@@ -84,10 +84,9 @@ struct SendMessageView: View {
}
}
.padding(.vertical, 1)
.overlay(
RoundedRectangle(cornerSize: CGSize(width: 20, height: 20))
.strokeBorder(.secondary, lineWidth: 0.3, antialiased: true)
)
.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
@@ -35,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 {
@@ -122,7 +122,7 @@ 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
@@ -40,7 +40,7 @@ struct GroupChatInfoView: View {
case blockForAllAlert(mem: GroupMember)
case unblockForAllAlert(mem: GroupMember)
case removeMemberAlert(mem: GroupMember)
case error(title: LocalizedStringKey, error: LocalizedStringKey)
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -158,7 +158,7 @@ struct GroupChatInfoView: View {
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 Alert(title: Text(title), message: Text(error))
case let .error(title, error): return mkAlert(title: title, message: error)
}
}
.onAppear {
@@ -22,7 +22,7 @@ struct GroupLinkView: View {
private enum GroupLinkAlert: Identifiable {
case deleteLink
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -113,7 +113,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
@@ -37,7 +37,7 @@ struct GroupMemberInfoView: View {
case syncConnectionForceAlert
case planAndConnectAlert(alert: PlanAndConnectAlert)
case queueInfo(info: String)
case error(title: LocalizedStringKey, error: LocalizedStringKey)
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -76,155 +76,153 @@ struct GroupMemberInfoView: View {
private func groupMemberInfoView() -> some View {
ZStack {
VStack {
let member = groupMember.wrapped
List {
groupMemberInfoHeader(member)
.listRowBackground(Color.clear)
let member = groupMember.wrapped
List {
groupMemberInfoHeader(member)
.listRowBackground(Color.clear)
if member.memberActive {
Section {
if let contactId = member.memberContactId, let chat = knownDirectChat(contactId) {
knownDirectChatButton(chat)
} else if groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
if let contactId = member.memberContactId {
newDirectChatButton(contactId)
} else if member.activeConn?.peerChatVRange.isCompatibleRange(CREATE_MEMBER_CONTACT_VRANGE) ?? false {
createMemberContactButton()
}
}
if let code = connectionCode { verifyCodeButton(code) }
if let connStats = connectionStats,
connStats.ratchetSyncAllowed {
synchronizeConnectionButton()
}
// } else if developerTools {
// synchronizeConnectionButtonForce()
// }
}
}
if let contactLink = member.contactLink {
Section {
SimpleXLinkQRCode(uri: contactLink)
Button {
showShareSheet(items: [simplexChatLink(contactLink)])
} label: {
Label("Share address", systemImage: "square.and.arrow.up")
}
if member.memberActive {
Section {
if let contactId = member.memberContactId, let chat = knownDirectChat(contactId) {
knownDirectChatButton(chat)
} else if groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
if let contactId = member.memberContactId {
if knownDirectChat(contactId) == nil && !groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
connectViaAddressButton(contactLink)
}
} else {
newDirectChatButton(contactId)
} else if member.activeConn?.peerChatVRange.isCompatibleRange(CREATE_MEMBER_CONTACT_VRANGE) ?? false {
createMemberContactButton()
}
}
if let code = connectionCode { verifyCodeButton(code) }
if let connStats = connectionStats,
connStats.ratchetSyncAllowed {
synchronizeConnectionButton()
}
// } else if developerTools {
// synchronizeConnectionButtonForce()
// }
}
}
if let contactLink = member.contactLink {
Section {
SimpleXLinkQRCode(uri: contactLink)
Button {
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(for: groupInfo.membership) {
connectViaAddressButton(contactLink)
}
} 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(header: Text("Member").foregroundColor(theme.colors.secondary)) {
infoRow("Group", groupInfo.displayName)
if let roles = member.canChangeRoleTo(groupInfo: groupInfo) {
Picker("Change role", selection: $newRole) {
ForEach(roles) { role in
Text(role.text)
}
}
.frame(height: 36)
} else {
infoRow("Role", member.memberRole.text)
connectViaAddressButton(contactLink)
}
} 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)
}
}
if let connStats = connectionStats {
Section(header: Text("Servers").foregroundColor(theme.colors.secondary)) {
// TODO network connection status
Button("Change receiving address") {
alert = .switchAddressAlert
Section(header: Text("Member").foregroundColor(theme.colors.secondary)) {
infoRow("Group", groupInfo.displayName)
if let roles = member.canChangeRoleTo(groupInfo: groupInfo) {
Picker("Change role", selection: $newRole) {
ForEach(roles) { role in
Text(role.text)
}
}
.frame(height: 36)
} else {
infoRow("Role", member.memberRole.text)
}
}
if let connStats = connectionStats {
Section(header: Text("Servers").foregroundColor(theme.colors.secondary)) {
// TODO network connection status
Button("Change receiving address") {
alert = .switchAddressAlert
}
.disabled(
connStats.rcvQueuesInfo.contains { $0.rcvSwitchStatus != nil }
|| connStats.ratchetSyncSendProhibited
)
if connStats.rcvQueuesInfo.contains(where: { $0.rcvSwitchStatus != nil }) {
Button("Abort changing address") {
alert = .abortSwitchAddressAlert
}
.disabled(
connStats.rcvQueuesInfo.contains { $0.rcvSwitchStatus != nil }
connStats.rcvQueuesInfo.contains { $0.rcvSwitchStatus != nil && !$0.canAbortSwitch }
|| connStats.ratchetSyncSendProhibited
)
if connStats.rcvQueuesInfo.contains(where: { $0.rcvSwitchStatus != nil }) {
Button("Abort changing address") {
alert = .abortSwitchAddressAlert
}
.disabled(
connStats.rcvQueuesInfo.contains { $0.rcvSwitchStatus != nil && !$0.canAbortSwitch }
|| connStats.ratchetSyncSendProhibited
)
}
smpServers("Receiving via", connStats.rcvQueuesInfo.map { $0.rcvServer }, theme.colors.secondary)
smpServers("Sending via", connStats.sndQueuesInfo.map { $0.sndServer }, theme.colors.secondary)
}
smpServers("Receiving via", connStats.rcvQueuesInfo.map { $0.rcvServer }, theme.colors.secondary)
smpServers("Sending via", connStats.sndQueuesInfo.map { $0.sndServer }, theme.colors.secondary)
}
}
if groupInfo.membership.memberRole >= .admin {
adminDestructiveSection(member)
} else {
nonAdminBlockSection(member)
}
if groupInfo.membership.memberRole >= .admin {
adminDestructiveSection(member)
} else {
nonAdminBlockSection(member)
}
if developerTools {
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) }
}
if developerTools {
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) }
}
}
}
}
}
.navigationBarHidden(true)
.onAppear {
if #unavailable(iOS 16) {
// this condition prevents re-setting picker
if !justOpened { return }
}
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))")
}
}
.navigationBarHidden(true)
.onAppear {
if #unavailable(iOS 16) {
// this condition prevents re-setting picker
if !justOpened { return }
}
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) { newRole in
if newRole != member.memberRole {
alert = .changeMemberRoleAlert(mem: member, role: newRole)
}
}
.onChange(of: member.memberRole) { role in
newRole = role
}
.onChange(of: newRole) { newRole in
if newRole != member.memberRole {
alert = .changeMemberRoleAlert(mem: member, role: newRole)
}
}
.onChange(of: member.memberRole) { role in
newRole = role
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.alert(item: $alert) { alertItem in
switch(alertItem) {
@@ -239,7 +237,7 @@ struct GroupMemberInfoView: View {
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 .error(title, error): return Alert(title: Text(title), message: Text(error))
case let .error(title, error): return mkAlert(title: title, message: error)
}
}
.actionSheet(item: $sheet) { s in planAndConnectActionSheet(s, dismiss: true) }
+2 -1
View File
@@ -129,8 +129,9 @@ struct ReverseList<Item: Identifiable & Hashable & Sendable, Content: View>: UIV
from: nil,
for: nil
)
NotificationCenter.default.post(name: .chatViewWillBeginScrolling, object: nil)
}
/// Scrolls up
func scrollToNextPage() {
tableView.setContentOffset(
@@ -9,25 +9,34 @@
import SwiftUI
import SimpleXChat
private let rowHeights: [DynamicTypeSize: CGFloat] = [
.xSmall: 68,
.small: 72,
.medium: 76,
.large: 80,
.xLarge: 88,
.xxLarge: 94,
.xxxLarge: 104,
.accessibility1: 90,
.accessibility2: 100,
.accessibility3: 120,
.accessibility4: 130,
.accessibility5: 140
let dynamicSizes: [
DynamicTypeSize: (
rowHeight: CGFloat,
profileImageSize: CGFloat,
mediaSize: CGFloat,
chatInfoSize: CGFloat,
unreadCorner: CGFloat,
unreadPadding: CGFloat
)
] = [
.xSmall: (68, 55, 33, 18, 9, 3),
.small: (72, 57, 34, 18, 9, 3),
.medium: (76, 60, 36, 18, 10, 4),
.large: (80, 63, 38, 20, 10, 4),
.xLarge: (88, 67, 41, 20, 10, 4),
.xxLarge: (94, 71, 44, 22, 11, 4),
.xxxLarge: (104, 75, 48, 24, 12, 5),
.accessibility1: (104, 75, 48, 24, 12, 5),
.accessibility2: (114, 75, 48, 24, 12, 5),
.accessibility3: (124, 75, 48, 24, 12, 5),
.accessibility4: (134, 75, 48, 24, 12, 5),
.accessibility5: (144, 75, 48, 24, 12, 5)
]
struct ChatListNavLink: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
@Environment(\.dynamicTypeSize) private var userFont: DynamicTypeSize
@ObservedObject var chat: Chat
@State private var showContactRequestDialog = false
@State private var showJoinGroupDialog = false
@@ -38,6 +47,8 @@ struct ChatListNavLink: View {
@State private var inProgress = false
@State private var progressByTimeout = false
var dynamicRowHeight: CGFloat { dynamicSizes[userFont]?.rowHeight ?? 80 }
var body: some View {
Group {
switch chat.chatInfo {
@@ -70,7 +81,7 @@ struct ChatListNavLink: View {
Group {
if contact.activeConn == nil && contact.profile.contactLink != nil {
ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false))
.frame(height: rowHeights[dynamicTypeSize])
.frame(height: dynamicRowHeight)
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button {
showDeleteContactActionSheet = true
@@ -100,7 +111,7 @@ struct ChatListNavLink: View {
clearChatButton()
}
Button {
if contact.ready || !contact.active {
if contact.sndReady || !contact.active {
showDeleteContactActionSheet = true
} else {
AlertManager.shared.showAlert(deletePendingContactAlert(chat, contact))
@@ -110,11 +121,11 @@ struct ChatListNavLink: View {
}
.tint(.red)
}
.frame(height: rowHeights[dynamicTypeSize])
.frame(height: dynamicRowHeight)
}
}
.actionSheet(isPresented: $showDeleteContactActionSheet) {
if contact.ready && contact.active {
if contact.sndReady && contact.active {
return ActionSheet(
title: Text("Delete contact?\nThis cannot be undone!"),
buttons: [
@@ -139,7 +150,7 @@ struct ChatListNavLink: View {
switch (groupInfo.membership.memberStatus) {
case .memInvited:
ChatPreviewView(chat: chat, progressByTimeout: $progressByTimeout)
.frame(height: rowHeights[dynamicTypeSize])
.frame(height: dynamicRowHeight)
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
joinGroupButton()
if groupInfo.canDelete {
@@ -159,7 +170,7 @@ struct ChatListNavLink: View {
.disabled(inProgress)
case .memAccepted:
ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false))
.frame(height: rowHeights[dynamicTypeSize])
.frame(height: dynamicRowHeight)
.onTapGesture {
AlertManager.shared.showAlert(groupInvitationAcceptedAlert())
}
@@ -178,7 +189,7 @@ struct ChatListNavLink: View {
label: { ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false)) },
disabled: !groupInfo.ready
)
.frame(height: rowHeights[dynamicTypeSize])
.frame(height: dynamicRowHeight)
.swipeActions(edge: .leading, allowsFullSwipe: true) {
markReadButton()
toggleFavoriteButton()
@@ -205,7 +216,7 @@ struct ChatListNavLink: View {
label: { ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false)) },
disabled: !noteFolder.ready
)
.frame(height: rowHeights[dynamicTypeSize])
.frame(height: dynamicRowHeight)
.swipeActions(edge: .leading, allowsFullSwipe: true) {
markReadButton()
}
@@ -321,7 +332,7 @@ struct ChatListNavLink: View {
}
.tint(.red)
}
.frame(height: rowHeights[dynamicTypeSize])
.frame(height: dynamicRowHeight)
.onTapGesture { showContactRequestDialog = true }
.confirmationDialog("Accept connection request?", isPresented: $showContactRequestDialog, titleVisibility: .visible) {
Button("Accept") { Task { await acceptContactRequest(incognito: false, contactRequest: contactRequest) } }
@@ -349,7 +360,7 @@ struct ChatListNavLink: View {
}
.tint(theme.colors.primary)
}
.frame(height: rowHeights[dynamicTypeSize])
.frame(height: dynamicRowHeight)
.appSheet(isPresented: $showContactConnectionInfo) {
Group {
if case let .contactConnection(contactConnection) = chat.chatInfo {
@@ -469,7 +480,7 @@ struct ChatListNavLink: View {
Text("invalid chat data")
.foregroundColor(.red)
.padding(4)
.frame(height: rowHeights[dynamicTypeSize])
.frame(height: dynamicRowHeight)
.onTapGesture { showInvalidJSON = true }
.appSheet(isPresented: $showInvalidJSON) {
invalidJSONView(json)
@@ -21,6 +21,7 @@ struct ChatListView: View {
@State private var newChatMenuOption: NewChatMenuOption? = nil
@State private var userPickerVisible = false
@State private var showConnectDesktop = false
@AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false
var body: some View {
@@ -162,6 +163,10 @@ struct ChatListView: View {
chatModel.chatToTop = nil
chatModel.popChat(chatId)
}
stopAudioPlayer()
}
.onChange(of: chatModel.currentUser?.userId) { _ in
stopAudioPlayer()
}
if cs.isEmpty && !chatModel.chats.isEmpty {
Text("No filtered chats").foregroundColor(theme.colors.secondary)
@@ -217,6 +222,11 @@ struct ChatListView: View {
}
}
func stopAudioPlayer() {
VoiceItemState.smallView.values.forEach { $0.audioPlayer?.stop() }
VoiceItemState.smallView = [:]
}
private func filteredChats() -> [Chat] {
if let linkChatId = searchChatFilteredBySimplexLink {
return chatModel.chats.filter { $0.id == linkChatId }
@@ -266,9 +276,9 @@ struct ChatListView: View {
}
struct SubsStatusIndicator: View {
@State private var serversSummary: PresentedServersSummary?
@State private var subs: SMPServerSubs = SMPServerSubs.newSMPServerSubs
@State private var hasSess: Bool = false
@State private var timer: Timer? = nil
@State private var timerCounter = 0
@State private var showServersSummary = false
@AppStorage(DEFAULT_SHOW_SUBSCRIPTION_PERCENTAGE) private var showSubscriptionPercentage = false
@@ -277,12 +287,10 @@ struct SubsStatusIndicator: View {
Button {
showServersSummary = true
} label: {
let subs = serversSummary?.allUsersSMP.smpTotals.subs ?? SMPServerSubs.newSMPServerSubs
let sess = serversSummary?.allUsersSMP.smpTotals.sessions ?? ServerSessions.newServerSessions
HStack(spacing: 4) {
SubscriptionStatusIndicatorView(subs: subs, sess: sess)
SubscriptionStatusIndicatorView(subs: subs, hasSess: hasSess)
if showSubscriptionPercentage {
SubscriptionStatusPercentageView(subs: subs, sess: sess)
SubscriptionStatusPercentageView(subs: subs, hasSess: hasSess)
}
}
}
@@ -293,14 +301,14 @@ struct SubsStatusIndicator: View {
stopTimer()
}
.sheet(isPresented: $showServersSummary) {
ServersSummaryView(serversSummary: $serversSummary)
ServersSummaryView()
}
}
private func startTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
if AppChatState.shared.value == .active {
getServersSummary()
getSubsTotal()
}
}
}
@@ -310,11 +318,11 @@ struct SubsStatusIndicator: View {
timer = nil
}
private func getServersSummary() {
private func getSubsTotal() {
do {
serversSummary = try getAgentServersSummary()
(subs, hasSess) = try getAgentSubsTotal()
} catch let error {
logger.error("getAgentServersSummary error: \(responseError(error))")
logger.error("getSubsTotal error: \(responseError(error))")
}
}
}
@@ -12,18 +12,24 @@ import SimpleXChat
struct ChatPreviewView: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@Environment(\.dynamicTypeSize) private var userFont: DynamicTypeSize
@ObservedObject var chat: Chat
@Binding var progressByTimeout: Bool
@State var deleting: Bool = false
var darkGreen = Color(red: 0, green: 0.5, blue: 0)
@State private var activeContentPreview: ActiveContentPreview? = nil
@State private var showFullscreenGallery: Bool = false
@AppStorage(DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS) private var showChatPreviews = true
var dynamicMediaSize: CGFloat { dynamicSizes[userFont]?.mediaSize ?? 36 }
var dynamicChatInfoSize: CGFloat { dynamicSizes[userFont]?.chatInfoSize ?? 18 }
var body: some View {
let cItem = chat.chatItems.last
return HStack(spacing: 8) {
ZStack(alignment: .bottomTrailing) {
ChatInfoImage(chat: chat, size: 63)
ChatInfoImage(chat: chat, size: dynamicSizes[userFont]?.profileImageSize ?? 63)
chatPreviewImageOverlayIcon()
.padding([.bottom, .trailing], 1)
}
@@ -43,11 +49,38 @@ struct ChatPreviewView: View {
.padding(.horizontal, 8)
ZStack(alignment: .topTrailing) {
chatMessagePreview(cItem)
let chat = activeContentPreview?.chat ?? chat
let ci = activeContentPreview?.ci ?? chat.chatItems.last
let mc = ci?.content.msgContent
HStack(alignment: .top) {
let deleted = ci?.isDeletedContent == true || ci?.meta.itemDeleted != nil
let showContentPreview = (showChatPreviews && chatModel.draftChatId != chat.id && !deleted) || activeContentPreview != nil
if let ci, showContentPreview {
chatItemContentPreview(chat, ci)
}
let mcIsVoice = switch mc { case .voice: true; default: false }
if !mcIsVoice || !showContentPreview || mc?.text != "" || chatModel.draftChatId == chat.id {
let hasFilePreview = if case .file = mc { true } else { false }
chatMessagePreview(cItem, hasFilePreview)
} else {
Spacer()
chatInfoIcon(chat).frame(minWidth: 37, alignment: .trailing)
}
}
.onChange(of: chatModel.stopPreviousRecPlay?.path) { _ in
checkActiveContentPreview(chat, ci, mc)
}
.onChange(of: activeContentPreview) { _ in
checkActiveContentPreview(chat, ci, mc)
}
.onChange(of: showFullscreenGallery) { _ in
checkActiveContentPreview(chat, ci, mc)
}
chatStatusImage()
.padding(.top, 26)
.frame(maxWidth: .infinity, alignment: .trailing)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.trailing, 8)
Spacer()
@@ -57,6 +90,33 @@ struct ChatPreviewView: View {
.padding(.bottom, -8)
.onChange(of: chatModel.deletedChats.contains(chat.chatInfo.id)) { contains in
deleting = contains
// Stop voice when deleting the chat
if contains, let ci = activeContentPreview?.ci {
VoiceItemState.stopVoiceInSmallView(chat.chatInfo, ci)
}
}
func checkActiveContentPreview(_ chat: Chat, _ ci: ChatItem?, _ mc: MsgContent?) {
let playing = chatModel.stopPreviousRecPlay
if case .voice = activeContentPreview?.mc, playing == nil {
activeContentPreview = nil
} else if activeContentPreview == nil {
if case .image = mc, let ci, let mc, showFullscreenGallery {
activeContentPreview = ActiveContentPreview(chat: chat, ci: ci, mc: mc)
}
if case .video = mc, let ci, let mc, showFullscreenGallery {
activeContentPreview = ActiveContentPreview(chat: chat, ci: ci, mc: mc)
}
if case .voice = mc, let ci, let mc, let fileSource = ci.file?.fileSource, playing?.path.hasSuffix(fileSource.filePath) == true {
activeContentPreview = ActiveContentPreview(chat: chat, ci: ci, mc: mc)
}
} else if case .voice = activeContentPreview?.mc {
if let playing, let fileSource = ci?.file?.fileSource, !playing.path.hasSuffix(fileSource.filePath) {
activeContentPreview = nil
}
} else if !showFullscreenGallery {
activeContentPreview = nil
}
}
}
@@ -113,39 +173,50 @@ struct ChatPreviewView: View {
.kerning(-2)
}
private func chatPreviewLayout(_ text: Text, draft: Bool = false) -> some View {
private func chatPreviewLayout(_ text: Text?, draft: Bool = false, _ hasFilePreview: Bool = false) -> some View {
ZStack(alignment: .topTrailing) {
let t = text
.lineLimit(2)
.lineLimit(userFont <= .xxxLarge ? 2 : 1)
.multilineTextAlignment(.leading)
.frame(maxWidth: .infinity, alignment: .topLeading)
.padding(.leading, 8)
.padding(.trailing, 36)
.padding(.leading, hasFilePreview ? 0 : 8)
.padding(.trailing, hasFilePreview ? 38 : 36)
.offset(x: hasFilePreview ? -2 : 0)
.fixedSize(horizontal: false, vertical: true)
if !showChatPreviews && !draft {
t.privacySensitive(true).redacted(reason: .privacy)
} else {
t
}
let s = chat.chatStats
if s.unreadCount > 0 || s.unreadChat {
unreadCountText(s.unreadCount)
.font(.caption)
.foregroundColor(.white)
.padding(.horizontal, 4)
.frame(minWidth: 18, minHeight: 18)
.background(chat.chatInfo.ntfsEnabled || chat.chatInfo.chatType == .local ? theme.colors.primary : theme.colors.secondary)
.cornerRadius(10)
} else if !chat.chatInfo.ntfsEnabled && chat.chatInfo.chatType != .local {
Image(systemName: "speaker.slash.fill")
.foregroundColor(theme.colors.secondary)
} else if chat.chatInfo.chatSettings?.favorite ?? false {
Image(systemName: "star.fill")
.resizable()
.scaledToFill()
.frame(width: 18, height: 18)
.padding(.trailing, 1)
.foregroundColor(.secondary.opacity(0.65))
}
chatInfoIcon(chat).frame(minWidth: 37, alignment: .trailing)
}
}
@ViewBuilder private func chatInfoIcon(_ chat: Chat) -> some View {
let s = chat.chatStats
if s.unreadCount > 0 || s.unreadChat {
unreadCountText(s.unreadCount)
.font(userFont <= .xxxLarge ? .caption : .caption2)
.foregroundColor(.white)
.padding(.horizontal, dynamicSizes[userFont]?.unreadPadding ?? 4)
.frame(minWidth: dynamicChatInfoSize, minHeight: dynamicChatInfoSize)
.background(chat.chatInfo.ntfsEnabled || chat.chatInfo.chatType == .local ? theme.colors.primary : theme.colors.secondary)
.cornerRadius(dynamicSizes[userFont]?.unreadCorner ?? 10)
} else if !chat.chatInfo.ntfsEnabled && chat.chatInfo.chatType != .local {
Image(systemName: "speaker.slash.fill")
.resizable()
.scaledToFill()
.frame(width: dynamicChatInfoSize, height: dynamicChatInfoSize)
.foregroundColor(theme.colors.secondary)
} else if chat.chatInfo.chatSettings?.favorite ?? false {
Image(systemName: "star.fill")
.resizable()
.scaledToFill()
.frame(width: dynamicChatInfoSize, height: dynamicChatInfoSize)
.padding(.trailing, 1)
.foregroundColor(theme.colors.secondary.opacity(0.65))
} else {
Color.clear.frame(width: 0)
}
}
@@ -172,7 +243,7 @@ struct ChatPreviewView: View {
func chatItemPreview(_ cItem: ChatItem) -> Text {
let itemText = cItem.meta.itemDeleted == nil ? cItem.text : markedDeletedText()
let itemFormattedText = cItem.meta.itemDeleted == nil ? cItem.formattedText : nil
return messageText(itemText, itemFormattedText, cItem.memberDisplayName, icon: attachment(), preview: true, showSecrets: false, secondaryColor: theme.colors.secondary)
return messageText(itemText, itemFormattedText, cItem.memberDisplayName, icon: nil, preview: true, showSecrets: false, secondaryColor: theme.colors.secondary)
// same texts are in markedDeletedText in MarkedDeletedItemView, but it returns LocalizedStringKey;
// can be refactored into a single function if functions calling these are changed to return same type
@@ -196,18 +267,18 @@ struct ChatPreviewView: View {
}
}
@ViewBuilder private func chatMessagePreview(_ cItem: ChatItem?) -> some View {
@ViewBuilder private func chatMessagePreview(_ cItem: ChatItem?, _ hasFilePreview: Bool = false) -> some View {
if chatModel.draftChatId == chat.id, let draft = chatModel.draft {
chatPreviewLayout(messageDraft(draft), draft: true)
chatPreviewLayout(messageDraft(draft), draft: true, hasFilePreview)
} else if let cItem = cItem {
chatPreviewLayout(itemStatusMark(cItem) + chatItemPreview(cItem))
chatPreviewLayout(itemStatusMark(cItem) + chatItemPreview(cItem), hasFilePreview)
} else {
switch (chat.chatInfo) {
case let .direct(contact):
if contact.activeConn == nil && contact.profile.contactLink != nil {
chatPreviewInfoText("Tap to Connect")
.foregroundColor(theme.colors.primary)
} else if !contact.ready && contact.activeConn != nil {
} else if !contact.sndReady && contact.activeConn != nil {
if contact.nextSendGrpInv {
chatPreviewInfoText("send direct message")
} else if contact.active {
@@ -225,6 +296,54 @@ struct ChatPreviewView: View {
}
}
@ViewBuilder func chatItemContentPreview(_ chat: Chat, _ ci: ChatItem) -> some View {
let mc = ci.content.msgContent
switch mc {
case let .link(_, preview):
smallContentPreview(size: dynamicMediaSize) {
ZStack(alignment: .topTrailing) {
Image(uiImage: UIImage(base64Encoded: preview.image) ?? UIImage(systemName: "arrow.up.right")!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: dynamicMediaSize, height: dynamicMediaSize)
ZStack {
Image(systemName: "arrow.up.right")
.resizable()
.foregroundColor(Color.white)
.font(.system(size: 15, weight: .black))
.frame(width: 8, height: 8)
}
.frame(width: 16, height: 16)
.background(Color.black.opacity(0.25))
.cornerRadius(8)
}
.onTapGesture {
UIApplication.shared.open(preview.uri)
}
}
case let .image(_, image):
smallContentPreview(size: dynamicMediaSize) {
CIImageView(chatItem: ci, preview: UIImage(base64Encoded: image), maxWidth: dynamicMediaSize, smallView: true, showFullScreenImage: $showFullscreenGallery)
.environmentObject(ReverseListScrollModel<ChatItem>())
}
case let .video(_,image, duration):
smallContentPreview(size: dynamicMediaSize) {
CIVideoView(chatItem: ci, preview: UIImage(base64Encoded: image), duration: duration, maxWidth: dynamicMediaSize, videoWidth: nil, smallView: true, showFullscreenPlayer: $showFullscreenGallery)
.environmentObject(ReverseListScrollModel<ChatItem>())
}
case let .voice(_, duration):
smallContentPreviewVoice(size: dynamicMediaSize) {
CIVoiceView(chat: chat, chatItem: ci, recordingFile: ci.file, duration: duration, allowMenu: Binding.constant(true), smallViewSize: dynamicMediaSize)
}
case .file:
smallContentPreviewFile(size: dynamicMediaSize) {
CIFileView(file: ci.file, edited: ci.meta.itemEdited, smallViewSize: dynamicMediaSize)
}
default: EmptyView()
}
}
@ViewBuilder private func groupInvitationPreviewText(_ groupInfo: GroupInfo) -> some View {
groupInfo.membership.memberIncognito
? chatPreviewInfoText("join as \(groupInfo.membership.memberProfile.displayName)")
@@ -294,10 +413,45 @@ struct ChatPreviewView: View {
}
}
func smallContentPreview(size: CGFloat, _ view: @escaping () -> some View) -> some View {
view()
.frame(width: size, height: size)
.cornerRadius(8)
.overlay(RoundedRectangle(cornerSize: CGSize(width: 8, height: 8))
.strokeBorder(.secondary, lineWidth: 0.3, antialiased: true))
.padding(.vertical, size / 6)
.padding(.leading, 3)
.offset(x: 6)
}
func smallContentPreviewVoice(size: CGFloat, _ view: @escaping () -> some View) -> some View {
view()
.frame(height: voiceMessageSizeBasedOnSquareSize(size))
.padding(.vertical, size / 6)
.padding(.leading, 8)
}
func smallContentPreviewFile(size: CGFloat, _ view: @escaping () -> some View) -> some View {
view()
.frame(width: size, height: size)
.padding(.vertical, size / 7)
.padding(.leading, 5)
}
func unreadCountText(_ n: Int) -> Text {
Text(n > 999 ? "\(n / 1000)k" : n > 0 ? "\(n)" : "")
}
private struct ActiveContentPreview: Equatable {
var chat: Chat
var ci: ChatItem
var mc: MsgContent
static func == (lhs: ActiveContentPreview, rhs: ActiveContentPreview) -> Bool {
lhs.chat.id == rhs.chat.id && lhs.ci.id == rhs.ci.id && lhs.mc == rhs.mc
}
}
struct ChatPreviewView_Previews: PreviewProvider {
static var previews: some View {
Group {
@@ -21,7 +21,7 @@ struct ContactConnectionInfo: View {
enum CCInfoAlert: Identifiable {
case deleteInvitationAlert
case error(title: LocalizedStringKey, error: LocalizedStringKey)
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -102,7 +102,7 @@ struct ContactConnectionInfo: View {
} success: {
dismiss()
}
case let .error(title, error): return Alert(title: Text(title), message: Text(error))
case let .error(title, error): return mkAlert(title: title, message: error)
}
}
.onAppear {
@@ -12,12 +12,13 @@ import SimpleXChat
struct ContactRequestView: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@Environment(\.dynamicTypeSize) private var userFont: DynamicTypeSize
var contactRequest: UserContactRequest
@ObservedObject var chat: Chat
var body: some View {
HStack(spacing: 8) {
ChatInfoImage(chat: chat, size: 63)
ChatInfoImage(chat: chat, size: dynamicSizes[userFont]?.profileImageSize ?? 63)
.padding(.leading, 4)
VStack(alignment: .leading, spacing: 0) {
HStack(alignment: .top) {
@@ -12,11 +12,12 @@ import SimpleXChat
struct ServersSummaryView: View {
@EnvironmentObject var m: ChatModel
@EnvironmentObject var theme: AppTheme
@Binding var serversSummary: PresentedServersSummary?
@State private var serversSummary: PresentedServersSummary? = nil
@State private var selectedUserCategory: PresentedUserCategory = .allUsers
@State private var selectedServerType: PresentedServerType = .smp
@State private var selectedSMPServer: String? = nil
@State private var selectedXFTPServer: String? = nil
@State private var timer: Timer? = nil
@State private var alert: SomeAlert?
@AppStorage(DEFAULT_SHOW_SUBSCRIPTION_PERCENTAGE) private var showSubscriptionPercentage = false
@@ -47,10 +48,36 @@ struct ServersSummaryView: View {
if m.users.filter({ u in u.user.activeUser || !u.user.hidden }).count == 1 {
selectedUserCategory = .currentUser
}
getServersSummary()
startTimer()
}
.onDisappear {
stopTimer()
}
.alert(item: $alert) { $0.alert }
}
private func startTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
if AppChatState.shared.value == .active {
getServersSummary()
}
}
}
private func getServersSummary() {
do {
serversSummary = try getAgentServersSummary()
} catch let error {
logger.error("getAgentServersSummary error: \(responseError(error))")
}
}
private func stopTimer() {
timer?.invalidate()
timer = nil
}
private func shareButton() -> some View {
Button {
if let serversSummary = serversSummary {
@@ -75,8 +102,8 @@ struct ServersSummaryView: View {
Group {
if m.users.filter({ u in u.user.activeUser || !u.user.hidden }).count > 1 {
Picker("User selection", selection: $selectedUserCategory) {
Text("All users").tag(PresentedUserCategory.allUsers)
Text("Current user").tag(PresentedUserCategory.currentUser)
Text("All profiles").tag(PresentedUserCategory.allUsers)
Text("Current profile").tag(PresentedUserCategory.currentUser)
}
.pickerStyle(.segmented)
}
@@ -174,14 +201,15 @@ struct ServersSummaryView: View {
private func smpSubsSection(_ totals: SMPTotals) -> some View {
Section {
infoRow("Connections subscribed", numOrDash(totals.subs.ssActive))
infoRow("Active connections", numOrDash(totals.subs.ssActive))
infoRow("Total", numOrDash(totals.subs.total))
Toggle("Show percentage", isOn: $showSubscriptionPercentage)
} header: {
HStack {
Text("Message subscriptions")
SubscriptionStatusIndicatorView(subs: totals.subs, sess: totals.sessions)
Text("Message reception")
SubscriptionStatusIndicatorView(subs: totals.subs, hasSess: totals.sessions.hasSess)
if showSubscriptionPercentage {
SubscriptionStatusPercentageView(subs: totals.subs, sess: totals.sessions)
SubscriptionStatusPercentageView(subs: totals.subs, hasSess: totals.sessions.hasSess)
}
}
}
@@ -259,9 +287,9 @@ struct ServersSummaryView: View {
if let subs = srvSumm.subs {
Spacer()
if showSubscriptionPercentage {
SubscriptionStatusPercentageView(subs: subs, sess: srvSumm.sessionsOrNew)
SubscriptionStatusPercentageView(subs: subs, hasSess: srvSumm.sessionsOrNew.hasSess)
}
SubscriptionStatusIndicatorView(subs: subs, sess: srvSumm.sessionsOrNew)
SubscriptionStatusIndicatorView(subs: subs, hasSess: srvSumm.sessionsOrNew.hasSess)
} else if let sess = srvSumm.sessions {
Spacer()
Image(systemName: "arrow.up.circle")
@@ -355,6 +383,7 @@ struct ServersSummaryView: View {
Task {
do {
try await resetAgentServersStats()
getServersSummary()
} catch let error {
alert = SomeAlert(
alert: mkAlert(
@@ -379,11 +408,11 @@ struct ServersSummaryView: View {
struct SubscriptionStatusIndicatorView: View {
@EnvironmentObject var m: ChatModel
var subs: SMPServerSubs
var sess: ServerSessions
var hasSess: Bool
var body: some View {
let onionHosts = networkUseOnionHostsGroupDefault.get()
let (color, variableValue, opacity, _) = subscriptionStatusColorAndPercentage(m.networkInfo.online, onionHosts, subs, sess)
let (color, variableValue, opacity, _) = subscriptionStatusColorAndPercentage(m.networkInfo.online, onionHosts, subs, hasSess)
if #available(iOS 16.0, *) {
Image(systemName: "dot.radiowaves.up.forward", variableValue: variableValue)
.foregroundColor(color)
@@ -397,18 +426,18 @@ struct SubscriptionStatusIndicatorView: View {
struct SubscriptionStatusPercentageView: View {
@EnvironmentObject var m: ChatModel
var subs: SMPServerSubs
var sess: ServerSessions
var hasSess: Bool
var body: some View {
let onionHosts = networkUseOnionHostsGroupDefault.get()
let (_, _, _, statusPercent) = subscriptionStatusColorAndPercentage(m.networkInfo.online, onionHosts, subs, sess)
let (_, _, _, statusPercent) = subscriptionStatusColorAndPercentage(m.networkInfo.online, onionHosts, subs, hasSess)
Text(verbatim: "\(Int(floor(statusPercent * 100)))%")
.foregroundColor(.secondary)
.font(.caption)
}
}
func subscriptionStatusColorAndPercentage(_ online: Bool, _ onionHosts: OnionHosts, _ subs: SMPServerSubs, _ sess: ServerSessions) -> (Color, Double, Double, Double) {
func subscriptionStatusColorAndPercentage(_ online: Bool, _ onionHosts: OnionHosts, _ subs: SMPServerSubs, _ hasSess: Bool) -> (Color, Double, Double, Double) {
func roundedToQuarter(_ n: Double) -> Double {
n >= 1 ? 1
: n <= 0 ? 0
@@ -423,12 +452,12 @@ func subscriptionStatusColorAndPercentage(_ online: Bool, _ onionHosts: OnionHos
? (
subs.ssActive == 0
? (
sess.ssConnected == 0 ? noConnColorAndPercent : (activeColor, activeSubsRounded, subs.shareOfActive, subs.shareOfActive)
hasSess ? (activeColor, activeSubsRounded, subs.shareOfActive, subs.shareOfActive) : noConnColorAndPercent
)
: ( // ssActive > 0
sess.ssConnected == 0
? (.orange, activeSubsRounded, subs.shareOfActive, subs.shareOfActive) // This would mean implementation error
: (activeColor, activeSubsRounded, subs.shareOfActive, subs.shareOfActive)
hasSess
? (activeColor, activeSubsRounded, subs.shareOfActive, subs.shareOfActive)
: (.orange, activeSubsRounded, subs.shareOfActive, subs.shareOfActive) // This would mean implementation error
)
)
: noConnColorAndPercent
@@ -474,16 +503,16 @@ struct SMPServerSummaryView: View {
private func smpSubsSection(_ subs: SMPServerSubs) -> some View {
Section {
infoRow("Connections subscribed", numOrDash(subs.ssActive))
infoRow("Active connections", numOrDash(subs.ssActive))
infoRow("Pending", numOrDash(subs.ssPending))
infoRow("Total", numOrDash(subs.total))
reconnectButton()
} header: {
HStack {
Text("Message subscriptions")
SubscriptionStatusIndicatorView(subs: subs, sess: summary.sessionsOrNew)
Text("Message reception")
SubscriptionStatusIndicatorView(subs: subs, hasSess: summary.sessionsOrNew.hasSess)
if showSubscriptionPercentage {
SubscriptionStatusPercentageView(subs: subs, sess: summary.sessionsOrNew)
SubscriptionStatusPercentageView(subs: subs, hasSess: summary.sessionsOrNew.hasSess)
}
}
}
@@ -588,7 +617,7 @@ struct DetailedSMPStatsView: View {
infoRow(Text(verbatim: "NO_MSG errors"), numOrDash(stats._ackNoMsgErrs)).padding(.leading, 24)
infoRow("other errors", numOrDash(stats._ackOtherErrs)).padding(.leading, 24)
}
Section {
Section("Connections") {
infoRow("Created", numOrDash(stats._connCreated))
infoRow("Secured", numOrDash(stats._connCreated))
infoRow("Completed", numOrDash(stats._connCompleted))
@@ -597,8 +626,12 @@ struct DetailedSMPStatsView: View {
infoRowTwoValues("Subscribed", "attempts", stats._connSubscribed, stats._connSubAttempts)
infoRow("Subscriptions ignored", numOrDash(stats._connSubIgnored))
infoRow("Subscription errors", numOrDash(stats._connSubErrs))
}
Section {
infoRowTwoValues("Enabled", "attempts", stats._ntfKey, stats._ntfKeyAttempts)
infoRowTwoValues("Disabled", "attempts", stats._ntfKeyDeleted, stats._ntfKeyDeleteAttempts)
} header: {
Text("Connections")
Text("Connection notifications")
} footer: {
Text("Starting from \(localTimestamp(statsStartedAt)).")
}
@@ -711,7 +744,5 @@ struct DetailedXFTPStatsView: View {
}
#Preview {
ServersSummaryView(
serversSummary: Binding.constant(nil)
)
ServersSummaryView()
}
@@ -64,7 +64,7 @@ struct DatabaseErrorView: View {
case let .migrationError(mtrError):
titleText("Incompatible database version")
fileNameText(dbFile)
Text("Error: ") + Text(DatabaseErrorView.mtrErrorDescription(mtrError))
Text("Error: ") + Text(mtrErrorDescription(mtrError))
}
case let .errorSQL(dbFile, migrationSQLError):
titleText("Database error")
@@ -105,15 +105,6 @@ struct DatabaseErrorView: View {
Text("Migrations: \(ms.joined(separator: ", "))")
}
static func mtrErrorDescription(_ err: MTRError) -> LocalizedStringKey {
switch err {
case let .noDown(dbMigrations):
return "database version is newer than the app, but no down migration for: \(dbMigrations.joined(separator: ", "))"
case let .different(appMigration, dbMigration):
return "different migration in the app/database: \(appMigration) / \(dbMigration)"
}
}
private func databaseKeyField(onSubmit: @escaping () -> Void) -> some View {
PassphraseField(key: $dbKey, placeholder: "Enter passphrase…", valid: validKey(dbKey), onSubmit: onSubmit)
}
@@ -16,18 +16,10 @@ struct ChatInfoImage: View {
var color = Color(uiColor: .tertiarySystemGroupedBackground)
var body: some View {
var iconName: String
switch chat.chatInfo {
case .direct: iconName = "person.crop.circle.fill"
case .group: iconName = "person.2.circle.fill"
case .local: iconName = "folder.circle.fill"
case .contactRequest: iconName = "person.crop.circle.fill"
default: iconName = "circle.fill"
}
let iconColor = if case .local = chat.chatInfo { theme.appColors.primaryVariant2 } else { color }
return ProfileImage(
imageStr: chat.chatInfo.image,
iconName: iconName,
iconName: chatIconName(chat.chatInfo),
size: size,
color: iconColor
)
@@ -23,8 +23,10 @@ struct ChatViewBackground: ViewModifier {
var image = context.resolve(image)
let rect = CGRectMake(0, 0, size.width, size.height)
func repeatDraw(_ imageScale: CGFloat) {
// Prevent range bounds crash and dividing by zero
if size.height == 0 || size.width == 0 || image.size.height == 0 || image.size.width == 0 { return }
image.shading = .color(tint)
let scale = imageScale * 1.57 // for some reason a wallpaper on iOS looks smaller than on Android
let scale = imageScale * 2.5 // scale wallpaper for iOS
for h in 0 ... Int(size.height / image.size.height / scale) {
for w in 0 ... Int(size.width / image.size.width / scale) {
let rect = CGRectMake(CGFloat(w) * image.size.width * scale, CGFloat(h) * image.size.height * scale, image.size.width * scale, image.size.height * scale)
@@ -1,26 +0,0 @@
//
// VideoUtils.swift
// SimpleX (iOS)
//
// Created by Avently on 25.12.2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import AVFoundation
import Foundation
import SimpleXChat
func makeVideoQualityLower(_ input: URL, outputUrl: URL) async -> Bool {
let asset: AVURLAsset = AVURLAsset(url: input, options: nil)
if let s = AVAssetExportSession(asset: asset, presetName: AVAssetExportPreset640x480) {
s.outputURL = outputUrl
s.outputFileType = .mp4
s.metadataItemFilter = AVMetadataItemFilter.forSharing()
await s.export()
if let err = s.error {
logger.error("Failed to export video with error: \(err)")
}
return s.status == .completed
}
return false
}
@@ -17,3 +17,37 @@ extension View {
}
}
}
extension Notification.Name {
static let chatViewWillBeginScrolling = Notification.Name("chatWillBeginScrolling")
}
struct PrivacyBlur: ViewModifier {
var enabled: Bool = true
@Binding var blurred: Bool
@AppStorage(DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS) private var blurRadius: Int = 0
func body(content: Content) -> some View {
if blurRadius > 0 {
// parallel ifs are necessary here because otherwise some views flicker,
// e.g. when playing video
content
.blur(radius: blurred && enabled ? CGFloat(blurRadius) * 0.5 : 0)
.overlay {
if (blurred && enabled) {
Color.clear.contentShape(Rectangle())
.onTapGesture {
blurred = false
}
}
}
.onReceive(NotificationCenter.default.publisher(for: .chatViewWillBeginScrolling)) { _ in
if !blurred {
blurred = true
}
}
} else {
content
}
}
}
@@ -662,7 +662,7 @@ private struct PassphraseConfirmationView: View {
if case .chatCmdError(_, .errorDatabase(.errorOpen(.errorNotADatabase))) = error as? ChatResponse {
showErrorOnMigrationIfNeeded(.errorNotADatabase(dbFile: ""), $alert)
} else {
alert = .error(title: "Error", error: NSLocalizedString("Error verifying passphrase:", comment: "") + " " + String(String(describing: error)))
alert = .error(title: "Error", error: NSLocalizedString("Error verifying passphrase:", comment: "") + " " + String(responseError(error)))
}
}
}
@@ -331,7 +331,7 @@ struct MigrateToDevice: View {
case let .migrationError(mtrError):
("Incompatible database version",
nil,
"\(NSLocalizedString("Error: ", comment: "")) \(DatabaseErrorView.mtrErrorDescription(mtrError))",
"\(NSLocalizedString("Error: ", comment: "")) \(mtrErrorDescription(mtrError))",
nil)
}
default: ("Error", nil, "Unknown error", nil)
@@ -37,7 +37,7 @@ struct ConnectDesktopView: View {
case badInvitationError
case badVersionError(version: String?)
case desktopDisconnectedError
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -160,7 +160,7 @@ struct ConnectDesktopView: View {
case .desktopDisconnectedError:
Alert(title: Text("Connection terminated"))
case let .error(title, error):
Alert(title: Text(title), message: Text(error))
mkAlert(title: title, message: error)
}
}
.interactiveDismissDisabled(m.activeRemoteCtrl)
@@ -32,6 +32,7 @@ extension AppSettings {
if let val = privacyShowChatPreviews { def.setValue(val, forKey: DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS) }
if let val = privacySaveLastDraft { def.setValue(val, forKey: DEFAULT_PRIVACY_SAVE_LAST_DRAFT) }
if let val = privacyProtectScreen { def.setValue(val, forKey: DEFAULT_PRIVACY_PROTECT_SCREEN) }
if let val = privacyMediaBlurRadius { def.setValue(val, forKey: DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS) }
if let val = notificationMode { ChatModel.shared.notificationMode = val.toNotificationsMode() }
if let val = notificationPreviewMode { ntfPreviewModeGroupDefault.set(val) }
if let val = webrtcPolicyRelay { def.setValue(val, forKey: DEFAULT_WEBRTC_POLICY_RELAY) }
@@ -62,6 +63,7 @@ extension AppSettings {
c.privacyShowChatPreviews = def.bool(forKey: DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS)
c.privacySaveLastDraft = def.bool(forKey: DEFAULT_PRIVACY_SAVE_LAST_DRAFT)
c.privacyProtectScreen = def.bool(forKey: DEFAULT_PRIVACY_PROTECT_SCREEN)
c.privacyMediaBlurRadius = def.integer(forKey: DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS)
c.notificationMode = AppSettingsNotificationMode.from(ChatModel.shared.notificationMode)
c.notificationPreviewMode = ntfPreviewModeGroupDefault.get()
c.webrtcPolicyRelay = def.bool(forKey: DEFAULT_WEBRTC_POLICY_RELAY)
@@ -32,7 +32,6 @@ struct NetworkAndServers: View {
@EnvironmentObject var theme: AppTheme
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = false
@AppStorage(DEFAULT_SHOW_SUBSCRIPTION_PERCENTAGE) private var showSubscriptionPercentage = false
@State private var cfgLoaded = false
@State private var currentNetCfg = NetCfg.defaults
@State private var netCfg = NetCfg.defaults
@@ -62,8 +61,6 @@ struct NetworkAndServers: View {
Text("XFTP servers")
}
Toggle("Subscription percentage", isOn: $showSubscriptionPercentage)
Picker("Use .onion hosts", selection: $onionHosts) {
ForEach(OnionHosts.values, id: \.self) { Text($0.text) }
}
@@ -22,6 +22,7 @@ struct PrivacySettings: View {
@AppStorage(DEFAULT_PRIVACY_PROTECT_SCREEN) private var protectScreen = false
@AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false
@State private var currentLAMode = privacyLocalAuthModeDefault.get()
@AppStorage(DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS) private var privacyMediaBlurRadius: Int = 0
@State private var contactReceipts = false
@State private var contactReceiptsReset = false
@State private var contactReceiptsOverrides = 0
@@ -113,6 +114,22 @@ struct PrivacySettings: View {
privacyAcceptImagesGroupDefault.set($0)
}
}
settingsRow("circle.rectangle.filled.pattern.diagonalline", color: theme.colors.secondary) {
Picker("Blur media", selection: $privacyMediaBlurRadius) {
let values = [0, 12, 24, 48] + ([0, 12, 24, 48].contains(privacyMediaBlurRadius) ? [] : [privacyMediaBlurRadius])
ForEach(values, id: \.self) { radius in
let text: String = switch radius {
case 0: NSLocalizedString("Off", comment: "blur media")
case 12: NSLocalizedString("Soft", comment: "blur media")
case 24: NSLocalizedString("Medium", comment: "blur media")
case 48: NSLocalizedString("Strong", comment: "blur media")
default: "\(radius)"
}
Text(text)
}
}
}
.frame(height: 36)
settingsRow("network.badge.shield.half.filled", color: theme.colors.secondary) {
Toggle("Protect IP address", isOn: $askToApproveRelays)
}
@@ -175,10 +175,6 @@ func testServerConnection(server: Binding<ServerCfg>) async -> ProtocolTestFailu
}
}
func serverHostname(_ srv: String) -> String {
parseServerAddress(srv)?.hostnames.first ?? srv
}
struct ProtocolServerView_Previews: PreviewProvider {
static var previews: some View {
ProtocolServerView(
@@ -34,6 +34,7 @@ let DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS = "privacyShowChatPreviews"
let DEFAULT_PRIVACY_SAVE_LAST_DRAFT = "privacySaveLastDraft"
let DEFAULT_PRIVACY_PROTECT_SCREEN = "privacyProtectScreen"
let DEFAULT_PRIVACY_DELIVERY_RECEIPTS_SET = "privacyDeliveryReceiptsSet"
let DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS = "privacyMediaBlurRadius"
let DEFAULT_EXPERIMENTAL_CALLS = "experimentalCalls"
let DEFAULT_CHAT_ARCHIVE_NAME = "chatArchiveName"
let DEFAULT_CHAT_ARCHIVE_TIME = "chatArchiveTime"
@@ -87,6 +88,7 @@ let appDefaults: [String: Any] = [
DEFAULT_PRIVACY_SAVE_LAST_DRAFT: true,
DEFAULT_PRIVACY_PROTECT_SCREEN: false,
DEFAULT_PRIVACY_DELIVERY_RECEIPTS_SET: false,
DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS: 0,
DEFAULT_EXPERIMENTAL_CALLS: false,
DEFAULT_CHAT_V3_DB_MIGRATION: V3DBMigrationState.offer.rawValue,
DEFAULT_DEVELOPER_TOOLS: false,
@@ -30,7 +30,7 @@ struct UserAddressView: View {
case deleteAddress
case profileAddress(on: Bool)
case shareOnCreate
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -185,7 +185,7 @@ struct UserAddressView: View {
}, secondaryButton: .cancel()
)
case let .error(title, error):
return Alert(title: Text(title), message: Text(error))
return mkAlert(title: title, message: error)
}
}
}
@@ -30,7 +30,7 @@ struct UserProfilesView: View {
case hiddenProfilesNotice
case muteProfileAlert
case activateUserError(error: String)
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
case error(title: LocalizedStringKey, error: LocalizedStringKey?)
var id: String {
switch self {
@@ -172,7 +172,7 @@ struct UserProfilesView: View {
message: Text(err)
)
case let .error(title, error):
return Alert(title: Text(title), message: Text(error))
return mkAlert(title: title, message: error)
}
}
}
@@ -127,11 +127,6 @@
<target>%@ е потвърдено</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ сървъри</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ качено</target>
@@ -590,6 +585,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Добавете адрес към вашия профил, така че вашите контакти да могат да го споделят с други хора. Актуализацията на профила ще бъде изпратена до вашите контакти.</target>
@@ -610,16 +609,16 @@
<target>Добави профил</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Добави сървъри чрез сканиране на QR кодове.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Добави сървър</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Добави сървъри чрез сканиране на QR кодове.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Добави към друго устройство</target>
@@ -710,8 +709,8 @@
<target>Всички нови съобщения от %@ ще бъдат скрити!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1351,6 +1350,10 @@
<target>Конфигурирай ICE сървъри</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Потвърди</target>
@@ -1529,10 +1532,6 @@ This is your own one-time link!</source>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>Контактът позволява</target>
@@ -1706,8 +1705,8 @@ This is your own one-time link!</source>
<target>Текуща парола…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3926,6 +3925,10 @@ This is your link for group %@!</source>
<target>Реакциите на съобщения са забранени в тази група.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<note>No comment provided by engineer.</note>
@@ -3947,10 +3950,6 @@ This is your link for group %@!</source>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Текст на съобщението</target>
@@ -4469,6 +4468,10 @@ This is your link for group %@!</source>
<target>Други</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>PING бройка</target>
@@ -4635,6 +4638,10 @@ Error: %@</source>
<target>Моля, съхранявайте паролата на сигурно място, НЯМА да можете да я промените, ако я загубите.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Полски интерфейс</target>
@@ -4701,6 +4708,10 @@ Error: %@</source>
<source>Private routing</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Профилни и сървърни връзки</target>
@@ -5601,6 +5612,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server address is incompatible with network settings.</source>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Сървърът изисква оторизация за създаване на опашки, проверете паролата</target>
@@ -5624,6 +5639,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server version is incompatible with network settings.</source>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Сървъри</target>
@@ -5760,6 +5783,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Show message status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Показване на визуализация</target>
@@ -5983,10 +6010,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -7041,8 +7064,8 @@ Repeat join request?</source>
<target>Можете да го направите видим за вашите контакти в SimpleX чрез Настройки.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Вече можете да изпращате съобщения до %@</target>
<note>notification body</note>
</trans-unit>
@@ -7449,7 +7472,7 @@ SimpleX сървърите не могат да видят вашия профи
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>блокиран от админ</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -126,11 +126,6 @@
<target>%@ je ověřený</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ servery</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<note>No comment provided by engineer.</note>
@@ -572,6 +567,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Přidejte adresu do svého profilu, aby ji vaše kontakty mohly sdílet s dalšími lidmi. Aktualizace profilu bude zaslána vašim kontaktům.</target>
@@ -591,16 +590,16 @@
<target>Přidat profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Přidejte servery skenováním QR kódů.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Přidat server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Přidejte servery skenováním QR kódů.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Přidat do jiného zařízení</target>
@@ -688,8 +687,8 @@
<source>All new messages from %@ will be hidden!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1305,6 +1304,10 @@
<target>Konfigurace serverů ICE</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Potvrdit</target>
@@ -1467,10 +1470,6 @@ This is your own one-time link!</source>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>Kontakt povolil</target>
@@ -1636,8 +1635,8 @@ This is your own one-time link!</source>
<target>Aktuální přístupová fráze…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3783,6 +3782,10 @@ This is your link for group %@!</source>
<target>Reakce na zprávy jsou v této skupině zakázány.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<note>No comment provided by engineer.</note>
@@ -3803,10 +3806,6 @@ This is your link for group %@!</source>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Text zprávy</target>
@@ -4299,6 +4298,10 @@ This is your link for group %@!</source>
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>Počet PING</target>
@@ -4457,6 +4460,10 @@ Error: %@</source>
<target>Heslo uložte bezpečně, v případě jeho ztráty jej NEBUDE možné změnit.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Polské rozhraní</target>
@@ -4522,6 +4529,10 @@ Error: %@</source>
<source>Private routing</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Profil a připojení k serveru</target>
@@ -5399,6 +5410,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server address is incompatible with network settings.</source>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Server vyžaduje autorizaci pro vytváření front, zkontrolujte heslo</target>
@@ -5422,6 +5437,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server version is incompatible with network settings.</source>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Servery</target>
@@ -5553,6 +5576,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Show message status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Zobrazení náhledu</target>
@@ -5770,10 +5797,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -6774,8 +6797,8 @@ Repeat join request?</source>
<source>You can make it visible to your SimpleX contacts via Settings.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Nyní můžete posílat zprávy %@</target>
<note>notification body</note>
</trans-unit>
@@ -7168,7 +7191,7 @@ Servery SimpleX nevidí váš profil.</target>
</trans-unit>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
File diff suppressed because it is too large Load Diff
@@ -127,11 +127,6 @@
<target>%@ is verified</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ uploaded</target>
@@ -593,6 +588,11 @@
<target>Acknowledgement errors</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<target>Active connections</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</target>
@@ -613,16 +613,16 @@
<target>Add profile</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Add servers by scanning QR codes.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Add server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Add servers by scanning QR codes.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Add to another device</target>
@@ -718,9 +718,9 @@
<target>All new messages from %@ will be hidden!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<target>All users</target>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>All profiles</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1374,6 +1374,11 @@
<target>Configure ICE servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<target>Configured %@ servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Confirm</target>
@@ -1558,11 +1563,6 @@ This is your own one-time link!</target>
<target>Connections</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<target>Connections subscribed</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>Contact allows</target>
@@ -1738,9 +1738,9 @@ This is your own one-time link!</target>
<target>Current passphrase…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<target>Current user</target>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<target>Current profile</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3998,6 +3998,11 @@ This is your link for group %@!</target>
<target>Message reactions are prohibited in this group.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<target>Message reception</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Message routing fallback</target>
@@ -4023,11 +4028,6 @@ This is your link for group %@!</target>
<target>Message status: %@</target>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<target>Message subscriptions</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Message text</target>
@@ -4552,6 +4552,11 @@ This is your link for group %@!</target>
<target>Other</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<target>Other %@ servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>PING count</target>
@@ -4721,6 +4726,11 @@ Error: %@</target>
<target>Please store passphrase securely, you will NOT be able to change it if you lose it.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<target>Please try later.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Polish interface</target>
@@ -4791,6 +4801,11 @@ Error: %@</target>
<target>Private routing</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<target>Private routing error</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Profile and server connections</target>
@@ -5728,6 +5743,11 @@ Enable in *Network &amp; servers* settings.</target>
<target>Server address is incompatible with network settings.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<target>Server address is incompatible with network settings: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Server requires authorization to create queues, check password</target>
@@ -5753,6 +5773,16 @@ Enable in *Network &amp; servers* settings.</target>
<target>Server version is incompatible with network settings.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<target>Server version is incompatible with network settings: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<target>Server version is incompatible with your app: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Servers</target>
@@ -5893,6 +5923,11 @@ Enable in *Network &amp; servers* settings.</target>
<target>Show message status</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<target>Show percentage</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Show preview</target>
@@ -6123,11 +6158,6 @@ Enable in *Network &amp; servers* settings.</target>
<target>Subscription errors</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<target>Subscription percentage</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<target>Subscriptions ignored</target>
@@ -7206,9 +7236,9 @@ Repeat join request?</target>
<target>You can make it visible to your SimpleX contacts via Settings.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<target>You can now send messages to %@</target>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>You can now chat with %@</target>
<note>notification body</note>
</trans-unit>
<trans-unit id="You can set lock screen notification preview via settings." xml:space="preserve">
@@ -7615,7 +7645,7 @@ SimpleX servers cannot see your profile.</target>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>blocked by admin</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -127,11 +127,6 @@
<target>%@ está verificado</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>Servidores %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ subido</target>
@@ -590,6 +585,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Añade la dirección a tu perfil para que tus contactos puedan compartirla con otros. La actualización del perfil se enviará a tus contactos.</target>
@@ -610,16 +609,16 @@
<target>Añadir perfil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Añadir servidores mediante el escaneo de códigos QR.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Añadir servidor</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Añadir servidores mediante el escaneo de códigos QR.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Añadir a otro dispositivo</target>
@@ -710,8 +709,8 @@
<target>¡Los mensajes nuevos de %@ estarán ocultos!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1354,6 +1353,10 @@
<target>Configure servidores ICE</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Confirmar</target>
@@ -1533,10 +1536,6 @@ This is your own one-time link!</source>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>El contacto permite</target>
@@ -1710,8 +1709,8 @@ This is your own one-time link!</source>
<target>Contraseña actual…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3941,6 +3940,10 @@ This is your link for group %@!</source>
<target>Las reacciones a los mensajes no están permitidas en este grupo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Enrutamiento de mensajes alternativo</target>
@@ -3964,10 +3967,6 @@ This is your link for group %@!</source>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Contacto y texto</target>
@@ -4487,6 +4486,10 @@ This is your link for group %@!</source>
<target>Otro</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>Contador PING</target>
@@ -4653,6 +4656,10 @@ Error: %@</target>
<target>Guarda la contraseña de forma segura, NO podrás cambiarla si la pierdes.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Interfaz en polaco</target>
@@ -4722,6 +4729,10 @@ Error: %@</target>
<target>Enrutamiento privado</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Datos del perfil y conexiones</target>
@@ -5629,6 +5640,10 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
<target>La dirección del servidor es incompatible con la configuración de la red.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>El servidor requiere autorización para crear colas, comprueba la contraseña</target>
@@ -5653,6 +5668,14 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
<target>La versión del servidor es incompatible con la configuración de red.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Servidores</target>
@@ -5790,6 +5813,10 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
<target>Estado del mensaje</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Mostrar vista previa</target>
@@ -6014,10 +6041,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -7080,8 +7103,8 @@ Repeat join request?</source>
<target>Puedes hacerlo visible para tus contactos de SimpleX en Configuración.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Ya puedes enviar mensajes a %@</target>
<note>notification body</note>
</trans-unit>
@@ -7488,7 +7511,7 @@ Los servidores SimpleX no pueden ver tu perfil.</target>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>bloqueado por administrador</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -124,11 +124,6 @@
<target>%@ on vahvistettu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ palvelimet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<note>No comment provided by engineer.</note>
@@ -567,6 +562,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Lisää osoite profiiliisi, jotta kontaktisi voivat jakaa sen muiden kanssa. Profiilipäivitys lähetetään kontakteillesi.</target>
@@ -586,16 +585,16 @@
<target>Lisää profiili</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Lisää palvelimia skannaamalla QR-koodeja.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Lisää palvelin</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Lisää palvelimia skannaamalla QR-koodeja.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Lisää toiseen laitteeseen</target>
@@ -683,8 +682,8 @@
<source>All new messages from %@ will be hidden!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1298,6 +1297,10 @@
<target>Määritä ICE-palvelimet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Vahvista</target>
@@ -1460,10 +1463,6 @@ This is your own one-time link!</source>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>Kontakti sallii</target>
@@ -1629,8 +1628,8 @@ This is your own one-time link!</source>
<target>Nykyinen tunnuslause…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3773,6 +3772,10 @@ This is your link for group %@!</source>
<target>Viestireaktiot ovat kiellettyjä tässä ryhmässä.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<note>No comment provided by engineer.</note>
@@ -3793,10 +3796,6 @@ This is your link for group %@!</source>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Viestin teksti</target>
@@ -4287,6 +4286,10 @@ This is your link for group %@!</source>
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>PING-määrä</target>
@@ -4445,6 +4448,10 @@ Error: %@</source>
<target>Säilytä tunnuslause turvallisesti, ET voi muuttaa sitä, jos kadotat sen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Puolalainen käyttöliittymä</target>
@@ -4510,6 +4517,10 @@ Error: %@</source>
<source>Private routing</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Profiili- ja palvelinyhteydet</target>
@@ -5386,6 +5397,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server address is incompatible with network settings.</source>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Palvelin vaatii valtuutuksen jonojen luomiseen, tarkista salasana</target>
@@ -5409,6 +5424,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server version is incompatible with network settings.</source>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Palvelimet</target>
@@ -5540,6 +5563,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Show message status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Näytä esikatselu</target>
@@ -5756,10 +5783,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -6759,8 +6782,8 @@ Repeat join request?</source>
<source>You can make it visible to your SimpleX contacts via Settings.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Voit nyt lähettää viestejä %@:lle</target>
<note>notification body</note>
</trans-unit>
@@ -7153,7 +7176,7 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
</trans-unit>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -127,11 +127,6 @@
<target>%@ est vérifié·e</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>Serveurs %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ envoyé</target>
@@ -590,6 +585,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Ajoutez une adresse à votre profil, afin que vos contacts puissent la partager avec d'autres personnes. La mise à jour du profil sera envoyée à vos contacts.</target>
@@ -610,16 +609,16 @@
<target>Ajouter un profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Ajoutez des serveurs en scannant des codes QR.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Ajouter un serveur</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Ajoutez des serveurs en scannant des codes QR.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Ajouter à un autre appareil</target>
@@ -710,8 +709,8 @@
<target>Tous les nouveaux messages de %@ seront cachés !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1354,6 +1353,10 @@
<target>Configurer les serveurs ICE</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Confirmer</target>
@@ -1533,10 +1536,6 @@ Il s'agit de votre propre lien unique !</target>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>Votre contact autorise</target>
@@ -1710,8 +1709,8 @@ Il s'agit de votre propre lien unique !</target>
<target>Phrase secrète actuelle…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3941,6 +3940,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Les réactions aux messages sont interdites dans ce groupe.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Rabattement du routage des messages</target>
@@ -3964,10 +3967,6 @@ Voici votre lien pour le groupe %@ !</target>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Texte du message</target>
@@ -4487,6 +4486,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Autres</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>Nombre de PING</target>
@@ -4653,6 +4656,10 @@ Erreur: %@</target>
<target>Veuillez conserver votre phrase secrète en lieu sûr, vous NE pourrez PAS la changer si vous la perdez.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Interface en polonais</target>
@@ -4722,6 +4729,10 @@ Erreur: %@</target>
<target>Routage privé</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Profil et connexions au serveur</target>
@@ -5629,6 +5640,10 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>L'adresse du serveur est incompatible avec les paramètres du réseau.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Le serveur requiert une autorisation pour créer des files d'attente, vérifiez le mot de passe</target>
@@ -5653,6 +5668,14 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>La version du serveur est incompatible avec les paramètres du réseau.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Serveurs</target>
@@ -5790,6 +5813,10 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>Afficher le statut du message</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Afficher l'aperçu</target>
@@ -6014,10 +6041,6 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -7080,8 +7103,8 @@ Répéter la demande d'adhésion ?</target>
<target>Vous pouvez le rendre visible à vos contacts SimpleX via Paramètres.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Vous pouvez maintenant envoyer des messages à %@</target>
<note>notification body</note>
</trans-unit>
@@ -7488,7 +7511,7 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>bloqué par l'administrateur</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -127,11 +127,6 @@
<target>%@ ellenőrizve</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ kiszolgáló</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ feltöltve</target>
@@ -559,6 +554,7 @@
</trans-unit>
<trans-unit id="Accent" xml:space="preserve">
<source>Accent</source>
<target>Kiemelés</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Accept" xml:space="preserve">
@@ -584,10 +580,16 @@
</trans-unit>
<trans-unit id="Acknowledged" xml:space="preserve">
<source>Acknowledged</source>
<target>Nyugtázva</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Acknowledgement errors" xml:space="preserve">
<source>Acknowledgement errors</source>
<target>Nyugtázott hibák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
@@ -610,16 +612,16 @@
<target>Profil hozzáadása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Kiszolgáló hozzáadása QR-kód beolvasásával.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Kiszolgáló hozzáadása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Kiszolgáló hozzáadása QR-kód beolvasásával.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Hozzáadás egy másik eszközhöz</target>
@@ -632,14 +634,17 @@
</trans-unit>
<trans-unit id="Additional accent" xml:space="preserve">
<source>Additional accent</source>
<target>További kiemelés</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Additional accent 2" xml:space="preserve">
<source>Additional accent 2</source>
<target>További kiemelés 2</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Additional secondary" xml:space="preserve">
<source>Additional secondary</source>
<target>További másodlagos</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Address" xml:space="preserve">
@@ -669,6 +674,7 @@
</trans-unit>
<trans-unit id="Advanced settings" xml:space="preserve">
<source>Advanced settings</source>
<target>Haladó beállítások</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All app data is deleted." xml:space="preserve">
@@ -688,6 +694,7 @@
</trans-unit>
<trans-unit id="All data is private to your device." xml:space="preserve">
<source>All data is private to your device.</source>
<target>Minden adat biztonságban van a készülékén.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All group members will remain connected." xml:space="preserve">
@@ -710,8 +717,9 @@
<target>Minden új üzenet elrejtésre kerül tőle: %@!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>Minden profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -916,6 +924,7 @@
</trans-unit>
<trans-unit id="Apply to" xml:space="preserve">
<source>Apply to</source>
<target>Alkalmazás erre</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
@@ -995,6 +1004,7 @@
</trans-unit>
<trans-unit id="Background" xml:space="preserve">
<source>Background</source>
<target>Háttér</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
@@ -1024,6 +1034,7 @@
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Fekete</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block" xml:space="preserve">
@@ -1138,6 +1149,7 @@
</trans-unit>
<trans-unit id="Cannot forward message" xml:space="preserve">
<source>Cannot forward message</source>
<target>Nem lehet továbbítani az üzenetet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Cannot receive file" xml:space="preserve">
@@ -1213,6 +1225,7 @@
</trans-unit>
<trans-unit id="Chat colors" xml:space="preserve">
<source>Chat colors</source>
<target>Csevegés színei</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat console" xml:space="preserve">
@@ -1262,6 +1275,7 @@
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Csevegés témája</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chats" xml:space="preserve">
@@ -1296,14 +1310,17 @@
</trans-unit>
<trans-unit id="Chunks deleted" xml:space="preserve">
<source>Chunks deleted</source>
<target>Törölt fájltöredékek</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chunks downloaded" xml:space="preserve">
<source>Chunks downloaded</source>
<target>Letöltött fájltöredékek</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chunks uploaded" xml:space="preserve">
<source>Chunks uploaded</source>
<target>Feltöltött fájltöredékek</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear" xml:space="preserve">
@@ -1333,6 +1350,7 @@
</trans-unit>
<trans-unit id="Color mode" xml:space="preserve">
<source>Color mode</source>
<target>Színmód</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Compare file" xml:space="preserve">
@@ -1347,6 +1365,7 @@
</trans-unit>
<trans-unit id="Completed" xml:space="preserve">
<source>Completed</source>
<target>Elkészült</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configure ICE servers" xml:space="preserve">
@@ -1354,6 +1373,10 @@
<target>ICE kiszolgálók beállítása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Megerősítés</target>
@@ -1460,6 +1483,7 @@ Ez az egyszer használatos hivatkozása!</target>
</trans-unit>
<trans-unit id="Connected" xml:space="preserve">
<source>Connected</source>
<target>Kapcsolódva</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
@@ -1469,6 +1493,7 @@ Ez az egyszer használatos hivatkozása!</target>
</trans-unit>
<trans-unit id="Connected servers" xml:space="preserve">
<source>Connected servers</source>
<target>Kapcsolódott kiszolgálók</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
@@ -1478,6 +1503,7 @@ Ez az egyszer használatos hivatkozása!</target>
</trans-unit>
<trans-unit id="Connecting" xml:space="preserve">
<source>Connecting</source>
<target>Kapcsolódás</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
@@ -1527,14 +1553,12 @@ Ez az egyszer használatos hivatkozása!</target>
</trans-unit>
<trans-unit id="Connection with desktop stopped" xml:space="preserve">
<source>Connection with desktop stopped</source>
<target>A kapcsolat a számítógéppel megszakadt</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections" xml:space="preserve">
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<target>Kapcsolatok</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
@@ -1594,6 +1618,7 @@ Ez az egyszer használatos hivatkozása!</target>
</trans-unit>
<trans-unit id="Copy error" xml:space="preserve">
<source>Copy error</source>
<target>Másolási hiba</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Core version: v%@" xml:space="preserve">
@@ -1673,6 +1698,7 @@ Ez az egyszer használatos hivatkozása!</target>
</trans-unit>
<trans-unit id="Created" xml:space="preserve">
<source>Created</source>
<target>Létrehozva</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Created at" xml:space="preserve">
@@ -1710,8 +1736,9 @@ Ez az egyszer használatos hivatkozása!</target>
<target>Jelenlegi jelmondat…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<target>Jelenlegi profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -1726,6 +1753,7 @@ Ez az egyszer használatos hivatkozása!</target>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Téma személyre szabása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Dark" xml:space="preserve">
@@ -1735,6 +1763,7 @@ Ez az egyszer használatos hivatkozása!</target>
</trans-unit>
<trans-unit id="Dark mode colors" xml:space="preserve">
<source>Dark mode colors</source>
<target>Sötét mód színei</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Database ID" xml:space="preserve">
@@ -2044,6 +2073,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Deleted" xml:space="preserve">
<source>Deleted</source>
<target>Törölve</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Deleted at" xml:space="preserve">
@@ -2058,6 +2088,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Deletion errors" xml:space="preserve">
<source>Deletion errors</source>
<target>Törlési hibák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delivery" xml:space="preserve">
@@ -2102,10 +2133,12 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Detailed statistics" xml:space="preserve">
<source>Detailed statistics</source>
<target>Részletes statisztikák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Details" xml:space="preserve">
<source>Details</source>
<target>Részletek</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2265,6 +2298,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Download errors" xml:space="preserve">
<source>Download errors</source>
<target>Letöltési hibák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve">
@@ -2279,10 +2313,12 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Downloaded" xml:space="preserve">
<source>Downloaded</source>
<target>Letöltve</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Downloaded files" xml:space="preserve">
<source>Downloaded files</source>
<target>Letöltött fájlok</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Downloading archive" xml:space="preserve">
@@ -2657,6 +2693,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Error exporting theme: %@" xml:space="preserve">
<source>Error exporting theme: %@</source>
<target>Hiba a téma exportálásakor: %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error importing chat database" xml:space="preserve">
@@ -2686,10 +2723,12 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Error reconnecting server" xml:space="preserve">
<source>Error reconnecting server</source>
<target>Hiba a kiszolgálóhoz való újrakapcsolódáskor</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error reconnecting servers" xml:space="preserve">
<source>Error reconnecting servers</source>
<target>Hiba a kiszolgálókhoz való újrakapcsolódáskor</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
@@ -2699,6 +2738,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Error resetting statistics" xml:space="preserve">
<source>Error resetting statistics</source>
<target>Hiba a statisztikák visszaállításakor</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error saving %@ servers" xml:space="preserve">
@@ -2834,6 +2874,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Errors" xml:space="preserve">
<source>Errors</source>
<target>Hibák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Even when disabled in the conversation." xml:space="preserve">
@@ -2863,6 +2904,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Export theme" xml:space="preserve">
<source>Export theme</source>
<target>Téma exportálása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Exported database archive." xml:space="preserve">
@@ -2902,22 +2944,27 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="File error" xml:space="preserve">
<source>File error</source>
<target>Fájlhiba</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
<source>File not found - most likely file was deleted or cancelled.</source>
<target>A fájl nem található - valószínűleg a fájlt törölték vagy visszavonták.</target>
<note>file error text</note>
</trans-unit>
<trans-unit id="File server error: %@" xml:space="preserve">
<source>File server error: %@</source>
<target>Fájlkiszolgáló hiba: %@</target>
<note>file error text</note>
</trans-unit>
<trans-unit id="File status" xml:space="preserve">
<source>File status</source>
<target>Fájlállapot</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="File status: %@" xml:space="preserve">
<source>File status: %@</source>
<target>Fájlállapot: %@</target>
<note>copied message info</note>
</trans-unit>
<trans-unit id="File will be deleted from servers." xml:space="preserve">
@@ -3111,10 +3158,12 @@ Hiba: %2$@</target>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<target>Jó napot!</target>
<note>message preview</note>
</trans-unit>
<trans-unit id="Good morning!" xml:space="preserve">
<source>Good morning!</source>
<target>Jó reggelt!</target>
<note>message preview</note>
</trans-unit>
<trans-unit id="Group" xml:space="preserve">
@@ -3399,6 +3448,7 @@ Hiba: %2$@</target>
</trans-unit>
<trans-unit id="Import theme" xml:space="preserve">
<source>Import theme</source>
<target>Téma importálása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Importing archive" xml:space="preserve">
@@ -3525,6 +3575,7 @@ Hiba: %2$@</target>
</trans-unit>
<trans-unit id="Interface colors" xml:space="preserve">
<source>Interface colors</source>
<target>Kezelőfelület színei</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
@@ -3872,6 +3923,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Member inactive" xml:space="preserve">
<source>Member inactive</source>
<target>Inaktív tag</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All group members will be notified." xml:space="preserve">
@@ -3891,6 +3943,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<target>Menük</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message delivery error" xml:space="preserve">
@@ -3915,10 +3968,12 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Message forwarded" xml:space="preserve">
<source>Message forwarded</source>
<target>Továbbított üzenet</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message may be delivered later if member becomes active." xml:space="preserve">
<source>Message may be delivered later if member becomes active.</source>
<target>Az üzenet később is kézbesíthető, ha a tag aktívvá válik.</target>
<note>item status description</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
@@ -3941,6 +3996,10 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
<target>Az üzenetreakciók küldése le van tiltva ebben a csoportban.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Üzenet útválasztási tartalék</target>
@@ -3958,16 +4017,14 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Message status" xml:space="preserve">
<source>Message status</source>
<target>Üzenetállapot</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message status: %@" xml:space="preserve">
<source>Message status: %@</source>
<target>Üzenetállapot: %@</target>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Üzenet szövege</target>
@@ -3995,10 +4052,12 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Messages received" xml:space="preserve">
<source>Messages received</source>
<target>Fogadott üzenetek</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages sent" xml:space="preserve">
<source>Messages sent</source>
<target>Elküldött üzenetek</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
@@ -4238,6 +4297,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="No direct connection yet, message is forwarded by admin." xml:space="preserve">
<source>No direct connection yet, message is forwarded by admin.</source>
<target>Még nincs közvetlen kapcsolat, az üzenetet az admin továbbítja.</target>
<note>item status description</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
@@ -4257,6 +4317,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="No info, try to reload" xml:space="preserve">
<source>No info, try to reload</source>
<target>Nincs információ, próbálja meg újratölteni</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
@@ -4445,6 +4506,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Open server settings" xml:space="preserve">
<source>Open server settings</source>
<target>Kiszolgáló beállításainak megnyitása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Open user profiles" xml:space="preserve">
@@ -4487,6 +4549,10 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
<target>További</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>PING számláló</target>
@@ -4554,6 +4620,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Pending" xml:space="preserve">
<source>Pending</source>
<target>Függő</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="People can connect to you only via the links you share." xml:space="preserve">
@@ -4584,6 +4651,8 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
<trans-unit id="Please check that mobile and desktop are connected to the same local network, and that desktop firewall allows the connection.&#10;Please share any other issues with the developers." xml:space="preserve">
<source>Please check that mobile and desktop are connected to the same local network, and that desktop firewall allows the connection.
Please share any other issues with the developers.</source>
<target>Ellenőrizze, hogy a mobil és az asztali számítógép ugyanahhoz a helyi hálózathoz csatlakozik-e, valamint az asztali számítógép tűzfalában engedélyezve van-e a kapcsolat.
Minden további problémát osszon meg a fejlesztőkkel.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please check that you used the correct link or ask your contact to send you another one." xml:space="preserve">
@@ -4653,6 +4722,10 @@ Hiba: %@</target>
<target>Tárolja el biztonságosan jelmondatát, mert ha elveszíti azt, NEM tudja megváltoztatni.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Lengyel kezelőfelület</target>
@@ -4685,6 +4758,7 @@ Hiba: %@</target>
</trans-unit>
<trans-unit id="Previously connected servers" xml:space="preserve">
<source>Previously connected servers</source>
<target>Korábban kapcsolódott kiszolgálók</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Privacy &amp; security" xml:space="preserve">
@@ -4722,6 +4796,10 @@ Hiba: %@</target>
<target>Privát útválasztás</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Profil és kiszolgálókapcsolatok</target>
@@ -4754,6 +4832,7 @@ Hiba: %@</target>
</trans-unit>
<trans-unit id="Profile theme" xml:space="preserve">
<source>Profile theme</source>
<target>Profiltéma</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile update will be sent to your contacts." xml:space="preserve">
@@ -4840,10 +4919,12 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Proxied" xml:space="preserve">
<source>Proxied</source>
<target>Proxyzott</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Proxied servers" xml:space="preserve">
<source>Proxied servers</source>
<target>Proxyzott kiszolgálók</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Push notifications" xml:space="preserve">
@@ -4913,6 +4994,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Receive errors" xml:space="preserve">
<source>Receive errors</source>
<target>Üzenetfogadási hibák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Received at" xml:space="preserve">
@@ -4937,14 +5019,17 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Received messages" xml:space="preserve">
<source>Received messages</source>
<target>Fogadott üzenetek</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Received reply" xml:space="preserve">
<source>Received reply</source>
<target>Fogadott válasz</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Received total" xml:space="preserve">
<source>Received total</source>
<target>Összes fogadott</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving address will be changed to a different server. Address change will complete after sender comes online." xml:space="preserve">
@@ -4979,6 +5064,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Reconnect" xml:space="preserve">
<source>Reconnect</source>
<target>Újrakapcsolás</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reconnect all connected servers to force message delivery. It uses additional traffic." xml:space="preserve">
@@ -4988,18 +5074,22 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Reconnect all servers" xml:space="preserve">
<source>Reconnect all servers</source>
<target>Újrakapcsolódás minden kiszolgálóhoz</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reconnect all servers?" xml:space="preserve">
<source>Reconnect all servers?</source>
<target>Újrakapcsolódás minden kiszolgálóhoz?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reconnect server to force message delivery. It uses additional traffic." xml:space="preserve">
<source>Reconnect server to force message delivery. It uses additional traffic.</source>
<target>A kiszolgálóhoz való újrakapcsolódás az üzenet kézbesítésének kikényszerítéséhez. Ez további adatforgalmat használ.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reconnect server?" xml:space="preserve">
<source>Reconnect server?</source>
<target>Újrakapcsolódás a kiszolgálóhoz?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reconnect servers?" xml:space="preserve">
@@ -5054,6 +5144,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Remove image" xml:space="preserve">
<source>Remove image</source>
<target>Kép eltávolítása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Remove member" xml:space="preserve">
@@ -5128,10 +5219,12 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Reset all statistics" xml:space="preserve">
<source>Reset all statistics</source>
<target>Minden statisztika visszaállítása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reset all statistics?" xml:space="preserve">
<source>Reset all statistics?</source>
<target>Minden statisztika visszaállítása?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reset colors" xml:space="preserve">
@@ -5141,6 +5234,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Reset to app theme" xml:space="preserve">
<source>Reset to app theme</source>
<target>Alkalmazás témájának visszaállítása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reset to defaults" xml:space="preserve">
@@ -5150,6 +5244,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Reset to user theme" xml:space="preserve">
<source>Reset to user theme</source>
<target>Felhasználó által létrehozott téma visszaállítása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Restart the app to create a new chat profile" xml:space="preserve">
@@ -5224,6 +5319,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="SMP server" xml:space="preserve">
<source>SMP server</source>
<target>SMP-kiszolgáló</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SMP servers" xml:space="preserve">
@@ -5343,10 +5439,12 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Scale" xml:space="preserve">
<source>Scale</source>
<target>Méretezés</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan / Paste link" xml:space="preserve">
<source>Scan / Paste link</source>
<target>Hivatkozás beolvasása / beillesztése</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code" xml:space="preserve">
@@ -5391,6 +5489,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Secondary" xml:space="preserve">
<source>Secondary</source>
<target>Másodlagos</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Secure queue" xml:space="preserve">
@@ -5400,6 +5499,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Secured" xml:space="preserve">
<source>Secured</source>
<target>Biztosítva</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Security assessment" xml:space="preserve">
@@ -5419,6 +5519,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Selected chat preferences prohibit this message." xml:space="preserve">
<source>Selected chat preferences prohibit this message.</source>
<target>A kiválasztott csevegési beállítások tiltják ezt az üzenetet.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Self-destruct" xml:space="preserve">
@@ -5473,6 +5574,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Send errors" xml:space="preserve">
<source>Send errors</source>
<target>Üzenetküldési hibák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send link previews" xml:space="preserve">
@@ -5587,6 +5689,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Sent directly" xml:space="preserve">
<source>Sent directly</source>
<target>Közvetlenül küldött</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Sent file event" xml:space="preserve">
@@ -5601,6 +5704,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Sent messages" xml:space="preserve">
<source>Sent messages</source>
<target>Elküldött üzenetek</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Sent messages will be deleted after set time." xml:space="preserve">
@@ -5610,18 +5714,22 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Sent reply" xml:space="preserve">
<source>Sent reply</source>
<target>Elküldött válasz</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Sent total" xml:space="preserve">
<source>Sent total</source>
<target>Összes elküldött</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Sent via proxy" xml:space="preserve">
<source>Sent via proxy</source>
<target>Proxyn keresztül küldve</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>Kiszolgáló címe</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
@@ -5629,6 +5737,10 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
<target>A kiszolgáló címe nem kompatibilis a hálózati beállításokkal.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>A kiszolgálónak engedélyre van szüksége a várólisták létrehozásához, ellenőrizze jelszavát</target>
@@ -5646,6 +5758,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Server type" xml:space="preserve">
<source>Server type</source>
<target>Kiszolgáló típusa</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
@@ -5653,6 +5766,14 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
<target>A kiszolgáló verziója nem kompatibilis a hálózati beállításokkal.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Kiszolgálók</target>
@@ -5660,10 +5781,12 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Servers info" xml:space="preserve">
<source>Servers info</source>
<target>információk a kiszolgálókról</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers statistics will be reset - this cannot be undone!" xml:space="preserve">
<source>Servers statistics will be reset - this cannot be undone!</source>
<target>A kiszolgálók statisztikái visszaállnak - ez nem vonható vissza!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
@@ -5683,6 +5806,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Set default theme" xml:space="preserve">
<source>Set default theme</source>
<target>Alapértelmezett téma beállítása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set group preferences" xml:space="preserve">
@@ -5790,6 +5914,10 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
<target>Üzenet állapot megjelenítése</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Előnézet megjelenítése</target>
@@ -5807,6 +5935,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="SimpleX" xml:space="preserve">
<source>SimpleX</source>
<target>SimpleX</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX Address" xml:space="preserve">
@@ -5886,6 +6015,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Size" xml:space="preserve">
<source>Size</source>
<target>Méret</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Skip" xml:space="preserve">
@@ -5935,10 +6065,12 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Starting from %@." xml:space="preserve">
<source>Starting from %@.</source>
<target>Kezdve ettől %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Statistics" xml:space="preserve">
<source>Statistics</source>
<target>Statisztikák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop" xml:space="preserve">
@@ -6008,18 +6140,17 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Subscribed" xml:space="preserve">
<source>Subscribed</source>
<target>Feliratkozva</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription errors" xml:space="preserve">
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<target>Feliratkozási hibák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<target>Elutasított feliratkozások</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Support SimpleX Chat" xml:space="preserve">
@@ -6104,6 +6235,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.<
</trans-unit>
<trans-unit id="Temporary file error" xml:space="preserve">
<source>Temporary file error</source>
<target>Ideiglenes fájlhiba</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test failed at step %@." xml:space="preserve">
@@ -6245,6 +6377,7 @@ Ez valamilyen hiba, vagy sérült kapcsolat esetén fordulhat elő.</target>
</trans-unit>
<trans-unit id="Themes" xml:space="preserve">
<source>Themes</source>
<target>Témák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="These settings are for your current profile **%@**." xml:space="preserve">
@@ -6314,6 +6447,7 @@ Ez valamilyen hiba, vagy sérült kapcsolat esetén fordulhat elő.</target>
</trans-unit>
<trans-unit id="This link was used with another mobile device, please create a new link on the desktop." xml:space="preserve">
<source>This link was used with another mobile device, please create a new link on the desktop.</source>
<target>Ezt a hivatkozást egy másik mobilleszközön már használták, hozzon létre egy új hivatkozást az asztali számítógépén.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
@@ -6323,6 +6457,7 @@ Ez valamilyen hiba, vagy sérült kapcsolat esetén fordulhat elő.</target>
</trans-unit>
<trans-unit id="Title" xml:space="preserve">
<source>Title</source>
<target>Cím</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To ask any questions and to receive updates:" xml:space="preserve">
@@ -6394,6 +6529,7 @@ A funkció engedélyezése előtt a rendszer felszólítja a hitelesítés befej
</trans-unit>
<trans-unit id="Total" xml:space="preserve">
<source>Total</source>
<target>Összesen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transport isolation" xml:space="preserve">
@@ -6403,6 +6539,7 @@ A funkció engedélyezése előtt a rendszer felszólítja a hitelesítés befej
</trans-unit>
<trans-unit id="Transport sessions" xml:space="preserve">
<source>Transport sessions</source>
<target>Munkamenetek átvitele</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Trying to connect to the server used to receive messages from this contact (error: %@)." xml:space="preserve">
@@ -6599,6 +6736,7 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol
</trans-unit>
<trans-unit id="Upload errors" xml:space="preserve">
<source>Upload errors</source>
<target>Feltöltési hibák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Upload failed" xml:space="preserve">
@@ -6613,10 +6751,12 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol
</trans-unit>
<trans-unit id="Uploaded" xml:space="preserve">
<source>Uploaded</source>
<target>Feltöltve</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Uploaded files" xml:space="preserve">
<source>Uploaded files</source>
<target>Feltöltött fájlok</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Uploading archive" xml:space="preserve">
@@ -6696,6 +6836,7 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Felhasználó kiválasztása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Using .onion hosts requires compatible VPN provider." xml:space="preserve">
@@ -6835,10 +6976,12 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol
</trans-unit>
<trans-unit id="Wallpaper accent" xml:space="preserve">
<source>Wallpaper accent</source>
<target>Háttérkép kiemelés</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wallpaper background" xml:space="preserve">
<source>Wallpaper background</source>
<target>Háttérkép háttérszíne</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
@@ -6948,6 +7091,7 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol
</trans-unit>
<trans-unit id="Wrong key or unknown file chunk address - most likely file is deleted." xml:space="preserve">
<source>Wrong key or unknown file chunk address - most likely file is deleted.</source>
<target>Hibás kulcs vagy ismeretlen fájltöredék cím - valószínűleg a fájl törlődött.</target>
<note>file error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -6957,6 +7101,7 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol
</trans-unit>
<trans-unit id="XFTP server" xml:space="preserve">
<source>XFTP server</source>
<target>XFTP-kiszolgáló</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="XFTP servers" xml:space="preserve">
@@ -7043,6 +7188,7 @@ Csatlakozási kérés megismétlése?</target>
</trans-unit>
<trans-unit id="You are not connected to these servers. Private routing is used to deliver messages to them." xml:space="preserve">
<source>You are not connected to these servers. Private routing is used to deliver messages to them.</source>
<target>Ön nem kapcsolódik ezekhez a kiszolgálókhoz. A privát útválasztás az üzenetek kézbesítésére szolgál.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can accept calls from lock screen, without device and app authentication." xml:space="preserve">
@@ -7080,8 +7226,8 @@ Csatlakozási kérés megismétlése?</target>
<target>Láthatóvá teheti SimpleX ismerősök számára a Beállításokban.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Mostantól küldhet üzeneteket %@ számára</target>
<note>notification body</note>
</trans-unit>
@@ -7453,6 +7599,7 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
</trans-unit>
<trans-unit id="attempts" xml:space="preserve">
<source>attempts</source>
<target>próbálkozások</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
@@ -7488,7 +7635,7 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>letiltva az admin által</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -7647,6 +7794,7 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
</trans-unit>
<trans-unit id="decryption errors" xml:space="preserve">
<source>decryption errors</source>
<target>visszafejtési hibák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="default (%@)" xml:space="preserve">
@@ -7701,6 +7849,7 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
</trans-unit>
<trans-unit id="duplicates" xml:space="preserve">
<source>duplicates</source>
<target>duplikációk</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="e2e encrypted" xml:space="preserve">
@@ -7785,6 +7934,7 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
</trans-unit>
<trans-unit id="expired" xml:space="preserve">
<source>expired</source>
<target>lejárt</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
@@ -7819,6 +7969,7 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
</trans-unit>
<trans-unit id="inactive" xml:space="preserve">
<source>inactive</source>
<target>inaktív</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="incognito via contact address link" xml:space="preserve">
@@ -8000,10 +8151,12 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
</trans-unit>
<trans-unit id="other" xml:space="preserve">
<source>other</source>
<target>egyéb</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="other errors" xml:space="preserve">
<source>other errors</source>
<target>egyéb hibák</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="owner" xml:space="preserve">
@@ -127,11 +127,6 @@
<target>%@ è verificato/a</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>Server %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ caricati</target>
@@ -559,6 +554,7 @@
</trans-unit>
<trans-unit id="Accent" xml:space="preserve">
<source>Accent</source>
<target>Principale</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Accept" xml:space="preserve">
@@ -584,10 +580,16 @@
</trans-unit>
<trans-unit id="Acknowledged" xml:space="preserve">
<source>Acknowledged</source>
<target>Riconosciuto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Acknowledgement errors" xml:space="preserve">
<source>Acknowledgement errors</source>
<target>Errori di riconoscimento</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
@@ -610,16 +612,16 @@
<target>Aggiungi profilo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Aggiungi server scansionando codici QR.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Aggiungi server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Aggiungi server scansionando codici QR.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Aggiungi ad un altro dispositivo</target>
@@ -632,14 +634,17 @@
</trans-unit>
<trans-unit id="Additional accent" xml:space="preserve">
<source>Additional accent</source>
<target>Principale aggiuntivo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Additional accent 2" xml:space="preserve">
<source>Additional accent 2</source>
<target>Principale aggiuntivo 2</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Additional secondary" xml:space="preserve">
<source>Additional secondary</source>
<target>Secondario aggiuntivo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Address" xml:space="preserve">
@@ -669,6 +674,7 @@
</trans-unit>
<trans-unit id="Advanced settings" xml:space="preserve">
<source>Advanced settings</source>
<target>Impostazioni avanzate</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All app data is deleted." xml:space="preserve">
@@ -688,6 +694,7 @@
</trans-unit>
<trans-unit id="All data is private to your device." xml:space="preserve">
<source>All data is private to your device.</source>
<target>Tutti i dati sono privati, nel tuo dispositivo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All group members will remain connected." xml:space="preserve">
@@ -710,8 +717,9 @@
<target>Tutti i nuovi messaggi da %@ verrranno nascosti!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>Tutti gli profili</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -916,6 +924,7 @@
</trans-unit>
<trans-unit id="Apply to" xml:space="preserve">
<source>Apply to</source>
<target>Applica a</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
@@ -995,6 +1004,7 @@
</trans-unit>
<trans-unit id="Background" xml:space="preserve">
<source>Background</source>
<target>Sfondo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
@@ -1024,6 +1034,7 @@
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Nero</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block" xml:space="preserve">
@@ -1138,6 +1149,7 @@
</trans-unit>
<trans-unit id="Cannot forward message" xml:space="preserve">
<source>Cannot forward message</source>
<target>Impossibile inoltrare il messaggio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Cannot receive file" xml:space="preserve">
@@ -1213,6 +1225,7 @@
</trans-unit>
<trans-unit id="Chat colors" xml:space="preserve">
<source>Chat colors</source>
<target>Colori della chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat console" xml:space="preserve">
@@ -1262,6 +1275,7 @@
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Tema della chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chats" xml:space="preserve">
@@ -1296,14 +1310,17 @@
</trans-unit>
<trans-unit id="Chunks deleted" xml:space="preserve">
<source>Chunks deleted</source>
<target>Blocchi eliminati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chunks downloaded" xml:space="preserve">
<source>Chunks downloaded</source>
<target>Blocchi scaricati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chunks uploaded" xml:space="preserve">
<source>Chunks uploaded</source>
<target>Blocchi inviati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear" xml:space="preserve">
@@ -1333,6 +1350,7 @@
</trans-unit>
<trans-unit id="Color mode" xml:space="preserve">
<source>Color mode</source>
<target>Modalità di colore</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Compare file" xml:space="preserve">
@@ -1347,6 +1365,7 @@
</trans-unit>
<trans-unit id="Completed" xml:space="preserve">
<source>Completed</source>
<target>Completato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configure ICE servers" xml:space="preserve">
@@ -1354,6 +1373,10 @@
<target>Configura server ICE</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Conferma</target>
@@ -1460,6 +1483,7 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Connected" xml:space="preserve">
<source>Connected</source>
<target>Connesso</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
@@ -1469,6 +1493,7 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Connected servers" xml:space="preserve">
<source>Connected servers</source>
<target>Server connessi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
@@ -1478,6 +1503,7 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Connecting" xml:space="preserve">
<source>Connecting</source>
<target>In connessione</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
@@ -1527,14 +1553,12 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Connection with desktop stopped" xml:space="preserve">
<source>Connection with desktop stopped</source>
<target>Connessione con il desktop fermata</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections" xml:space="preserve">
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<target>Connessioni</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
@@ -1594,6 +1618,7 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Copy error" xml:space="preserve">
<source>Copy error</source>
<target>Copia errore</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Core version: v%@" xml:space="preserve">
@@ -1673,6 +1698,7 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Created" xml:space="preserve">
<source>Created</source>
<target>Creato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Created at" xml:space="preserve">
@@ -1710,8 +1736,9 @@ Questo è il tuo link una tantum!</target>
<target>Password attuale…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<target>Profilo attuale</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -1726,6 +1753,7 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Personalizza il tema</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Dark" xml:space="preserve">
@@ -1735,6 +1763,7 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Dark mode colors" xml:space="preserve">
<source>Dark mode colors</source>
<target>Colori modalità scura</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Database ID" xml:space="preserve">
@@ -2044,6 +2073,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Deleted" xml:space="preserve">
<source>Deleted</source>
<target>Eliminato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Deleted at" xml:space="preserve">
@@ -2058,6 +2088,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Deletion errors" xml:space="preserve">
<source>Deletion errors</source>
<target>Errori di eliminazione</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delivery" xml:space="preserve">
@@ -2102,10 +2133,12 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Detailed statistics" xml:space="preserve">
<source>Detailed statistics</source>
<target>Statistiche dettagliate</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Details" xml:space="preserve">
<source>Details</source>
<target>Dettagli</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2265,6 +2298,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Download errors" xml:space="preserve">
<source>Download errors</source>
<target>Errori di scaricamento</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve">
@@ -2279,10 +2313,12 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Downloaded" xml:space="preserve">
<source>Downloaded</source>
<target>Scaricato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Downloaded files" xml:space="preserve">
<source>Downloaded files</source>
<target>File scaricati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Downloading archive" xml:space="preserve">
@@ -2657,6 +2693,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Error exporting theme: %@" xml:space="preserve">
<source>Error exporting theme: %@</source>
<target>Errore di esportazione del tema: %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error importing chat database" xml:space="preserve">
@@ -2686,10 +2723,12 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Error reconnecting server" xml:space="preserve">
<source>Error reconnecting server</source>
<target>Errore di riconnessione al server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error reconnecting servers" xml:space="preserve">
<source>Error reconnecting servers</source>
<target>Errore di riconnessione ai server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
@@ -2699,6 +2738,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Error resetting statistics" xml:space="preserve">
<source>Error resetting statistics</source>
<target>Errore di azzeramento statistiche</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error saving %@ servers" xml:space="preserve">
@@ -2834,6 +2874,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Errors" xml:space="preserve">
<source>Errors</source>
<target>Errori</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Even when disabled in the conversation." xml:space="preserve">
@@ -2863,6 +2904,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Export theme" xml:space="preserve">
<source>Export theme</source>
<target>Esporta tema</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Exported database archive." xml:space="preserve">
@@ -2902,22 +2944,27 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="File error" xml:space="preserve">
<source>File error</source>
<target>Errore del file</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
<source>File not found - most likely file was deleted or cancelled.</source>
<target>File non trovato - probabilmente è stato eliminato o annullato.</target>
<note>file error text</note>
</trans-unit>
<trans-unit id="File server error: %@" xml:space="preserve">
<source>File server error: %@</source>
<target>Errore del server dei file: %@</target>
<note>file error text</note>
</trans-unit>
<trans-unit id="File status" xml:space="preserve">
<source>File status</source>
<target>Stato del file</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="File status: %@" xml:space="preserve">
<source>File status: %@</source>
<target>Stato del file: %@</target>
<note>copied message info</note>
</trans-unit>
<trans-unit id="File will be deleted from servers." xml:space="preserve">
@@ -3111,10 +3158,12 @@ Errore: %2$@</target>
</trans-unit>
<trans-unit id="Good afternoon!" xml:space="preserve">
<source>Good afternoon!</source>
<target>Buon pomeriggio!</target>
<note>message preview</note>
</trans-unit>
<trans-unit id="Good morning!" xml:space="preserve">
<source>Good morning!</source>
<target>Buongiorno!</target>
<note>message preview</note>
</trans-unit>
<trans-unit id="Group" xml:space="preserve">
@@ -3399,6 +3448,7 @@ Errore: %2$@</target>
</trans-unit>
<trans-unit id="Import theme" xml:space="preserve">
<source>Import theme</source>
<target>Importa tema</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Importing archive" xml:space="preserve">
@@ -3525,6 +3575,7 @@ Errore: %2$@</target>
</trans-unit>
<trans-unit id="Interface colors" xml:space="preserve">
<source>Interface colors</source>
<target>Colori dell'interfaccia</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid QR code" xml:space="preserve">
@@ -3872,6 +3923,7 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Member inactive" xml:space="preserve">
<source>Member inactive</source>
<target>Membro inattivo</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All group members will be notified." xml:space="preserve">
@@ -3891,6 +3943,7 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Menus" xml:space="preserve">
<source>Menus</source>
<target>Menu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message delivery error" xml:space="preserve">
@@ -3915,10 +3968,12 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Message forwarded" xml:space="preserve">
<source>Message forwarded</source>
<target>Messaggio inoltrato</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message may be delivered later if member becomes active." xml:space="preserve">
<source>Message may be delivered later if member becomes active.</source>
<target>Il messaggio può essere consegnato più tardi se il membro diventa attivo.</target>
<note>item status description</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
@@ -3941,6 +3996,10 @@ Questo è il tuo link per il gruppo %@!</target>
<target>Le reazioni ai messaggi sono vietate in questo gruppo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Ripiego instradamento messaggio</target>
@@ -3958,16 +4017,14 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Message status" xml:space="preserve">
<source>Message status</source>
<target>Stato del messaggio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message status: %@" xml:space="preserve">
<source>Message status: %@</source>
<target>Stato del messaggio: %@</target>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Testo del messaggio</target>
@@ -3995,10 +4052,12 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Messages received" xml:space="preserve">
<source>Messages received</source>
<target>Messaggi ricevuti</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages sent" xml:space="preserve">
<source>Messages sent</source>
<target>Messaggi inviati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
@@ -4238,6 +4297,7 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="No direct connection yet, message is forwarded by admin." xml:space="preserve">
<source>No direct connection yet, message is forwarded by admin.</source>
<target>Ancora nessuna connessione diretta, il messaggio viene inoltrato dall'amministratore.</target>
<note>item status description</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
@@ -4257,6 +4317,7 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="No info, try to reload" xml:space="preserve">
<source>No info, try to reload</source>
<target>Nessuna informazione, prova a ricaricare</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
@@ -4445,6 +4506,7 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Open server settings" xml:space="preserve">
<source>Open server settings</source>
<target>Apri impostazioni server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Open user profiles" xml:space="preserve">
@@ -4487,6 +4549,10 @@ Questo è il tuo link per il gruppo %@!</target>
<target>Altro</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>Conteggio PING</target>
@@ -4554,6 +4620,7 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Pending" xml:space="preserve">
<source>Pending</source>
<target>In attesa</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="People can connect to you only via the links you share." xml:space="preserve">
@@ -4584,6 +4651,8 @@ Questo è il tuo link per il gruppo %@!</target>
<trans-unit id="Please check that mobile and desktop are connected to the same local network, and that desktop firewall allows the connection.&#10;Please share any other issues with the developers." xml:space="preserve">
<source>Please check that mobile and desktop are connected to the same local network, and that desktop firewall allows the connection.
Please share any other issues with the developers.</source>
<target>Controlla che mobile e desktop siano collegati alla stessa rete locale e che il firewall del desktop consenta la connessione.
Si prega di condividere qualsiasi altro problema con gli sviluppatori.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please check that you used the correct link or ask your contact to send you another one." xml:space="preserve">
@@ -4653,6 +4722,10 @@ Errore: %@</target>
<target>Conserva la password in modo sicuro, NON potrai cambiarla se la perdi.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Interfaccia polacca</target>
@@ -4685,6 +4758,7 @@ Errore: %@</target>
</trans-unit>
<trans-unit id="Previously connected servers" xml:space="preserve">
<source>Previously connected servers</source>
<target>Server precedentemente connessi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Privacy &amp; security" xml:space="preserve">
@@ -4722,6 +4796,10 @@ Errore: %@</target>
<target>Instradamento privato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Profilo e connessioni al server</target>
@@ -4754,6 +4832,7 @@ Errore: %@</target>
</trans-unit>
<trans-unit id="Profile theme" xml:space="preserve">
<source>Profile theme</source>
<target>Tema del profilo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile update will be sent to your contacts." xml:space="preserve">
@@ -4840,10 +4919,12 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Proxied" xml:space="preserve">
<source>Proxied</source>
<target>Via proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Proxied servers" xml:space="preserve">
<source>Proxied servers</source>
<target>Server via proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Push notifications" xml:space="preserve">
@@ -4913,6 +4994,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Receive errors" xml:space="preserve">
<source>Receive errors</source>
<target>Errori di ricezione</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Received at" xml:space="preserve">
@@ -4937,14 +5019,17 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Received messages" xml:space="preserve">
<source>Received messages</source>
<target>Messaggi ricevuti</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Received reply" xml:space="preserve">
<source>Received reply</source>
<target>Risposta ricevuta</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Received total" xml:space="preserve">
<source>Received total</source>
<target>Totale ricevuto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving address will be changed to a different server. Address change will complete after sender comes online." xml:space="preserve">
@@ -4979,6 +5064,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Reconnect" xml:space="preserve">
<source>Reconnect</source>
<target>Riconnetti</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reconnect all connected servers to force message delivery. It uses additional traffic." xml:space="preserve">
@@ -4988,18 +5074,22 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Reconnect all servers" xml:space="preserve">
<source>Reconnect all servers</source>
<target>Riconnetti tutti i server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reconnect all servers?" xml:space="preserve">
<source>Reconnect all servers?</source>
<target>Riconnettere tutti i server?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reconnect server to force message delivery. It uses additional traffic." xml:space="preserve">
<source>Reconnect server to force message delivery. It uses additional traffic.</source>
<target>Riconnetti il server per forzare la consegna dei messaggi. Usa traffico aggiuntivo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reconnect server?" xml:space="preserve">
<source>Reconnect server?</source>
<target>Riconnettere il server?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reconnect servers?" xml:space="preserve">
@@ -5054,6 +5144,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Remove image" xml:space="preserve">
<source>Remove image</source>
<target>Rimuovi immagine</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Remove member" xml:space="preserve">
@@ -5128,10 +5219,12 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Reset all statistics" xml:space="preserve">
<source>Reset all statistics</source>
<target>Azzera tutte le statistiche</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reset all statistics?" xml:space="preserve">
<source>Reset all statistics?</source>
<target>Azzerare tutte le statistiche?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reset colors" xml:space="preserve">
@@ -5141,6 +5234,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Reset to app theme" xml:space="preserve">
<source>Reset to app theme</source>
<target>Ripristina al tema dell'app</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reset to defaults" xml:space="preserve">
@@ -5150,6 +5244,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Reset to user theme" xml:space="preserve">
<source>Reset to user theme</source>
<target>Ripristina al tema dell'utente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Restart the app to create a new chat profile" xml:space="preserve">
@@ -5224,6 +5319,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="SMP server" xml:space="preserve">
<source>SMP server</source>
<target>Server SMP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SMP servers" xml:space="preserve">
@@ -5343,10 +5439,12 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Scale" xml:space="preserve">
<source>Scale</source>
<target>Scala</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan / Paste link" xml:space="preserve">
<source>Scan / Paste link</source>
<target>Scansiona / Incolla link</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code" xml:space="preserve">
@@ -5391,6 +5489,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Secondary" xml:space="preserve">
<source>Secondary</source>
<target>Secondario</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Secure queue" xml:space="preserve">
@@ -5400,6 +5499,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Secured" xml:space="preserve">
<source>Secured</source>
<target>Protetto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Security assessment" xml:space="preserve">
@@ -5419,6 +5519,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Selected chat preferences prohibit this message." xml:space="preserve">
<source>Selected chat preferences prohibit this message.</source>
<target>Le preferenze della chat selezionata vietano questo messaggio.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Self-destruct" xml:space="preserve">
@@ -5473,6 +5574,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Send errors" xml:space="preserve">
<source>Send errors</source>
<target>Errori di invio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send link previews" xml:space="preserve">
@@ -5587,6 +5689,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Sent directly" xml:space="preserve">
<source>Sent directly</source>
<target>Inviato direttamente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Sent file event" xml:space="preserve">
@@ -5601,6 +5704,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Sent messages" xml:space="preserve">
<source>Sent messages</source>
<target>Messaggi inviati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Sent messages will be deleted after set time." xml:space="preserve">
@@ -5610,18 +5714,22 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Sent reply" xml:space="preserve">
<source>Sent reply</source>
<target>Risposta inviata</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Sent total" xml:space="preserve">
<source>Sent total</source>
<target>Totale inviato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Sent via proxy" xml:space="preserve">
<source>Sent via proxy</source>
<target>Inviato via proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>Indirizzo server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
@@ -5629,6 +5737,10 @@ Attivalo nelle impostazioni *Rete e server*.</target>
<target>L'indirizzo del server non è compatibile con le impostazioni di rete.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Il server richiede l'autorizzazione di creare code, controlla la password</target>
@@ -5646,6 +5758,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Server type" xml:space="preserve">
<source>Server type</source>
<target>Tipo server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
@@ -5653,6 +5766,14 @@ Attivalo nelle impostazioni *Rete e server*.</target>
<target>La versione del server non è compatibile con le impostazioni di rete.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Server</target>
@@ -5660,10 +5781,12 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Servers info" xml:space="preserve">
<source>Servers info</source>
<target>Info dei server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers statistics will be reset - this cannot be undone!" xml:space="preserve">
<source>Servers statistics will be reset - this cannot be undone!</source>
<target>Le statistiche dei server verranno azzerate - è irreversibile!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
@@ -5683,6 +5806,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Set default theme" xml:space="preserve">
<source>Set default theme</source>
<target>Imposta tema predefinito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set group preferences" xml:space="preserve">
@@ -5790,6 +5914,10 @@ Attivalo nelle impostazioni *Rete e server*.</target>
<target>Mostra stato del messaggio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Mostra anteprima</target>
@@ -5807,6 +5935,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="SimpleX" xml:space="preserve">
<source>SimpleX</source>
<target>SimpleX</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX Address" xml:space="preserve">
@@ -5886,6 +6015,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Size" xml:space="preserve">
<source>Size</source>
<target>Dimensione</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Skip" xml:space="preserve">
@@ -5935,10 +6065,12 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Starting from %@." xml:space="preserve">
<source>Starting from %@.</source>
<target>Inizio da %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Statistics" xml:space="preserve">
<source>Statistics</source>
<target>Statistiche</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop" xml:space="preserve">
@@ -6008,18 +6140,17 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Subscribed" xml:space="preserve">
<source>Subscribed</source>
<target>Iscritto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription errors" xml:space="preserve">
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<target>Errori di iscrizione</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<target>Iscrizioni ignorate</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Support SimpleX Chat" xml:space="preserve">
@@ -6104,6 +6235,7 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Temporary file error" xml:space="preserve">
<source>Temporary file error</source>
<target>Errore del file temporaneo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Test failed at step %@." xml:space="preserve">
@@ -6245,6 +6377,7 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.</ta
</trans-unit>
<trans-unit id="Themes" xml:space="preserve">
<source>Themes</source>
<target>Temi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="These settings are for your current profile **%@**." xml:space="preserve">
@@ -6314,6 +6447,7 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.</ta
</trans-unit>
<trans-unit id="This link was used with another mobile device, please create a new link on the desktop." xml:space="preserve">
<source>This link was used with another mobile device, please create a new link on the desktop.</source>
<target>Questo link è stato usato con un altro dispositivo mobile, creane uno nuovo sul desktop.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
@@ -6323,6 +6457,7 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.</ta
</trans-unit>
<trans-unit id="Title" xml:space="preserve">
<source>Title</source>
<target>Titoli</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To ask any questions and to receive updates:" xml:space="preserve">
@@ -6394,6 +6529,7 @@ Ti verrà chiesto di completare l'autenticazione prima di attivare questa funzio
</trans-unit>
<trans-unit id="Total" xml:space="preserve">
<source>Total</source>
<target>Totale</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transport isolation" xml:space="preserve">
@@ -6403,6 +6539,7 @@ Ti verrà chiesto di completare l'autenticazione prima di attivare questa funzio
</trans-unit>
<trans-unit id="Transport sessions" xml:space="preserve">
<source>Transport sessions</source>
<target>Sessioni di trasporto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Trying to connect to the server used to receive messages from this contact (error: %@)." xml:space="preserve">
@@ -6599,6 +6736,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="Upload errors" xml:space="preserve">
<source>Upload errors</source>
<target>Errori di invio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Upload failed" xml:space="preserve">
@@ -6613,10 +6751,12 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="Uploaded" xml:space="preserve">
<source>Uploaded</source>
<target>Inviato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Uploaded files" xml:space="preserve">
<source>Uploaded files</source>
<target>File inviati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Uploading archive" xml:space="preserve">
@@ -6696,6 +6836,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Selezione utente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Using .onion hosts requires compatible VPN provider." xml:space="preserve">
@@ -6835,10 +6976,12 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="Wallpaper accent" xml:space="preserve">
<source>Wallpaper accent</source>
<target>Tinta dello sfondo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wallpaper background" xml:space="preserve">
<source>Wallpaper background</source>
<target>Retro dello sfondo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
@@ -6948,6 +7091,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="Wrong key or unknown file chunk address - most likely file is deleted." xml:space="preserve">
<source>Wrong key or unknown file chunk address - most likely file is deleted.</source>
<target>Chiave sbagliata o indirizzo sconosciuto per frammento del file - probabilmente il file è stato eliminato.</target>
<note>file error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -6957,6 +7101,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="XFTP server" xml:space="preserve">
<source>XFTP server</source>
<target>Server XFTP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="XFTP servers" xml:space="preserve">
@@ -7043,6 +7188,7 @@ Ripetere la richiesta di ingresso?</target>
</trans-unit>
<trans-unit id="You are not connected to these servers. Private routing is used to deliver messages to them." xml:space="preserve">
<source>You are not connected to these servers. Private routing is used to deliver messages to them.</source>
<target>Non sei connesso/a a questi server. L'instradamento privato è usato per consegnare loro i messaggi.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can accept calls from lock screen, without device and app authentication." xml:space="preserve">
@@ -7080,8 +7226,8 @@ Ripetere la richiesta di ingresso?</target>
<target>Puoi renderlo visibile ai tuoi contatti SimpleX nelle impostazioni.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Ora puoi inviare messaggi a %@</target>
<note>notification body</note>
</trans-unit>
@@ -7453,6 +7599,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="attempts" xml:space="preserve">
<source>attempts</source>
<target>tentativi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
@@ -7488,7 +7635,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>bloccato dall'amministratore</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -7647,6 +7794,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="decryption errors" xml:space="preserve">
<source>decryption errors</source>
<target>errori di decifrazione</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="default (%@)" xml:space="preserve">
@@ -7701,6 +7849,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="duplicates" xml:space="preserve">
<source>duplicates</source>
<target>doppi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="e2e encrypted" xml:space="preserve">
@@ -7785,6 +7934,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="expired" xml:space="preserve">
<source>expired</source>
<target>scaduto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
@@ -7819,6 +7969,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="inactive" xml:space="preserve">
<source>inactive</source>
<target>inattivo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="incognito via contact address link" xml:space="preserve">
@@ -8000,10 +8151,12 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="other" xml:space="preserve">
<source>other</source>
<target>altro</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="other errors" xml:space="preserve">
<source>other errors</source>
<target>altri errori</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="owner" xml:space="preserve">
@@ -127,11 +127,6 @@
<target>%@ は検証されています</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ サーバー</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ アップロード済</target>
@@ -584,6 +579,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>プロフィールにアドレスを追加し、連絡先があなたのアドレスを他の人と共有できるようにします。プロフィールの更新は連絡先に送信されます。</target>
@@ -603,16 +602,16 @@
<target>プロフィールを追加</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>QRコードでサーバを追加する。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>サーバを追加</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>QRコードでサーバを追加する。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>別の端末に追加</target>
@@ -700,8 +699,8 @@
<source>All new messages from %@ will be hidden!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1322,6 +1321,10 @@
<target>ICEサーバを設定</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>確認</target>
@@ -1484,10 +1487,6 @@ This is your own one-time link!</source>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>連絡先の許可</target>
@@ -1653,8 +1652,8 @@ This is your own one-time link!</source>
<target>現在の暗証フレーズ…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3797,6 +3796,10 @@ This is your link for group %@!</source>
<target>このグループではメッセージへのリアクションは禁止されています。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<note>No comment provided by engineer.</note>
@@ -3817,10 +3820,6 @@ This is your link for group %@!</source>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>メッセージ内容</target>
@@ -4313,6 +4312,10 @@ This is your link for group %@!</source>
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>PING回数</target>
@@ -4471,6 +4474,10 @@ Error: %@</source>
<target>パスフレーズを失くさないように保管してください。失くすと変更できなくなります。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>ポーランド語UI</target>
@@ -4536,6 +4543,10 @@ Error: %@</source>
<source>Private routing</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>プロフィールとサーバ接続</target>
@@ -5404,6 +5415,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server address is incompatible with network settings.</source>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>キューを作成するにはサーバーの認証が必要です。パスワードを確認してください</target>
@@ -5427,6 +5442,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server version is incompatible with network settings.</source>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>サーバ</target>
@@ -5558,6 +5581,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Show message status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>プレビューを表示</target>
@@ -5775,10 +5802,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -6777,8 +6800,8 @@ Repeat join request?</source>
<source>You can make it visible to your SimpleX contacts via Settings.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>%@ にメッセージを送信できるようになりました</target>
<note>notification body</note>
</trans-unit>
@@ -7171,7 +7194,7 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
</trans-unit>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -127,11 +127,6 @@
<target>%@ is geverifieerd</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ geüpload</target>
@@ -590,6 +585,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Voeg een adres toe aan uw profiel, zodat uw contacten het met andere mensen kunnen delen. Profiel update wordt naar uw contacten verzonden.</target>
@@ -610,16 +609,16 @@
<target>Profiel toevoegen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Servers toevoegen door QR-codes te scannen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Server toevoegen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Servers toevoegen door QR-codes te scannen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Toevoegen aan een ander apparaat</target>
@@ -710,8 +709,8 @@
<target>Alle nieuwe berichten van %@ worden verborgen!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1354,6 +1353,10 @@
<target>ICE servers configureren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Bevestigen</target>
@@ -1533,10 +1536,6 @@ Dit is uw eigen eenmalige link!</target>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>Contact maakt het mogelijk</target>
@@ -1710,8 +1709,8 @@ Dit is uw eigen eenmalige link!</target>
<target>Huidige wachtwoord…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3941,6 +3940,10 @@ Dit is jouw link voor groep %@!</target>
<target>Reacties op berichten zijn verboden in deze groep.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Terugval op berichtroutering</target>
@@ -3964,10 +3967,6 @@ Dit is jouw link voor groep %@!</target>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Bericht tekst</target>
@@ -4487,6 +4486,10 @@ Dit is jouw link voor groep %@!</target>
<target>Ander</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>PING count</target>
@@ -4653,6 +4656,10 @@ Fout: %@</target>
<target>Bewaar het wachtwoord veilig, u kunt deze NIET wijzigen als u het kwijtraakt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Poolse interface</target>
@@ -4722,6 +4729,10 @@ Fout: %@</target>
<target>Privéroutering</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Profiel- en serververbindingen</target>
@@ -5629,6 +5640,10 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
<target>Serveradres is niet compatibel met netwerkinstellingen.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Server vereist autorisatie om wachtrijen te maken, controleer wachtwoord</target>
@@ -5653,6 +5668,14 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
<target>Serverversie is incompatibel met netwerkinstellingen.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Servers</target>
@@ -5790,6 +5813,10 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
<target>Toon berichtstatus</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Toon voorbeeld</target>
@@ -6014,10 +6041,6 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -7080,8 +7103,8 @@ Deelnameverzoek herhalen?</target>
<target>Je kunt het via Instellingen zichtbaar maken voor je SimpleX contacten.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Je kunt nu berichten sturen naar %@</target>
<note>notification body</note>
</trans-unit>
@@ -7488,7 +7511,7 @@ SimpleX servers kunnen uw profiel niet zien.</target>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>geblokkeerd door beheerder</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -127,11 +127,6 @@
<target>%@ jest zweryfikowany</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ serwery</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ wgrane</target>
@@ -590,6 +585,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Dodaj adres do swojego profilu, aby Twoje kontakty mogły go udostępnić innym osobom. Aktualizacja profilu zostanie wysłana do Twoich kontaktów.</target>
@@ -610,16 +609,16 @@
<target>Dodaj profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Dodaj serwery, skanując kody QR.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Dodaj serwer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Dodaj serwery, skanując kody QR.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Dodaj do innego urządzenia</target>
@@ -710,8 +709,8 @@
<target>Wszystkie nowe wiadomości z %@ zostaną ukryte!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1354,6 +1353,10 @@
<target>Skonfiguruj serwery ICE</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Potwierdź</target>
@@ -1533,10 +1536,6 @@ To jest twój jednorazowy link!</target>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>Kontakt pozwala</target>
@@ -1710,8 +1709,8 @@ To jest twój jednorazowy link!</target>
<target>Obecne hasło…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3941,6 +3940,10 @@ To jest twój link do grupy %@!</target>
<target>Reakcje wiadomości są zabronione w tej grupie.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Rezerwowe trasowania wiadomości</target>
@@ -3964,10 +3967,6 @@ To jest twój link do grupy %@!</target>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Tekst wiadomości</target>
@@ -4487,6 +4486,10 @@ To jest twój link do grupy %@!</target>
<target>Inne</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>Liczba PINGÓW</target>
@@ -4653,6 +4656,10 @@ Błąd: %@</target>
<target>Przechowuj kod dostępu w bezpieczny sposób, w przypadku jego utraty NIE będzie można go zmienić.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Polski interfejs</target>
@@ -4722,6 +4729,10 @@ Błąd: %@</target>
<target>Prywatne trasowanie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Profil i połączenia z serwerem</target>
@@ -5629,6 +5640,10 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Adres serwera jest niekompatybilny z ustawieniami sieciowymi.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Serwer wymaga autoryzacji do tworzenia kolejek, sprawdź hasło</target>
@@ -5653,6 +5668,14 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Wersja serwera jest niekompatybilna z ustawieniami sieciowymi.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Serwery</target>
@@ -5790,6 +5813,10 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Pokaż status wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Pokaż podgląd</target>
@@ -6014,10 +6041,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -7080,8 +7103,8 @@ Powtórzyć prośbę dołączenia?</target>
<target>Możesz ustawić go jako widoczny dla swoich kontaktów SimpleX w Ustawieniach.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Możesz teraz wysyłać wiadomości do %@</target>
<note>notification body</note>
</trans-unit>
@@ -7488,7 +7511,7 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>zablokowany przez admina</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -127,11 +127,6 @@
<target>%@ подтверждён</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ серверы</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ загружено</target>
@@ -590,6 +585,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Добавьте адрес в свой профиль, чтобы Ваши контакты могли поделиться им. Профиль будет отправлен Вашим контактам.</target>
@@ -610,16 +609,16 @@
<target>Добавить профиль</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Добавить серверы через QR код.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Добавить сервер</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Добавить серверы через QR код.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Добавить на другое устройство</target>
@@ -710,8 +709,8 @@
<target>Все новые сообщения от %@ будут скрыты!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1354,6 +1353,10 @@
<target>Настройка ICE серверов</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Подтвердить</target>
@@ -1533,10 +1536,6 @@ This is your own one-time link!</source>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>Контакт разрешает</target>
@@ -1710,8 +1709,8 @@ This is your own one-time link!</source>
<target>Текущий пароль…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3939,6 +3938,10 @@ This is your link for group %@!</source>
<target>Реакции на сообщения запрещены в этой группе.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Прямая доставка сообщений</target>
@@ -3962,10 +3965,6 @@ This is your link for group %@!</source>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Текст сообщения</target>
@@ -4485,6 +4484,10 @@ This is your link for group %@!</source>
<target>Другaя сеть</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>Количество PING</target>
@@ -4651,6 +4654,10 @@ Error: %@</source>
<target>Пожалуйста, надежно сохраните пароль, Вы НЕ сможете его поменять, если потеряете.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Польский интерфейс</target>
@@ -4720,6 +4727,10 @@ Error: %@</source>
<target>Конфиденциальная доставка</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Профиль и соединения на сервере</target>
@@ -5627,6 +5638,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Адрес сервера несовместим с настройками сети.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Сервер требует авторизации для создания очередей, проверьте пароль</target>
@@ -5651,6 +5666,14 @@ Enable in *Network &amp; servers* settings.</source>
<target>Версия сервера несовместима с настройками сети.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Серверы</target>
@@ -5788,6 +5811,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Показать статус сообщения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Показывать уведомления</target>
@@ -6012,10 +6039,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -7078,9 +7101,9 @@ Repeat join request?</source>
<target>Вы можете сделать его видимым для ваших контактов в SimpleX через Настройки.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<target>Вы теперь можете отправлять сообщения %@</target>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Вы теперь можете общаться с %@</target>
<note>notification body</note>
</trans-unit>
<trans-unit id="You can set lock screen notification preview via settings." xml:space="preserve">
@@ -7486,7 +7509,7 @@ SimpleX серверы не могут получить доступ к Ваше
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>заблокировано администратором</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -120,11 +120,6 @@
<target>%@ ได้รับการตรวจสอบแล้ว</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ เซิร์ฟเวอร์</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<note>No comment provided by engineer.</note>
@@ -559,6 +554,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>เพิ่มที่อยู่ลงในโปรไฟล์ของคุณ เพื่อให้ผู้ติดต่อของคุณสามารถแชร์กับผู้อื่นได้ การอัปเดตโปรไฟล์จะถูกส่งไปยังผู้ติดต่อของคุณ</target>
@@ -578,16 +577,16 @@
<target>เพิ่มโปรไฟล์</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>เพิ่มเซิร์ฟเวอร์โดยการสแกนรหัสคิวอาร์โค้ด</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>เพิ่มเซิร์ฟเวอร์</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>เพิ่มเซิร์ฟเวอร์โดยการสแกนรหัสคิวอาร์โค้ด</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>เพิ่มเข้าไปในอุปกรณ์อื่น</target>
@@ -675,8 +674,8 @@
<source>All new messages from %@ will be hidden!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1290,6 +1289,10 @@
<target>กำหนดค่าเซิร์ฟเวอร์ ICE</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>ยืนยัน</target>
@@ -1450,10 +1453,6 @@ This is your own one-time link!</source>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>ผู้ติดต่ออนุญาต</target>
@@ -1618,8 +1617,8 @@ This is your own one-time link!</source>
<target>รหัสผ่านปัจจุบัน…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3756,6 +3755,10 @@ This is your link for group %@!</source>
<target>ปฏิกิริยาบนข้อความเป็นสิ่งต้องห้ามในกลุ่มนี้</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<note>No comment provided by engineer.</note>
@@ -3776,10 +3779,6 @@ This is your link for group %@!</source>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>ข้อความ</target>
@@ -4268,6 +4267,10 @@ This is your link for group %@!</source>
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>จํานวน PING</target>
@@ -4426,6 +4429,10 @@ Error: %@</source>
<target>โปรดจัดเก็บรหัสผ่านอย่างปลอดภัย คุณจะไม่สามารถเปลี่ยนรหัสผ่านได้หากคุณทำรหัสผ่านหาย</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>อินเตอร์เฟซภาษาโปแลนด์</target>
@@ -4491,6 +4498,10 @@ Error: %@</source>
<source>Private routing</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>การเชื่อมต่อโปรไฟล์และเซิร์ฟเวอร์</target>
@@ -5363,6 +5374,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server address is incompatible with network settings.</source>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>เซิร์ฟเวอร์ต้องการการอนุญาตในการสร้างคิว โปรดตรวจสอบรหัสผ่าน</target>
@@ -5386,6 +5401,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server version is incompatible with network settings.</source>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>เซิร์ฟเวอร์</target>
@@ -5516,6 +5539,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Show message status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>แสดงตัวอย่าง</target>
@@ -5731,10 +5758,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -6731,8 +6754,8 @@ Repeat join request?</source>
<source>You can make it visible to your SimpleX contacts via Settings.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>ตอนนี้คุณสามารถส่งข้อความถึง %@</target>
<note>notification body</note>
</trans-unit>
@@ -7123,7 +7146,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -127,11 +127,6 @@
<target>%@ onaylandı</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ sunucuları</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ yüklendi</target>
@@ -590,6 +585,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Kişilerinizin başkalarıyla paylaşabilmesi için profilinize adres ekleyin. Profil güncellemesi kişilerinize gönderilecek.</target>
@@ -610,16 +609,16 @@
<target>Profil ekle</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Karekod taratarak sunucuları ekleyin.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Sunucu ekle</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Karekod taratarak sunucuları ekleyin.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Başka bir cihaza ekle</target>
@@ -710,8 +709,8 @@
<target>%@ 'den gelen bütün yeni mesajlar saklı olacak!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1354,6 +1353,10 @@
<target>ICE sunucularını ayarla</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Onayla</target>
@@ -1533,10 +1536,6 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>Kişi izin veriyor</target>
@@ -1710,8 +1709,8 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Şu anki parola…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3941,6 +3940,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Mesaj tepkileri bu grupta yasaklandı.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Mesaj yönlendirme yedeklemesi</target>
@@ -3964,10 +3967,6 @@ Bu senin grup için bağlantın %@!</target>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Mesaj yazısı</target>
@@ -4487,6 +4486,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Diğer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>PING sayısı</target>
@@ -4653,6 +4656,10 @@ Hata: %@</target>
<target>Lütfen parolayı güvenli bir şekilde saklayın, kaybederseniz parolayı DEĞİŞTİREMEZSİNİZ.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Lehçe arayüz</target>
@@ -4722,6 +4729,10 @@ Hata: %@</target>
<target>Gizli yönlendirme</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Profil ve sunucu bağlantıları</target>
@@ -5629,6 +5640,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Sunucu adresi ağ ayarlarıyla uyumlu değil.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Sunucunun sıra oluşturması için yetki gereklidir, şifreyi kontrol edin</target>
@@ -5653,6 +5668,14 @@ Enable in *Network &amp; servers* settings.</source>
<target>Sunucu sürümü ağ ayarlarıyla uyumlu değil.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Sunucular</target>
@@ -5790,6 +5813,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Mesaj durumunu göster</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Ön gösterimi göser</target>
@@ -6014,10 +6041,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -7080,8 +7103,8 @@ Katılma isteği tekrarlansın mı?</target>
<target>Ayarlardan SimpleX kişilerinize görünür yapabilirsiniz.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Artık %@ adresine mesaj gönderebilirsin</target>
<note>notification body</note>
</trans-unit>
@@ -7488,7 +7511,7 @@ SimpleX sunucuları profilinizi göremez.</target>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>yönetici tarafından engellendi</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -127,11 +127,6 @@
<target>%@ перевірено</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ сервери</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<target>%@ завантажено</target>
@@ -590,6 +585,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>Додайте адресу до свого профілю, щоб ваші контакти могли поділитися нею з іншими людьми. Повідомлення про оновлення профілю буде надіслано вашим контактам.</target>
@@ -610,16 +609,16 @@
<target>Додати профіль</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Додайте сервери, відсканувавши QR-код.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>Додати сервер</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>Додайте сервери, відсканувавши QR-код.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>Додати до іншого пристрою</target>
@@ -710,8 +709,8 @@
<target>Всі нові повідомлення від %@ будуть приховані!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1354,6 +1353,10 @@
<target>Налаштування серверів ICE</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>Підтвердити</target>
@@ -1533,10 +1536,6 @@ This is your own one-time link!</source>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>Контакт дозволяє</target>
@@ -1710,8 +1709,8 @@ This is your own one-time link!</source>
<target>Поточна парольна фраза…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3941,6 +3940,10 @@ This is your link for group %@!</source>
<target>Реакції на повідомлення в цій групі заборонені.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Запасний варіант маршрутизації повідомлень</target>
@@ -3964,10 +3967,6 @@ This is your link for group %@!</source>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>Текст повідомлення</target>
@@ -4487,6 +4486,10 @@ This is your link for group %@!</source>
<target>Інше</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>Кількість PING</target>
@@ -4653,6 +4656,10 @@ Error: %@</source>
<target>Будь ласка, зберігайте пароль надійно, ви НЕ зможете змінити його, якщо втратите.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>Польський інтерфейс</target>
@@ -4722,6 +4729,10 @@ Error: %@</source>
<target>Приватна маршрутизація</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>З'єднання профілю та сервера</target>
@@ -5629,6 +5640,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Адреса сервера несумісна з налаштуваннями мережі.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>Сервер вимагає авторизації для створення черг, перевірте пароль</target>
@@ -5653,6 +5668,14 @@ Enable in *Network &amp; servers* settings.</source>
<target>Серверна версія несумісна з мережевими налаштуваннями.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>Сервери</target>
@@ -5790,6 +5813,10 @@ Enable in *Network &amp; servers* settings.</source>
<target>Показати статус повідомлення</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Показати попередній перегляд</target>
@@ -6014,10 +6041,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -7080,8 +7103,8 @@ Repeat join request?</source>
<target>Ви можете зробити його видимим для ваших контактів у SimpleX за допомогою налаштувань.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>Тепер ви можете надсилати повідомлення на адресу %@</target>
<note>notification body</note>
</trans-unit>
@@ -7488,7 +7511,7 @@ SimpleX servers cannot see your profile.</source>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>заблоковано адміністратором</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
@@ -126,11 +126,6 @@
<target>%@ 已认证</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ servers" xml:space="preserve">
<source>%@ servers</source>
<target>%@ 服务器</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<note>No comment provided by engineer.</note>
@@ -578,6 +573,10 @@
<source>Acknowledgement errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Active connections" xml:space="preserve">
<source>Active connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." xml:space="preserve">
<source>Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts.</source>
<target>将地址添加到您的个人资料,以便您的联系人可以与其他人共享。个人资料更新将发送给您的联系人。</target>
@@ -598,16 +597,16 @@
<target>添加个人资料</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>扫描二维码来添加服务器。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add server" xml:space="preserve">
<source>Add server</source>
<target>添加服务器</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add servers by scanning QR codes." xml:space="preserve">
<source>Add servers by scanning QR codes.</source>
<target>扫描二维码来添加服务器。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add to another device" xml:space="preserve">
<source>Add to another device</source>
<target>添加另一设备</target>
@@ -697,8 +696,8 @@
<source>All new messages from %@ will be hidden!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All users" xml:space="preserve">
<source>All users</source>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -1337,6 +1336,10 @@
<target>配置 ICE 服务器</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configured %@ servers" xml:space="preserve">
<source>Configured %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm" xml:space="preserve">
<source>Confirm</source>
<target>确认</target>
@@ -1509,10 +1512,6 @@ This is your own one-time link!</source>
<source>Connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connections subscribed" xml:space="preserve">
<source>Connections subscribed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Contact allows" xml:space="preserve">
<source>Contact allows</source>
<target>联系人允许</target>
@@ -1684,8 +1683,8 @@ This is your own one-time link!</source>
<target>现有密码……</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Current user" xml:space="preserve">
<source>Current user</source>
<trans-unit id="Current profile" xml:space="preserve">
<source>Current profile</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Currently maximum supported file size is %@." xml:space="preserve">
@@ -3888,6 +3887,10 @@ This is your link for group %@!</source>
<target>该群组禁用了消息回应。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reception" xml:space="preserve">
<source>Message reception</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<note>No comment provided by engineer.</note>
@@ -3909,10 +3912,6 @@ This is your link for group %@!</source>
<source>Message status: %@</source>
<note>copied message info</note>
</trans-unit>
<trans-unit id="Message subscriptions" xml:space="preserve">
<source>Message subscriptions</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
<source>Message text</source>
<target>消息正文</target>
@@ -4426,6 +4425,10 @@ This is your link for group %@!</source>
<target>其他</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Other %@ servers" xml:space="preserve">
<source>Other %@ servers</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
<source>PING count</source>
<target>PING 次数</target>
@@ -4589,6 +4592,10 @@ Error: %@</source>
<target>请安全地保存密码,如果您丢失了密码,您将无法更改它。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please try later." xml:space="preserve">
<source>Please try later.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Polish interface" xml:space="preserve">
<source>Polish interface</source>
<target>波兰语界面</target>
@@ -4655,6 +4662,10 @@ Error: %@</source>
<source>Private routing</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private routing error" xml:space="preserve">
<source>Private routing error</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>资料和服务器连接</target>
@@ -5551,6 +5562,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server address is incompatible with network settings.</source>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings: %@." xml:space="preserve">
<source>Server address is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
<source>Server requires authorization to create queues, check password</source>
<target>服务器需要授权才能创建队列,检查密码</target>
@@ -5574,6 +5589,14 @@ Enable in *Network &amp; servers* settings.</source>
<source>Server version is incompatible with network settings.</source>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings: %@." xml:space="preserve">
<source>Server version is incompatible with network settings: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server version is incompatible with your app: %@." xml:space="preserve">
<source>Server version is incompatible with your app: %@.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
<source>Servers</source>
<target>服务器</target>
@@ -5710,6 +5733,10 @@ Enable in *Network &amp; servers* settings.</source>
<source>Show message status</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show percentage" xml:space="preserve">
<source>Show percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>显示预览</target>
@@ -5933,10 +5960,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Subscription errors</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription percentage" xml:space="preserve">
<source>Subscription percentage</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<note>No comment provided by engineer.</note>
@@ -6981,8 +7004,8 @@ Repeat join request?</source>
<target>你可以通过设置让它对你的 SimpleX 联系人可见。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can now send messages to %@" xml:space="preserve">
<source>You can now send messages to %@</source>
<trans-unit id="You can now chat with %@" xml:space="preserve">
<source>You can now chat with %@</source>
<target>您现在可以给 %@ 发送消息</target>
<note>notification body</note>
</trans-unit>
@@ -7384,7 +7407,7 @@ SimpleX 服务器无法看到您的资料。</target>
<trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source>
<target>由管理员封禁</target>
<note>blocked chat item</note>
<note>marked deleted chat item preview text</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
<source>bold</source>
+22 -14
View File
@@ -119,7 +119,7 @@ class NotificationService: UNNotificationServiceExtension {
var threadId: UUID? = NSEThreads.shared.newThread()
var notificationInfo: NtfMessages?
var receiveEntityId: String?
var expectedMessages: Set<String> = []
var expectedMessage: String?
// return true if the message is taken - it prevents sending it to another NotificationService instance for processing
var shouldProcessNtf = false
var appSubscriber: AppSubscriber?
@@ -191,7 +191,7 @@ class NotificationService: UNNotificationServiceExtension {
let dbStatus = startChat()
if case .ok = dbStatus,
let ntfInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) {
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfInfo.ntfMessages.count))")
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfInfo.ntfMessage_ == nil ? 0 : 1))")
if let connEntity = ntfInfo.connEntity_ {
setBestAttemptNtf(
ntfInfo.ntfsEnabled
@@ -201,7 +201,7 @@ class NotificationService: UNNotificationServiceExtension {
if let id = connEntity.id, ntfInfo.msgTs != nil {
notificationInfo = ntfInfo
receiveEntityId = id
expectedMessages = Set(ntfInfo.ntfMessages.map { $0.msgId })
expectedMessage = ntfInfo.ntfMessage_.flatMap { $0.msgId }
shouldProcessNtf = true
return
}
@@ -224,12 +224,10 @@ class NotificationService: UNNotificationServiceExtension {
self.setBestAttemptNtf(.empty)
}
if case let .msgInfo(info) = ntf {
let found = expectedMessages.remove(info.msgId)
if found != nil {
logger.debug("NotificationService processNtf: msgInfo, last: \(self.expectedMessages.isEmpty)")
if expectedMessages.isEmpty {
self.deliverBestAttemptNtf()
}
if info.msgId == expectedMessage {
expectedMessage = nil
logger.debug("NotificationService processNtf: msgInfo")
self.deliverBestAttemptNtf()
return true
} else if info.msgTs > msgTs {
logger.debug("NotificationService processNtf: unexpected msgInfo, let other instance to process it, stopping this one")
@@ -392,6 +390,16 @@ func appStateSubscriber(onState: @escaping (AppState) -> Void) -> AppSubscriber
}
}
let seSubscriber = seMessageSubscriber {
switch $0 {
case let .state(state):
if state == .sendingMessage && NSEChatState.shared.value.canSuspend {
logger.debug("NotificationService: seSubscriber app state \(state.rawValue), suspending")
suspendChat(fastNSESuspendSchedule.timeout)
}
}
}
var receiverStarted = false
let startLock = DispatchSemaphore(value: 1)
let suspendLock = DispatchSemaphore(value: 1)
@@ -636,7 +644,7 @@ func apiGetActiveUser() -> User? {
}
func apiStartChat() throws -> Bool {
let r = sendSimpleXCmd(.startChat(mainApp: false))
let r = sendSimpleXCmd(.startChat(mainApp: false, enableSndFiles: false))
switch r {
case .chatStarted: return true
case .chatRunning: return false
@@ -677,9 +685,9 @@ func apiGetNtfMessage(nonce: String, encNtfInfo: String) -> NtfMessages? {
return nil
}
let r = sendSimpleXCmd(.apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo))
if case let .ntfMessages(user, connEntity_, msgTs, ntfMessages) = r, let user = user {
logger.debug("apiGetNtfMessage response ntfMessages: \(ntfMessages.count)")
return NtfMessages(user: user, connEntity_: connEntity_, msgTs: msgTs, ntfMessages: ntfMessages)
if case let .ntfMessages(user, connEntity_, msgTs, ntfMessage_) = r, let user = user {
logger.debug("apiGetNtfMessage response ntfMessages: \(ntfMessage_ == nil ? 0 : 1)")
return NtfMessages(user: user, connEntity_: connEntity_, msgTs: msgTs, ntfMessage_: ntfMessage_)
} else if case let .chatCmdError(_, error) = r {
logger.debug("apiGetNtfMessage error response: \(String.init(describing: error))")
} else {
@@ -726,7 +734,7 @@ struct NtfMessages {
var user: User
var connEntity_: ConnectionEntity?
var msgTs: Date?
var ntfMessages: [NtfMsgInfo]
var ntfMessage_: NtfMsgInfo?
var ntfsEnabled: Bool {
user.showNotifications && (connEntity_?.ntfsEnabled ?? false)
+35
View File
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsAttachmentsWithMinCount</key>
<integer>0</integer>
<key>NSExtensionActivationSupportsAttachmentsWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
<key>NSExtensionPrincipalClass</key>
<string>ShareViewController</string>
</dict>
</dict>
</plist>
+39
View File
@@ -0,0 +1,39 @@
//
// SEChatState.swift
// SimpleX SE
//
// Created by User on 18/07/2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
// SEStateGroupDefault must not be used in the share extension directly, only via this singleton
class SEChatState {
static let shared = SEChatState()
private var value_ = seStateGroupDefault.get()
var value: SEState {
value_
}
func set(_ state: SEState) {
seStateGroupDefault.set(state)
sendSEState(state)
value_ = state
}
}
/// Waits for other processes to set their state to suspended
/// Will wait for maximum of two seconds, since they might not be running
func waitForOtherProcessesToSuspend() async {
let startTime = CFAbsoluteTimeGetCurrent()
while CFAbsoluteTimeGetCurrent() - startTime < 2 {
try? await Task.sleep(nanoseconds: 100 * NSEC_PER_MSEC)
if appStateGroupDefault.get() == .suspended &&
nseStateGroupDefault.get() == .suspended {
break
}
}
}
+115
View File
@@ -0,0 +1,115 @@
//
// ShareAPI.swift
// SimpleX SE
//
// Created by User on 15/07/2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import OSLog
import Foundation
import SimpleXChat
let logger = Logger()
func apiGetActiveUser() throws -> User? {
let r = sendSimpleXCmd(.showActiveUser)
switch r {
case let .activeUser(user): return user
case .chatCmdError(_, .error(.noActiveUser)): return nil
default: throw r
}
}
func apiStartChat() throws -> Bool {
let r = sendSimpleXCmd(.startChat(mainApp: false, enableSndFiles: true))
switch r {
case .chatStarted: return true
case .chatRunning: return false
default: throw r
}
}
func apiSetNetworkConfig(_ cfg: NetCfg) throws {
let r = sendSimpleXCmd(.apiSetNetworkConfig(networkConfig: cfg))
if case .cmdOk = r { return }
throw r
}
func apiSetAppFilePaths(filesFolder: String, tempFolder: String, assetsFolder: String) throws {
let r = sendSimpleXCmd(.apiSetAppFilePaths(filesFolder: filesFolder, tempFolder: tempFolder, assetsFolder: assetsFolder))
if case .cmdOk = r { return }
throw r
}
func apiSetEncryptLocalFiles(_ enable: Bool) throws {
let r = sendSimpleXCmd(.apiSetEncryptLocalFiles(enable: enable))
if case .cmdOk = r { return }
throw r
}
func apiGetChats(userId: User.ID) throws -> Array<ChatData> {
let r = sendSimpleXCmd(.apiGetChats(userId: userId))
if case let .apiChats(user: _, chats: chats) = r { return chats }
throw r
}
func apiSendMessage(
chatInfo: ChatInfo,
cryptoFile: CryptoFile?,
msgContent: MsgContent
) throws -> AChatItem {
let r = sendSimpleXCmd(
chatInfo.chatType == .local
? .apiCreateChatItem(
noteFolderId: chatInfo.apiId,
file: cryptoFile,
msg: msgContent
)
: .apiSendMessage(
type: chatInfo.chatType,
id: chatInfo.apiId,
file: cryptoFile,
quotedItemId: nil,
msg: msgContent,
live: false,
ttl: nil
)
)
if case let .newChatItem(_, chatItem) = r {
return chatItem
} else {
if let filePath = cryptoFile?.filePath { removeFile(filePath) }
throw r
}
}
func apiActivateChat() throws {
chatReopenStore()
let r = sendSimpleXCmd(.apiActivateChat(restoreChat: false))
if case .cmdOk = r { return }
throw r
}
func apiSuspendChat(expired: Bool) {
let r = sendSimpleXCmd(.apiSuspendChat(timeoutMicroseconds: expired ? 0 : 3_000000))
// Block until `chatSuspended` received or 3 seconds has passed
var suspended = false
if case .cmdOk = r, !expired {
let startTime = CFAbsoluteTimeGetCurrent()
while CFAbsoluteTimeGetCurrent() - startTime < 3 {
switch recvSimpleXMsg(messageTimeout: 3_500000) {
case .chatSuspended:
suspended = false
break
default: continue
}
}
}
if !suspended {
_ = sendSimpleXCmd(.apiSuspendChat(timeoutMicroseconds: 0))
}
logger.debug("close store")
chatCloseStore()
SEChatState.shared.set(.inactive)
}
+500
View File
@@ -0,0 +1,500 @@
//
// ShareModel.swift
// SimpleX SE
//
// Created by Levitating Pineapple on 09/07/2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import UniformTypeIdentifiers
import AVFoundation
import SwiftUI
import SimpleXChat
/// Maximum size of hex encoded media previews
private let MAX_DATA_SIZE: Int64 = 14000
/// Maximum dimension (width or height) of an image, before passed for processing
private let MAX_DOWNSAMPLE_SIZE: Int64 = 2000
class ShareModel: ObservableObject {
@Published var sharedContent: SharedContent?
@Published var chats = Array<ChatData>()
@Published var profileImages = Dictionary<ChatInfo.ID, UIImage>()
@Published var search = String()
@Published var comment = String()
@Published var selected: ChatData?
@Published var isLoaded = false
@Published var bottomBar: BottomBar = .loadingSpinner
@Published var errorAlert: ErrorAlert?
enum BottomBar {
case sendButton
case loadingSpinner
case loadingBar(progress: Double)
var isLoading: Bool {
switch self {
case .sendButton: false
case .loadingSpinner: true
case .loadingBar: true
}
}
}
var completion: () -> Void = {
fatalError("completion has not been set")
}
private var itemProvider: NSItemProvider?
var isSendDisbled: Bool { sharedContent == nil || selected == nil }
var filteredChats: Array<ChatData> {
search.isEmpty
? filterChatsToForwardTo(chats: chats)
: filterChatsToForwardTo(chats: chats)
.filter { foundChat($0, search.localizedLowercase) }
}
func setup(context: NSExtensionContext) {
if let item = context.inputItems.first as? NSExtensionItem,
let itemProvider = item.attachments?.first {
self.itemProvider = itemProvider
self.completion = {
ShareModel.CompletionHandler.isEventLoopEnabled = false
context.completeRequest(returningItems: [item]) {
apiSuspendChat(expired: $0)
}
}
// Init Chat
Task {
if let e = initChat() {
await MainActor.run { errorAlert = e }
} else {
// Load Chats
Task {
switch fetchChats() {
case let .success(chats):
// Decode base64 images on background thread
let profileImages = chats.reduce(into: Dictionary<ChatInfo.ID, UIImage>()) { dict, chatData in
if let profileImage = chatData.chatInfo.image,
let uiImage = UIImage(base64Encoded: profileImage) {
dict[chatData.id] = uiImage
}
}
await MainActor.run {
self.chats = chats
self.profileImages = profileImages
withAnimation { isLoaded = true }
}
case let .failure(error):
await MainActor.run { errorAlert = error }
}
}
// Process Attachment
Task {
switch await self.itemProvider!.sharedContent() {
case let .success(chatItemContent):
await MainActor.run {
self.sharedContent = chatItemContent
self.bottomBar = .sendButton
if case let .text(string) = chatItemContent { comment = string }
}
case let .failure(errorAlert):
await MainActor.run { self.errorAlert = errorAlert }
}
}
}
}
}
}
func send() {
if let sharedContent, let selected {
Task {
await MainActor.run { self.bottomBar = .loadingSpinner }
do {
SEChatState.shared.set(.sendingMessage)
await waitForOtherProcessesToSuspend()
let ci = try apiSendMessage(
chatInfo: selected.chatInfo,
cryptoFile: sharedContent.cryptoFile,
msgContent: sharedContent.msgContent(comment: self.comment)
)
if selected.chatInfo.chatType == .local {
completion()
} else {
await MainActor.run { self.bottomBar = .loadingBar(progress: .zero) }
if let e = await handleEvents(
isGroupChat: ci.chatInfo.chatType == .group,
isWithoutFile: sharedContent.cryptoFile == nil,
chatItemId: ci.chatItem.id
) {
await MainActor.run { errorAlert = e }
} else {
completion()
}
}
} catch {
if let e = error as? ErrorAlert {
await MainActor.run { errorAlert = e }
}
}
}
}
}
private func initChat() -> ErrorAlert? {
do {
if hasChatCtrl() {
try apiActivateChat()
} else {
registerGroupDefaults()
haskell_init_se()
let (_, result) = chatMigrateInit(confirmMigrations: defaultMigrationConfirmation())
if let e = migrationError(result) { return e }
try apiSetAppFilePaths(
filesFolder: getAppFilesDirectory().path,
tempFolder: getTempFilesDirectory().path,
assetsFolder: getWallpaperDirectory().deletingLastPathComponent().path
)
let isRunning = try apiStartChat()
logger.log(level: .debug, "chat started, running: \(isRunning)")
}
try apiSetNetworkConfig(getNetCfg())
try apiSetEncryptLocalFiles(privacyEncryptLocalFilesGroupDefault.get())
} catch { return ErrorAlert(error) }
return nil
}
private func migrationError(_ r: DBMigrationResult) -> ErrorAlert? {
let useKeychain = storeDBPassphraseGroupDefault.get()
let storedDBKey = kcDatabasePassword.get()
// This switch duplicates DatabaseErrorView.
// TODO allow entering passphrase and make messages the same as in DatabaseErrorView.
return switch r {
case .errorNotADatabase:
if useKeychain && storedDBKey != nil && storedDBKey != "" {
ErrorAlert(
title: "Wrong database passphrase",
message: "Database passphrase is different from saved in the keychain."
)
} else {
ErrorAlert(
title: "Encrypted database",
message: "Sharing is not supported when passphrase is not stored in KeyChain."
)
}
case let .errorMigration(_, migrationError):
switch migrationError {
case .upgrade:
ErrorAlert(
title: "Database upgrade required",
message: "Open the app to upgrade the database."
)
case .downgrade:
ErrorAlert(
title: "Database downgrade required",
message: "Open the app to downgrade the database."
)
case let .migrationError(mtrError):
ErrorAlert(
title: "Incompatible database version",
message: mtrErrorDescription(mtrError)
)
}
case let .errorSQL(_, migrationSQLError):
ErrorAlert(
title: "Database error",
message: "Error: \(migrationSQLError)"
)
case .errorKeychain:
ErrorAlert(
title: "Keychain error",
message: "Cannot access keychain to save database password"
)
case .invalidConfirmation:
ErrorAlert("Invalid migration confirmation")
case let .unknown(json):
ErrorAlert(
title: "Database error",
message: "Unknown database error: \(json)"
)
case .ok: nil
}
}
private func fetchChats() -> Result<Array<ChatData>, ErrorAlert> {
do {
guard let user = try apiGetActiveUser() else {
return .failure(
ErrorAlert(
title: "No active profile",
message: "Please create a profile in the SimpleX app"
)
)
}
return .success(try apiGetChats(userId: user.id))
} catch {
return .failure(ErrorAlert(error))
}
}
actor CompletionHandler {
static var isEventLoopEnabled = false
private var fileCompleted = false
private var messageCompleted = false
func completeFile() { fileCompleted = true }
func completeMessage() { messageCompleted = true }
var isRunning: Bool {
Self.isEventLoopEnabled && !(fileCompleted && messageCompleted)
}
}
/// Polls and processes chat events
/// Returns when message sending has completed optionally returning and error.
private func handleEvents(isGroupChat: Bool, isWithoutFile: Bool, chatItemId: ChatItem.ID) async -> ErrorAlert? {
func isMessage(for item: AChatItem?) -> Bool {
item.map { $0.chatItem.id == chatItemId } ?? false
}
CompletionHandler.isEventLoopEnabled = true
let ch = CompletionHandler()
if isWithoutFile { await ch.completeFile() }
var networkTimeout = CFAbsoluteTimeGetCurrent()
while await ch.isRunning {
if CFAbsoluteTimeGetCurrent() - networkTimeout > 30 {
networkTimeout = CFAbsoluteTimeGetCurrent()
await MainActor.run {
self.errorAlert = ErrorAlert(title: "No network connection") {
Button("Keep Trying", role: .cancel) { }
Button("Dismiss Sheet", role: .destructive) { self.completion() }
}
}
}
switch recvSimpleXMsg(messageTimeout: 1_000_000) {
case let .sndFileProgressXFTP(_, ci, _, sentSize, totalSize):
guard isMessage(for: ci) else { continue }
networkTimeout = CFAbsoluteTimeGetCurrent()
await MainActor.run {
withAnimation {
let progress = Double(sentSize) / Double(totalSize)
bottomBar = .loadingBar(progress: progress)
}
}
case let .sndFileCompleteXFTP(_, ci, _):
guard isMessage(for: ci) else { continue }
if isGroupChat {
await MainActor.run { bottomBar = .loadingSpinner }
}
await ch.completeFile()
if await !ch.isRunning { break }
case let .chatItemStatusUpdated(_, ci):
guard isMessage(for: ci) else { continue }
if let (title, message) = ci.chatItem.meta.itemStatus.statusInfo {
// `title` and `message` already localized and interpolated
return ErrorAlert(
title: "\(title)",
message: "\(message)"
)
} else if case let .sndSent(sndProgress) = ci.chatItem.meta.itemStatus {
switch sndProgress {
case .complete:
await ch.completeMessage()
case .partial:
if isGroupChat {
Task {
try? await Task.sleep(nanoseconds: 5 * NSEC_PER_SEC)
await ch.completeMessage()
}
}
}
}
case let .sndFileError(_, ci, _, errorMessage):
guard isMessage(for: ci) else { continue }
if let ci { cleanupFile(ci) }
return ErrorAlert(title: "File error", message: "\(fileErrorInfo(ci) ?? errorMessage)")
case let .sndFileWarning(_, ci, _, errorMessage):
guard isMessage(for: ci) else { continue }
if let ci { cleanupFile(ci) }
return ErrorAlert(title: "File error", message: "\(fileErrorInfo(ci) ?? errorMessage)")
case let .chatError(_, chatError):
return ErrorAlert(chatError)
case let .chatCmdError(_, chatError):
return ErrorAlert(chatError)
default: continue
}
}
return nil
}
private func fileErrorInfo(_ ci: AChatItem?) -> String? {
switch ci?.chatItem.file?.fileStatus {
case let .sndError(e): e.errorInfo
case let .sndWarning(e): e.errorInfo
default: nil
}
}
}
/// Chat Item Content extracted from `NSItemProvider` without the comment
enum SharedContent {
case image(preview: String, cryptoFile: CryptoFile)
case movie(preview: String, duration: Int, cryptoFile: CryptoFile)
case url(preview: LinkPreview)
case text(string: String)
case data(cryptoFile: CryptoFile)
var cryptoFile: CryptoFile? {
switch self {
case let .image(_, cryptoFile): cryptoFile
case let .movie(_, _, cryptoFile): cryptoFile
case .url: nil
case .text: nil
case let .data(cryptoFile): cryptoFile
}
}
func msgContent(comment: String) -> MsgContent {
switch self {
case let .image(preview, _): .image(text: comment, image: preview)
case let .movie(preview, duration, _): .video(text: comment, image: preview, duration: duration)
case let .url(preview): .link(text: comment, preview: preview)
case .text: .text(comment)
case .data: .file(comment)
}
}
}
extension NSItemProvider {
fileprivate func sharedContent() async -> Result<SharedContent, ErrorAlert> {
if let type = firstMatching(of: [.image, .movie, .fileURL, .url, .text]) {
switch type {
// Prepare Image message
case .image:
// Animated
return if hasItemConformingToTypeIdentifier(UTType.gif.identifier) {
if let url = try? await inPlaceUrl(type: type),
let data = try? Data(contentsOf: url),
let image = UIImage(data: data),
let cryptoFile = saveFile(data, generateNewFileName("IMG", "gif"), encrypted: privacyEncryptLocalFilesGroupDefault.get()),
let preview = resizeImageToStrSize(image, maxDataSize: MAX_DATA_SIZE) {
.success(.image(preview: preview, cryptoFile: cryptoFile))
} else { .failure(ErrorAlert("Error preparing message")) }
// Static
} else {
if let url = try? await inPlaceUrl(type: type),
let image = downsampleImage(at: url, to: MAX_DOWNSAMPLE_SIZE),
let cryptoFile = saveImage(image),
let preview = resizeImageToStrSize(image, maxDataSize: MAX_DATA_SIZE) {
.success(.image(preview: preview, cryptoFile: cryptoFile))
} else { .failure(ErrorAlert("Error preparing message")) }
}
// Prepare Movie message
case .movie:
if let url = try? await inPlaceUrl(type: type),
let trancodedUrl = await transcodeVideo(from: url),
let (image, duration) = AVAsset(url: trancodedUrl).generatePreview(),
let preview = resizeImageToStrSize(image, maxDataSize: MAX_DATA_SIZE),
let cryptoFile = moveTempFileFromURL(trancodedUrl) {
try? FileManager.default.removeItem(at: trancodedUrl)
return .success(.movie(preview: preview, duration: duration, cryptoFile: cryptoFile))
} else { return .failure(ErrorAlert("Error preparing message")) }
// Prepare Data message
case .fileURL:
if let url = try? await inPlaceUrl(type: .data) {
if isFileTooLarge(for: url) {
let sizeString = ByteCountFormatter.string(
fromByteCount: Int64(getMaxFileSize(.xftp)),
countStyle: .binary
)
return .failure(
ErrorAlert(
title: "Large file!",
message: "Currently maximum supported file size is \(sizeString)."
)
)
}
if let file = saveFileFromURL(url) {
return .success(.data(cryptoFile: file))
}
}
return .failure(ErrorAlert("Error preparing file"))
// Prepare Link message
case .url:
if let url = try? await loadItem(forTypeIdentifier: type.identifier) as? URL {
let content: SharedContent =
// Option to disable previews needs to be taken into account
// if let linkPreview = await getLinkPreview(for: url) {
// .url(preview: linkPreview)
// } else {
.text(string: url.absoluteString)
// }
return .success(content)
} else { return .failure(ErrorAlert("Error preparing message")) }
// Prepare Text message
case .text:
return if let text = try? await loadItem(forTypeIdentifier: type.identifier) as? String {
.success(.text(string: text))
} else { .failure(ErrorAlert("Error preparing message")) }
default: return .failure(ErrorAlert("Unsupported format"))
}
} else {
return .failure(ErrorAlert("Unsupported format"))
}
}
private func inPlaceUrl(type: UTType) async throws -> URL {
try await withCheckedThrowingContinuation { cont in
let _ = loadInPlaceFileRepresentation(forTypeIdentifier: type.identifier) { url, bool, error in
if let url = url {
cont.resume(returning: url)
} else if let error = error {
cont.resume(throwing: error)
} else {
fatalError("Either `url` or `error` must be present")
}
}
}
}
private func firstMatching(of types: Array<UTType>) -> UTType? {
for type in types {
if hasItemConformingToTypeIdentifier(type.identifier) { return type }
}
return nil
}
}
fileprivate func transcodeVideo(from input: URL) async -> URL? {
let outputUrl = URL(
fileURLWithPath: generateNewFileName(
getTempFilesDirectory().path + "/" + "video", "mp4",
fullPath: true
)
)
if await makeVideoQualityLower(input, outputUrl: outputUrl) {
return outputUrl
} else {
try? FileManager.default.removeItem(at: outputUrl)
return nil
}
}
fileprivate func isFileTooLarge(for url: URL) -> Bool {
fileSize(url)
.map { $0 > getMaxFileSize(.xftp) }
?? false
}
+180
View File
@@ -0,0 +1,180 @@
//
// ShareView.swift
// SimpleX SE
//
// Created by Levitating Pineapple on 09/07/2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct ShareView: View {
@ObservedObject var model: ShareModel
@Environment(\.colorScheme) var colorScheme
var body: some View {
NavigationView {
ZStack(alignment: .bottom) {
if model.isLoaded {
List(model.filteredChats) { chat in
HStack {
profileImage(
chatInfoId: chat.chatInfo.id,
systemFallback: chatIconName(chat.chatInfo),
size: 30
)
Text(chat.chatInfo.displayName)
Spacer()
radioButton(selected: chat == model.selected)
}
.contentShape(Rectangle())
.onTapGesture { model.selected = model.selected == chat ? nil : chat }
.tag(chat)
}
} else {
ProgressView().frame(maxHeight: .infinity)
}
}
.navigationTitle("Share")
.safeAreaInset(edge: .bottom) {
switch model.bottomBar {
case .sendButton:
compose(isLoading: false)
case .loadingSpinner:
compose(isLoading: true)
case .loadingBar(let progress):
loadingBar(progress: progress)
}
}
}
.searchable(
text: $model.search,
placement: .navigationBarDrawer(displayMode: .always)
)
.alert($model.errorAlert) { alert in
Button("Ok") { model.completion() }
}
}
private func compose(isLoading: Bool) -> some View {
VStack(spacing: .zero) {
Divider()
if let content = model.sharedContent {
itemPreview(content)
}
HStack {
Group {
if #available(iOSApplicationExtension 16.0, *) {
TextField("Comment", text: $model.comment, axis: .vertical)
} else {
TextField("Comment", text: $model.comment)
}
}
.contentShape(Rectangle())
.disabled(isLoading)
.padding(.horizontal, 12)
.padding(.vertical, 4)
Group {
if isLoading {
ProgressView()
} else {
Button(action: model.send) {
Image(systemName: "arrow.up.circle.fill")
.resizable()
}
.disabled(model.isSendDisbled)
}
}
.frame(width: 28, height: 28)
.padding(6)
}
.background(Color(.systemBackground))
.clipShape(RoundedRectangle(cornerRadius: 20))
.overlay(
RoundedRectangle(cornerRadius: 20)
.strokeBorder(.secondary, lineWidth: 0.5).opacity(0.7)
)
.padding(8)
}
.background(.thinMaterial)
}
@ViewBuilder private func itemPreview(_ content: SharedContent) -> some View {
switch content {
case let .image(preview, _): imagePreview(preview)
case let .movie(preview, _, _): imagePreview(preview)
case let .url(linkPreview): imagePreview(linkPreview.image)
case let .data(cryptoFile):
previewArea {
Image(systemName: "doc.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30)
.foregroundColor(Color(uiColor: .tertiaryLabel))
.padding(.leading, 4)
Text(cryptoFile.filePath)
}
case .text: EmptyView()
}
}
@ViewBuilder private func imagePreview(_ img: String) -> some View {
if let img = UIImage(base64Encoded: img) {
previewArea {
Image(uiImage: img)
.resizable()
.scaledToFit()
.frame(minHeight: 40, maxHeight: 60)
}
} else {
EmptyView()
}
}
@ViewBuilder private func previewArea<V: View>(@ViewBuilder content: @escaping () -> V) -> some View {
HStack(alignment: .center, spacing: 8) {
content()
Spacer()
}
.padding(.vertical, 1)
.frame(minHeight: 54)
.background {
switch colorScheme {
case .light: LightColorPaletteApp.sentMessage
case .dark: DarkColorPaletteApp.sentMessage
@unknown default: Color(.tertiarySystemBackground)
}
}
Divider()
}
private func loadingBar(progress: Double) -> some View {
VStack {
Text("Sending File")
ProgressView(value: progress)
}
.padding()
.background(Material.ultraThin)
}
private func profileImage(chatInfoId: ChatInfo.ID, systemFallback: String, size: Double) -> some View {
Group {
if let uiImage = model.profileImages[chatInfoId] {
Image(uiImage: uiImage).resizable()
} else {
Image(systemName: systemFallback).resizable()
}
}
.foregroundStyle(Color(.tertiaryLabel))
.frame(width: size, height: size)
.clipShape(RoundedRectangle(cornerRadius: size * 0.225, style: .continuous))
}
private func radioButton(selected: Bool) -> some View {
Image(systemName: selected ? "checkmark.circle.fill" : "circle")
.imageScale(.large)
.foregroundStyle(selected ? Color.accentColor : Color(.tertiaryLabel))
}
}
@@ -0,0 +1,46 @@
//
// ShareViewController.swift
// SimpleX SE
//
// Created by Levitating Pineapple on 08/07/2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import UIKit
import SwiftUI
import SimpleXChat
/// Extension Entry point
/// System will create this controller each time share sheet is invoked
/// using `NSExtensionPrincipalClass` in the info.plist
@objc(ShareViewController)
class ShareViewController: UIHostingController<ShareView> {
private let model = ShareModel()
// Assuming iOS continues to only allow single share sheet to be presented at once
static var isVisible: Bool = false
@objc init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(rootView: ShareView(model: model))
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) { fatalError() }
override func viewDidLoad() {
ShareModel.CompletionHandler.isEventLoopEnabled = false
model.setup(context: extensionContext!)
}
override func viewWillAppear(_ animated: Bool) {
logger.debug("ShareSheet will appear")
super.viewWillAppear(animated)
Self.isVisible = true
}
override func viewWillDisappear(_ animated: Bool) {
logger.debug("ShareSheet will dissappear")
super.viewWillDisappear(animated)
ShareModel.CompletionHandler.isEventLoopEnabled = false
Self.isVisible = false
}
}
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.chat.simplex.app</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)chat.simplex.app</string>
</array>
</dict>
</plist>
+222 -35
View File
@@ -178,7 +178,6 @@
64E972072881BB22008DBC02 /* CIGroupInvitationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64E972062881BB22008DBC02 /* CIGroupInvitationView.swift */; };
64EEB0F72C353F1C00972D62 /* ServersSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64EEB0F62C353F1C00972D62 /* ServersSummaryView.swift */; };
64F1CC3B28B39D8600CD1FB1 /* IncognitoHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */; };
8C05382E2B39887E006436DC /* VideoUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C05382D2B39887E006436DC /* VideoUtils.swift */; };
8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */; };
8C74C3E52C1B900600039E77 /* ThemeTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7E3CE32C0DEAC400BFF63A /* ThemeTypes.swift */; };
8C74C3E72C1B901900039E77 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C852B072C1086D100BA61E8 /* Color.swift */; };
@@ -194,9 +193,17 @@
8C9BC2652C240D5200875A27 /* ThemeModeEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C9BC2642C240D5100875A27 /* ThemeModeEditor.swift */; };
8CC4ED902BD7B8530078AEE8 /* CallAudioDeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */; };
8CC956EE2BC0041000412A11 /* NetworkObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC956ED2BC0041000412A11 /* NetworkObserver.swift */; };
CE1EB0E42C459A660099D896 /* ShareAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1EB0E32C459A660099D896 /* ShareAPI.swift */; };
CE2AD9CE2C452A4D00E844E3 /* ChatUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2AD9CD2C452A4D00E844E3 /* ChatUtils.swift */; };
CE3097FB2C4C0C9F00180898 /* ErrorAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3097FA2C4C0C9F00180898 /* ErrorAlert.swift */; };
CE38A29A2C3FCA54005ED185 /* ImageUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBD2859295711D700EC2CF4 /* ImageUtils.swift */; };
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = CE38A29B2C3FCD72005ED185 /* SwiftyGif */; };
CE984D4B2C36C5D500E3AEFF /* ChatItemClipShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE984D4A2C36C5D500E3AEFF /* ChatItemClipShape.swift */; };
CEDE70222C48FD9500233B1F /* SEChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEDE70212C48FD9500233B1F /* SEChatState.swift */; };
CEE723AA2C3BD3D70009AE93 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEE723A92C3BD3D70009AE93 /* ShareViewController.swift */; };
CEE723B12C3BD3D70009AE93 /* SimpleX SE.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = CEE723A72C3BD3D70009AE93 /* SimpleX SE.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
CEE723F02C3D25C70009AE93 /* ShareView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEE723EF2C3D25C70009AE93 /* ShareView.swift */; };
CEE723F22C3D25ED0009AE93 /* ShareModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEE723F12C3D25ED0009AE93 /* ShareModel.swift */; };
CEEA861D2C2ABCB50084E1EA /* ReverseList.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEA861C2C2ABCB50084E1EA /* ReverseList.swift */; };
D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; };
D72A9088294BD7A70047C86D /* NativeTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A9087294BD7A70047C86D /* NativeTextEditor.swift */; };
@@ -204,12 +211,13 @@
D741547A29AF90B00022400A /* PushKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547929AF90B00022400A /* PushKit.framework */; };
D77B92DC2952372200A5A1CC /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = D77B92DB2952372200A5A1CC /* SwiftyGif */; };
D7F0E33929964E7E0068AF69 /* LZString in Frameworks */ = {isa = PBXBuildFile; productRef = D7F0E33829964E7E0068AF69 /* LZString */; };
E50581002C3DDD7F009C3F71 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E50580FB2C3DDD7F009C3F71 /* libffi.a */; };
E50581012C3DDD7F009C3F71 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E50580FC2C3DDD7F009C3F71 /* libgmp.a */; };
E50581022C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E50580FD2C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN-ghc9.6.3.a */; };
E50581032C3DDD7F009C3F71 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E50580FE2C3DDD7F009C3F71 /* libgmpxx.a */; };
E50581042C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E50580FF2C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN.a */; };
E50581062C3DDD9D009C3F71 /* Yams in Frameworks */ = {isa = PBXBuildFile; productRef = E50581052C3DDD9D009C3F71 /* Yams */; };
E5DCF8D52C56F7EF007928CC /* libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5DCF8D02C56F7EF007928CC /* libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp-ghc9.6.3.a */; };
E5DCF8D62C56F7EF007928CC /* libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5DCF8D12C56F7EF007928CC /* libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp.a */; };
E5DCF8D72C56F7EF007928CC /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5DCF8D22C56F7EF007928CC /* libffi.a */; };
E5DCF8D82C56F7EF007928CC /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5DCF8D32C56F7EF007928CC /* libgmp.a */; };
E5DCF8D92C56F7EF007928CC /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5DCF8D42C56F7EF007928CC /* libgmpxx.a */; };
E5DCF8DB2C56FAC1007928CC /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -241,6 +249,20 @@
remoteGlobalIDString = 5CE2BA672845308900EC33A6;
remoteInfo = SimpleXChat;
};
CEE723AF2C3BD3D70009AE93 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5CA059BE279559F40002BEB4 /* Project object */;
proxyType = 1;
remoteGlobalIDString = CEE723A62C3BD3D70009AE93;
remoteInfo = "SimpleX SE";
};
CEE723D12C3C21C90009AE93 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5CA059BE279559F40002BEB4 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5CE2BA672845308900EC33A6;
remoteInfo = SimpleXChat;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -261,6 +283,7 @@
dstPath = "";
dstSubfolderSpec = 13;
files = (
CEE723B12C3BD3D70009AE93 /* SimpleX SE.appex in Embed App Extensions */,
5CE2BA9D284555F500EC33A6 /* SimpleX NSE.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
@@ -489,7 +512,6 @@
64E972062881BB22008DBC02 /* CIGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIGroupInvitationView.swift; sourceTree = "<group>"; };
64EEB0F62C353F1C00972D62 /* ServersSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServersSummaryView.swift; sourceTree = "<group>"; };
64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncognitoHelp.swift; sourceTree = "<group>"; };
8C05382D2B39887E006436DC /* VideoUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoUtils.swift; sourceTree = "<group>"; };
8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
8C74C3EB2C1B92A900039E77 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
8C74C3ED2C1B942300039E77 /* ChatWallpaper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatWallpaper.swift; sourceTree = "<group>"; };
@@ -504,17 +526,27 @@
8C9BC2642C240D5100875A27 /* ThemeModeEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeModeEditor.swift; sourceTree = "<group>"; };
8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallAudioDeviceManager.swift; sourceTree = "<group>"; };
8CC956ED2BC0041000412A11 /* NetworkObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkObserver.swift; sourceTree = "<group>"; };
CE1EB0E32C459A660099D896 /* ShareAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareAPI.swift; sourceTree = "<group>"; };
CE2AD9CD2C452A4D00E844E3 /* ChatUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatUtils.swift; sourceTree = "<group>"; };
CE3097FA2C4C0C9F00180898 /* ErrorAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorAlert.swift; sourceTree = "<group>"; };
CE984D4A2C36C5D500E3AEFF /* ChatItemClipShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemClipShape.swift; sourceTree = "<group>"; };
CEDE70212C48FD9500233B1F /* SEChatState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SEChatState.swift; sourceTree = "<group>"; };
CEE723A72C3BD3D70009AE93 /* SimpleX SE.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "SimpleX SE.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
CEE723A92C3BD3D70009AE93 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
CEE723AE2C3BD3D70009AE93 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
CEE723D42C3C21F50009AE93 /* SimpleX SE.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX SE.entitlements"; sourceTree = "<group>"; };
CEE723EF2C3D25C70009AE93 /* ShareView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareView.swift; sourceTree = "<group>"; };
CEE723F12C3D25ED0009AE93 /* ShareModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareModel.swift; sourceTree = "<group>"; };
CEEA861C2C2ABCB50084E1EA /* ReverseList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseList.swift; sourceTree = "<group>"; };
D72A9087294BD7A70047C86D /* NativeTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTextEditor.swift; sourceTree = "<group>"; };
D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; };
D7AA2C3429A936B400737B40 /* MediaEncryption.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; name = MediaEncryption.playground; path = Shared/MediaEncryption.playground; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
E50580FB2C3DDD7F009C3F71 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
E50580FC2C3DDD7F009C3F71 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
E50580FD2C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN-ghc9.6.3.a"; sourceTree = "<group>"; };
E50580FE2C3DDD7F009C3F71 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
E50580FF2C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN.a"; sourceTree = "<group>"; };
E5DCF8D02C56F7EF007928CC /* libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp-ghc9.6.3.a"; sourceTree = "<group>"; };
E5DCF8D12C56F7EF007928CC /* libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp.a"; sourceTree = "<group>"; };
E5DCF8D22C56F7EF007928CC /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
E5DCF8D32C56F7EF007928CC /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
E5DCF8D42C56F7EF007928CC /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -553,18 +585,26 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
E50581032C3DDD7F009C3F71 /* libgmpxx.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
E50581002C3DDD7F009C3F71 /* libffi.a in Frameworks */,
E50581012C3DDD7F009C3F71 /* libgmp.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
E50581022C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN-ghc9.6.3.a in Frameworks */,
E5DCF8D82C56F7EF007928CC /* libgmp.a in Frameworks */,
E50581062C3DDD9D009C3F71 /* Yams in Frameworks */,
E50581042C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN.a in Frameworks */,
E5DCF8D62C56F7EF007928CC /* libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp.a in Frameworks */,
E5DCF8D72C56F7EF007928CC /* libffi.a in Frameworks */,
E5DCF8D92C56F7EF007928CC /* libgmpxx.a in Frameworks */,
E5DCF8D52C56F7EF007928CC /* libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp-ghc9.6.3.a in Frameworks */,
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
E5DCF8DA2C56FABA007928CC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
E5DCF8DB2C56FAC1007928CC /* SimpleXChat.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -628,11 +668,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
E50580FB2C3DDD7F009C3F71 /* libffi.a */,
E50580FC2C3DDD7F009C3F71 /* libgmp.a */,
E50580FE2C3DDD7F009C3F71 /* libgmpxx.a */,
E50580FD2C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN-ghc9.6.3.a */,
E50580FF2C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN.a */,
E5DCF8D22C56F7EF007928CC /* libffi.a */,
E5DCF8D32C56F7EF007928CC /* libgmp.a */,
E5DCF8D42C56F7EF007928CC /* libgmpxx.a */,
E5DCF8D02C56F7EF007928CC /* libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp-ghc9.6.3.a */,
E5DCF8D12C56F7EF007928CC /* libHSsimplex-chat-6.0.0.2-B4oiZFZeYN0AY2321yyqdp.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -684,7 +724,6 @@
64466DCB29FFE3E800E3D48D /* MailView.swift */,
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */,
5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */,
8C05382D2B39887E006436DC /* VideoUtils.swift */,
8C7F8F0D2C19C0C100D16888 /* ViewModifiers.swift */,
8C74C3ED2C1B942300039E77 /* ChatWallpaper.swift */,
8C9BC2642C240D5100875A27 /* ThemeModeEditor.swift */,
@@ -703,6 +742,7 @@
5C764E5C279C70B7000C6508 /* Libraries */,
5CA059C2279559F40002BEB4 /* Shared */,
5CDCAD462818589900503DA2 /* SimpleX NSE */,
CEE723A82C3BD3D70009AE93 /* SimpleX SE */,
5CA059DA279559F40002BEB4 /* Tests iOS */,
5CE2BA692845308900EC33A6 /* SimpleXChat */,
5CA059CB279559F40002BEB4 /* Products */,
@@ -733,6 +773,7 @@
5CA059D7279559F40002BEB4 /* Tests iOS.xctest */,
5CDCAD452818589900503DA2 /* SimpleX NSE.appex */,
5CE2BA682845308900EC33A6 /* SimpleXChat.framework */,
CEE723A72C3BD3D70009AE93 /* SimpleX SE.appex */,
);
name = Products;
sourceTree = "<group>";
@@ -856,10 +897,12 @@
5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */,
5CDCAD7428188D2900503DA2 /* APITypes.swift */,
5C5E5D3C282447AB00B0488A /* CallTypes.swift */,
CE3097FA2C4C0C9F00180898 /* ErrorAlert.swift */,
5C9FD96A27A56D4D0075386C /* JSON.swift */,
5CDCAD7D2818941F00503DA2 /* API.swift */,
5CDCAD80281A7E2700503DA2 /* Notifications.swift */,
5CBD2859295711D700EC2CF4 /* ImageUtils.swift */,
CE2AD9CD2C452A4D00E844E3 /* ChatUtils.swift */,
64DAE1502809D9F5000DA960 /* FileUtils.swift */,
5C9D81182AA7A4F1001D49FD /* CryptoFile.swift */,
5C00168028C4FE760094D739 /* KeyChain.swift */,
@@ -974,6 +1017,20 @@
path = Theme;
sourceTree = "<group>";
};
CEE723A82C3BD3D70009AE93 /* SimpleX SE */ = {
isa = PBXGroup;
children = (
CEE723D42C3C21F50009AE93 /* SimpleX SE.entitlements */,
CEE723AE2C3BD3D70009AE93 /* Info.plist */,
CEDE70212C48FD9500233B1F /* SEChatState.swift */,
CE1EB0E32C459A660099D896 /* ShareAPI.swift */,
CEE723F12C3D25ED0009AE93 /* ShareModel.swift */,
CEE723EF2C3D25C70009AE93 /* ShareView.swift */,
CEE723A92C3BD3D70009AE93 /* ShareViewController.swift */,
);
path = "SimpleX SE";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -1005,6 +1062,7 @@
dependencies = (
5CE2BA6F2845308900EC33A6 /* PBXTargetDependency */,
5CE2BA9F284555F500EC33A6 /* PBXTargetDependency */,
CEE723B02C3BD3D70009AE93 /* PBXTargetDependency */,
);
name = "SimpleX (iOS)";
packageProductDependencies = (
@@ -1076,6 +1134,24 @@
productReference = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */;
productType = "com.apple.product-type.framework";
};
CEE723A62C3BD3D70009AE93 /* SimpleX SE */ = {
isa = PBXNativeTarget;
buildConfigurationList = CEE723B42C3BD3D70009AE93 /* Build configuration list for PBXNativeTarget "SimpleX SE" */;
buildPhases = (
CEE723A32C3BD3D70009AE93 /* Sources */,
CEE723A52C3BD3D70009AE93 /* Resources */,
E5DCF8DA2C56FABA007928CC /* Frameworks */,
);
buildRules = (
);
dependencies = (
CEE723D22C3C21C90009AE93 /* PBXTargetDependency */,
);
name = "SimpleX SE";
productName = "SimpleX SE";
productReference = CEE723A72C3BD3D70009AE93 /* SimpleX SE.appex */;
productType = "com.apple.product-type.app-extension";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -1083,7 +1159,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1330;
LastSwiftUpdateCheck = 1540;
LastUpgradeCheck = 1340;
ORGANIZATIONNAME = "SimpleX Chat";
TargetAttributes = {
@@ -1103,6 +1179,9 @@
CreatedOnToolsVersion = 13.3;
LastSwiftMigration = 1330;
};
CEE723A62C3BD3D70009AE93 = {
CreatedOnToolsVersion = 15.4;
};
};
};
buildConfigurationList = 5CA059C1279559F40002BEB4 /* Build configuration list for PBXProject "SimpleX" */;
@@ -1144,6 +1223,7 @@
5CA059C9279559F40002BEB4 /* SimpleX (iOS) */,
5CA059D6279559F40002BEB4 /* Tests iOS */,
5CDCAD442818589900503DA2 /* SimpleX NSE */,
CEE723A62C3BD3D70009AE93 /* SimpleX SE */,
5CE2BA672845308900EC33A6 /* SimpleXChat */,
);
};
@@ -1183,6 +1263,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
CEE723A52C3BD3D70009AE93 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -1299,7 +1386,6 @@
5C55A91F283AD0E400C4E99E /* CallManager.swift in Sources */,
5CFA59D12864782E00863A68 /* ChatArchiveView.swift in Sources */,
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */,
8C05382E2B39887E006436DC /* VideoUtils.swift in Sources */,
5CADE79C292131E900072E13 /* ContactPreferencesView.swift in Sources */,
5CB346E52868AA7F001FD2EF /* SuspendChat.swift in Sources */,
5C9C2DA52894777E00CC63B1 /* GroupProfileView.swift in Sources */,
@@ -1368,6 +1454,7 @@
buildActionMask = 2147483647;
files = (
5CF937202B24DE8C00E1D781 /* SharedFileSubscriber.swift in Sources */,
CE3097FB2C4C0C9F00180898 /* ErrorAlert.swift in Sources */,
5C00168128C4FE760094D739 /* KeyChain.swift in Sources */,
5CE2BA97284537A800EC33A6 /* dummy.m in Sources */,
5CE2BA922845340900EC33A6 /* FileUtils.swift in Sources */,
@@ -1384,10 +1471,23 @@
8C74C3E52C1B900600039E77 /* ThemeTypes.swift in Sources */,
5CE2BA8D284533A300EC33A6 /* CallTypes.swift in Sources */,
8C74C3E82C1B905B00039E77 /* ChatWallpaperTypes.swift in Sources */,
CE2AD9CE2C452A4D00E844E3 /* ChatUtils.swift in Sources */,
5CE2BA8E284533A300EC33A6 /* API.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
CEE723A32C3BD3D70009AE93 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CEDE70222C48FD9500233B1F /* SEChatState.swift in Sources */,
CEE723F02C3D25C70009AE93 /* ShareView.swift in Sources */,
CE1EB0E42C459A660099D896 /* ShareAPI.swift in Sources */,
CEE723F22C3D25ED0009AE93 /* ShareModel.swift in Sources */,
CEE723AA2C3BD3D70009AE93 /* ShareViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
@@ -1412,6 +1512,16 @@
target = 5CE2BA672845308900EC33A6 /* SimpleXChat */;
targetProxy = 5CE2BAA82845617C00EC33A6 /* PBXContainerItemProxy */;
};
CEE723B02C3BD3D70009AE93 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = CEE723A62C3BD3D70009AE93 /* SimpleX SE */;
targetProxy = CEE723AF2C3BD3D70009AE93 /* PBXContainerItemProxy */;
};
CEE723D22C3C21C90009AE93 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5CE2BA672845308900EC33A6 /* SimpleXChat */;
targetProxy = CEE723D12C3C21C90009AE93 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -1618,7 +1728,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 227;
CURRENT_PROJECT_VERSION = 228;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1667,7 +1777,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 227;
CURRENT_PROJECT_VERSION = 228;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1753,7 +1863,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 227;
CURRENT_PROJECT_VERSION = 228;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
@@ -1790,7 +1900,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 227;
CURRENT_PROJECT_VERSION = 228;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
@@ -1827,7 +1937,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 227;
CURRENT_PROJECT_VERSION = 228;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1878,7 +1988,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 227;
CURRENT_PROJECT_VERSION = 228;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1922,6 +2032,74 @@
};
name = Release;
};
CEE723B22C3BD3D70009AE93 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "SimpleX SE/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "SimpleX SE";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 SimpleX Chat. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
CEE723B32C3BD3D70009AE93 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "SimpleX SE/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "SimpleX SE";
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 SimpleX Chat. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -1970,6 +2148,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
CEE723B42C3BD3D70009AE93 /* Build configuration list for PBXNativeTarget "SimpleX SE" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CEE723B22C3BD3D70009AE93 /* Debug */,
CEE723B32C3BD3D70009AE93 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
@@ -1977,8 +2164,8 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/twostraws/CodeScanner";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 2.0.0;
kind = exactVersion;
version = 2.1.1;
};
};
8C73C1162C21E17B00892670 /* XCRemoteSwiftPackageReference "Yams" */ = {
@@ -2001,8 +2188,8 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/kirualex/SwiftyGif";
requirement = {
branch = master;
kind = branch;
kind = revision;
revision = 5e8619335d394901379c9add5c4c1c2f420b3800;
};
};
D7F0E33729964E7D0068AF69 /* XCRemoteSwiftPackageReference "lzstring-swift" */ = {
@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CEE723A62C3BD3D70009AE93"
BuildableName = "SimpleX SE.appex"
BlueprintName = "SimpleX SE"
ReferencedContainer = "container:SimpleX.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5CA059C9279559F40002BEB4"
BuildableName = "SimpleX.app"
BlueprintName = "SimpleX (iOS)"
ReferencedContainer = "container:SimpleX.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5CA059C9279559F40002BEB4"
BuildableName = "SimpleX.app"
BlueprintName = "SimpleX (iOS)"
ReferencedContainer = "container:SimpleX.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5CA059C9279559F40002BEB4"
BuildableName = "SimpleX.app"
BlueprintName = "SimpleX (iOS)"
ReferencedContainer = "container:SimpleX.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+18 -10
View File
@@ -117,10 +117,10 @@ public func sendSimpleXCmd(_ cmd: ChatCommand, _ ctrl: chat_ctrl? = nil) -> Chat
}
// in microseconds
let MESSAGE_TIMEOUT: Int32 = 15_000_000
public let MESSAGE_TIMEOUT: Int32 = 15_000_000
public func recvSimpleXMsg(_ ctrl: chat_ctrl? = nil) -> ChatResponse? {
if let cjson = chat_recv_msg_wait(ctrl ?? getChatCtrl(), MESSAGE_TIMEOUT) {
public func recvSimpleXMsg(_ ctrl: chat_ctrl? = nil, messageTimeout: Int32 = MESSAGE_TIMEOUT) -> ChatResponse? {
if let cjson = chat_recv_msg_wait(ctrl ?? getChatCtrl(), messageTimeout) {
let s = fromCString(cjson)
return s == "" ? nil : chatResponse(s)
}
@@ -205,7 +205,7 @@ public func chatResponse(_ s: String) -> ChatResponse {
if let chatData = try? parseChatData(jChat) {
return chatData
}
return ChatData.invalidJSON(prettyJSON(jChat) ?? "")
return ChatData.invalidJSON(serializeJSON(jChat, options: .prettyPrinted) ?? "")
}
return .apiChats(user: user, chats: chats)
}
@@ -218,15 +218,15 @@ public func chatResponse(_ s: String) -> ChatResponse {
}
} else if type == "chatCmdError" {
if let jError = jResp["chatCmdError"] as? NSDictionary {
return .chatCmdError(user_: decodeUser_(jError), chatError: .invalidJSON(json: prettyJSON(jError) ?? ""))
return .chatCmdError(user_: decodeUser_(jError), chatError: .invalidJSON(json: errorJson(jError) ?? ""))
}
} else if type == "chatError" {
if let jError = jResp["chatError"] as? NSDictionary {
return .chatError(user_: decodeUser_(jError), chatError: .invalidJSON(json: prettyJSON(jError) ?? ""))
return .chatError(user_: decodeUser_(jError), chatError: .invalidJSON(json: errorJson(jError) ?? ""))
}
}
}
json = prettyJSON(j)
json = serializeJSON(j, options: .prettyPrinted)
}
return ChatResponse.response(type: type ?? "invalid", json: json ?? s)
}
@@ -239,6 +239,14 @@ private func decodeUser_(_ jDict: NSDictionary) -> UserRef? {
}
}
private func errorJson(_ jDict: NSDictionary) -> String? {
if let chatError = jDict["chatError"] {
serializeJSON(chatError)
} else {
serializeJSON(jDict)
}
}
func parseChatData(_ jChat: Any) throws -> ChatData {
let jChatDict = jChat as! NSDictionary
let chatInfo: ChatInfo = try decodeObject(jChatDict["chatInfo"]!)
@@ -251,7 +259,7 @@ func parseChatData(_ jChat: Any) throws -> ChatData {
return ChatItem.invalidJSON(
chatDir: decodeProperty(jCI, "chatDir"),
meta: decodeProperty(jCI, "meta"),
json: prettyJSON(jCI) ?? ""
json: serializeJSON(jCI, options: .prettyPrinted) ?? ""
)
}
return ChatData(chatInfo: chatInfo, chatItems: chatItems, chatStats: chatStats)
@@ -268,8 +276,8 @@ func decodeProperty<T: Decodable>(_ obj: Any, _ prop: NSString) -> T? {
return nil
}
func prettyJSON(_ obj: Any) -> String? {
if let d = try? JSONSerialization.data(withJSONObject: obj, options: .prettyPrinted) {
func serializeJSON(_ obj: Any, options: JSONSerialization.WritingOptions = []) -> String? {
if let d = try? JSONSerialization.data(withJSONObject: obj, options: options) {
return String(decoding: d, as: UTF8.self)
}
return nil
+43 -23
View File
@@ -26,7 +26,8 @@ public enum ChatCommand {
case apiMuteUser(userId: Int64)
case apiUnmuteUser(userId: Int64)
case apiDeleteUser(userId: Int64, delSMPQueues: Bool, viewPwd: String?)
case startChat(mainApp: Bool)
case startChat(mainApp: Bool, enableSndFiles: Bool)
case checkChatRunning
case apiStopChat
case apiActivateChat(restoreChat: Bool)
case apiSuspendChat(timeoutMicroseconds: Int)
@@ -146,6 +147,7 @@ public enum ChatCommand {
case apiStandaloneFileInfo(url: String)
// misc
case showVersion
case getAgentSubsTotal(userId: Int64)
case getAgentServersSummary(userId: Int64)
case resetAgentServersStats
case string(String)
@@ -171,7 +173,8 @@ public enum ChatCommand {
case let .apiMuteUser(userId): return "/_mute user \(userId)"
case let .apiUnmuteUser(userId): return "/_unmute user \(userId)"
case let .apiDeleteUser(userId, delSMPQueues, viewPwd): return "/_delete user \(userId) del_smp=\(onOff(delSMPQueues))\(maybePwd(viewPwd))"
case let .startChat(mainApp): return "/_start main=\(onOff(mainApp))"
case let .startChat(mainApp, enableSndFiles): return "/_start main=\(onOff(mainApp)) snd_files=\(onOff(enableSndFiles))"
case .checkChatRunning: return "/_check running"
case .apiStopChat: return "/_stop"
case let .apiActivateChat(restore): return "/_app activate restore=\(onOff(restore))"
case let .apiSuspendChat(timeoutMicroseconds): return "/_app suspend \(timeoutMicroseconds)"
@@ -309,6 +312,7 @@ public enum ChatCommand {
case let .apiDownloadStandaloneFile(userId, link, file): return "/_download \(userId) \(link) \(file.filePath)"
case let .apiStandaloneFileInfo(link): return "/_download info \(link)"
case .showVersion: return "/version"
case let .getAgentSubsTotal(userId): return "/get subs total \(userId)"
case let .getAgentServersSummary(userId): return "/get servers summary \(userId)"
case .resetAgentServersStats: return "/reset servers stats"
case let .string(str): return str
@@ -332,6 +336,7 @@ public enum ChatCommand {
case .apiUnmuteUser: return "apiUnmuteUser"
case .apiDeleteUser: return "apiDeleteUser"
case .startChat: return "startChat"
case .checkChatRunning: return "checkChatRunning"
case .apiStopChat: return "apiStopChat"
case .apiActivateChat: return "apiActivateChat"
case .apiSuspendChat: return "apiSuspendChat"
@@ -447,6 +452,7 @@ public enum ChatCommand {
case .apiDownloadStandaloneFile: return "apiDownloadStandaloneFile"
case .apiStandaloneFileInfo: return "apiStandaloneFileInfo"
case .showVersion: return "showVersion"
case .getAgentSubsTotal: return "getAgentSubsTotal"
case .getAgentServersSummary: return "getAgentServersSummary"
case .resetAgentServersStats: return "resetAgentServersStats"
case .string: return "console command"
@@ -575,6 +581,7 @@ public enum ChatResponse: Decodable, Error {
case userContactLinkDeleted(user: User)
case contactConnected(user: UserRef, contact: Contact, userCustomProfile: Profile?)
case contactConnecting(user: UserRef, contact: Contact)
case contactSndReady(user: UserRef, contact: Contact)
case receivedContactRequest(user: UserRef, contactRequest: UserContactRequest)
case acceptingContactRequest(user: UserRef, contact: Contact)
case contactRequestRejected(user: UserRef)
@@ -661,7 +668,7 @@ public enum ChatResponse: Decodable, Error {
case callInvitations(callInvitations: [RcvCallInvitation])
case ntfTokenStatus(status: NtfTknStatus)
case ntfToken(token: DeviceToken, status: NtfTknStatus, ntfMode: NotificationsMode, ntfServer: String)
case ntfMessages(user_: User?, connEntity_: ConnectionEntity?, msgTs: Date?, ntfMessages: [NtfMsgInfo])
case ntfMessages(user_: User?, connEntity_: ConnectionEntity?, msgTs: Date?, ntfMessage_: NtfMsgInfo?)
case ntfMessage(user: UserRef, connEntity: ConnectionEntity, ntfMessage: NtfMsgInfo)
case contactConnectionDeleted(user: UserRef, connection: PendingContactConnection)
case contactDisabled(user: UserRef, contact: Contact)
@@ -677,6 +684,7 @@ public enum ChatResponse: Decodable, Error {
// misc
case versionInfo(versionInfo: CoreVersionInfo, chatMigrations: [UpMigration], agentMigrations: [UpMigration])
case cmdOk(user: UserRef?)
case agentSubsTotal(user: UserRef, subsTotal: SMPServerSubs, hasSession: Bool)
case agentServersSummary(user: UserRef, serversSummary: PresentedServersSummary)
case agentSubsSummary(user: UserRef, subsSummary: SMPServerSubs)
case chatCmdError(user_: UserRef?, chatError: ChatError)
@@ -742,6 +750,7 @@ public enum ChatResponse: Decodable, Error {
case .userContactLinkDeleted: return "userContactLinkDeleted"
case .contactConnected: return "contactConnected"
case .contactConnecting: return "contactConnecting"
case .contactSndReady: return "contactSndReady"
case .receivedContactRequest: return "receivedContactRequest"
case .acceptingContactRequest: return "acceptingContactRequest"
case .contactRequestRejected: return "contactRequestRejected"
@@ -837,6 +846,7 @@ public enum ChatResponse: Decodable, Error {
case .contactPQEnabled: return "contactPQEnabled"
case .versionInfo: return "versionInfo"
case .cmdOk: return "cmdOk"
case .agentSubsTotal: return "agentSubsTotal"
case .agentServersSummary: return "agentServersSummary"
case .agentSubsSummary: return "agentSubsSummary"
case .chatCmdError: return "chatCmdError"
@@ -907,6 +917,7 @@ public enum ChatResponse: Decodable, Error {
case .userContactLinkDeleted: return noDetails
case let .contactConnected(u, contact, _): return withUser(u, String(describing: contact))
case let .contactConnecting(u, contact): return withUser(u, String(describing: contact))
case let .contactSndReady(u, contact): return withUser(u, String(describing: contact))
case let .receivedContactRequest(u, contactRequest): return withUser(u, String(describing: contactRequest))
case let .acceptingContactRequest(u, contact): return withUser(u, String(describing: contact))
case .contactRequestRejected: return noDetails
@@ -1002,6 +1013,7 @@ public enum ChatResponse: Decodable, Error {
case let .contactPQEnabled(u, contact, pqEnabled): return withUser(u, "contact: \(String(describing: contact))\npqEnabled: \(pqEnabled)")
case let .versionInfo(versionInfo, chatMigrations, agentMigrations): return "\(String(describing: versionInfo))\n\nchat migrations: \(chatMigrations.map(\.upName))\n\nagent migrations: \(agentMigrations.map(\.upName))"
case .cmdOk: return noDetails
case let .agentSubsTotal(u, subsTotal, hasSession): return withUser(u, "subsTotal: \(String(describing: subsTotal))\nhasSession: \(hasSession)")
case let .agentServersSummary(u, serversSummary): return withUser(u, String(describing: serversSummary))
case let .agentSubsSummary(u, subsSummary): return withUser(u, String(describing: subsSummary))
case let .chatCmdError(u, chatError): return withUser(u, String(describing: chatError))
@@ -1228,7 +1240,7 @@ public struct ProtocolTestFailure: Decodable, Error, Equatable {
public var localizedDescription: String {
let err = String.localizedStringWithFormat(NSLocalizedString("Test failed at step %@.", comment: "server test failure"), testStep.text)
switch testError {
case .SMP(.AUTH):
case .SMP(_, .AUTH):
return err + " " + NSLocalizedString("Server requires authorization to create queues, check password", comment: "server test error")
case .XFTP(.AUTH):
return err + " " + NSLocalizedString("Server requires authorization to upload, check password", comment: "server test error")
@@ -1287,42 +1299,32 @@ public struct NetCfg: Codable, Equatable, Hashable {
var socksMode: SocksMode = .always
public var hostMode: HostMode = .publicHost
public var requiredHostMode = true
public var sessionMode: TransportSessionMode
public var smpProxyMode: SMPProxyMode = .never
public var smpProxyFallback: SMPProxyFallback = .allow
public var sessionMode = TransportSessionMode.user
public var smpProxyMode: SMPProxyMode = .unknown
public var smpProxyFallback: SMPProxyFallback = .allowProtected
public var tcpConnectTimeout: Int // microseconds
public var tcpTimeout: Int // microseconds
public var tcpTimeoutPerKb: Int // microseconds
public var rcvConcurrency: Int // pool size
public var tcpKeepAlive: KeepAliveOpts?
public var tcpKeepAlive: KeepAliveOpts? = KeepAliveOpts.defaults
public var smpPingInterval: Int // microseconds
public var smpPingCount: Int // times
public var logTLSErrors: Bool
public var smpPingCount: Int = 3 // times
public var logTLSErrors: Bool = false
public static let defaults: NetCfg = NetCfg(
socksProxy: nil,
sessionMode: TransportSessionMode.user,
tcpConnectTimeout: 25_000_000,
tcpTimeout: 15_000_000,
tcpTimeoutPerKb: 10_000,
rcvConcurrency: 12,
tcpKeepAlive: KeepAliveOpts.defaults,
smpPingInterval: 1200_000_000,
smpPingCount: 3,
logTLSErrors: false
smpPingInterval: 1200_000_000
)
public static let proxyDefaults: NetCfg = NetCfg(
socksProxy: nil,
sessionMode: TransportSessionMode.user,
tcpConnectTimeout: 35_000_000,
tcpTimeout: 20_000_000,
tcpTimeoutPerKb: 15_000,
rcvConcurrency: 8,
tcpKeepAlive: KeepAliveOpts.defaults,
smpPingInterval: 1200_000_000,
smpPingCount: 3,
logTLSErrors: false
smpPingInterval: 1200_000_000
)
public var enableKeepAlive: Bool { tcpKeepAlive != nil }
@@ -1897,7 +1899,7 @@ public enum SQLiteError: Decodable, Hashable {
public enum AgentErrorType: Decodable, Hashable {
case CMD(cmdErr: CommandErrorType)
case CONN(connErr: ConnectionErrorType)
case SMP(smpErr: ProtocolErrorType)
case SMP(serverAddress: String, smpErr: ProtocolErrorType)
case NTF(ntfErr: ProtocolErrorType)
case XFTP(xftpErr: XFTPErrorType)
case PROXY(proxyServer: String, relayServer: String, proxyErr: ProxyClientError)
@@ -2097,6 +2099,7 @@ public struct AppSettings: Codable, Equatable, Hashable {
public var privacyShowChatPreviews: Bool? = nil
public var privacySaveLastDraft: Bool? = nil
public var privacyProtectScreen: Bool? = nil
public var privacyMediaBlurRadius: Int? = nil
public var notificationMode: AppSettingsNotificationMode? = nil
public var notificationPreviewMode: NotificationPreviewMode? = nil
public var webrtcPolicyRelay: Bool? = nil
@@ -2126,6 +2129,7 @@ public struct AppSettings: Codable, Equatable, Hashable {
if privacyShowChatPreviews != def.privacyShowChatPreviews { empty.privacyShowChatPreviews = privacyShowChatPreviews }
if privacySaveLastDraft != def.privacySaveLastDraft { empty.privacySaveLastDraft = privacySaveLastDraft }
if privacyProtectScreen != def.privacyProtectScreen { empty.privacyProtectScreen = privacyProtectScreen }
if privacyMediaBlurRadius != def.privacyMediaBlurRadius { empty.privacyMediaBlurRadius = privacyMediaBlurRadius }
if notificationMode != def.notificationMode { empty.notificationMode = notificationMode }
if notificationPreviewMode != def.notificationPreviewMode { empty.notificationPreviewMode = notificationPreviewMode }
if webrtcPolicyRelay != def.webrtcPolicyRelay { empty.webrtcPolicyRelay = webrtcPolicyRelay }
@@ -2156,6 +2160,7 @@ public struct AppSettings: Codable, Equatable, Hashable {
privacyShowChatPreviews: true,
privacySaveLastDraft: true,
privacyProtectScreen: false,
privacyMediaBlurRadius: 0,
notificationMode: AppSettingsNotificationMode.instant,
notificationPreviewMode: NotificationPreviewMode.message,
webrtcPolicyRelay: true,
@@ -2331,6 +2336,8 @@ public struct ServerSessions: Codable {
ssErrors: 0,
ssConnecting: 0
)
public var hasSess: Bool { ssConnected > 0 }
}
public struct SMPServerSubs: Codable {
@@ -2384,6 +2391,10 @@ public struct AgentSMPServerStatsData: Codable {
public var _connSubAttempts: Int
public var _connSubIgnored: Int
public var _connSubErrs: Int
public var _ntfKey: Int
public var _ntfKeyAttempts: Int
public var _ntfKeyDeleted: Int
public var _ntfKeyDeleteAttempts: Int
}
public struct XFTPServersSummary: Codable {
@@ -2423,3 +2434,12 @@ public struct AgentXFTPServerStatsData: Codable {
public var _deleteAttempts: Int
public var _deleteErrs: Int
}
public struct AgentNtfServerStatsData: Codable {
public var _ntfCreated: Int
public var _ntfCreateAttempts: Int
public var _ntfChecked: Int
public var _ntfCheckAttempts: Int
public var _ntfDeleted: Int
public var _ntfDelAttempts: Int
}
+12
View File
@@ -13,6 +13,7 @@ public let appSuspendTimeout: Int = 15 // seconds
let GROUP_DEFAULT_APP_STATE = "appState"
let GROUP_DEFAULT_NSE_STATE = "nseState"
let GROUP_DEFAULT_SE_STATE = "seState"
let GROUP_DEFAULT_DB_CONTAINER = "dbContainer"
public let GROUP_DEFAULT_CHAT_LAST_START = "chatLastStart"
public let GROUP_DEFAULT_CHAT_LAST_BACKGROUND_RUN = "chatLastBackgroundRun"
@@ -136,6 +137,11 @@ public enum NSEState: String, Codable {
}
}
public enum SEState: String, Codable {
case inactive
case sendingMessage
}
public enum DBContainer: String {
case documents
case group
@@ -155,6 +161,12 @@ public let nseStateGroupDefault = EnumDefault<NSEState>(
withDefault: .suspended // so that NSE that was never launched does not delay the app from resuming
)
public let seStateGroupDefault = EnumDefault<SEState>(
defaults: groupDefaults,
forKey: GROUP_DEFAULT_SE_STATE,
withDefault: .inactive
)
// inactive app states do not include "stopped" state
public func allowBackgroundRefresh() -> Bool {
appStateGroupDefault.get().inactive && nseStateGroupDefault.get().inactive
+26 -3
View File
@@ -1463,7 +1463,7 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat, Hashable {
)
}
public struct ChatData: Decodable, Identifiable, Hashable {
public struct ChatData: Decodable, Identifiable, Hashable, ChatLike {
public var chatInfo: ChatInfo
public var chatItems: [ChatItem]
public var chatStats: ChatStats
@@ -1512,10 +1512,11 @@ public struct Contact: Identifiable, Decodable, NamedChat, Hashable {
public var id: ChatId { get { "@\(contactId)" } }
public var apiId: Int64 { get { contactId } }
public var ready: Bool { get { activeConn?.connStatus == .ready } }
public var sndReady: Bool { get { ready || activeConn?.connStatus == .sndReady } }
public var active: Bool { get { contactStatus == .active } }
public var sendMsgEnabled: Bool { get {
(
ready
sndReady
&& active
&& !(activeConn?.connectionStats?.ratchetSyncSendProhibited ?? false)
&& !(activeConn?.connDisabled ?? true)
@@ -1824,7 +1825,7 @@ public enum ConnStatus: String, Decodable, Hashable {
case .joined: return false
case .requested: return true
case .accepted: return true
case .sndReady: return false
case .sndReady: return nil
case .ready: return nil
case .deleted: return nil
}
@@ -3293,6 +3294,28 @@ public struct CIFile: Decodable, Hashable {
}
}
}
public var showStatusIconInSmallView: Bool {
get {
switch fileStatus {
case .sndStored: fileProtocol != .local
case .sndTransfer: true
case .sndComplete: false
case .sndCancelled: true
case .sndError: true
case .sndWarning: true
case .rcvInvitation: false
case .rcvAccepted: true
case .rcvTransfer: true
case .rcvAborted: true
case .rcvCancelled: true
case .rcvComplete: false
case .rcvError: true
case .rcvWarning: true
case .invalid: true
}
}
}
}
public struct CryptoFile: Codable, Hashable {
+62
View File
@@ -0,0 +1,62 @@
//
// ChatUtils.swift
// SimpleXChat
//
// Created by Levitating Pineapple on 15/07/2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import Foundation
public protocol ChatLike {
var chatInfo: ChatInfo { get}
var chatItems: [ChatItem] { get }
var chatStats: ChatStats { get }
}
public func filterChatsToForwardTo<C: ChatLike>(chats: [C]) -> [C] {
var filteredChats = chats.filter { c in
c.chatInfo.chatType != .local && canForwardToChat(c.chatInfo)
}
if let privateNotes = chats.first(where: { $0.chatInfo.chatType == .local }) {
filteredChats.insert(privateNotes, at: 0)
}
return filteredChats
}
public func foundChat(_ chat: ChatLike, _ searchStr: String) -> Bool {
let cInfo = chat.chatInfo
return switch cInfo {
case let .direct(contact):
viewNameContains(cInfo, searchStr) ||
contact.profile.displayName.localizedLowercase.contains(searchStr) ||
contact.fullName.localizedLowercase.contains(searchStr)
default:
viewNameContains(cInfo, searchStr)
}
func viewNameContains(_ cInfo: ChatInfo, _ s: String) -> Bool {
cInfo.chatViewName.localizedLowercase.contains(s)
}
}
private func canForwardToChat(_ cInfo: ChatInfo) -> Bool {
switch cInfo {
case let .direct(contact): contact.sendMsgEnabled && !contact.nextSendGrpInv
case let .group(groupInfo): groupInfo.sendMsgEnabled
case let .local(noteFolder): noteFolder.sendMsgEnabled
case .contactRequest: false
case .contactConnection: false
case .invalidJSON: false
}
}
public func chatIconName(_ cInfo: ChatInfo) -> String {
switch cInfo {
case .direct: "person.crop.circle.fill"
case .group: "person.2.circle.fill"
case .local: "folder.circle.fill"
case .contactRequest: "person.crop.circle.fill"
default: "circle.fill"
}
}
+159
View File
@@ -0,0 +1,159 @@
//
// ErrorAlert.swift
// SimpleXChat
//
// Created by Levitating Pineapple on 20/07/2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
public struct ErrorAlert: Error {
public let title: LocalizedStringKey
public let message: LocalizedStringKey?
public let actions: Optional<() -> AnyView>
public init(
title: LocalizedStringKey,
message: LocalizedStringKey? = nil
) {
self.title = title
self.message = message
self.actions = nil
}
public init<A: View>(
title: LocalizedStringKey,
message: LocalizedStringKey? = nil,
@ViewBuilder actions: @escaping () -> A
) {
self.title = title
self.message = message
self.actions = { AnyView(actions()) }
}
public init(_ title: LocalizedStringKey) {
self = ErrorAlert(title: title)
}
public init(_ error: any Error) {
self = if let chatResponse = error as? ChatResponse {
ErrorAlert(chatResponse)
} else {
ErrorAlert(LocalizedStringKey(error.localizedDescription))
}
}
public init(_ chatError: ChatError) {
self = ErrorAlert("\(chatErrorString(chatError))")
}
public init(_ chatResponse: ChatResponse) {
self = if let networkErrorAlert = getNetworkErrorAlert(chatResponse) {
networkErrorAlert
} else {
ErrorAlert("\(responseError(chatResponse))")
}
}
}
extension LocalizedStringKey: @unchecked Sendable { }
extension View {
/// Bridges ``ErrorAlert`` to the generic alert API.
/// - Parameters:
/// - errorAlert: Binding to the Error, which is rendered in the alert
/// - actions: View Builder containing action buttons.
/// System defaults to `Ok` dismiss error action, when no actions are provided.
/// System implicitly adds `Cancel` action, if a destructive action is present
///
/// - Returns: View, which displays ErrorAlert?, when set.
@ViewBuilder public func alert<A: View>(
_ errorAlert: Binding<ErrorAlert?>,
@ViewBuilder actions: (ErrorAlert) -> A = { _ in EmptyView() }
) -> some View {
if let alert = errorAlert.wrappedValue {
self.alert(
alert.title,
isPresented: Binding<Bool>(
get: { errorAlert.wrappedValue != nil },
set: { if !$0 { errorAlert.wrappedValue = nil } }
),
actions: {
if let actions_ = alert.actions {
actions_()
} else {
actions(alert)
}
},
message: {
if let message = alert.message { Text(message) }
}
)
} else { self }
}
}
public func getNetworkErrorAlert(_ r: ChatResponse) -> ErrorAlert? {
switch r {
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TIMEOUT))):
return ErrorAlert(title: "Connection timeout", message: "Please check your network connection with \(serverHostname(addr)) and try again.")
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .NETWORK))):
return ErrorAlert(title: "Connection error", message: "Please check your network connection with \(serverHostname(addr)) and try again.")
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .HOST))):
return ErrorAlert(title: "Connection error", message: "Server address is incompatible with network settings: \(serverHostname(addr)).")
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TRANSPORT(.version)))):
return ErrorAlert(title: "Connection error", message: "Server version is incompatible with your app: \(serverHostname(addr)).")
case let .chatCmdError(_, .errorAgent(.SMP(serverAddress, .PROXY(proxyErr)))):
return smpProxyErrorAlert(proxyErr, serverAddress)
case let .chatCmdError(_, .errorAgent(.PROXY(proxyServer, relayServer, .protocolError(.PROXY(proxyErr))))):
return proxyDestinationErrorAlert(proxyErr, proxyServer, relayServer)
default:
return nil
}
}
private func smpProxyErrorAlert(_ proxyErr: ProxyError, _ srvAddr: String) -> ErrorAlert? {
switch proxyErr {
case .BROKER(brokerErr: .TIMEOUT):
return ErrorAlert(title: "Private routing error", message: "Error connecting to forwarding server \(serverHostname(srvAddr)). Please try later.")
case .BROKER(brokerErr: .NETWORK):
return ErrorAlert(title: "Private routing error", message: "Error connecting to forwarding server \(serverHostname(srvAddr)). Please try later.")
case .BROKER(brokerErr: .HOST):
return ErrorAlert(title: "Private routing error", message: "Forwarding server address is incompatible with network settings: \(serverHostname(srvAddr)).")
case .BROKER(brokerErr: .TRANSPORT(.version)):
return ErrorAlert(title: "Private routing error", message: "Forwarding server version is incompatible with network settings: \(serverHostname(srvAddr)).")
default:
return nil
}
}
private func proxyDestinationErrorAlert(_ proxyErr: ProxyError, _ proxyServer: String, _ relayServer: String) -> ErrorAlert? {
switch proxyErr {
case .BROKER(brokerErr: .TIMEOUT):
return ErrorAlert(title: "Private routing error", message: "Forwarding server \(serverHostname(proxyServer)) failed to connect to destination server \(serverHostname(relayServer)). Please try later.")
case .BROKER(brokerErr: .NETWORK):
return ErrorAlert(title: "Private routing error", message: "Forwarding server \(serverHostname(proxyServer)) failed to connect to destination server \(serverHostname(relayServer)). Please try later.")
case .NO_SESSION:
return ErrorAlert(title: "Private routing error", message: "Forwarding server \(serverHostname(proxyServer)) failed to connect to destination server \(serverHostname(relayServer)). Please try later.")
case .BROKER(brokerErr: .HOST):
return ErrorAlert(title: "Private routing error", message: "Destination server address of \(serverHostname(relayServer)) is incompatible with forwarding server \(serverHostname(proxyServer)) settings.")
case .BROKER(brokerErr: .TRANSPORT(.version)):
return ErrorAlert(title: "Private routing error", message: "Destination server version of \(serverHostname(relayServer)) is incompatible with forwarding server \(serverHostname(proxyServer)).")
default:
return nil
}
}
public func serverHostname(_ srv: String) -> String {
parseServerAddress(srv)?.hostnames.first ?? srv
}
public func mtrErrorDescription(_ err: MTRError) -> LocalizedStringKey {
switch err {
case let .noDown(dbMigrations):
"database version is newer than the app, but no down migration for: \(dbMigrations.joined(separator: ", "))"
case let .different(appMigration, dbMigration):
"different migration in the app/database: \(appMigration) / \(dbMigration)"
}
}
+80
View File
@@ -10,6 +10,7 @@ import Foundation
import SwiftUI
import AVKit
import SwiftyGif
import LinkPresentation
public func getLoadedFileSource(_ file: CIFile?) -> CryptoFile? {
if let file = file, file.loaded {
@@ -158,6 +159,34 @@ public func imageHasAlpha(_ img: UIImage) -> Bool {
return false
}
/// Reduces image size, while consuming less RAM
///
/// Used by ShareExtension to downsize large images
/// before passing them to regular image processing pipeline
/// to avoid exceeding 120MB memory
///
/// - Parameters:
/// - url: Location of the image data
/// - size: Maximum dimension (width or height)
/// - Returns: Downsampled image or `nil`, if the image can't be located
public func downsampleImage(at url: URL, to size: Int64) -> UIImage? {
autoreleasepool {
if let source = CGImageSourceCreateWithURL(url as CFURL, nil) {
CGImageSourceCreateThumbnailAtIndex(
source,
Int.zero,
[
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceShouldCacheImmediately: true,
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceThumbnailMaxPixelSize: String(size) as CFString
] as CFDictionary
)
.map { UIImage(cgImage: $0) }
} else { nil }
}
}
public func saveFileFromURL(_ url: URL) -> CryptoFile? {
let encrypted = privacyEncryptLocalFilesGroupDefault.get()
let savedFile: CryptoFile?
@@ -281,6 +310,21 @@ private func dropPrefix(_ s: String, _ prefix: String) -> String {
s.hasPrefix(prefix) ? String(s.dropFirst(prefix.count)) : s
}
public func makeVideoQualityLower(_ input: URL, outputUrl: URL) async -> Bool {
let asset: AVURLAsset = AVURLAsset(url: input, options: nil)
if let s = AVAssetExportSession(asset: asset, presetName: AVAssetExportPreset640x480) {
s.outputURL = outputUrl
s.outputFileType = .mp4
s.metadataItemFilter = AVMetadataItemFilter.forSharing()
await s.export()
if let err = s.error {
logger.error("Failed to export video with error: \(err)")
}
return s.status == .completed
}
return false
}
extension AVAsset {
public func generatePreview() -> (UIImage, Int)? {
let generator = AVAssetImageGenerator(asset: self)
@@ -348,3 +392,39 @@ extension UIImage {
}
}
}
public 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 {
logger.error("Could not load link preview image")
cb(nil)
}
}
}
public func getLinkPreview(for url: URL) async -> LinkPreview? {
await withCheckedContinuation { cont in
getLinkPreview(url: url) { cont.resume(returning: $0) }
}
}
+1 -1
View File
@@ -47,7 +47,7 @@ public func createContactConnectedNtf(_ user: any UserLike, _ contact: Contact)
hideContent ? NSLocalizedString("A new contact", comment: "notification title") : contact.displayName
),
body: String.localizedStringWithFormat(
NSLocalizedString("You can now send messages to %@", comment: "notification body"),
NSLocalizedString("You can now chat with %@", comment: "notification body"),
hideContent ? NSLocalizedString("this contact", comment: "notification title") : contact.chatViewName
),
targetContentIdentifier: contact.id,
@@ -12,6 +12,8 @@ public typealias AppSubscriber = SharedFileSubscriber<ProcessMessage<AppProcessM
public typealias NSESubscriber = SharedFileSubscriber<ProcessMessage<NSEProcessMessage>>
public typealias SESubscriber = SharedFileSubscriber<ProcessMessage<SEProcessMessage>>
public class SharedFileSubscriber<Message: Codable>: NSObject, NSFilePresenter {
var fileURL: URL
public var presentedItemURL: URL?
@@ -57,6 +59,8 @@ let appMessagesSharedFile = getGroupContainerDirectory().appendingPathComponent(
let nseMessagesSharedFile = getGroupContainerDirectory().appendingPathComponent("chat.simplex.app.SimpleX-NSE.messages", isDirectory: false)
let seMessagesSharedFile = getGroupContainerDirectory().appendingPathComponent("chat.simplex.app.SimpleX-SE.messages", isDirectory: false)
public struct ProcessMessage<Message: Codable>: Codable {
var createdAt: Date = Date.now
var message: Message
@@ -70,6 +74,10 @@ public enum NSEProcessMessage: Codable {
case state(state: NSEState)
}
public enum SEProcessMessage: Codable {
case state(state: SEState)
}
public func sendAppProcessMessage(_ message: AppProcessMessage) {
SharedFileSubscriber.notify(url: appMessagesSharedFile, message: ProcessMessage(message: message))
}
@@ -78,6 +86,10 @@ public func sendNSEProcessMessage(_ message: NSEProcessMessage) {
SharedFileSubscriber.notify(url: nseMessagesSharedFile, message: ProcessMessage(message: message))
}
public func sendSEProcessMessage(_ message: SEProcessMessage) {
SharedFileSubscriber.notify(url: seMessagesSharedFile, message: ProcessMessage(message: message))
}
public func appMessageSubscriber(onMessage: @escaping (AppProcessMessage) -> Void) -> AppSubscriber {
SharedFileSubscriber(fileURL: appMessagesSharedFile) { (msg: ProcessMessage<AppProcessMessage>) in
onMessage(msg.message)
@@ -90,6 +102,12 @@ public func nseMessageSubscriber(onMessage: @escaping (NSEProcessMessage) -> Voi
}
}
public func seMessageSubscriber(onMessage: @escaping (SEProcessMessage) -> Void) -> SESubscriber {
SharedFileSubscriber(fileURL: seMessagesSharedFile) { (msg: ProcessMessage<SEProcessMessage>) in
onMessage(msg.message)
}
}
public func sendAppState(_ state: AppState) {
sendAppProcessMessage(.state(state: state))
}
@@ -97,3 +115,7 @@ public func sendAppState(_ state: AppState) {
public func sendNSEState(_ state: NSEState) {
sendNSEProcessMessage(.state(state: state))
}
public func sendSEState(_ state: SEState) {
sendSEProcessMessage(.state(state: state))
}
+16
View File
@@ -39,3 +39,19 @@ void haskell_init_nse(void) {
char **pargv = argv;
hs_init_with_rtsopts(&argc, &pargv);
}
void haskell_init_se(void) {
int argc = 7;
char *argv[] = {
"simplex",
"+RTS", // requires `hs_init_with_rtsopts`
"-A1m", // chunk size for new allocations
"-H1m", // initial heap size
"-F0.5", // heap growth triggering GC
"-Fd1", // memory return
"-c", // compacting garbage collector
0
};
char **pargv = argv;
hs_init_with_rtsopts(&argc, &pargv);
}
+2
View File
@@ -13,4 +13,6 @@ void haskell_init(void);
void haskell_init_nse(void);
void haskell_init_se(void);
#endif /* hs_init_h */
+2 -5
View File
@@ -154,9 +154,6 @@
/* No comment provided by engineer. */
"%@ is verified" = "%@ е потвърдено";
/* No comment provided by engineer. */
"%@ servers" = "%@ сървъри";
/* No comment provided by engineer. */
"%@ uploaded" = "%@ качено";
@@ -644,7 +641,7 @@
/* rcv group event chat item */
"blocked %@" = "блокиран %@";
/* blocked chat item */
/* marked deleted chat item preview text */
"blocked by admin" = "блокиран от админ";
/* No comment provided by engineer. */
@@ -4297,7 +4294,7 @@
"You can make it visible to your SimpleX contacts via Settings." = "Можете да го направите видим за вашите контакти в SimpleX чрез Настройки.";
/* notification body */
"You can now send messages to %@" = "Вече можете да изпращате съобщения до %@";
"You can now chat with %@" = "Вече можете да изпращате съобщения до %@";
/* No comment provided by engineer. */
"You can set lock screen notification preview via settings." = "Можете да зададете визуализация на известията на заключен екран през настройките.";
+1 -4
View File
@@ -130,9 +130,6 @@
/* No comment provided by engineer. */
"%@ is verified" = "%@ je ověřený";
/* No comment provided by engineer. */
"%@ servers" = "%@ servery";
/* notification title */
"%@ wants to connect!" = "%@ se chce připojit!";
@@ -3439,7 +3436,7 @@
"You can hide or mute a user profile - swipe it to the right." = "Profil uživatele můžete skrýt nebo ztlumit - přejeďte prstem doprava.";
/* notification body */
"You can now send messages to %@" = "Nyní můžete posílat zprávy %@";
"You can now chat with %@" = "Nyní můžete posílat zprávy %@";
/* No comment provided by engineer. */
"You can set lock screen notification preview via settings." = "Náhled oznámení na zamykací obrazovce můžete změnit v nastavení.";
File diff suppressed because it is too large Load Diff
@@ -2,7 +2,7 @@
"CFBundleName" = "SimpleX";
/* Privacy - Camera Usage Description */
"NSCameraUsageDescription" = "SimpleX benötigt Zugriff auf die Kamera, um QR Codes für die Verbindung mit anderen Nutzern zu scannen und Videoanrufe durchzuführen.";
"NSCameraUsageDescription" = "SimpleX benötigt Zugriff auf die Kamera, um QR Codes für die Verbindung mit anderen Benutzern zu scannen und Videoanrufe durchzuführen.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "Face ID wird von SimpleX für die lokale Authentifizierung genutzt";
+2 -5
View File
@@ -154,9 +154,6 @@
/* No comment provided by engineer. */
"%@ is verified" = "%@ está verificado";
/* No comment provided by engineer. */
"%@ servers" = "Servidores %@";
/* No comment provided by engineer. */
"%@ uploaded" = "%@ subido";
@@ -650,7 +647,7 @@
/* rcv group event chat item */
"blocked %@" = "ha bloqueado a %@";
/* blocked chat item */
/* marked deleted chat item preview text */
"blocked by admin" = "bloqueado por administrador";
/* No comment provided by engineer. */
@@ -4417,7 +4414,7 @@
"You can make it visible to your SimpleX contacts via Settings." = "Puedes hacerlo visible para tus contactos de SimpleX en Configuración.";
/* notification body */
"You can now send messages to %@" = "Ya puedes enviar mensajes a %@";
"You can now chat with %@" = "Ya puedes enviar mensajes a %@";
/* No comment provided by engineer. */
"You can set lock screen notification preview via settings." = "Puedes configurar las notificaciones de la pantalla de bloqueo desde Configuración.";
+1 -4
View File
@@ -121,9 +121,6 @@
/* No comment provided by engineer. */
"%@ is verified" = "%@ on vahvistettu";
/* No comment provided by engineer. */
"%@ servers" = "%@ palvelimet";
/* notification title */
"%@ wants to connect!" = "%@ haluaa muodostaa yhteyden!";
@@ -3397,7 +3394,7 @@
"You can hide or mute a user profile - swipe it to the right." = "Voit piilottaa tai mykistää käyttäjäprofiilin pyyhkäisemällä sitä oikealle.";
/* notification body */
"You can now send messages to %@" = "Voit nyt lähettää viestejä %@:lle";
"You can now chat with %@" = "Voit nyt lähettää viestejä %@:lle";
/* No comment provided by engineer. */
"You can set lock screen notification preview via settings." = "Voit määrittää lukitusnäytön ilmoituksen esikatselun asetuksista.";
+2 -5
View File
@@ -154,9 +154,6 @@
/* No comment provided by engineer. */
"%@ is verified" = "%@ est vérifié·e";
/* No comment provided by engineer. */
"%@ servers" = "Serveurs %@";
/* No comment provided by engineer. */
"%@ uploaded" = "%@ envoyé";
@@ -650,7 +647,7 @@
/* rcv group event chat item */
"blocked %@" = "%@ bloqué";
/* blocked chat item */
/* marked deleted chat item preview text */
"blocked by admin" = "bloqué par l'administrateur";
/* No comment provided by engineer. */
@@ -4417,7 +4414,7 @@
"You can make it visible to your SimpleX contacts via Settings." = "Vous pouvez le rendre visible à vos contacts SimpleX via Paramètres.";
/* notification body */
"You can now send messages to %@" = "Vous pouvez maintenant envoyer des messages à %@";
"You can now chat with %@" = "Vous pouvez maintenant envoyer des messages à %@";
/* No comment provided by engineer. */
"You can set lock screen notification preview via settings." = "Vous pouvez configurer l'aperçu des notifications sur l'écran de verrouillage via les paramètres.";
+389 -5
View File
@@ -154,9 +154,6 @@
/* No comment provided by engineer. */
"%@ is verified" = "%@ ellenőrizve";
/* No comment provided by engineer. */
"%@ servers" = "%@ kiszolgáló";
/* No comment provided by engineer. */
"%@ uploaded" = "%@ feltöltve";
@@ -337,6 +334,9 @@
/* No comment provided by engineer. */
"above, then choose:" = "gombra fent, majd válassza ki:";
/* No comment provided by engineer. */
"Accent" = "Kiemelés";
/* accept contact request via notification
accept incoming call via notification */
"Accept" = "Elfogadás";
@@ -353,6 +353,12 @@
/* call status */
"accepted call" = "elfogadott hívás";
/* No comment provided by engineer. */
"Acknowledged" = "Nyugtázva";
/* No comment provided by engineer. */
"Acknowledgement errors" = "Nyugtázott hibák";
/* No comment provided by engineer. */
"Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." = "Cím hozzáadása a profilhoz, hogy az ismerősei megoszthassák másokkal. A profilfrissítés elküldésre kerül az ismerősei számára.";
@@ -377,6 +383,15 @@
/* No comment provided by engineer. */
"Add welcome message" = "Üdvözlő üzenet hozzáadása";
/* No comment provided by engineer. */
"Additional accent" = "További kiemelés";
/* No comment provided by engineer. */
"Additional accent 2" = "További kiemelés 2";
/* No comment provided by engineer. */
"Additional secondary" = "További másodlagos";
/* No comment provided by engineer. */
"Address" = "Cím";
@@ -398,6 +413,9 @@
/* No comment provided by engineer. */
"Advanced network settings" = "Speciális hálózati beállítások";
/* No comment provided by engineer. */
"Advanced settings" = "Haladó beállítások";
/* chat item text */
"agreeing encryption for %@…" = "titkosítás jóváhagyása %@ számára…";
@@ -413,6 +431,9 @@
/* No comment provided by engineer. */
"All data is erased when it is entered." = "A jelkód megadása után minden adat törlésre kerül.";
/* No comment provided by engineer. */
"All data is private to your device." = "Minden adat biztonságban van a készülékén.";
/* No comment provided by engineer. */
"All group members will remain connected." = "Minden csoporttag kapcsolódva marad.";
@@ -428,6 +449,9 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Minden új üzenet elrejtésre kerül tőle: %@!";
/* No comment provided by engineer. */
"All profiles" = "Minden profil";
/* No comment provided by engineer. */
"All your contacts will remain connected." = "Minden ismerős kapcsolódva marad.";
@@ -554,6 +578,9 @@
/* No comment provided by engineer. */
"Apply" = "Alkalmaz";
/* No comment provided by engineer. */
"Apply to" = "Alkalmazás erre";
/* No comment provided by engineer. */
"Archive and upload" = "Archiválás és feltöltés";
@@ -563,6 +590,9 @@
/* No comment provided by engineer. */
"Attach" = "Csatolás";
/* No comment provided by engineer. */
"attempts" = "próbálkozások";
/* No comment provided by engineer. */
"Audio & video calls" = "Hang- és videóhívások";
@@ -605,6 +635,9 @@
/* No comment provided by engineer. */
"Back" = "Vissza";
/* No comment provided by engineer. */
"Background" = "Háttér";
/* No comment provided by engineer. */
"Bad desktop address" = "Hibás számítógép cím";
@@ -626,6 +659,9 @@
/* No comment provided by engineer. */
"Better messages" = "Jobb üzenetek";
/* No comment provided by engineer. */
"Black" = "Fekete";
/* No comment provided by engineer. */
"Block" = "Blokkolás";
@@ -650,7 +686,7 @@
/* rcv group event chat item */
"blocked %@" = "letiltotta őt: %@";
/* blocked chat item */
/* marked deleted chat item preview text */
"blocked by admin" = "letiltva az admin által";
/* No comment provided by engineer. */
@@ -716,6 +752,9 @@
/* No comment provided by engineer. */
"Cannot access keychain to save database password" = "Nem lehet hozzáférni a kulcstartóhoz az adatbázis jelszavának mentéséhez";
/* No comment provided by engineer. */
"Cannot forward message" = "Nem lehet továbbítani az üzenetet";
/* No comment provided by engineer. */
"Cannot receive file" = "Nem lehet fogadni a fájlt";
@@ -774,6 +813,9 @@
/* No comment provided by engineer. */
"Chat archive" = "Csevegési archívum";
/* No comment provided by engineer. */
"Chat colors" = "Csevegés színei";
/* No comment provided by engineer. */
"Chat console" = "Csevegési konzol";
@@ -801,6 +843,9 @@
/* No comment provided by engineer. */
"Chat preferences" = "Csevegési beállítások";
/* No comment provided by engineer. */
"Chat theme" = "Csevegés témája";
/* No comment provided by engineer. */
"Chats" = "Csevegések";
@@ -819,6 +864,15 @@
/* No comment provided by engineer. */
"Choose from library" = "Választás a könyvtárból";
/* No comment provided by engineer. */
"Chunks deleted" = "Törölt fájltöredékek";
/* No comment provided by engineer. */
"Chunks downloaded" = "Letöltött fájltöredékek";
/* No comment provided by engineer. */
"Chunks uploaded" = "Feltöltött fájltöredékek";
/* No comment provided by engineer. */
"Clear" = "Kiürítés";
@@ -834,6 +888,9 @@
/* No comment provided by engineer. */
"Clear verification" = "Hitelesítés törlése";
/* No comment provided by engineer. */
"Color mode" = "Színmód";
/* No comment provided by engineer. */
"colored" = "színes";
@@ -846,6 +903,9 @@
/* No comment provided by engineer. */
"complete" = "befejezett";
/* No comment provided by engineer. */
"Completed" = "Elkészült";
/* No comment provided by engineer. */
"Configure ICE servers" = "ICE kiszolgálók beállítása";
@@ -915,18 +975,27 @@
/* No comment provided by engineer. */
"connected" = "kapcsolódva";
/* No comment provided by engineer. */
"Connected" = "Kapcsolódva";
/* No comment provided by engineer. */
"Connected desktop" = "Csatlakoztatott számítógép";
/* rcv group event chat item */
"connected directly" = "közvetlenül kapcsolódva";
/* No comment provided by engineer. */
"Connected servers" = "Kapcsolódott kiszolgálók";
/* No comment provided by engineer. */
"Connected to desktop" = "Kapcsolódva a számítógéphez";
/* No comment provided by engineer. */
"connecting" = "kapcsolódás";
/* No comment provided by engineer. */
"Connecting" = "Kapcsolódás";
/* No comment provided by engineer. */
"connecting (accepted)" = "kapcsolódás (elfogadva)";
@@ -975,9 +1044,15 @@
/* No comment provided by engineer. */
"Connection timeout" = "Kapcsolat időtúllépés";
/* No comment provided by engineer. */
"Connection with desktop stopped" = "A kapcsolat a számítógéppel megszakadt";
/* connection information */
"connection:%@" = "kapcsolat: %@";
/* No comment provided by engineer. */
"Connections" = "Kapcsolatok";
/* profile update event chat item */
"contact %@ changed to %@" = "%1$@ megváltoztatta a nevét erre: %2$@";
@@ -1020,6 +1095,9 @@
/* No comment provided by engineer. */
"Copy" = "Másolás";
/* No comment provided by engineer. */
"Copy error" = "Másolási hiba";
/* No comment provided by engineer. */
"Core version: v%@" = "Alapverziószám: v%@";
@@ -1065,6 +1143,9 @@
/* No comment provided by engineer. */
"Create your profile" = "Saját profil létrehozása";
/* No comment provided by engineer. */
"Created" = "Létrehozva";
/* No comment provided by engineer. */
"Created at" = "Létrehozva ekkor:";
@@ -1089,6 +1170,9 @@
/* No comment provided by engineer. */
"Current passphrase…" = "Jelenlegi jelmondat…";
/* No comment provided by engineer. */
"Current profile" = "Jelenlegi profil";
/* No comment provided by engineer. */
"Currently maximum supported file size is %@." = "Jelenleg a maximális támogatott fájlméret %@.";
@@ -1098,9 +1182,15 @@
/* No comment provided by engineer. */
"Custom time" = "Személyreszabott idő";
/* No comment provided by engineer. */
"Customize theme" = "Téma személyre szabása";
/* No comment provided by engineer. */
"Dark" = "Sötét";
/* No comment provided by engineer. */
"Dark mode colors" = "Sötét mód színei";
/* No comment provided by engineer. */
"Database downgrade" = "Visszatérés a korábbi adatbázis verzióra";
@@ -1170,6 +1260,9 @@
/* message decrypt error item */
"Decryption error" = "Titkosítás visszafejtési hiba";
/* No comment provided by engineer. */
"decryption errors" = "visszafejtési hibák";
/* pref value */
"default (%@)" = "alapértelmezett (%@)";
@@ -1296,6 +1389,9 @@
/* deleted chat item */
"deleted" = "törölve";
/* No comment provided by engineer. */
"Deleted" = "Törölve";
/* No comment provided by engineer. */
"Deleted at" = "Törölve ekkor:";
@@ -1308,6 +1404,9 @@
/* rcv group event chat item */
"deleted group" = "törölt csoport";
/* No comment provided by engineer. */
"Deletion errors" = "Törlési hibák";
/* No comment provided by engineer. */
"Delivery" = "Kézbesítés";
@@ -1332,6 +1431,12 @@
/* snd error text */
"Destination server error: %@" = "Célkiszolgáló hiba: %@";
/* No comment provided by engineer. */
"Detailed statistics" = "Részletes statisztikák";
/* No comment provided by engineer. */
"Details" = "Részletek";
/* No comment provided by engineer. */
"Develop" = "Fejlesztés";
@@ -1434,12 +1539,21 @@
/* chat item action */
"Download" = "Letöltés";
/* No comment provided by engineer. */
"Download errors" = "Letöltési hibák";
/* No comment provided by engineer. */
"Download failed" = "Sikertelen letöltés";
/* server test step */
"Download file" = "Fájl letöltése";
/* No comment provided by engineer. */
"Downloaded" = "Letöltve";
/* No comment provided by engineer. */
"Downloaded files" = "Letöltött fájlok";
/* No comment provided by engineer. */
"Downloading archive" = "Archívum letöltése";
@@ -1452,6 +1566,9 @@
/* integrity error chat item */
"duplicate message" = "duplikált üzenet";
/* No comment provided by engineer. */
"duplicates" = "duplikációk";
/* No comment provided by engineer. */
"Duration" = "Időtartam";
@@ -1710,6 +1827,9 @@
/* No comment provided by engineer. */
"Error exporting chat database" = "Hiba a csevegési adatbázis exportálásakor";
/* No comment provided by engineer. */
"Error exporting theme: %@" = "Hiba a téma exportálásakor: %@";
/* No comment provided by engineer. */
"Error importing chat database" = "Hiba a csevegési adatbázis importálásakor";
@@ -1725,9 +1845,18 @@
/* No comment provided by engineer. */
"Error receiving file" = "Hiba a fájl fogadásakor";
/* No comment provided by engineer. */
"Error reconnecting server" = "Hiba a kiszolgálóhoz való újrakapcsolódáskor";
/* No comment provided by engineer. */
"Error reconnecting servers" = "Hiba a kiszolgálókhoz való újrakapcsolódáskor";
/* No comment provided by engineer. */
"Error removing member" = "Hiba a tag eltávolításakor";
/* No comment provided by engineer. */
"Error resetting statistics" = "Hiba a statisztikák visszaállításakor";
/* No comment provided by engineer. */
"Error saving %@ servers" = "Hiba történt a %@ kiszolgálók mentése közben";
@@ -1807,6 +1936,9 @@
/* No comment provided by engineer. */
"Error: URL is invalid" = "Hiba: az URL érvénytelen";
/* No comment provided by engineer. */
"Errors" = "Hibák";
/* No comment provided by engineer. */
"Even when disabled in the conversation." = "Akkor is, ha le van tiltva a beszélgetésben.";
@@ -1819,12 +1951,18 @@
/* chat item action */
"Expand" = "Kibontás";
/* No comment provided by engineer. */
"expired" = "lejárt";
/* No comment provided by engineer. */
"Export database" = "Adatbázis exportálása";
/* No comment provided by engineer. */
"Export error:" = "Exportálási hiba:";
/* No comment provided by engineer. */
"Export theme" = "Téma exportálása";
/* No comment provided by engineer. */
"Exported database archive." = "Exportált adatbázis-archívum.";
@@ -1846,6 +1984,21 @@
/* No comment provided by engineer. */
"Favorite" = "Kedvenc";
/* No comment provided by engineer. */
"File error" = "Fájlhiba";
/* file error text */
"File not found - most likely file was deleted or cancelled." = "A fájl nem található - valószínűleg a fájlt törölték vagy visszavonták.";
/* file error text */
"File server error: %@" = "Fájlkiszolgáló hiba: %@";
/* No comment provided by engineer. */
"File status" = "Fájlállapot";
/* copied message info */
"File status: %@" = "Fájlállapot: %@";
/* No comment provided by engineer. */
"File will be deleted from servers." = "A fájl törölve lesz a kiszolgálóról.";
@@ -1960,6 +2113,12 @@
/* No comment provided by engineer. */
"GIFs and stickers" = "GIF-ek és matricák";
/* message preview */
"Good afternoon!" = "Jó napot!";
/* message preview */
"Good morning!" = "Jó reggelt!";
/* No comment provided by engineer. */
"Group" = "Csoport";
@@ -2137,6 +2296,9 @@
/* No comment provided by engineer. */
"Import failed" = "Sikertelen importálás";
/* No comment provided by engineer. */
"Import theme" = "Téma importálása";
/* No comment provided by engineer. */
"Importing archive" = "Archívum importálása";
@@ -2158,6 +2320,9 @@
/* No comment provided by engineer. */
"In-call sounds" = "Bejövő hívás csengőhangja";
/* No comment provided by engineer. */
"inactive" = "inaktív";
/* No comment provided by engineer. */
"Incognito" = "Inkognitó";
@@ -2221,6 +2386,9 @@
/* No comment provided by engineer. */
"Interface" = "Felület";
/* No comment provided by engineer. */
"Interface colors" = "Kezelőfelület színei";
/* invalid chat data */
"invalid chat" = "érvénytelen csevegés";
@@ -2473,6 +2641,9 @@
/* rcv group event chat item */
"member connected" = "kapcsolódott";
/* item status text */
"Member inactive" = "Inaktív tag";
/* No comment provided by engineer. */
"Member role will be changed to \"%@\". All group members will be notified." = "A tag szerepköre meg fog változni erre: „%@”. A csoport minden tagja értesítést kap róla.";
@@ -2482,6 +2653,9 @@
/* No comment provided by engineer. */
"Member will be removed from group - this cannot be undone!" = "A tag eltávolítása a csoportból - ez a művelet nem vonható vissza!";
/* No comment provided by engineer. */
"Menus" = "Menük";
/* item status text */
"Message delivery error" = "Üzenetkézbesítési hiba";
@@ -2494,6 +2668,12 @@
/* No comment provided by engineer. */
"Message draft" = "Üzenetvázlat";
/* item status text */
"Message forwarded" = "Továbbított üzenet";
/* item status description */
"Message may be delivered later if member becomes active." = "Az üzenet később is kézbesíthető, ha a tag aktívvá válik.";
/* No comment provided by engineer. */
"Message queue info" = "Üzenet-várakoztatási információ";
@@ -2518,6 +2698,12 @@
/* No comment provided by engineer. */
"Message source remains private." = "Az üzenet forrása titokban marad.";
/* No comment provided by engineer. */
"Message status" = "Üzenetállapot";
/* copied message info */
"Message status: %@" = "Üzenetállapot: %@";
/* No comment provided by engineer. */
"Message text" = "Üzenet szövege";
@@ -2533,6 +2719,12 @@
/* No comment provided by engineer. */
"Messages from %@ will be shown!" = "A(z) %@ által írt üzenetek megjelennek!";
/* No comment provided by engineer. */
"Messages received" = "Fogadott üzenetek";
/* No comment provided by engineer. */
"Messages sent" = "Elküldött üzenetek";
/* No comment provided by engineer. */
"Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." = "Az üzeneteket, fájlokat és hívásokat **végpontok közötti titkosítással**, sérülés utáni titkosság-védelemmel és -helyreállítással, továbbá visszautasítással védi.";
@@ -2698,6 +2890,9 @@
/* No comment provided by engineer. */
"No device token!" = "Nincs eszköztoken!";
/* item status description */
"No direct connection yet, message is forwarded by admin." = "Még nincs közvetlen kapcsolat, az üzenetet az admin továbbítja.";
/* No comment provided by engineer. */
"no e2e encryption" = "nincs e2e titkosítás";
@@ -2710,6 +2905,9 @@
/* No comment provided by engineer. */
"No history" = "Nincsenek előzmények";
/* No comment provided by engineer. */
"No info, try to reload" = "Nincs információ, próbálja meg újratölteni";
/* No comment provided by engineer. */
"No network connection" = "Nincs hálózati kapcsolat";
@@ -2835,6 +3033,9 @@
/* authentication reason */
"Open migration to another device" = "Átköltöztetés megkezdése egy másik eszközre";
/* No comment provided by engineer. */
"Open server settings" = "Kiszolgáló beállításainak megnyitása";
/* No comment provided by engineer. */
"Open Settings" = "Beállítások megnyitása";
@@ -2859,9 +3060,15 @@
/* No comment provided by engineer. */
"Or show this code" = "Vagy mutassa meg ezt a kódot";
/* No comment provided by engineer. */
"other" = "egyéb";
/* No comment provided by engineer. */
"Other" = "További";
/* No comment provided by engineer. */
"other errors" = "egyéb hibák";
/* member role */
"owner" = "tulajdonos";
@@ -2904,6 +3111,9 @@
/* No comment provided by engineer. */
"peer-to-peer" = "ponttól-pontig";
/* No comment provided by engineer. */
"Pending" = "Függő";
/* No comment provided by engineer. */
"People can connect to you only via the links you share." = "Az emberek csak az ön által megosztott hivatkozáson keresztül kapcsolódhatnak.";
@@ -2925,6 +3135,9 @@
/* No comment provided by engineer. */
"Please ask your contact to enable sending voice messages." = "Ismerős felkérése, hogy engedélyezze a hangüzenetek küldését.";
/* No comment provided by engineer. */
"Please check that mobile and desktop are connected to the same local network, and that desktop firewall allows the connection.\nPlease share any other issues with the developers." = "Ellenőrizze, hogy a mobil és az asztali számítógép ugyanahhoz a helyi hálózathoz csatlakozik-e, valamint az asztali számítógép tűzfalában engedélyezve van-e a kapcsolat.\nMinden további problémát osszon meg a fejlesztőkkel.";
/* No comment provided by engineer. */
"Please check that you used the correct link or ask your contact to send you another one." = "Ellenőrizze, hogy a megfelelő hivatkozást használta-e, vagy kérje meg ismerősét, hogy küldjön egy másikat.";
@@ -2982,6 +3195,9 @@
/* No comment provided by engineer. */
"Preview" = "Előnézet";
/* No comment provided by engineer. */
"Previously connected servers" = "Korábban kapcsolódott kiszolgálók";
/* No comment provided by engineer. */
"Privacy & security" = "Adatvédelem és biztonság";
@@ -3021,6 +3237,9 @@
/* No comment provided by engineer. */
"Profile password" = "Profiljelszó";
/* No comment provided by engineer. */
"Profile theme" = "Profiltéma";
/* No comment provided by engineer. */
"Profile update will be sent to your contacts." = "A profilfrissítés elküldésre került az ismerősök számára.";
@@ -3069,6 +3288,12 @@
/* No comment provided by engineer. */
"Protocol timeout per KB" = "Protokoll időkorlát KB-onként";
/* No comment provided by engineer. */
"Proxied" = "Proxyzott";
/* No comment provided by engineer. */
"Proxied servers" = "Proxyzott kiszolgálók";
/* No comment provided by engineer. */
"Push notifications" = "Push értesítések";
@@ -3111,6 +3336,9 @@
/* No comment provided by engineer. */
"Receipts are disabled" = "Üzenet kézbesítési jelentés letiltva";
/* No comment provided by engineer. */
"Receive errors" = "Üzenetfogadási hibák";
/* No comment provided by engineer. */
"received answer…" = "fogadott válasz…";
@@ -3129,6 +3357,15 @@
/* message info title */
"Received message" = "Fogadott üzenet";
/* No comment provided by engineer. */
"Received messages" = "Fogadott üzenetek";
/* No comment provided by engineer. */
"Received reply" = "Fogadott válasz";
/* No comment provided by engineer. */
"Received total" = "Összes fogadott";
/* No comment provided by engineer. */
"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "A fogadó cím egy másik kiszolgálóra változik. A címváltoztatás a feladó online állapotba kerülése után fejeződik be.";
@@ -3147,9 +3384,24 @@
/* No comment provided by engineer. */
"Recipients see updates as you type them." = "A címzettek a beírás közben látják a frissítéseket.";
/* No comment provided by engineer. */
"Reconnect" = "Újrakapcsolás";
/* No comment provided by engineer. */
"Reconnect all connected servers to force message delivery. It uses additional traffic." = "Újrakapcsolódás az összes kiszolgálóhoz az üzenetek kézbesítésének kikényszerítéséhez. Ez további forgalmat használ.";
/* No comment provided by engineer. */
"Reconnect all servers" = "Újrakapcsolódás minden kiszolgálóhoz";
/* No comment provided by engineer. */
"Reconnect all servers?" = "Újrakapcsolódás minden kiszolgálóhoz?";
/* No comment provided by engineer. */
"Reconnect server to force message delivery. It uses additional traffic." = "A kiszolgálóhoz való újrakapcsolódás az üzenet kézbesítésének kikényszerítéséhez. Ez további adatforgalmat használ.";
/* No comment provided by engineer. */
"Reconnect server?" = "Újrakapcsolódás a kiszolgálóhoz?";
/* No comment provided by engineer. */
"Reconnect servers?" = "Újrakapcsolódás a kiszolgálókhoz?";
@@ -3183,6 +3435,9 @@
/* No comment provided by engineer. */
"Remove" = "Eltávolítás";
/* No comment provided by engineer. */
"Remove image" = "Kép eltávolítása";
/* No comment provided by engineer. */
"Remove member" = "Eltávolítás";
@@ -3240,12 +3495,24 @@
/* No comment provided by engineer. */
"Reset" = "Alaphelyzetbe állítás";
/* No comment provided by engineer. */
"Reset all statistics" = "Minden statisztika visszaállítása";
/* No comment provided by engineer. */
"Reset all statistics?" = "Minden statisztika visszaállítása?";
/* No comment provided by engineer. */
"Reset colors" = "Színek alaphelyzetbe állítása";
/* No comment provided by engineer. */
"Reset to app theme" = "Alkalmazás témájának visszaállítása";
/* No comment provided by engineer. */
"Reset to defaults" = "Alaphelyzetbe állítás";
/* No comment provided by engineer. */
"Reset to user theme" = "Felhasználó által létrehozott téma visszaállítása";
/* No comment provided by engineer. */
"Restart the app to create a new chat profile" = "Új csevegési profil létrehozásához indítsa újra az alkalmazást";
@@ -3360,6 +3627,12 @@
/* No comment provided by engineer. */
"Saved WebRTC ICE servers will be removed" = "A mentett WebRTC ICE kiszolgálók eltávolításra kerülnek";
/* No comment provided by engineer. */
"Scale" = "Méretezés";
/* No comment provided by engineer. */
"Scan / Paste link" = "Hivatkozás beolvasása / beillesztése";
/* No comment provided by engineer. */
"Scan code" = "Beolvasás";
@@ -3387,6 +3660,9 @@
/* network option */
"sec" = "mp";
/* No comment provided by engineer. */
"Secondary" = "Másodlagos";
/* time unit */
"seconds" = "másodperc";
@@ -3396,6 +3672,9 @@
/* server test step */
"Secure queue" = "Biztonságos várólista";
/* No comment provided by engineer. */
"Secured" = "Biztosítva";
/* No comment provided by engineer. */
"Security assessment" = "Biztonsági kiértékelés";
@@ -3408,6 +3687,9 @@
/* No comment provided by engineer. */
"Select" = "Választás";
/* No comment provided by engineer. */
"Selected chat preferences prohibit this message." = "A kiválasztott csevegési beállítások tiltják ezt az üzenetet.";
/* No comment provided by engineer. */
"Self-destruct" = "Önmegsemmisítés";
@@ -3441,6 +3723,9 @@
/* No comment provided by engineer. */
"Send disappearing message" = "Eltűnő üzenet küldése";
/* No comment provided by engineer. */
"Send errors" = "Üzenetküldési hibák";
/* No comment provided by engineer. */
"Send link previews" = "Hivatkozás előnézetek küldése";
@@ -3507,15 +3792,33 @@
/* copied message info */
"Sent at: %@" = "Elküldve ekkor: %@";
/* No comment provided by engineer. */
"Sent directly" = "Közvetlenül küldött";
/* notification */
"Sent file event" = "Elküldött fájl esemény";
/* message info title */
"Sent message" = "Elküldött üzenet";
/* No comment provided by engineer. */
"Sent messages" = "Elküldött üzenetek";
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "Az elküldött üzenetek törlésre kerülnek a beállított idő után.";
/* No comment provided by engineer. */
"Sent reply" = "Elküldött válasz";
/* No comment provided by engineer. */
"Sent total" = "Összes elküldött";
/* No comment provided by engineer. */
"Sent via proxy" = "Proxyn keresztül küldve";
/* No comment provided by engineer. */
"Server address" = "Kiszolgáló címe";
/* srv error text. */
"Server address is incompatible with network settings." = "A kiszolgáló címe nem kompatibilis a hálózati beállításokkal.";
@@ -3531,12 +3834,21 @@
/* No comment provided by engineer. */
"Server test failed!" = "Sikertelen kiszolgáló-teszt!";
/* No comment provided by engineer. */
"Server type" = "Kiszolgáló típusa";
/* srv error text */
"Server version is incompatible with network settings." = "A kiszolgáló verziója nem kompatibilis a hálózati beállításokkal.";
/* No comment provided by engineer. */
"Servers" = "Kiszolgálók";
/* No comment provided by engineer. */
"Servers info" = "információk a kiszolgálókról";
/* No comment provided by engineer. */
"Servers statistics will be reset - this cannot be undone!" = "A kiszolgálók statisztikái visszaállnak - ez nem vonható vissza!";
/* No comment provided by engineer. */
"Session code" = "Munkamenet kód";
@@ -3546,6 +3858,9 @@
/* No comment provided by engineer. */
"Set contact name…" = "Ismerős nevének beállítása…";
/* No comment provided by engineer. */
"Set default theme" = "Alapértelmezett téma beállítása";
/* No comment provided by engineer. */
"Set group preferences" = "Csoportbeállítások megadása";
@@ -3624,6 +3939,9 @@
/* No comment provided by engineer. */
"Show:" = "Megjelenítés:";
/* No comment provided by engineer. */
"SimpleX" = "SimpleX";
/* No comment provided by engineer. */
"SimpleX address" = "SimpleX cím";
@@ -3669,6 +3987,9 @@
/* No comment provided by engineer. */
"Simplified incognito mode" = "Egyszerűsített inkognító mód";
/* No comment provided by engineer. */
"Size" = "Méret";
/* No comment provided by engineer. */
"Skip" = "Kihagyás";
@@ -3678,6 +3999,9 @@
/* No comment provided by engineer. */
"Small groups (max 20)" = "Kis csoportok (max. 20 tag)";
/* No comment provided by engineer. */
"SMP server" = "SMP-kiszolgáló";
/* No comment provided by engineer. */
"SMP servers" = "SMP kiszolgálók";
@@ -3702,9 +4026,15 @@
/* No comment provided by engineer. */
"Start migration" = "Átköltöztetés indítása";
/* No comment provided by engineer. */
"Starting from %@." = "Kezdve ettől %@.";
/* No comment provided by engineer. */
"starting…" = "indítás…";
/* No comment provided by engineer. */
"Statistics" = "Statisztikák";
/* No comment provided by engineer. */
"Stop" = "Megállítás";
@@ -3747,6 +4077,15 @@
/* No comment provided by engineer. */
"Submit" = "Elküldés";
/* No comment provided by engineer. */
"Subscribed" = "Feliratkozva";
/* No comment provided by engineer. */
"Subscription errors" = "Feliratkozási hibák";
/* No comment provided by engineer. */
"Subscriptions ignored" = "Elutasított feliratkozások";
/* No comment provided by engineer. */
"Support SimpleX Chat" = "Támogassa a SimpleX Chatet";
@@ -3795,6 +4134,9 @@
/* No comment provided by engineer. */
"TCP_KEEPINTVL" = "TCP_KEEPINTVL";
/* No comment provided by engineer. */
"Temporary file error" = "Ideiglenes fájlhiba";
/* server test failure */
"Test failed at step %@." = "A teszt sikertelen volt a(z) %@ lépésnél.";
@@ -3876,6 +4218,9 @@
/* No comment provided by engineer. */
"The text you pasted is not a SimpleX link." = "A beillesztett szöveg nem egy SimpleX hivatkozás.";
/* No comment provided by engineer. */
"Themes" = "Témák";
/* No comment provided by engineer. */
"These settings are for your current profile **%@**." = "Ezek a beállítások a jelenlegi **%@** profiljára vonatkoznak.";
@@ -3918,9 +4263,15 @@
/* No comment provided by engineer. */
"This is your own SimpleX address!" = "Ez az ön SimpleX címe!";
/* No comment provided by engineer. */
"This link was used with another mobile device, please create a new link on the desktop." = "Ezt a hivatkozást egy másik mobilleszközön már használták, hozzon létre egy új hivatkozást az asztali számítógépén.";
/* No comment provided by engineer. */
"This setting applies to messages in your current chat profile **%@**." = "Ez a beállítás a jelenlegi **%@** profiljában lévő üzenetekre érvényes.";
/* No comment provided by engineer. */
"Title" = "Cím";
/* No comment provided by engineer. */
"To ask any questions and to receive updates:" = "Bármilyen kérdés feltevéséhez és a frissítésekért:";
@@ -3960,9 +4311,15 @@
/* No comment provided by engineer. */
"Toggle incognito when connecting." = "Inkognitó mód kapcsolódáskor.";
/* No comment provided by engineer. */
"Total" = "Összesen";
/* No comment provided by engineer. */
"Transport isolation" = "Kapcsolat izolációs mód";
/* No comment provided by engineer. */
"Transport sessions" = "Munkamenetek átvitele";
/* No comment provided by engineer. */
"Trying to connect to the server used to receive messages from this contact (error: %@)." = "Kapcsolódási kísérlet ahhoz a kiszolgálóhoz, amely az adott ismerőstől érkező üzenetek fogadására szolgál (hiba: %@).";
@@ -4098,12 +4455,21 @@
/* No comment provided by engineer. */
"Upgrade and open chat" = "A csevegés frissítése és megnyitása";
/* No comment provided by engineer. */
"Upload errors" = "Feltöltési hibák";
/* No comment provided by engineer. */
"Upload failed" = "Sikertelen feltöltés";
/* server test step */
"Upload file" = "Fájl feltöltése";
/* No comment provided by engineer. */
"Uploaded" = "Feltöltve";
/* No comment provided by engineer. */
"Uploaded files" = "Feltöltött fájlok";
/* No comment provided by engineer. */
"Uploading archive" = "Archívum feltöltése";
@@ -4149,6 +4515,9 @@
/* No comment provided by engineer. */
"User profile" = "Felhasználói profil";
/* No comment provided by engineer. */
"User selection" = "Felhasználó kiválasztása";
/* No comment provided by engineer. */
"Using .onion hosts requires compatible VPN provider." = "A .onion kiszolgálók használatához kompatibilis VPN szolgáltatóra van szükség.";
@@ -4257,6 +4626,12 @@
/* No comment provided by engineer. */
"Waiting for video" = "Videóra várakozás";
/* No comment provided by engineer. */
"Wallpaper accent" = "Háttérkép kiemelés";
/* No comment provided by engineer. */
"Wallpaper background" = "Háttérkép háttérszíne";
/* No comment provided by engineer. */
"wants to connect to you!" = "kapcsolatba akar lépni önnel!";
@@ -4329,9 +4704,15 @@
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Rossz kulcs vagy ismeretlen kapcsolat - valószínűleg ez a kapcsolat törlődött.";
/* file error text */
"Wrong key or unknown file chunk address - most likely file is deleted." = "Hibás kulcs vagy ismeretlen fájltöredék cím - valószínűleg a fájl törlődött.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Téves jelmondat!";
/* No comment provided by engineer. */
"XFTP server" = "XFTP-kiszolgáló";
/* No comment provided by engineer. */
"XFTP servers" = "XFTP kiszolgálók";
@@ -4389,6 +4770,9 @@
/* No comment provided by engineer. */
"You are invited to group" = "Meghívást kapott a csoportba";
/* No comment provided by engineer. */
"You are not connected to these servers. Private routing is used to deliver messages to them." = "Ön nem kapcsolódik ezekhez a kiszolgálókhoz. A privát útválasztás az üzenetek kézbesítésére szolgál.";
/* No comment provided by engineer. */
"you are observer" = "megfigyelő szerep";
@@ -4417,7 +4801,7 @@
"You can make it visible to your SimpleX contacts via Settings." = "Láthatóvá teheti SimpleX ismerősök számára a Beállításokban.";
/* notification body */
"You can now send messages to %@" = "Mostantól küldhet üzeneteket %@ számára";
"You can now chat with %@" = "Mostantól küldhet üzeneteket %@ számára";
/* No comment provided by engineer. */
"You can set lock screen notification preview via settings." = "A beállításokon keresztül beállíthatja a lezárási képernyő értesítési előnézetét.";
+389 -5
View File
@@ -154,9 +154,6 @@
/* No comment provided by engineer. */
"%@ is verified" = "%@ è verificato/a";
/* No comment provided by engineer. */
"%@ servers" = "Server %@";
/* No comment provided by engineer. */
"%@ uploaded" = "%@ caricati";
@@ -337,6 +334,9 @@
/* No comment provided by engineer. */
"above, then choose:" = "sopra, quindi scegli:";
/* No comment provided by engineer. */
"Accent" = "Principale";
/* accept contact request via notification
accept incoming call via notification */
"Accept" = "Accetta";
@@ -353,6 +353,12 @@
/* call status */
"accepted call" = "chiamata accettata";
/* No comment provided by engineer. */
"Acknowledged" = "Riconosciuto";
/* No comment provided by engineer. */
"Acknowledgement errors" = "Errori di riconoscimento";
/* No comment provided by engineer. */
"Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." = "Aggiungi l'indirizzo al tuo profilo, in modo che i tuoi contatti possano condividerlo con altre persone. L'aggiornamento del profilo verrà inviato ai tuoi contatti.";
@@ -377,6 +383,15 @@
/* No comment provided by engineer. */
"Add welcome message" = "Aggiungi messaggio di benvenuto";
/* No comment provided by engineer. */
"Additional accent" = "Principale aggiuntivo";
/* No comment provided by engineer. */
"Additional accent 2" = "Principale aggiuntivo 2";
/* No comment provided by engineer. */
"Additional secondary" = "Secondario aggiuntivo";
/* No comment provided by engineer. */
"Address" = "Indirizzo";
@@ -398,6 +413,9 @@
/* No comment provided by engineer. */
"Advanced network settings" = "Impostazioni di rete avanzate";
/* No comment provided by engineer. */
"Advanced settings" = "Impostazioni avanzate";
/* chat item text */
"agreeing encryption for %@…" = "concordando la crittografia per %@…";
@@ -413,6 +431,9 @@
/* No comment provided by engineer. */
"All data is erased when it is entered." = "Tutti i dati vengono cancellati quando inserito.";
/* No comment provided by engineer. */
"All data is private to your device." = "Tutti i dati sono privati, nel tuo dispositivo.";
/* No comment provided by engineer. */
"All group members will remain connected." = "Tutti i membri del gruppo resteranno connessi.";
@@ -428,6 +449,9 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Tutti i nuovi messaggi da %@ verrranno nascosti!";
/* No comment provided by engineer. */
"All profiles" = "Tutti gli profili";
/* No comment provided by engineer. */
"All your contacts will remain connected." = "Tutti i tuoi contatti resteranno connessi.";
@@ -554,6 +578,9 @@
/* No comment provided by engineer. */
"Apply" = "Applica";
/* No comment provided by engineer. */
"Apply to" = "Applica a";
/* No comment provided by engineer. */
"Archive and upload" = "Archivia e carica";
@@ -563,6 +590,9 @@
/* No comment provided by engineer. */
"Attach" = "Allega";
/* No comment provided by engineer. */
"attempts" = "tentativi";
/* No comment provided by engineer. */
"Audio & video calls" = "Chiamate audio e video";
@@ -605,6 +635,9 @@
/* No comment provided by engineer. */
"Back" = "Indietro";
/* No comment provided by engineer. */
"Background" = "Sfondo";
/* No comment provided by engineer. */
"Bad desktop address" = "Indirizzo desktop errato";
@@ -626,6 +659,9 @@
/* No comment provided by engineer. */
"Better messages" = "Messaggi migliorati";
/* No comment provided by engineer. */
"Black" = "Nero";
/* No comment provided by engineer. */
"Block" = "Blocca";
@@ -650,7 +686,7 @@
/* rcv group event chat item */
"blocked %@" = "ha bloccato %@";
/* blocked chat item */
/* marked deleted chat item preview text */
"blocked by admin" = "bloccato dall'amministratore";
/* No comment provided by engineer. */
@@ -716,6 +752,9 @@
/* No comment provided by engineer. */
"Cannot access keychain to save database password" = "Impossibile accedere al portachiavi per salvare la password del database";
/* No comment provided by engineer. */
"Cannot forward message" = "Impossibile inoltrare il messaggio";
/* No comment provided by engineer. */
"Cannot receive file" = "Impossibile ricevere il file";
@@ -774,6 +813,9 @@
/* No comment provided by engineer. */
"Chat archive" = "Archivio chat";
/* No comment provided by engineer. */
"Chat colors" = "Colori della chat";
/* No comment provided by engineer. */
"Chat console" = "Console della chat";
@@ -801,6 +843,9 @@
/* No comment provided by engineer. */
"Chat preferences" = "Preferenze della chat";
/* No comment provided by engineer. */
"Chat theme" = "Tema della chat";
/* No comment provided by engineer. */
"Chats" = "Chat";
@@ -819,6 +864,15 @@
/* No comment provided by engineer. */
"Choose from library" = "Scegli dalla libreria";
/* No comment provided by engineer. */
"Chunks deleted" = "Blocchi eliminati";
/* No comment provided by engineer. */
"Chunks downloaded" = "Blocchi scaricati";
/* No comment provided by engineer. */
"Chunks uploaded" = "Blocchi inviati";
/* No comment provided by engineer. */
"Clear" = "Svuota";
@@ -834,6 +888,9 @@
/* No comment provided by engineer. */
"Clear verification" = "Annulla la verifica";
/* No comment provided by engineer. */
"Color mode" = "Modalità di colore";
/* No comment provided by engineer. */
"colored" = "colorato";
@@ -846,6 +903,9 @@
/* No comment provided by engineer. */
"complete" = "completo";
/* No comment provided by engineer. */
"Completed" = "Completato";
/* No comment provided by engineer. */
"Configure ICE servers" = "Configura server ICE";
@@ -915,18 +975,27 @@
/* No comment provided by engineer. */
"connected" = "connesso/a";
/* No comment provided by engineer. */
"Connected" = "Connesso";
/* No comment provided by engineer. */
"Connected desktop" = "Desktop connesso";
/* rcv group event chat item */
"connected directly" = "si è connesso/a direttamente";
/* No comment provided by engineer. */
"Connected servers" = "Server connessi";
/* No comment provided by engineer. */
"Connected to desktop" = "Connesso al desktop";
/* No comment provided by engineer. */
"connecting" = "in connessione";
/* No comment provided by engineer. */
"Connecting" = "In connessione";
/* No comment provided by engineer. */
"connecting (accepted)" = "in connessione (accettato)";
@@ -975,9 +1044,15 @@
/* No comment provided by engineer. */
"Connection timeout" = "Connessione scaduta";
/* No comment provided by engineer. */
"Connection with desktop stopped" = "Connessione con il desktop fermata";
/* connection information */
"connection:%@" = "connessione:% @";
/* No comment provided by engineer. */
"Connections" = "Connessioni";
/* profile update event chat item */
"contact %@ changed to %@" = "contatto %1$@ cambiato in %2$@";
@@ -1020,6 +1095,9 @@
/* No comment provided by engineer. */
"Copy" = "Copia";
/* No comment provided by engineer. */
"Copy error" = "Copia errore";
/* No comment provided by engineer. */
"Core version: v%@" = "Versione core: v%@";
@@ -1065,6 +1143,9 @@
/* No comment provided by engineer. */
"Create your profile" = "Crea il tuo profilo";
/* No comment provided by engineer. */
"Created" = "Creato";
/* No comment provided by engineer. */
"Created at" = "Creato il";
@@ -1089,6 +1170,9 @@
/* No comment provided by engineer. */
"Current passphrase…" = "Password attuale…";
/* No comment provided by engineer. */
"Current profile" = "Profilo attuale";
/* No comment provided by engineer. */
"Currently maximum supported file size is %@." = "Attualmente la dimensione massima supportata è di %@.";
@@ -1098,9 +1182,15 @@
/* No comment provided by engineer. */
"Custom time" = "Tempo personalizzato";
/* No comment provided by engineer. */
"Customize theme" = "Personalizza il tema";
/* No comment provided by engineer. */
"Dark" = "Scuro";
/* No comment provided by engineer. */
"Dark mode colors" = "Colori modalità scura";
/* No comment provided by engineer. */
"Database downgrade" = "Downgrade del database";
@@ -1170,6 +1260,9 @@
/* message decrypt error item */
"Decryption error" = "Errore di decifrazione";
/* No comment provided by engineer. */
"decryption errors" = "errori di decifrazione";
/* pref value */
"default (%@)" = "predefinito (%@)";
@@ -1296,6 +1389,9 @@
/* deleted chat item */
"deleted" = "eliminato";
/* No comment provided by engineer. */
"Deleted" = "Eliminato";
/* No comment provided by engineer. */
"Deleted at" = "Eliminato il";
@@ -1308,6 +1404,9 @@
/* rcv group event chat item */
"deleted group" = "gruppo eliminato";
/* No comment provided by engineer. */
"Deletion errors" = "Errori di eliminazione";
/* No comment provided by engineer. */
"Delivery" = "Consegna";
@@ -1332,6 +1431,12 @@
/* snd error text */
"Destination server error: %@" = "Errore del server di destinazione: %@";
/* No comment provided by engineer. */
"Detailed statistics" = "Statistiche dettagliate";
/* No comment provided by engineer. */
"Details" = "Dettagli";
/* No comment provided by engineer. */
"Develop" = "Sviluppa";
@@ -1434,12 +1539,21 @@
/* chat item action */
"Download" = "Scarica";
/* No comment provided by engineer. */
"Download errors" = "Errori di scaricamento";
/* No comment provided by engineer. */
"Download failed" = "Scaricamento fallito";
/* server test step */
"Download file" = "Scarica file";
/* No comment provided by engineer. */
"Downloaded" = "Scaricato";
/* No comment provided by engineer. */
"Downloaded files" = "File scaricati";
/* No comment provided by engineer. */
"Downloading archive" = "Scaricamento archivio";
@@ -1452,6 +1566,9 @@
/* integrity error chat item */
"duplicate message" = "messaggio duplicato";
/* No comment provided by engineer. */
"duplicates" = "doppi";
/* No comment provided by engineer. */
"Duration" = "Durata";
@@ -1710,6 +1827,9 @@
/* No comment provided by engineer. */
"Error exporting chat database" = "Errore nell'esportazione del database della chat";
/* No comment provided by engineer. */
"Error exporting theme: %@" = "Errore di esportazione del tema: %@";
/* No comment provided by engineer. */
"Error importing chat database" = "Errore nell'importazione del database della chat";
@@ -1725,9 +1845,18 @@
/* No comment provided by engineer. */
"Error receiving file" = "Errore nella ricezione del file";
/* No comment provided by engineer. */
"Error reconnecting server" = "Errore di riconnessione al server";
/* No comment provided by engineer. */
"Error reconnecting servers" = "Errore di riconnessione ai server";
/* No comment provided by engineer. */
"Error removing member" = "Errore nella rimozione del membro";
/* No comment provided by engineer. */
"Error resetting statistics" = "Errore di azzeramento statistiche";
/* No comment provided by engineer. */
"Error saving %@ servers" = "Errore nel salvataggio dei server %@";
@@ -1807,6 +1936,9 @@
/* No comment provided by engineer. */
"Error: URL is invalid" = "Errore: l'URL non è valido";
/* No comment provided by engineer. */
"Errors" = "Errori";
/* No comment provided by engineer. */
"Even when disabled in the conversation." = "Anche quando disattivato nella conversazione.";
@@ -1819,12 +1951,18 @@
/* chat item action */
"Expand" = "Espandi";
/* No comment provided by engineer. */
"expired" = "scaduto";
/* No comment provided by engineer. */
"Export database" = "Esporta database";
/* No comment provided by engineer. */
"Export error:" = "Errore di esportazione:";
/* No comment provided by engineer. */
"Export theme" = "Esporta tema";
/* No comment provided by engineer. */
"Exported database archive." = "Archivio database esportato.";
@@ -1846,6 +1984,21 @@
/* No comment provided by engineer. */
"Favorite" = "Preferito";
/* No comment provided by engineer. */
"File error" = "Errore del file";
/* file error text */
"File not found - most likely file was deleted or cancelled." = "File non trovato - probabilmente è stato eliminato o annullato.";
/* file error text */
"File server error: %@" = "Errore del server dei file: %@";
/* No comment provided by engineer. */
"File status" = "Stato del file";
/* copied message info */
"File status: %@" = "Stato del file: %@";
/* No comment provided by engineer. */
"File will be deleted from servers." = "Il file verrà eliminato dai server.";
@@ -1960,6 +2113,12 @@
/* No comment provided by engineer. */
"GIFs and stickers" = "GIF e adesivi";
/* message preview */
"Good afternoon!" = "Buon pomeriggio!";
/* message preview */
"Good morning!" = "Buongiorno!";
/* No comment provided by engineer. */
"Group" = "Gruppo";
@@ -2137,6 +2296,9 @@
/* No comment provided by engineer. */
"Import failed" = "Importazione fallita";
/* No comment provided by engineer. */
"Import theme" = "Importa tema";
/* No comment provided by engineer. */
"Importing archive" = "Importazione archivio";
@@ -2158,6 +2320,9 @@
/* No comment provided by engineer. */
"In-call sounds" = "Suoni nelle chiamate";
/* No comment provided by engineer. */
"inactive" = "inattivo";
/* No comment provided by engineer. */
"Incognito" = "Incognito";
@@ -2221,6 +2386,9 @@
/* No comment provided by engineer. */
"Interface" = "Interfaccia";
/* No comment provided by engineer. */
"Interface colors" = "Colori dell'interfaccia";
/* invalid chat data */
"invalid chat" = "chat non valida";
@@ -2473,6 +2641,9 @@
/* rcv group event chat item */
"member connected" = "si è connesso/a";
/* item status text */
"Member inactive" = "Membro inattivo";
/* No comment provided by engineer. */
"Member role will be changed to \"%@\". All group members will be notified." = "Il ruolo del membro verrà cambiato in \"%@\". Tutti i membri del gruppo verranno avvisati.";
@@ -2482,6 +2653,9 @@
/* No comment provided by engineer. */
"Member will be removed from group - this cannot be undone!" = "Il membro verrà rimosso dal gruppo, non è reversibile!";
/* No comment provided by engineer. */
"Menus" = "Menu";
/* item status text */
"Message delivery error" = "Errore di recapito del messaggio";
@@ -2494,6 +2668,12 @@
/* No comment provided by engineer. */
"Message draft" = "Bozza dei messaggi";
/* item status text */
"Message forwarded" = "Messaggio inoltrato";
/* item status description */
"Message may be delivered later if member becomes active." = "Il messaggio può essere consegnato più tardi se il membro diventa attivo.";
/* No comment provided by engineer. */
"Message queue info" = "Info coda messaggi";
@@ -2518,6 +2698,12 @@
/* No comment provided by engineer. */
"Message source remains private." = "La fonte del messaggio resta privata.";
/* No comment provided by engineer. */
"Message status" = "Stato del messaggio";
/* copied message info */
"Message status: %@" = "Stato del messaggio: %@";
/* No comment provided by engineer. */
"Message text" = "Testo del messaggio";
@@ -2533,6 +2719,12 @@
/* No comment provided by engineer. */
"Messages from %@ will be shown!" = "I messaggi da %@ verranno mostrati!";
/* No comment provided by engineer. */
"Messages received" = "Messaggi ricevuti";
/* No comment provided by engineer. */
"Messages sent" = "Messaggi inviati";
/* No comment provided by engineer. */
"Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." = "I messaggi, i file e le chiamate sono protetti da **crittografia end-to-end** con perfect forward secrecy, ripudio e recupero da intrusione.";
@@ -2698,6 +2890,9 @@
/* No comment provided by engineer. */
"No device token!" = "Nessun token del dispositivo!";
/* item status description */
"No direct connection yet, message is forwarded by admin." = "Ancora nessuna connessione diretta, il messaggio viene inoltrato dall'amministratore.";
/* No comment provided by engineer. */
"no e2e encryption" = "nessuna crittografia e2e";
@@ -2710,6 +2905,9 @@
/* No comment provided by engineer. */
"No history" = "Nessuna cronologia";
/* No comment provided by engineer. */
"No info, try to reload" = "Nessuna informazione, prova a ricaricare";
/* No comment provided by engineer. */
"No network connection" = "Nessuna connessione di rete";
@@ -2835,6 +3033,9 @@
/* authentication reason */
"Open migration to another device" = "Apri migrazione ad un altro dispositivo";
/* No comment provided by engineer. */
"Open server settings" = "Apri impostazioni server";
/* No comment provided by engineer. */
"Open Settings" = "Apri le impostazioni";
@@ -2859,9 +3060,15 @@
/* No comment provided by engineer. */
"Or show this code" = "O mostra questo codice";
/* No comment provided by engineer. */
"other" = "altro";
/* No comment provided by engineer. */
"Other" = "Altro";
/* No comment provided by engineer. */
"other errors" = "altri errori";
/* member role */
"owner" = "proprietario";
@@ -2904,6 +3111,9 @@
/* No comment provided by engineer. */
"peer-to-peer" = "peer-to-peer";
/* No comment provided by engineer. */
"Pending" = "In attesa";
/* No comment provided by engineer. */
"People can connect to you only via the links you share." = "Le persone possono connettersi a te solo tramite i link che condividi.";
@@ -2925,6 +3135,9 @@
/* No comment provided by engineer. */
"Please ask your contact to enable sending voice messages." = "Chiedi al tuo contatto di attivare l'invio dei messaggi vocali.";
/* No comment provided by engineer. */
"Please check that mobile and desktop are connected to the same local network, and that desktop firewall allows the connection.\nPlease share any other issues with the developers." = "Controlla che mobile e desktop siano collegati alla stessa rete locale e che il firewall del desktop consenta la connessione.\nSi prega di condividere qualsiasi altro problema con gli sviluppatori.";
/* No comment provided by engineer. */
"Please check that you used the correct link or ask your contact to send you another one." = "Controlla di aver usato il link giusto o chiedi al tuo contatto di inviartene un altro.";
@@ -2982,6 +3195,9 @@
/* No comment provided by engineer. */
"Preview" = "Anteprima";
/* No comment provided by engineer. */
"Previously connected servers" = "Server precedentemente connessi";
/* No comment provided by engineer. */
"Privacy & security" = "Privacy e sicurezza";
@@ -3021,6 +3237,9 @@
/* No comment provided by engineer. */
"Profile password" = "Password del profilo";
/* No comment provided by engineer. */
"Profile theme" = "Tema del profilo";
/* No comment provided by engineer. */
"Profile update will be sent to your contacts." = "L'aggiornamento del profilo verrà inviato ai tuoi contatti.";
@@ -3069,6 +3288,12 @@
/* No comment provided by engineer. */
"Protocol timeout per KB" = "Scadenza del protocollo per KB";
/* No comment provided by engineer. */
"Proxied" = "Via proxy";
/* No comment provided by engineer. */
"Proxied servers" = "Server via proxy";
/* No comment provided by engineer. */
"Push notifications" = "Notifiche push";
@@ -3111,6 +3336,9 @@
/* No comment provided by engineer. */
"Receipts are disabled" = "Le ricevute sono disattivate";
/* No comment provided by engineer. */
"Receive errors" = "Errori di ricezione";
/* No comment provided by engineer. */
"received answer…" = "risposta ricevuta…";
@@ -3129,6 +3357,15 @@
/* message info title */
"Received message" = "Messaggio ricevuto";
/* No comment provided by engineer. */
"Received messages" = "Messaggi ricevuti";
/* No comment provided by engineer. */
"Received reply" = "Risposta ricevuta";
/* No comment provided by engineer. */
"Received total" = "Totale ricevuto";
/* No comment provided by engineer. */
"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "L'indirizzo di ricezione verrà cambiato in un server diverso. La modifica dell'indirizzo verrà completata dopo che il mittente sarà in linea.";
@@ -3147,9 +3384,24 @@
/* No comment provided by engineer. */
"Recipients see updates as you type them." = "I destinatari vedono gli aggiornamenti mentre li digiti.";
/* No comment provided by engineer. */
"Reconnect" = "Riconnetti";
/* No comment provided by engineer. */
"Reconnect all connected servers to force message delivery. It uses additional traffic." = "Riconnetti tutti i server connessi per imporre il recapito dei messaggi. Utilizza traffico aggiuntivo.";
/* No comment provided by engineer. */
"Reconnect all servers" = "Riconnetti tutti i server";
/* No comment provided by engineer. */
"Reconnect all servers?" = "Riconnettere tutti i server?";
/* No comment provided by engineer. */
"Reconnect server to force message delivery. It uses additional traffic." = "Riconnetti il server per forzare la consegna dei messaggi. Usa traffico aggiuntivo.";
/* No comment provided by engineer. */
"Reconnect server?" = "Riconnettere il server?";
/* No comment provided by engineer. */
"Reconnect servers?" = "Riconnettere i server?";
@@ -3183,6 +3435,9 @@
/* No comment provided by engineer. */
"Remove" = "Rimuovi";
/* No comment provided by engineer. */
"Remove image" = "Rimuovi immagine";
/* No comment provided by engineer. */
"Remove member" = "Rimuovi membro";
@@ -3240,12 +3495,24 @@
/* No comment provided by engineer. */
"Reset" = "Ripristina";
/* No comment provided by engineer. */
"Reset all statistics" = "Azzera tutte le statistiche";
/* No comment provided by engineer. */
"Reset all statistics?" = "Azzerare tutte le statistiche?";
/* No comment provided by engineer. */
"Reset colors" = "Ripristina i colori";
/* No comment provided by engineer. */
"Reset to app theme" = "Ripristina al tema dell'app";
/* No comment provided by engineer. */
"Reset to defaults" = "Ripristina i predefiniti";
/* No comment provided by engineer. */
"Reset to user theme" = "Ripristina al tema dell'utente";
/* No comment provided by engineer. */
"Restart the app to create a new chat profile" = "Riavvia l'app per creare un nuovo profilo di chat";
@@ -3360,6 +3627,12 @@
/* No comment provided by engineer. */
"Saved WebRTC ICE servers will be removed" = "I server WebRTC ICE salvati verranno rimossi";
/* No comment provided by engineer. */
"Scale" = "Scala";
/* No comment provided by engineer. */
"Scan / Paste link" = "Scansiona / Incolla link";
/* No comment provided by engineer. */
"Scan code" = "Scansiona codice";
@@ -3387,6 +3660,9 @@
/* network option */
"sec" = "sec";
/* No comment provided by engineer. */
"Secondary" = "Secondario";
/* time unit */
"seconds" = "secondi";
@@ -3396,6 +3672,9 @@
/* server test step */
"Secure queue" = "Coda sicura";
/* No comment provided by engineer. */
"Secured" = "Protetto";
/* No comment provided by engineer. */
"Security assessment" = "Valutazione della sicurezza";
@@ -3408,6 +3687,9 @@
/* No comment provided by engineer. */
"Select" = "Seleziona";
/* No comment provided by engineer. */
"Selected chat preferences prohibit this message." = "Le preferenze della chat selezionata vietano questo messaggio.";
/* No comment provided by engineer. */
"Self-destruct" = "Autodistruzione";
@@ -3441,6 +3723,9 @@
/* No comment provided by engineer. */
"Send disappearing message" = "Invia messaggio a tempo";
/* No comment provided by engineer. */
"Send errors" = "Errori di invio";
/* No comment provided by engineer. */
"Send link previews" = "Invia anteprime dei link";
@@ -3507,15 +3792,33 @@
/* copied message info */
"Sent at: %@" = "Inviato il: %@";
/* No comment provided by engineer. */
"Sent directly" = "Inviato direttamente";
/* notification */
"Sent file event" = "Evento file inviato";
/* message info title */
"Sent message" = "Messaggio inviato";
/* No comment provided by engineer. */
"Sent messages" = "Messaggi inviati";
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "I messaggi inviati verranno eliminati dopo il tempo impostato.";
/* No comment provided by engineer. */
"Sent reply" = "Risposta inviata";
/* No comment provided by engineer. */
"Sent total" = "Totale inviato";
/* No comment provided by engineer. */
"Sent via proxy" = "Inviato via proxy";
/* No comment provided by engineer. */
"Server address" = "Indirizzo server";
/* srv error text. */
"Server address is incompatible with network settings." = "L'indirizzo del server non è compatibile con le impostazioni di rete.";
@@ -3531,12 +3834,21 @@
/* No comment provided by engineer. */
"Server test failed!" = "Test del server fallito!";
/* No comment provided by engineer. */
"Server type" = "Tipo server";
/* srv error text */
"Server version is incompatible with network settings." = "La versione del server non è compatibile con le impostazioni di rete.";
/* No comment provided by engineer. */
"Servers" = "Server";
/* No comment provided by engineer. */
"Servers info" = "Info dei server";
/* No comment provided by engineer. */
"Servers statistics will be reset - this cannot be undone!" = "Le statistiche dei server verranno azzerate - è irreversibile!";
/* No comment provided by engineer. */
"Session code" = "Codice di sessione";
@@ -3546,6 +3858,9 @@
/* No comment provided by engineer. */
"Set contact name…" = "Imposta nome del contatto…";
/* No comment provided by engineer. */
"Set default theme" = "Imposta tema predefinito";
/* No comment provided by engineer. */
"Set group preferences" = "Imposta le preferenze del gruppo";
@@ -3624,6 +3939,9 @@
/* No comment provided by engineer. */
"Show:" = "Mostra:";
/* No comment provided by engineer. */
"SimpleX" = "SimpleX";
/* No comment provided by engineer. */
"SimpleX address" = "Indirizzo SimpleX";
@@ -3669,6 +3987,9 @@
/* No comment provided by engineer. */
"Simplified incognito mode" = "Modalità incognito semplificata";
/* No comment provided by engineer. */
"Size" = "Dimensione";
/* No comment provided by engineer. */
"Skip" = "Salta";
@@ -3678,6 +3999,9 @@
/* No comment provided by engineer. */
"Small groups (max 20)" = "Piccoli gruppi (max 20)";
/* No comment provided by engineer. */
"SMP server" = "Server SMP";
/* No comment provided by engineer. */
"SMP servers" = "Server SMP";
@@ -3702,9 +4026,15 @@
/* No comment provided by engineer. */
"Start migration" = "Avvia la migrazione";
/* No comment provided by engineer. */
"Starting from %@." = "Inizio da %@.";
/* No comment provided by engineer. */
"starting…" = "avvio…";
/* No comment provided by engineer. */
"Statistics" = "Statistiche";
/* No comment provided by engineer. */
"Stop" = "Ferma";
@@ -3747,6 +4077,15 @@
/* No comment provided by engineer. */
"Submit" = "Invia";
/* No comment provided by engineer. */
"Subscribed" = "Iscritto";
/* No comment provided by engineer. */
"Subscription errors" = "Errori di iscrizione";
/* No comment provided by engineer. */
"Subscriptions ignored" = "Iscrizioni ignorate";
/* No comment provided by engineer. */
"Support SimpleX Chat" = "Supporta SimpleX Chat";
@@ -3795,6 +4134,9 @@
/* No comment provided by engineer. */
"TCP_KEEPINTVL" = "TCP_KEEPINTVL";
/* No comment provided by engineer. */
"Temporary file error" = "Errore del file temporaneo";
/* server test failure */
"Test failed at step %@." = "Test fallito al passo %@.";
@@ -3876,6 +4218,9 @@
/* No comment provided by engineer. */
"The text you pasted is not a SimpleX link." = "Il testo che hai incollato non è un link SimpleX.";
/* No comment provided by engineer. */
"Themes" = "Temi";
/* No comment provided by engineer. */
"These settings are for your current profile **%@**." = "Queste impostazioni sono per il tuo profilo attuale **%@**.";
@@ -3918,9 +4263,15 @@
/* No comment provided by engineer. */
"This is your own SimpleX address!" = "Questo è il tuo indirizzo SimpleX!";
/* No comment provided by engineer. */
"This link was used with another mobile device, please create a new link on the desktop." = "Questo link è stato usato con un altro dispositivo mobile, creane uno nuovo sul desktop.";
/* No comment provided by engineer. */
"This setting applies to messages in your current chat profile **%@**." = "Questa impostazione si applica ai messaggi del profilo di chat attuale **%@**.";
/* No comment provided by engineer. */
"Title" = "Titoli";
/* No comment provided by engineer. */
"To ask any questions and to receive updates:" = "Per porre domande e ricevere aggiornamenti:";
@@ -3960,9 +4311,15 @@
/* No comment provided by engineer. */
"Toggle incognito when connecting." = "Attiva/disattiva l'incognito quando ti colleghi.";
/* No comment provided by engineer. */
"Total" = "Totale";
/* No comment provided by engineer. */
"Transport isolation" = "Isolamento del trasporto";
/* No comment provided by engineer. */
"Transport sessions" = "Sessioni di trasporto";
/* No comment provided by engineer. */
"Trying to connect to the server used to receive messages from this contact (error: %@)." = "Tentativo di connessione al server usato per ricevere messaggi da questo contatto (errore: %@).";
@@ -4098,12 +4455,21 @@
/* No comment provided by engineer. */
"Upgrade and open chat" = "Aggiorna e apri chat";
/* No comment provided by engineer. */
"Upload errors" = "Errori di invio";
/* No comment provided by engineer. */
"Upload failed" = "Invio fallito";
/* server test step */
"Upload file" = "Invia file";
/* No comment provided by engineer. */
"Uploaded" = "Inviato";
/* No comment provided by engineer. */
"Uploaded files" = "File inviati";
/* No comment provided by engineer. */
"Uploading archive" = "Invio dell'archivio";
@@ -4149,6 +4515,9 @@
/* No comment provided by engineer. */
"User profile" = "Profilo utente";
/* No comment provided by engineer. */
"User selection" = "Selezione utente";
/* No comment provided by engineer. */
"Using .onion hosts requires compatible VPN provider." = "L'uso di host .onion richiede un fornitore di VPN compatibile.";
@@ -4257,6 +4626,12 @@
/* No comment provided by engineer. */
"Waiting for video" = "In attesa del video";
/* No comment provided by engineer. */
"Wallpaper accent" = "Tinta dello sfondo";
/* No comment provided by engineer. */
"Wallpaper background" = "Retro dello sfondo";
/* No comment provided by engineer. */
"wants to connect to you!" = "vuole connettersi con te!";
@@ -4329,9 +4704,15 @@
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Chiave sbagliata o connessione sconosciuta - molto probabilmente questa connessione è stata eliminata.";
/* file error text */
"Wrong key or unknown file chunk address - most likely file is deleted." = "Chiave sbagliata o indirizzo sconosciuto per frammento del file - probabilmente il file è stato eliminato.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Password sbagliata!";
/* No comment provided by engineer. */
"XFTP server" = "Server XFTP";
/* No comment provided by engineer. */
"XFTP servers" = "Server XFTP";
@@ -4389,6 +4770,9 @@
/* No comment provided by engineer. */
"You are invited to group" = "Sei stato/a invitato/a al gruppo";
/* No comment provided by engineer. */
"You are not connected to these servers. Private routing is used to deliver messages to them." = "Non sei connesso/a a questi server. L'instradamento privato è usato per consegnare loro i messaggi.";
/* No comment provided by engineer. */
"you are observer" = "sei un osservatore";
@@ -4417,7 +4801,7 @@
"You can make it visible to your SimpleX contacts via Settings." = "Puoi renderlo visibile ai tuoi contatti SimpleX nelle impostazioni.";
/* notification body */
"You can now send messages to %@" = "Ora puoi inviare messaggi a %@";
"You can now chat with %@" = "Ora puoi inviare messaggi a %@";
/* No comment provided by engineer. */
"You can set lock screen notification preview via settings." = "Puoi impostare l'anteprima della notifica nella schermata di blocco tramite le impostazioni.";
+1 -4
View File
@@ -148,9 +148,6 @@
/* No comment provided by engineer. */
"%@ is verified" = "%@ は検証されています";
/* No comment provided by engineer. */
"%@ servers" = "%@ サーバー";
/* No comment provided by engineer. */
"%@ uploaded" = "%@ アップロード済";
@@ -3451,7 +3448,7 @@
"You can hide or mute a user profile - swipe it to the right." = "ユーザープロファイルを右にスワイプすると、非表示またはミュートにすることができます。";
/* notification body */
"You can now send messages to %@" = "%@ にメッセージを送信できるようになりました";
"You can now chat with %@" = "%@ にメッセージを送信できるようになりました";
/* No comment provided by engineer. */
"You can set lock screen notification preview via settings." = "設定からロック画面の通知プレビューを設定できます。";
+2 -5
View File
@@ -154,9 +154,6 @@
/* No comment provided by engineer. */
"%@ is verified" = "%@ is geverifieerd";
/* No comment provided by engineer. */
"%@ servers" = "%@ servers";
/* No comment provided by engineer. */
"%@ uploaded" = "%@ geüpload";
@@ -650,7 +647,7 @@
/* rcv group event chat item */
"blocked %@" = "geblokkeerd %@";
/* blocked chat item */
/* marked deleted chat item preview text */
"blocked by admin" = "geblokkeerd door beheerder";
/* No comment provided by engineer. */
@@ -4417,7 +4414,7 @@
"You can make it visible to your SimpleX contacts via Settings." = "Je kunt het via Instellingen zichtbaar maken voor je SimpleX contacten.";
/* notification body */
"You can now send messages to %@" = "Je kunt nu berichten sturen naar %@";
"You can now chat with %@" = "Je kunt nu berichten sturen naar %@";
/* No comment provided by engineer. */
"You can set lock screen notification preview via settings." = "U kunt een voorbeeld van een melding op het vergrendeld scherm instellen via instellingen.";

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