Compare commits

..

33 Commits

Author SHA1 Message Date
Levitating Pineapple c2c689ca91 fix animator crash 2024-10-07 21:24:07 +03:00
Arturs Krumins 56922c6323 ios: remove showSettings and withNavigation (#4980)
* remove showSettings

* pass dismiss action trough navigation links

* move auth to all sheets
2024-10-07 18:16:01 +01:00
Levitating Pineapple 91823eec95 fix keyboard related glitches 2024-10-04 13:58:32 +03:00
Levitating Pineapple 8547fab700 improve handling of repeated sheet presentation state changes 2024-10-04 10:30:11 +03:00
Levitating Pineapple 5c078f91fc Merge branch 'master' into lp/custom-user-picker-sheet 2024-10-03 21:21:09 +03:00
Arturs Krumins ec444e7ce1 load sheet navigation titles before presenting (#4963)
* load sheet navigation titles before presenting

* list background during loading
2024-10-03 21:18:13 +03:00
Levitating Pineapple e69d94896d async camera authorization in 'Use from desktop' sheet 2024-10-01 19:20:48 +03:00
Levitating Pineapple a134b3cb2f fix iOS15 sheet animation when presenting sheet multiple times 2024-10-01 17:01:36 +03:00
Levitating Pineapple ab24369333 async qr code generation 2024-10-01 15:27:47 +03:00
Levitating Pineapple 592b8d49d0 Merge branch 'master' into lp/custom-user-picker-sheet 2024-09-30 22:47:40 +03:00
Arturs Krumins af7ebe1587 ios: user picker sheet concurent animation (#4955)
* ios: user picker sheet concurent animation

* bind showSettings; cleanup
2024-09-30 22:45:39 +03:00
Levitating Pineapple 2a8df6ace1 remove touchdown animation 2024-09-30 16:04:14 +03:00
Levitating Pineapple bbe614aef7 cubic animation curve; dynamic backdrop opacity 2024-09-30 13:55:51 +03:00
Levitating Pineapple 63ffcbc4e7 instantanious longPress; tweak animations 2024-09-27 15:33:21 +03:00
Levitating Pineapple 01edff3ca3 refactor separators 2024-09-27 11:58:05 +03:00
Levitating Pineapple cd9aa120bc Merge branch 'master' into lp/custom-user-picker-sheet 2024-09-27 11:09:24 +03:00
Levitating Pineapple 86dce0921e fix layout loop; add upper animation speed constraint 2024-09-26 20:43:59 +03:00
Levitating Pineapple e21d49db18 fix dark mode tap target; retain highlight; highlight in user scroller 2024-09-26 17:48:29 +03:00
Evgeny Poberezkin 73673ab073 Merge branch 'master' into lp/custom-user-picker-sheet 2024-09-26 13:50:40 +01:00
Levitating Pineapple ff065d7720 Merge branch 'master' into lp/custom-user-picker-sheet 2024-09-26 15:29:38 +03:00
Levitating Pineapple 07165039a8 touchable list row; prevent tap gesture passtrough 2024-09-26 14:58:15 +03:00
Levitating Pineapple 240aa6a2b1 delay user picker closing 2024-09-26 10:32:18 +03:00
Levitating Pineapple fcde05e9a4 reduce dif 2024-09-26 00:03:26 +03:00
Levitating Pineapple cabf8aba16 reset user scroll position on dismiss; cleanup 2024-09-25 23:42:19 +03:00
Levitating Pineapple de594aac88 user picker bottom padding 2024-09-25 21:07:55 +03:00
Levitating Pineapple 91f3335503 Merge branch 'master' into lp/custom-user-picker-sheet 2024-09-25 19:15:15 +03:00
Levitating Pineapple 2663e6330a resolve warning 2024-09-25 19:00:17 +03:00
Levitating Pineapple f28a5b6e92 implement UIViewPropertyAnimator 2024-09-25 18:58:10 +03:00
Evgeny Poberezkin d59fdb1e09 Merge branch 'master' into lp/custom-user-picker-sheet 2024-09-24 11:55:26 +01:00
Levitating Pineapple b4ec4df687 cleanup; dismiss 2024-09-23 23:55:05 +03:00
Levitating Pineapple f154a0bcb4 distance based animation duration 2024-09-23 23:02:53 +03:00
Levitating Pineapple ce5d113ff6 tweak appearance 2024-09-23 21:43:40 +03:00
Levitating Pineapple a35b20f54c ios: hide user picker sheet instantly, when opening another sheet 2024-09-23 18:43:05 +03:00
148 changed files with 1951 additions and 7885 deletions
+3 -12
View File
@@ -297,18 +297,9 @@ struct ContentView: View {
if let contactId = contacts?.first?.personHandle?.value,
let chat = chatModel.getChat(contactId),
case let .direct(contact) = chat.chatInfo {
let activeCall = chatModel.activeCall
// This line works when a user clicks on a video button in CallKit UI while in call.
// The app tries to make another call to the same contact and overwite activeCall instance making its state broken
if let activeCall, contactId == activeCall.contact.id, mediaType == .video, !activeCall.hasVideo {
Task {
await chatModel.callCommand.processCommand(.media(source: .camera, enable: true))
}
} else if activeCall == nil {
logger.debug("callToRecentContact: schedule call")
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
CallController.shared.startCall(contact, mediaType)
}
logger.debug("callToRecentContact: schedule call")
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
CallController.shared.startCall(contact, mediaType)
}
}
}
+1 -1
View File
@@ -526,7 +526,7 @@ final class ChatModel: ObservableObject {
}
func updateCurrentUserUiThemes(uiThemes: ThemeModeOverrides?) {
guard var current = currentUser, current.uiThemes != uiThemes else { return }
guard var current = currentUser else { return }
current.uiThemes = uiThemes
let i = users.firstIndex(where: { $0.user.userId == current.userId })
if let i {
+4 -9
View File
@@ -585,18 +585,12 @@ func apiContactInfo(_ contactId: Int64) async throws -> (ConnectionStats?, Profi
throw r
}
func apiGroupMemberInfoSync(_ groupId: Int64, _ groupMemberId: Int64) throws -> (GroupMember, ConnectionStats?) {
func apiGroupMemberInfo(_ groupId: Int64, _ groupMemberId: Int64) throws -> (GroupMember, ConnectionStats?) {
let r = chatSendCmdSync(.apiGroupMemberInfo(groupId: groupId, groupMemberId: groupMemberId))
if case let .groupMemberInfo(_, _, member, connStats_) = r { return (member, connStats_) }
throw r
}
func apiGroupMemberInfo(_ groupId: Int64, _ groupMemberId: Int64) async throws -> (GroupMember, ConnectionStats?) {
let r = await chatSendCmd(.apiGroupMemberInfo(groupId: groupId, groupMemberId: groupMemberId))
if case let .groupMemberInfo(_, _, member, connStats_) = r { return (member, connStats_) }
throw r
}
func apiContactQueueInfo(_ contactId: Int64) async throws -> (RcvMsgInfo?, ServerQueueInfo) {
let r = await chatSendCmd(.apiContactQueueInfo(contactId: contactId))
if case let .queueInfo(_, rcvMsgInfo, queueInfo) = r { return (rcvMsgInfo, queueInfo) }
@@ -651,8 +645,8 @@ func apiGetContactCode(_ contactId: Int64) async throws -> (Contact, String) {
throw r
}
func apiGetGroupMemberCode(_ groupId: Int64, _ groupMemberId: Int64) async throws -> (GroupMember, String) {
let r = await chatSendCmd(.apiGetGroupMemberCode(groupId: groupId, groupMemberId: groupMemberId))
func apiGetGroupMemberCode(_ groupId: Int64, _ groupMemberId: Int64) throws -> (GroupMember, String) {
let r = chatSendCmdSync(.apiGetGroupMemberCode(groupId: groupId, groupMemberId: groupMemberId))
if case let .groupMemberCode(_, _, member, connectionCode) = r { return (member, connectionCode) }
throw r
}
@@ -2090,6 +2084,7 @@ func processReceivedMsg(_ res: ChatResponse) async {
await withCall(contact) { call in
await MainActor.run {
call.callState = .offerReceived
call.peerMedia = callType.media
call.sharedKey = sharedKey
}
let useRelay = UserDefaults.standard.bool(forKey: DEFAULT_WEBRTC_POLICY_RELAY)
+1 -1
View File
@@ -122,7 +122,7 @@ extension ThemeWallpaper {
let preset: String? = if case let WallpaperType.preset(filename, _) = type { filename } else { nil }
let scale: Float? = if case let WallpaperType.preset(_, scale) = type { scale } else { if case let WallpaperType.image(_, scale, _) = type { scale } else { 1.0 } }
let scaleType: WallpaperScaleType? = if case let WallpaperType.image(_, _, scaleType) = type { scaleType } else { nil }
let image: String? = if case WallpaperType.image = type, let image = type.uiImage { resizeImageToStrSizeSync(image, maxDataSize: 5_000_000) } else { nil }
let image: String? = if case WallpaperType.image = type, let image = type.uiImage { resizeImageToStrSize(image, maxDataSize: 5_000_000) } else { nil }
return ThemeWallpaper (
preset: preset,
scale: scale,
+106 -156
View File
@@ -17,8 +17,8 @@ struct ActiveCallView: View {
@ObservedObject var call: Call
@Environment(\.scenePhase) var scenePhase
@State private var client: WebRTCClient? = nil
@State private var activeCall: WebRTCClient.Call? = nil
@State private var localRendererAspectRatio: CGFloat? = nil
@State var remoteContentMode: UIView.ContentMode = .scaleAspectFill
@Binding var canConnectCall: Bool
@State var prevColorScheme: ColorScheme = .dark
@State var pipShown = false
@@ -27,39 +27,24 @@ struct ActiveCallView: View {
var body: some View {
ZStack(alignment: .topLeading) {
ZStack(alignment: .bottom) {
if let client = client, call.hasVideo {
if let client = client, [call.peerMedia, call.localMedia].contains(.video), activeCall != nil {
GeometryReader { g in
let width = g.size.width * 0.3
ZStack(alignment: .topTrailing) {
CallViewRemote(client: client, activeCall: $activeCall, activeCallViewIsCollapsed: $m.activeCallViewIsCollapsed, pipShown: $pipShown)
CallViewLocal(client: client, activeCall: $activeCall, localRendererAspectRatio: $localRendererAspectRatio, pipShown: $pipShown)
.cornerRadius(10)
.frame(width: width, height: width / (localRendererAspectRatio ?? 1))
.padding([.top, .trailing], 17)
ZStack(alignment: .center) {
// For some reason, when the view in GeometryReader and ZStack is visible, it steals clicks on a back button, so showing something on top like this with background color helps (.clear color doesn't work)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.primary.opacity(0.000001))
CallViewRemote(client: client, call: call, activeCallViewIsCollapsed: $m.activeCallViewIsCollapsed, contentMode: $remoteContentMode, pipShown: $pipShown)
.onTapGesture {
remoteContentMode = remoteContentMode == .scaleAspectFill ? .scaleAspectFit : .scaleAspectFill
}
Group {
let localVideoTrack = client.activeCall?.localVideoTrack ?? client.notConnectedCall?.localCameraAndTrack?.1
if localVideoTrack != nil {
CallViewLocal(client: client, localRendererAspectRatio: $localRendererAspectRatio, pipShown: $pipShown)
.onDisappear {
localRendererAspectRatio = nil
}
} else {
Rectangle().fill(.black)
}
}
.cornerRadius(10)
.frame(width: width, height: localRendererAspectRatio == nil ? (g.size.width < g.size.height ? width * 1.33 : width / 1.33) : width / (localRendererAspectRatio ?? 1))
.padding([.top, .trailing], 17)
}
}
}
if let call = m.activeCall, let client = client, (!pipShown || !call.hasVideo) {
if let call = m.activeCall, let client = client, (!pipShown || !call.supportsVideo) {
ActiveCallOverlay(call: call, client: client)
}
}
@@ -69,9 +54,6 @@ struct ActiveCallView: View {
.onAppear {
logger.debug("ActiveCallView: appear client is nil \(client == nil), scenePhase \(String(describing: scenePhase)), canConnectCall \(canConnectCall)")
AppDelegate.keepScreenOn(true)
Task {
await askRequiredPermissions()
}
createWebRTCClient()
dismissAllSheets()
hideKeyboard()
@@ -102,7 +84,7 @@ struct ActiveCallView: View {
private func createWebRTCClient() {
if client == nil && canConnectCall {
client = WebRTCClient({ msg in await MainActor.run { processRtcMessage(msg: msg) } }, $localRendererAspectRatio)
client = WebRTCClient($activeCall, { msg in await MainActor.run { processRtcMessage(msg: msg) } }, $localRendererAspectRatio)
Task {
await m.callCommand.setClient(client)
}
@@ -117,7 +99,7 @@ struct ActiveCallView: View {
logger.debug("ActiveCallView: response \(msg.resp.respType)")
switch msg.resp {
case let .capabilities(capabilities):
let callType = CallType(media: call.initialCallType, capabilities: capabilities)
let callType = CallType(media: call.localMedia, capabilities: capabilities)
Task {
do {
try await apiSendCallInvitation(call.contact, callType)
@@ -128,7 +110,7 @@ struct ActiveCallView: View {
call.callState = .invitationSent
call.localCapabilities = capabilities
}
if call.hasVideo && !AVAudioSession.sharedInstance().hasExternalAudioDevice() {
if call.supportsVideo && !AVAudioSession.sharedInstance().hasExternalAudioDevice() {
try? AVAudioSession.sharedInstance().setCategory(.playback, options: [.allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
}
CallSoundsPlayer.shared.startConnectingCallSound()
@@ -138,7 +120,7 @@ struct ActiveCallView: View {
Task {
do {
try await apiSendCallOffer(call.contact, offer, iceCandidates,
media: call.initialCallType, capabilities: capabilities)
media: call.localMedia, capabilities: capabilities)
} catch {
logger.error("apiSendCallOffer \(responseError(error))")
}
@@ -182,9 +164,6 @@ struct ActiveCallView: View {
}
if state.connectionState == "closed" {
closeCallView(client)
if let callUUID = m.activeCall?.callUUID {
CallController.shared.endCall(callUUID: callUUID)
}
m.activeCall = nil
m.activeCallViewIsCollapsed = false
}
@@ -203,14 +182,6 @@ struct ActiveCallView: View {
CallSoundsPlayer.shared.vibrate(long: false)
wasConnected = true
}
case let .peerMedia(source, enabled):
switch source {
case .mic: call.peerMediaSources.mic = enabled
case .camera: call.peerMediaSources.camera = enabled
case .screenAudio: call.peerMediaSources.screenAudio = enabled
case .screenVideo: call.peerMediaSources.screenVideo = enabled
case .unknown: ()
}
case .ended:
closeCallView(client)
call.callState = .ended
@@ -255,26 +226,6 @@ struct ActiveCallView: View {
}
}
private func askRequiredPermissions() async {
let mic = await WebRTCClient.isAuthorized(for: .audio)
await MainActor.run {
call.localMediaSources.mic = mic
}
let cameraAuthorized = AVCaptureDevice.authorizationStatus(for: .video) == .authorized
var camera = call.initialCallType == .audio || cameraAuthorized
if call.initialCallType == .video && !cameraAuthorized {
camera = await WebRTCClient.isAuthorized(for: .video)
await MainActor.run {
if camera, let client {
client.setCameraEnabled(true)
}
}
}
if !mic || !camera {
WebRTCClient.showUnauthorizedAlert(for: !mic ? .audio : .video)
}
}
private func closeCallView(_ client: WebRTCClient) {
if m.activeCall != nil {
m.showCallView = false
@@ -290,16 +241,44 @@ struct ActiveCallOverlay: View {
var body: some View {
VStack {
switch call.hasVideo {
case true:
switch call.localMedia {
case .video:
videoCallInfoView(call)
.foregroundColor(.white)
.opacity(0.8)
.padding(.horizontal)
// Fixed vertical padding required for preserving position of buttons row when changing audio-to-video and back in landscape orientation.
// Otherwise, bigger padding is added by SwiftUI when switching call types
.padding(.vertical, 10)
case false:
.padding()
Spacer()
HStack {
toggleAudioButton()
Spacer()
if deviceManager.availableInputs.allSatisfy({ $0.portType == .builtInMic }) {
toggleSpeakerButton()
.frame(width: 40, height: 40)
} else if call.hasMedia {
AudioDevicePicker()
.scaleEffect(2)
.frame(maxWidth: 40, maxHeight: 40)
} else {
Color.clear.frame(width: 40, height: 40)
}
Spacer()
endCallButton()
Spacer()
if call.videoEnabled {
flipCameraButton()
} else {
Color.clear.frame(width: 40, height: 40)
}
Spacer()
toggleVideoButton()
}
.padding(.horizontal, 20)
.padding(.bottom, 16)
.frame(maxWidth: .infinity, alignment: .center)
case .audio:
ZStack(alignment: .topLeading) {
Button {
chatModel.activeCallViewIsCollapsed = true
@@ -314,32 +293,35 @@ struct ActiveCallOverlay: View {
}
.foregroundColor(.white)
.opacity(0.8)
.padding(.horizontal)
.padding(.vertical, 10)
.padding()
.frame(maxHeight: .infinity)
}
}
Spacer()
Spacer()
HStack {
toggleMicButton()
Spacer()
audioDeviceButton()
Spacer()
endCallButton()
Spacer()
if call.localMediaSources.camera {
flipCameraButton()
} else {
Color.clear.frame(width: 60, height: 60)
ZStack(alignment: .bottom) {
toggleAudioButton()
.frame(maxWidth: .infinity, alignment: .leading)
endCallButton()
// Check if the only input is microphone. And in this case show toggle button,
// If there are more inputs, it probably means something like bluetooth headphones are available
// and in this case show iOS button for choosing different output.
// There is no way to get available outputs, only inputs
if deviceManager.availableInputs.allSatisfy({ $0.portType == .builtInMic }) {
toggleSpeakerButton()
.frame(maxWidth: .infinity, alignment: .trailing)
} else if call.hasMedia {
AudioDevicePicker()
.scaleEffect(2)
.frame(maxWidth: 50, maxHeight: 40)
.frame(maxWidth: .infinity, alignment: .trailing)
} else {
Color.clear.frame(width: 50, height: 40)
}
}
Spacer()
toggleCameraButton()
.padding(.bottom, 60)
.padding(.horizontal, 48)
}
.padding(.horizontal, 20)
.padding(.bottom, 16)
.frame(maxWidth: 440, alignment: .center)
}
.frame(maxWidth: .infinity)
.onAppear {
@@ -401,54 +383,36 @@ struct ActiveCallOverlay: View {
private func endCallButton() -> some View {
let cc = CallController.shared
return callButton("phone.down.fill", .red, padding: 10) {
return callButton("phone.down.fill", width: 60, height: 60) {
if let uuid = call.callUUID {
cc.endCall(callUUID: uuid)
} else {
cc.endCall(call: call) {}
}
}
.foregroundColor(.red)
}
private func toggleMicButton() -> some View {
controlButton(call, call.localMediaSources.mic ? "mic.fill" : "mic.slash", padding: 14) {
private func toggleAudioButton() -> some View {
controlButton(call, call.audioEnabled ? "mic.fill" : "mic.slash") {
Task {
if await WebRTCClient.isAuthorized(for: .audio) {
client.setAudioEnabled(!call.localMediaSources.mic)
} else { WebRTCClient.showUnauthorizedAlert(for: .audio) }
}
}
}
func audioDeviceButton() -> some View {
// Check if the only input is microphone. And in this case show toggle button,
// If there are more inputs, it probably means something like bluetooth headphones are available
// and in this case show iOS button for choosing different output.
// There is no way to get available outputs, only inputs
Group {
if deviceManager.availableInputs.allSatisfy({ $0.portType == .builtInMic }) {
toggleSpeakerButton()
} else {
audioDevicePickerButton()
}
}
.onChange(of: call.localMediaSources.hasVideo) { hasVideo in
let current = AVAudioSession.sharedInstance().currentRoute.outputs.first?.portType
let speakerEnabled = current == .builtInSpeaker
let receiverEnabled = current == .builtInReceiver
// react automatically only when receiver were selected, otherwise keep an external device selected
if !speakerEnabled && hasVideo && receiverEnabled {
client.setSpeakerEnabledAndConfigureSession(!speakerEnabled, skipExternalDevice: true)
call.speakerEnabled = !speakerEnabled
client.setAudioEnabled(!call.audioEnabled)
DispatchQueue.main.async {
call.audioEnabled = !call.audioEnabled
}
}
}
}
private func toggleSpeakerButton() -> some View {
controlButton(call, !call.peerMediaSources.mic ? "speaker.slash" : call.speakerEnabled ? "speaker.wave.2.fill" : "speaker.wave.1.fill", padding: !call.peerMediaSources.mic ? 16 : call.speakerEnabled ? 15 : 17) {
let speakerEnabled = AVAudioSession.sharedInstance().currentRoute.outputs.first?.portType == .builtInSpeaker
client.setSpeakerEnabledAndConfigureSession(!speakerEnabled)
call.speakerEnabled = !speakerEnabled
controlButton(call, call.speakerEnabled ? "speaker.wave.2.fill" : "speaker.wave.1.fill") {
Task {
let speakerEnabled = AVAudioSession.sharedInstance().currentRoute.outputs.first?.portType == .builtInSpeaker
client.setSpeakerEnabledAndConfigureSession(!speakerEnabled)
DispatchQueue.main.async {
call.speakerEnabled = !speakerEnabled
}
}
}
.onAppear {
deviceManager.call = call
@@ -456,67 +420,53 @@ struct ActiveCallOverlay: View {
}
}
private func toggleCameraButton() -> some View {
controlButton(call, call.localMediaSources.camera ? "video.fill" : "video.slash", padding: call.localMediaSources.camera ? 16 : 14) {
private func toggleVideoButton() -> some View {
controlButton(call, call.videoEnabled ? "video.fill" : "video.slash") {
Task {
if await WebRTCClient.isAuthorized(for: .video) {
client.setCameraEnabled(!call.localMediaSources.camera)
} else { WebRTCClient.showUnauthorizedAlert(for: .video) }
client.setVideoEnabled(!call.videoEnabled)
DispatchQueue.main.async {
call.videoEnabled = !call.videoEnabled
}
}
}
.disabled(call.initialCallType == .audio && client.activeCall?.peerHasOldVersion == true)
}
@ViewBuilder private func flipCameraButton() -> some View {
controlButton(call, "arrow.triangle.2.circlepath", padding: 12) {
controlButton(call, "arrow.triangle.2.circlepath") {
Task {
if await WebRTCClient.isAuthorized(for: .video) {
client.flipCamera()
}
client.flipCamera()
}
}
}
@ViewBuilder private func controlButton(_ call: Call, _ imageName: String, padding: CGFloat, _ perform: @escaping () -> Void) -> some View {
callButton(imageName, call.peerMediaSources.hasVideo ? Color.black.opacity(0.2) : Color.white.opacity(0.2), padding: padding, perform)
@ViewBuilder private func controlButton(_ call: Call, _ imageName: String, _ perform: @escaping () -> Void) -> some View {
if call.hasMedia {
callButton(imageName, width: 50, height: 38, perform)
.foregroundColor(.white)
.opacity(0.85)
} else {
Color.clear.frame(width: 50, height: 38)
}
}
@ViewBuilder private func audioDevicePickerButton() -> some View {
AudioDevicePicker()
.opacity(0.8)
.scaleEffect(2)
.padding(10)
.frame(width: 60, height: 60)
.background(call.peerMediaSources.hasVideo ? Color.black.opacity(0.2) : Color.white.opacity(0.2))
.clipShape(.circle)
}
private func callButton(_ imageName: String, _ background: Color, padding: CGFloat, _ perform: @escaping () -> Void) -> some View {
private func callButton(_ imageName: String, width: CGFloat, height: CGFloat, _ perform: @escaping () -> Void) -> some View {
Button {
perform()
} label: {
Image(systemName: imageName)
.resizable()
.scaledToFit()
.padding(padding)
.frame(width: 60, height: 60)
.background(background)
.frame(maxWidth: width, maxHeight: height)
}
.foregroundColor(whiteColorWithAlpha)
.clipShape(.circle)
}
private var whiteColorWithAlpha: Color {
get { Color(red: 204 / 255, green: 204 / 255, blue: 204 / 255) }
}
}
struct ActiveCallOverlay_Previews: PreviewProvider {
static var previews: some View {
Group{
ActiveCallOverlay(call: Call(direction: .incoming, contact: Contact.sampleData, callUUID: UUID().uuidString.lowercased(), callState: .offerSent, initialCallType: .video), client: WebRTCClient({ _ in }, Binding.constant(nil)))
ActiveCallOverlay(call: Call(direction: .incoming, contact: Contact.sampleData, callUUID: UUID().uuidString.lowercased(), callState: .offerSent, localMedia: .video), client: WebRTCClient(Binding.constant(nil), { _ in }, Binding.constant(nil)))
.background(.black)
ActiveCallOverlay(call: Call(direction: .incoming, contact: Contact.sampleData, callUUID: UUID().uuidString.lowercased(), callState: .offerSent, initialCallType: .audio), client: WebRTCClient({ _ in }, Binding.constant(nil)))
ActiveCallOverlay(call: Call(direction: .incoming, contact: Contact.sampleData, callUUID: UUID().uuidString.lowercased(), callState: .offerSent, localMedia: .audio), client: WebRTCClient(Binding.constant(nil), { _ in }, Binding.constant(nil)))
.background(.black)
}
}
@@ -104,7 +104,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
}
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
if callManager.enableMedia(source: .mic, enable: !action.isMuted, callUUID: action.callUUID.uuidString.lowercased()) {
if callManager.enableMedia(media: .audio, enable: !action.isMuted, callUUID: action.callUUID.uuidString.lowercased()) {
action.fulfill()
} else {
action.fail()
@@ -121,8 +121,8 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
RTCAudioSession.sharedInstance().audioSessionDidActivate(audioSession)
RTCAudioSession.sharedInstance().isAudioEnabled = true
do {
let hasVideo = ChatModel.shared.activeCall?.hasVideo == true
if hasVideo {
let supportsVideo = ChatModel.shared.activeCall?.supportsVideo == true
if supportsVideo {
try audioSession.setCategory(.playAndRecord, mode: .videoChat, options: [.defaultToSpeaker, .mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
} else {
try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: [.mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
@@ -133,7 +133,7 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
try? await Task.sleep(nanoseconds: UInt64(i) * 300_000000)
if let preferred = audioSession.preferredInputDevice() {
await MainActor.run { try? audioSession.setPreferredInput(preferred) }
} else if hasVideo {
} else if supportsVideo {
await MainActor.run { try? audioSession.overrideOutputAudioPort(.speaker) }
}
}
@@ -357,9 +357,11 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
self.provider.reportCall(with: uuid, updated: update)
}
} else if callManager.startOutgoingCall(callUUID: callUUID) {
logger.debug("CallController.startCall: call started")
} else {
logger.error("CallController.startCall: no active call")
if callManager.startOutgoingCall(callUUID: callUUID) {
logger.debug("CallController.startCall: call started")
} else {
logger.error("CallController.startCall: no active call")
}
}
}
+5 -5
View File
@@ -12,7 +12,7 @@ import SimpleXChat
class CallManager {
func newOutgoingCall(_ contact: Contact, _ media: CallMediaType) -> String {
let uuid = UUID().uuidString.lowercased()
let call = Call(direction: .outgoing, contact: contact, callUUID: uuid, callState: .waitCapabilities, initialCallType: media)
let call = Call(direction: .outgoing, contact: contact, callUUID: uuid, callState: .waitCapabilities, localMedia: media)
call.speakerEnabled = media == .video
ChatModel.shared.activeCall = call
return uuid
@@ -22,7 +22,7 @@ class CallManager {
let m = ChatModel.shared
if let call = m.activeCall, call.callUUID == callUUID {
m.showCallView = true
Task { await m.callCommand.processCommand(.capabilities(media: call.initialCallType)) }
Task { await m.callCommand.processCommand(.capabilities(media: call.localMedia)) }
return true
}
return false
@@ -44,7 +44,7 @@ class CallManager {
contact: invitation.contact,
callUUID: invitation.callUUID,
callState: .invitationAccepted,
initialCallType: invitation.callType.media,
localMedia: invitation.callType.media,
sharedKey: invitation.sharedKey
)
call.speakerEnabled = invitation.callType.media == .video
@@ -68,10 +68,10 @@ class CallManager {
}
}
func enableMedia(source: CallMediaSource, enable: Bool, callUUID: String) -> Bool {
func enableMedia(media: CallMediaType, enable: Bool, callUUID: String) -> Bool {
if let call = ChatModel.shared.activeCall, call.callUUID == callUUID {
let m = ChatModel.shared
Task { await m.callCommand.processCommand(.media(source: source, enable: enable)) }
Task { await m.callCommand.processCommand(.media(media: media, enable: enable)) }
return true
}
return false
@@ -10,49 +10,40 @@ import AVKit
struct CallViewRemote: UIViewRepresentable {
var client: WebRTCClient
@ObservedObject var call: Call
var activeCall: Binding<WebRTCClient.Call?>
@State var enablePip: (Bool) -> Void = {_ in }
@Binding var activeCallViewIsCollapsed: Bool
@Binding var contentMode: UIView.ContentMode
@Binding var pipShown: Bool
init(client: WebRTCClient, activeCall: Binding<WebRTCClient.Call?>, activeCallViewIsCollapsed: Binding<Bool>, pipShown: Binding<Bool>) {
self.client = client
self.activeCall = activeCall
self._activeCallViewIsCollapsed = activeCallViewIsCollapsed
self._pipShown = pipShown
}
func makeUIView(context: Context) -> UIView {
let view = UIView()
let remoteCameraRenderer = RTCMTLVideoView(frame: view.frame)
remoteCameraRenderer.videoContentMode = contentMode
remoteCameraRenderer.tag = 0
if let call = activeCall.wrappedValue {
let remoteRenderer = RTCMTLVideoView(frame: view.frame)
remoteRenderer.videoContentMode = .scaleAspectFill
client.addRemoteRenderer(call, remoteRenderer)
addSubviewAndResize(remoteRenderer, into: view)
let screenVideo = call.peerMediaSources.screenVideo
let remoteScreenRenderer = RTCMTLVideoView(frame: view.frame)
remoteScreenRenderer.videoContentMode = contentMode
remoteScreenRenderer.tag = 1
remoteScreenRenderer.alpha = screenVideo ? 1 : 0
context.coordinator.cameraRenderer = remoteCameraRenderer
context.coordinator.screenRenderer = remoteScreenRenderer
client.addRemoteCameraRenderer(remoteCameraRenderer)
client.addRemoteScreenRenderer(remoteScreenRenderer)
if screenVideo {
addSubviewAndResize(remoteScreenRenderer, remoteCameraRenderer, into: view)
} else {
addSubviewAndResize(remoteCameraRenderer, remoteScreenRenderer, into: view)
}
if AVPictureInPictureController.isPictureInPictureSupported() {
makeViewWithRTCRenderer(remoteCameraRenderer, remoteScreenRenderer, view, context)
if AVPictureInPictureController.isPictureInPictureSupported() {
makeViewWithRTCRenderer(call, remoteRenderer, view, context)
}
}
return view
}
func makeViewWithRTCRenderer(_ remoteCameraRenderer: RTCMTLVideoView, _ remoteScreenRenderer: RTCMTLVideoView, _ view: UIView, _ context: Context) {
let pipRemoteCameraRenderer = RTCMTLVideoView(frame: view.frame)
pipRemoteCameraRenderer.videoContentMode = .scaleAspectFill
let pipRemoteScreenRenderer = RTCMTLVideoView(frame: view.frame)
pipRemoteScreenRenderer.videoContentMode = .scaleAspectFill
func makeViewWithRTCRenderer(_ call: WebRTCClient.Call, _ remoteRenderer: RTCMTLVideoView, _ view: UIView, _ context: Context) {
let pipRemoteRenderer = RTCMTLVideoView(frame: view.frame)
pipRemoteRenderer.videoContentMode = .scaleAspectFill
let pipVideoCallViewController = AVPictureInPictureVideoCallViewController()
pipVideoCallViewController.preferredContentSize = CGSize(width: 1080, height: 1920)
addSubviewAndResize(pipRemoteRenderer, into: pipVideoCallViewController.view)
let pipContentSource = AVPictureInPictureController.ContentSource(
activeVideoCallSourceView: view,
contentViewController: pipVideoCallViewController
@@ -64,9 +55,7 @@ struct CallViewRemote: UIViewRepresentable {
context.coordinator.pipController = pipController
context.coordinator.willShowHide = { show in
if show {
client.addRemoteCameraRenderer(pipRemoteCameraRenderer)
client.addRemoteScreenRenderer(pipRemoteScreenRenderer)
context.coordinator.relayout()
client.addRemoteRenderer(call, pipRemoteRenderer)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
activeCallViewIsCollapsed = true
}
@@ -78,29 +67,13 @@ struct CallViewRemote: UIViewRepresentable {
}
context.coordinator.didShowHide = { show in
if show {
remoteCameraRenderer.isHidden = true
remoteScreenRenderer.isHidden = true
remoteRenderer.isHidden = true
} else {
client.removeRemoteCameraRenderer(pipRemoteCameraRenderer)
client.removeRemoteScreenRenderer(pipRemoteScreenRenderer)
remoteCameraRenderer.isHidden = false
remoteScreenRenderer.isHidden = false
client.removeRemoteRenderer(call, pipRemoteRenderer)
remoteRenderer.isHidden = false
}
pipShown = show
}
context.coordinator.relayout = {
let camera = call.peerMediaSources.camera
let screenVideo = call.peerMediaSources.screenVideo
pipRemoteCameraRenderer.alpha = camera ? 1 : 0
pipRemoteScreenRenderer.alpha = screenVideo ? 1 : 0
if screenVideo {
addSubviewAndResize(pipRemoteScreenRenderer, pipRemoteCameraRenderer, pip: true, into: pipVideoCallViewController.view)
} else {
addSubviewAndResize(pipRemoteCameraRenderer, pipRemoteScreenRenderer, pip: true, into: pipVideoCallViewController.view)
}
(pipVideoCallViewController.view.subviews[0] as! RTCMTLVideoView).videoContentMode = contentMode
(pipVideoCallViewController.view.subviews[1] as! RTCMTLVideoView).videoContentMode = .scaleAspectFill
}
DispatchQueue.main.async {
enablePip = { enable in
if enable != pipShown /* pipController.isPictureInPictureActive */ {
@@ -115,50 +88,24 @@ struct CallViewRemote: UIViewRepresentable {
}
func makeCoordinator() -> Coordinator {
Coordinator(client)
Coordinator()
}
func updateUIView(_ view: UIView, context: Context) {
logger.debug("CallView.updateUIView remote")
let camera = view.subviews.first(where: { $0.tag == 0 })!
let screen = view.subviews.first(where: { $0.tag == 1 })!
let screenVideo = call.peerMediaSources.screenVideo
if screenVideo && screen.alpha == 0 {
screen.alpha = 1
addSubviewAndResize(screen, camera, into: view)
} else if !screenVideo && screen.alpha == 1 {
screen.alpha = 0
addSubviewAndResize(camera, screen, into: view)
}
(view.subviews[0] as! RTCMTLVideoView).videoContentMode = contentMode
(view.subviews[1] as! RTCMTLVideoView).videoContentMode = .scaleAspectFill
camera.alpha = call.peerMediaSources.camera ? 1 : 0
screen.alpha = call.peerMediaSources.screenVideo ? 1 : 0
DispatchQueue.main.async {
if activeCallViewIsCollapsed != pipShown {
enablePip(activeCallViewIsCollapsed)
} else if pipShown {
context.coordinator.relayout()
}
}
}
// MARK: - Coordinator
class Coordinator: NSObject, AVPictureInPictureControllerDelegate {
var cameraRenderer: RTCMTLVideoView?
var screenRenderer: RTCMTLVideoView?
var client: WebRTCClient
var pipController: AVPictureInPictureController? = nil
var willShowHide: (Bool) -> Void = { _ in }
var didShowHide: (Bool) -> Void = { _ in }
var relayout: () -> Void = {}
required init(_ client: WebRTCClient) {
self.client = client
}
func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
willShowHide(true)
}
@@ -180,20 +127,11 @@ struct CallViewRemote: UIViewRepresentable {
}
deinit {
// TODO: deinit is not called when changing call type from audio to video and back,
// which causes many renderers can be created and added to stream (if enabling/disabling
// video while not yet connected in outgoing call)
pipController?.stopPictureInPicture()
pipController?.canStartPictureInPictureAutomaticallyFromInline = false
pipController?.contentSource = nil
pipController?.delegate = nil
pipController = nil
if let cameraRenderer {
client.removeRemoteCameraRenderer(cameraRenderer)
}
if let screenRenderer {
client.removeRemoteScreenRenderer(screenRenderer)
}
}
}
@@ -210,109 +148,51 @@ struct CallViewRemote: UIViewRepresentable {
struct CallViewLocal: UIViewRepresentable {
var client: WebRTCClient
var activeCall: Binding<WebRTCClient.Call?>
var localRendererAspectRatio: Binding<CGFloat?>
@State var pipStateChanged: (Bool) -> Void = {_ in }
@Binding var pipShown: Bool
init(client: WebRTCClient, localRendererAspectRatio: Binding<CGFloat?>, pipShown: Binding<Bool>) {
init(client: WebRTCClient, activeCall: Binding<WebRTCClient.Call?>, localRendererAspectRatio: Binding<CGFloat?>, pipShown: Binding<Bool>) {
self.client = client
self.activeCall = activeCall
self.localRendererAspectRatio = localRendererAspectRatio
self._pipShown = pipShown
}
func makeUIView(context: Context) -> UIView {
let view = UIView()
let localRenderer = RTCEAGLVideoView(frame: .zero)
context.coordinator.renderer = localRenderer
client.addLocalRenderer(localRenderer)
addSubviewAndResize(localRenderer, nil, into: view)
DispatchQueue.main.async {
pipStateChanged = { shown in
localRenderer.isHidden = shown
if let call = activeCall.wrappedValue {
let localRenderer = RTCEAGLVideoView(frame: .zero)
client.addLocalRenderer(call, localRenderer)
client.startCaptureLocalVideo(call)
addSubviewAndResize(localRenderer, into: view)
DispatchQueue.main.async {
pipStateChanged = { shown in
localRenderer.isHidden = shown
}
}
}
return view
}
func makeCoordinator() -> Coordinator {
Coordinator(client)
}
func updateUIView(_ view: UIView, context: Context) {
logger.debug("CallView.updateUIView local")
pipStateChanged(pipShown)
}
// MARK: - Coordinator
class Coordinator: NSObject, AVPictureInPictureControllerDelegate {
var renderer: RTCEAGLVideoView?
var client: WebRTCClient
required init(_ client: WebRTCClient) {
self.client = client
}
deinit {
if let renderer {
client.removeLocalRenderer(renderer)
}
}
}
}
private func addSubviewAndResize(_ fullscreen: UIView, _ end: UIView?, pip: Bool = false, into containerView: UIView) {
if containerView.subviews.firstIndex(of: fullscreen) == 0 && ((end == nil && containerView.subviews.count == 1) || (end != nil && containerView.subviews.firstIndex(of: end!) == 1)) {
// Nothing to do, elements on their places
return
}
containerView.removeConstraints(containerView.constraints)
containerView.subviews.forEach { sub in sub.removeFromSuperview()}
containerView.addSubview(fullscreen)
fullscreen.translatesAutoresizingMaskIntoConstraints = false
fullscreen.layer.cornerRadius = 0
fullscreen.layer.masksToBounds = false
if let end {
containerView.addSubview(end)
end.translatesAutoresizingMaskIntoConstraints = false
end.layer.cornerRadius = pip ? 8 : 10
end.layer.masksToBounds = true
}
let constraintFullscreenV = NSLayoutConstraint.constraints(
withVisualFormat: "V:|[fullscreen]|",
private func addSubviewAndResize(_ view: UIView, into containerView: UIView) {
containerView.addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
containerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[view]|",
options: [],
metrics: nil,
views: ["fullscreen": fullscreen]
)
let constraintFullscreenH = NSLayoutConstraint.constraints(
withVisualFormat: "H:|[fullscreen]|",
views: ["view": view]))
containerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[view]|",
options: [],
metrics: nil,
views: ["fullscreen": fullscreen]
)
containerView.addConstraints(constraintFullscreenV)
containerView.addConstraints(constraintFullscreenH)
if let end {
let constraintEndWidth = NSLayoutConstraint(
item: end, attribute: .width, relatedBy: .equal, toItem: containerView, attribute: .width, multiplier: pip ? 0.5 : 0.3, constant: 0
)
let constraintEndHeight = NSLayoutConstraint(
item: end, attribute: .height, relatedBy: .equal, toItem: containerView, attribute: .width, multiplier: pip ? 0.5 * 1.33 : 0.3 * 1.33, constant: 0
)
let constraintEndX = NSLayoutConstraint(
item: end, attribute: .leading, relatedBy: .equal, toItem: containerView, attribute: .trailing, multiplier: pip ? 0.5 : 0.7, constant: pip ? -8 : -17
)
let constraintEndY = NSLayoutConstraint(
item: end, attribute: .bottom, relatedBy: .equal, toItem: containerView, attribute: .bottom, multiplier: 1, constant: pip ? -8 : -92
)
containerView.addConstraint(constraintEndWidth)
containerView.addConstraint(constraintEndHeight)
containerView.addConstraint(constraintEndX)
containerView.addConstraint(constraintEndY)
}
views: ["view": view]))
containerView.layoutIfNeeded()
}
+17 -39
View File
@@ -19,13 +19,14 @@ class Call: ObservableObject, Equatable {
var direction: CallDirection
var contact: Contact
var callUUID: String?
var initialCallType: CallMediaType
@Published var localMediaSources: CallMediaSources
var localMedia: CallMediaType
@Published var callState: CallState
@Published var localCapabilities: CallCapabilities?
@Published var peerMediaSources: CallMediaSources = CallMediaSources()
@Published var peerMedia: CallMediaType?
@Published var sharedKey: String?
@Published var audioEnabled = true
@Published var speakerEnabled = false
@Published var videoEnabled: Bool
@Published var connectionInfo: ConnectionInfo?
@Published var connectedAt: Date? = nil
@@ -34,33 +35,32 @@ class Call: ObservableObject, Equatable {
contact: Contact,
callUUID: String?,
callState: CallState,
initialCallType: CallMediaType,
localMedia: CallMediaType,
sharedKey: String? = nil
) {
self.direction = direction
self.contact = contact
self.callUUID = callUUID
self.callState = callState
self.initialCallType = initialCallType
self.localMedia = localMedia
self.sharedKey = sharedKey
self.localMediaSources = CallMediaSources(
mic: AVCaptureDevice.authorizationStatus(for: .audio) == .authorized,
camera: initialCallType == .video && AVCaptureDevice.authorizationStatus(for: .video) == .authorized)
self.videoEnabled = localMedia == .video
}
var encrypted: Bool { get { localEncrypted && sharedKey != nil } }
private var localEncrypted: Bool { get { localCapabilities?.encryption ?? false } }
var localEncrypted: Bool { get { localCapabilities?.encryption ?? false } }
var encryptionStatus: LocalizedStringKey {
get {
switch callState {
case .waitCapabilities: return ""
case .invitationSent: return localEncrypted ? "e2e encrypted" : "no e2e encryption"
case .invitationAccepted: return sharedKey == nil ? "contact has no e2e encryption" : "contact has e2e encryption"
default: return !localEncrypted ? "no e2e encryption" : sharedKey == nil ? "contact has no e2e encryption" : "e2e encrypted"
default: return !localEncrypted ? "no e2e encryption" : sharedKey == nil ? "contact has no e2e encryption" : "e2e encrypted"
}
}
}
var hasVideo: Bool { get { localMediaSources.hasVideo || peerMediaSources.hasVideo } }
var hasMedia: Bool { get { callState == .offerSent || callState == .negotiated || callState == .connected } }
var supportsVideo: Bool { get { peerMedia == .video || localMedia == .video } }
}
enum CallDirection {
@@ -105,28 +105,18 @@ struct WVAPIMessage: Equatable, Decodable, Encodable {
var command: WCallCommand?
}
struct CallMediaSources: Equatable, Codable {
var mic: Bool = false
var camera: Bool = false
var screenAudio: Bool = false
var screenVideo: Bool = false
var hasVideo: Bool { get { camera || screenVideo } }
}
enum WCallCommand: Equatable, Encodable, Decodable {
case capabilities(media: CallMediaType)
case start(media: CallMediaType, aesKey: String? = nil, iceServers: [RTCIceServer]? = nil, relay: Bool? = nil)
case offer(offer: String, iceCandidates: String, media: CallMediaType, aesKey: String? = nil, iceServers: [RTCIceServer]? = nil, relay: Bool? = nil)
case answer(answer: String, iceCandidates: String)
case ice(iceCandidates: String)
case media(source: CallMediaSource, enable: Bool)
case media(media: CallMediaType, enable: Bool)
case end
enum CodingKeys: String, CodingKey {
case type
case media
case source
case aesKey
case offer
case answer
@@ -177,9 +167,9 @@ enum WCallCommand: Equatable, Encodable, Decodable {
case let .ice(iceCandidates):
try container.encode("ice", forKey: .type)
try container.encode(iceCandidates, forKey: .iceCandidates)
case let .media(source, enable):
case let .media(media, enable):
try container.encode("media", forKey: .type)
try container.encode(source, forKey: .media)
try container.encode(media, forKey: .media)
try container.encode(enable, forKey: .enable)
case .end:
try container.encode("end", forKey: .type)
@@ -215,9 +205,9 @@ enum WCallCommand: Equatable, Encodable, Decodable {
let iceCandidates = try container.decode(String.self, forKey: CodingKeys.iceCandidates)
self = .ice(iceCandidates: iceCandidates)
case "media":
let source = try container.decode(CallMediaSource.self, forKey: CodingKeys.source)
let media = try container.decode(CallMediaType.self, forKey: CodingKeys.media)
let enable = try container.decode(Bool.self, forKey: CodingKeys.enable)
self = .media(source: source, enable: enable)
self = .media(media: media, enable: enable)
case "end":
self = .end
default:
@@ -234,7 +224,6 @@ enum WCallResponse: Equatable, Decodable {
case ice(iceCandidates: String)
case connection(state: ConnectionState)
case connected(connectionInfo: ConnectionInfo)
case peerMedia(source: CallMediaSource, enabled: Bool)
case ended
case ok
case error(message: String)
@@ -249,8 +238,6 @@ enum WCallResponse: Equatable, Decodable {
case state
case connectionInfo
case message
case source
case enabled
}
var respType: String {
@@ -262,7 +249,6 @@ enum WCallResponse: Equatable, Decodable {
case .ice: return "ice"
case .connection: return "connection"
case .connected: return "connected"
case .peerMedia: return "peerMedia"
case .ended: return "ended"
case .ok: return "ok"
case .error: return "error"
@@ -297,10 +283,6 @@ enum WCallResponse: Equatable, Decodable {
case "connected":
let connectionInfo = try container.decode(ConnectionInfo.self, forKey: CodingKeys.connectionInfo)
self = .connected(connectionInfo: connectionInfo)
case "peerMedia":
let source = try container.decode(CallMediaSource.self, forKey: CodingKeys.source)
let enabled = try container.decode(Bool.self, forKey: CodingKeys.enabled)
self = .peerMedia(source: source, enabled: enabled)
case "ended":
self = .ended
case "ok":
@@ -342,10 +324,6 @@ extension WCallResponse: Encodable {
case let .connected(connectionInfo):
try container.encode("connected", forKey: .type)
try container.encode(connectionInfo, forKey: .connectionInfo)
case let .peerMedia(source, enabled):
try container.encode("peerMedia", forKey: .type)
try container.encode(source, forKey: .source)
try container.encode(enabled, forKey: .enabled)
case .ended:
try container.encode("ended", forKey: .type)
case .ok:
@@ -398,7 +376,7 @@ actor WebRTCCommandProcessor {
func shouldRunCommand(_ client: WebRTCClient, _ c: WCallCommand) -> Bool {
switch c {
case .capabilities, .start, .offer, .end: true
default: client.activeCall != nil
default: client.activeCall.wrappedValue != nil
}
}
}
+103 -414
View File
@@ -23,24 +23,15 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
struct Call {
var connection: RTCPeerConnection
var iceCandidates: IceCandidates
var localMedia: CallMediaType
var localCamera: RTCVideoCapturer?
var localAudioTrack: RTCAudioTrack?
var localVideoTrack: RTCVideoTrack?
var remoteAudioTrack: RTCAudioTrack?
var remoteVideoTrack: RTCVideoTrack?
var remoteScreenAudioTrack: RTCAudioTrack?
var remoteScreenVideoTrack: RTCVideoTrack?
var device: AVCaptureDevice.Position
var localVideoSource: RTCVideoSource?
var localStream: RTCVideoTrack?
var remoteStream: RTCVideoTrack?
var device: AVCaptureDevice.Position = .front
var aesKey: String?
var frameEncryptor: RTCFrameEncryptor?
var frameDecryptor: RTCFrameDecryptor?
var peerHasOldVersion: Bool
}
struct NotConnectedCall {
var audioTrack: RTCAudioTrack?
var localCameraAndTrack: (RTCVideoCapturer, RTCVideoTrack)?
var device: AVCaptureDevice.Position = .front
}
actor IceCandidates {
@@ -60,20 +51,17 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
private let rtcAudioSession = RTCAudioSession.sharedInstance()
private let audioQueue = DispatchQueue(label: "chat.simplex.app.audio")
private var sendCallResponse: (WVAPIMessage) async -> Void
var activeCall: Call?
var notConnectedCall: NotConnectedCall?
var activeCall: Binding<Call?>
private var localRendererAspectRatio: Binding<CGFloat?>
var cameraRenderers: [RTCVideoRenderer] = []
var screenRenderers: [RTCVideoRenderer] = []
@available(*, unavailable)
override init() {
fatalError("Unimplemented")
}
required init(_ sendCallResponse: @escaping (WVAPIMessage) async -> Void, _ localRendererAspectRatio: Binding<CGFloat?>) {
required init(_ activeCall: Binding<Call?>, _ sendCallResponse: @escaping (WVAPIMessage) async -> Void, _ localRendererAspectRatio: Binding<CGFloat?>) {
self.sendCallResponse = sendCallResponse
self.activeCall = activeCall
self.localRendererAspectRatio = localRendererAspectRatio
rtcAudioSession.useManualAudio = CallController.useCallKit()
rtcAudioSession.isAudioEnabled = !CallController.useCallKit()
@@ -90,45 +78,39 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
func initializeCall(_ iceServers: [WebRTC.RTCIceServer]?, _ mediaType: CallMediaType, _ aesKey: String?, _ relay: Bool?) -> Call {
let connection = createPeerConnection(iceServers ?? getWebRTCIceServers() ?? defaultIceServers, relay)
connection.delegate = self
let device = notConnectedCall?.device ?? .front
createAudioSender(connection)
var localStream: RTCVideoTrack? = nil
var remoteStream: RTCVideoTrack? = nil
var localCamera: RTCVideoCapturer? = nil
var localAudioTrack: RTCAudioTrack? = nil
var localVideoTrack: RTCVideoTrack? = nil
if let localCameraAndTrack = notConnectedCall?.localCameraAndTrack {
(localCamera, localVideoTrack) = localCameraAndTrack
} else if notConnectedCall == nil && mediaType == .video {
(localCamera, localVideoTrack) = createVideoTrackAndStartCapture(device)
var localVideoSource: RTCVideoSource? = nil
if mediaType == .video {
(localStream, remoteStream, localCamera, localVideoSource) = createVideoSender(connection)
}
if let audioTrack = notConnectedCall?.audioTrack {
localAudioTrack = audioTrack
} else if notConnectedCall == nil {
localAudioTrack = createAudioTrack()
}
notConnectedCall?.localCameraAndTrack = nil
notConnectedCall?.audioTrack = nil
var frameEncryptor: RTCFrameEncryptor? = nil
var frameDecryptor: RTCFrameDecryptor? = nil
if aesKey != nil {
let encryptor = RTCFrameEncryptor.init(sizeChange: Int32(WebRTCClient.ivTagBytes))
encryptor.delegate = self
frameEncryptor = encryptor
connection.senders.forEach { $0.setRtcFrameEncryptor(encryptor) }
let decryptor = RTCFrameDecryptor.init(sizeChange: -Int32(WebRTCClient.ivTagBytes))
decryptor.delegate = self
frameDecryptor = decryptor
// Has no video receiver in outgoing call if applied here, see [peerConnection(_ connection: RTCPeerConnection, didChange newState]
// connection.receivers.forEach { $0.setRtcFrameDecryptor(decryptor) }
}
return Call(
connection: connection,
iceCandidates: IceCandidates(),
localMedia: mediaType,
localCamera: localCamera,
localAudioTrack: localAudioTrack,
localVideoTrack: localVideoTrack,
device: device,
localVideoSource: localVideoSource,
localStream: localStream,
remoteStream: remoteStream,
aesKey: aesKey,
frameEncryptor: frameEncryptor,
frameDecryptor: frameDecryptor,
peerHasOldVersion: false
frameDecryptor: frameDecryptor
)
}
@@ -169,24 +151,18 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
func sendCallCommand(command: WCallCommand) async {
var resp: WCallResponse? = nil
let pc = activeCall?.connection
let pc = activeCall.wrappedValue?.connection
switch command {
case let .capabilities(media): // outgoing
let localCameraAndTrack: (RTCVideoCapturer, RTCVideoTrack)? = media == .video
? createVideoTrackAndStartCapture(.front)
: nil
notConnectedCall = NotConnectedCall(audioTrack: createAudioTrack(), localCameraAndTrack: localCameraAndTrack, device: .front)
case .capabilities:
resp = .capabilities(capabilities: CallCapabilities(encryption: WebRTCClient.enableEncryption))
case let .start(media: media, aesKey, iceServers, relay): // incoming
case let .start(media: media, aesKey, iceServers, relay):
logger.debug("starting incoming call - create webrtc session")
if activeCall != nil { endCall() }
if activeCall.wrappedValue != nil { endCall() }
let encryption = WebRTCClient.enableEncryption
let call = initializeCall(iceServers?.toWebRTCIceServers(), media, encryption ? aesKey : nil, relay)
activeCall = call
setupLocalTracks(true, call)
activeCall.wrappedValue = call
let (offer, error) = await call.connection.offer()
if let offer = offer {
setupEncryptionForLocalTracks(call)
resp = .offer(
offer: compressToBase64(input: encodeJSON(CustomRTCSessionDescription(type: offer.type.toSdpType(), sdp: offer.sdp))),
iceCandidates: compressToBase64(input: encodeJSON(await self.getInitialIceCandidates())),
@@ -196,24 +172,18 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
} else {
resp = .error(message: "offer error: \(error?.localizedDescription ?? "unknown error")")
}
case let .offer(offer, iceCandidates, media, aesKey, iceServers, relay): // outgoing
if activeCall != nil {
case let .offer(offer, iceCandidates, media, aesKey, iceServers, relay):
if activeCall.wrappedValue != nil {
resp = .error(message: "accept: call already started")
} else if !WebRTCClient.enableEncryption && aesKey != nil {
resp = .error(message: "accept: encryption is not supported")
} else if let offer: CustomRTCSessionDescription = decodeJSON(decompressFromBase64(input: offer)),
let remoteIceCandidates: [RTCIceCandidate] = decodeJSON(decompressFromBase64(input: iceCandidates)) {
let call = initializeCall(iceServers?.toWebRTCIceServers(), media, WebRTCClient.enableEncryption ? aesKey : nil, relay)
activeCall = call
activeCall.wrappedValue = call
let pc = call.connection
if let type = offer.type, let sdp = offer.sdp {
if (try? await pc.setRemoteDescription(RTCSessionDescription(type: type.toWebRTCSdpType(), sdp: sdp))) != nil {
setupLocalTracks(false, call)
setupEncryptionForLocalTracks(call)
pc.transceivers.forEach { transceiver in
transceiver.setDirection(.sendRecv, error: nil)
}
await adaptToOldVersion(pc.transceivers.count <= 2)
let (answer, error) = await pc.answer()
if let answer = answer {
self.addIceCandidates(pc, remoteIceCandidates)
@@ -230,7 +200,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
}
}
}
case let .answer(answer, iceCandidates): // incoming
case let .answer(answer, iceCandidates):
if pc == nil {
resp = .error(message: "answer: call not started")
} else if pc?.localDescription == nil {
@@ -242,9 +212,6 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
let type = answer.type, let sdp = answer.sdp,
let pc = pc {
if (try? await pc.setRemoteDescription(RTCSessionDescription(type: type.toWebRTCSdpType(), sdp: sdp))) != nil {
var currentDirection: RTCRtpTransceiverDirection = .sendOnly
pc.transceivers[2].currentDirection(&currentDirection)
await adaptToOldVersion(currentDirection == .sendOnly)
addIceCandidates(pc, remoteIceCandidates)
resp = .ok
} else {
@@ -259,11 +226,13 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
} else {
resp = .error(message: "ice: call not started")
}
case let .media(source, enable):
if activeCall == nil {
case let .media(media, enable):
if activeCall.wrappedValue == nil {
resp = .error(message: "media: call not started")
} else if activeCall.wrappedValue?.localMedia == .audio && media == .video {
resp = .error(message: "media: no video")
} else {
await enableMedia(source, enable)
enableMedia(media, enable)
resp = .ok
}
case .end:
@@ -278,7 +247,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
func getInitialIceCandidates() async -> [RTCIceCandidate] {
await untilIceComplete(timeoutMs: 750, stepMs: 150) {}
let candidates = await activeCall?.iceCandidates.getAndClear() ?? []
let candidates = await activeCall.wrappedValue?.iceCandidates.getAndClear() ?? []
logger.debug("WebRTCClient: sending initial ice candidates: \(candidates.count)")
return candidates
}
@@ -286,7 +255,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
func waitForMoreIceCandidates() {
Task {
await untilIceComplete(timeoutMs: 12000, stepMs: 1500) {
let candidates = await self.activeCall?.iceCandidates.getAndClear() ?? []
let candidates = await self.activeCall.wrappedValue?.iceCandidates.getAndClear() ?? []
if candidates.count > 0 {
logger.debug("WebRTCClient: sending more ice candidates: \(candidates.count)")
await self.sendIceCandidates(candidates)
@@ -303,202 +272,25 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
)
}
func setupMuteUnmuteListener(_ transceiver: RTCRtpTransceiver, _ track: RTCMediaStreamTrack) {
// logger.log("Setting up mute/unmute listener in the call without encryption for mid = \(transceiver.mid)")
Task {
var lastBytesReceived: Int64 = 0
// muted initially
var mutedSeconds = 4
while let call = self.activeCall, transceiver.receiver.track?.readyState == .live {
let stats: RTCStatisticsReport = await call.connection.statistics(for: transceiver.receiver)
let stat = stats.statistics.values.first(where: { stat in stat.type == "inbound-rtp"})
if let stat {
//logger.debug("Stat \(stat.debugDescription)")
let bytes = stat.values["bytesReceived"] as! Int64
if bytes <= lastBytesReceived {
mutedSeconds += 1
if mutedSeconds == 3 {
await MainActor.run {
self.onMediaMuteUnmute(transceiver.mid, true)
}
}
} else {
if mutedSeconds >= 3 {
await MainActor.run {
self.onMediaMuteUnmute(transceiver.mid, false)
}
}
lastBytesReceived = bytes
mutedSeconds = 0
}
}
try? await Task.sleep(nanoseconds: 1000_000000)
}
}
func enableMedia(_ media: CallMediaType, _ enable: Bool) {
logger.debug("WebRTCClient: enabling media \(media.rawValue) \(enable)")
media == .video ? setVideoEnabled(enable) : setAudioEnabled(enable)
}
@MainActor
func onMediaMuteUnmute(_ transceiverMid: String?, _ mute: Bool) {
guard let activeCall = ChatModel.shared.activeCall else { return }
let source = mediaSourceFromTransceiverMid(transceiverMid)
logger.log("Mute/unmute \(source.rawValue) track = \(mute) with mid = \(transceiverMid ?? "nil")")
if source == .mic && activeCall.peerMediaSources.mic == mute {
activeCall.peerMediaSources.mic = !mute
} else if (source == .camera && activeCall.peerMediaSources.camera == mute) {
activeCall.peerMediaSources.camera = !mute
} else if (source == .screenAudio && activeCall.peerMediaSources.screenAudio == mute) {
activeCall.peerMediaSources.screenAudio = !mute
} else if (source == .screenVideo && activeCall.peerMediaSources.screenVideo == mute) {
activeCall.peerMediaSources.screenVideo = !mute
}
}
@MainActor
func enableMedia(_ source: CallMediaSource, _ enable: Bool) {
logger.debug("WebRTCClient: enabling media \(source.rawValue) \(enable)")
source == .camera ? setCameraEnabled(enable) : setAudioEnabled(enable)
}
@MainActor
func adaptToOldVersion(_ peerHasOldVersion: Bool) {
activeCall?.peerHasOldVersion = peerHasOldVersion
if peerHasOldVersion {
logger.debug("The peer has an old version. Remote audio track is nil = \(self.activeCall?.remoteAudioTrack == nil), video = \(self.activeCall?.remoteVideoTrack == nil)")
onMediaMuteUnmute("0", false)
if activeCall?.remoteVideoTrack != nil {
onMediaMuteUnmute("1", false)
}
if ChatModel.shared.activeCall?.localMediaSources.camera == true && ChatModel.shared.activeCall?.peerMediaSources.camera == false {
logger.debug("Stopping video track for the old version")
activeCall?.connection.senders[1].track = nil
ChatModel.shared.activeCall?.localMediaSources.camera = false
(activeCall?.localCamera as? RTCCameraVideoCapturer)?.stopCapture()
activeCall?.localCamera = nil
activeCall?.localVideoTrack = nil
}
}
}
func addLocalRenderer(_ renderer: RTCEAGLVideoView) {
if let activeCall {
if let track = activeCall.localVideoTrack {
track.add(renderer)
}
} else if let notConnectedCall {
if let track = notConnectedCall.localCameraAndTrack?.1 {
track.add(renderer)
}
}
func addLocalRenderer(_ activeCall: Call, _ renderer: RTCEAGLVideoView) {
activeCall.localStream?.add(renderer)
// To get width and height of a frame, see videoView(videoView:, didChangeVideoSize)
renderer.delegate = self
}
func removeLocalRenderer(_ renderer: RTCEAGLVideoView) {
if let activeCall {
if let track = activeCall.localVideoTrack {
track.remove(renderer)
}
} else if let notConnectedCall {
if let track = notConnectedCall.localCameraAndTrack?.1 {
track.remove(renderer)
}
}
renderer.delegate = nil
}
func videoView(_ videoView: RTCVideoRenderer, didChangeVideoSize size: CGSize) {
guard size.height > 0 else { return }
localRendererAspectRatio.wrappedValue = size.width / size.height
}
func setupLocalTracks(_ incomingCall: Bool, _ call: Call) {
let pc = call.connection
let transceivers = call.connection.transceivers
let audioTrack = call.localAudioTrack
let videoTrack = call.localVideoTrack
if incomingCall {
let micCameraInit = RTCRtpTransceiverInit()
// streamIds required for old versions which adds tracks from stream, not from track property
micCameraInit.streamIds = ["micCamera"]
let screenAudioVideoInit = RTCRtpTransceiverInit()
screenAudioVideoInit.streamIds = ["screenAudioVideo"]
// incoming call, no transceivers yet. But they should be added in order: mic, camera, screen audio, screen video
// mid = 0, mic
if let audioTrack {
pc.addTransceiver(with: audioTrack, init: micCameraInit)
} else {
pc.addTransceiver(of: .audio, init: micCameraInit)
}
// mid = 1, camera
if let videoTrack {
pc.addTransceiver(with: videoTrack, init: micCameraInit)
} else {
pc.addTransceiver(of: .video, init: micCameraInit)
}
// mid = 2, screenAudio
pc.addTransceiver(of: .audio, init: screenAudioVideoInit)
// mid = 3, screenVideo
pc.addTransceiver(of: .video, init: screenAudioVideoInit)
} else {
// new version
if transceivers.count > 2 {
// Outgoing call. All transceivers are ready. Don't addTrack() because it will create new transceivers, replace existing (nil) tracks
transceivers
.first(where: { elem in mediaSourceFromTransceiverMid(elem.mid) == .mic })?
.sender.track = audioTrack
transceivers
.first(where: { elem in mediaSourceFromTransceiverMid(elem.mid) == .camera })?
.sender.track = videoTrack
} else {
// old version, only two transceivers
if let audioTrack {
pc.add(audioTrack, streamIds: ["micCamera"])
} else {
// it's important to have any track in order to be able to turn it on again (currently it's off)
let sender = pc.add(createAudioTrack(), streamIds: ["micCamera"])
sender?.track = nil
}
if let videoTrack {
pc.add(videoTrack, streamIds: ["micCamera"])
} else {
// it's important to have any track in order to be able to turn it on again (currently it's off)
let localVideoSource = WebRTCClient.factory.videoSource()
let localVideoTrack = WebRTCClient.factory.videoTrack(with: localVideoSource, trackId: "video0")
let sender = pc.add(localVideoTrack, streamIds: ["micCamera"])
sender?.track = nil
}
}
}
}
func mediaSourceFromTransceiverMid(_ mid: String?) -> CallMediaSource {
switch mid {
case "0":
return .mic
case "1":
return .camera
case "2":
return .screenAudio
case "3":
return .screenVideo
default:
return .unknown
}
}
// Should be called after local description set
func setupEncryptionForLocalTracks(_ call: Call) {
if let encryptor = call.frameEncryptor {
call.connection.senders.forEach { $0.setRtcFrameEncryptor(encryptor) }
}
}
func frameDecryptor(_ decryptor: RTCFrameDecryptor, mediaType: RTCRtpMediaType, withFrame encrypted: Data) -> Data? {
guard encrypted.count > 0 else { return nil }
if var key: [CChar] = activeCall?.aesKey?.cString(using: .utf8),
if var key: [CChar] = activeCall.wrappedValue?.aesKey?.cString(using: .utf8),
let pointer: UnsafeMutableRawPointer = malloc(encrypted.count) {
memcpy(pointer, (encrypted as NSData).bytes, encrypted.count)
let isKeyFrame = encrypted[0] & 1 == 0
@@ -512,7 +304,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
func frameEncryptor(_ encryptor: RTCFrameEncryptor, mediaType: RTCRtpMediaType, withFrame unencrypted: Data) -> Data? {
guard unencrypted.count > 0 else { return nil }
if var key: [CChar] = activeCall?.aesKey?.cString(using: .utf8),
if var key: [CChar] = activeCall.wrappedValue?.aesKey?.cString(using: .utf8),
let pointer: UnsafeMutableRawPointer = malloc(unencrypted.count + WebRTCClient.ivTagBytes) {
memcpy(pointer, (unencrypted as NSData).bytes, unencrypted.count)
let isKeyFrame = unencrypted[0] & 1 == 0
@@ -535,42 +327,18 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
}
}
func addRemoteCameraRenderer(_ renderer: RTCVideoRenderer) {
if activeCall?.remoteVideoTrack != nil {
activeCall?.remoteVideoTrack?.add(renderer)
} else {
cameraRenderers.append(renderer)
}
func addRemoteRenderer(_ activeCall: Call, _ renderer: RTCVideoRenderer) {
activeCall.remoteStream?.add(renderer)
}
func removeRemoteCameraRenderer(_ renderer: RTCVideoRenderer) {
if activeCall?.remoteVideoTrack != nil {
activeCall?.remoteVideoTrack?.remove(renderer)
} else {
cameraRenderers.removeAll(where: { $0.isEqual(renderer) })
}
func removeRemoteRenderer(_ activeCall: Call, _ renderer: RTCVideoRenderer) {
activeCall.remoteStream?.remove(renderer)
}
func addRemoteScreenRenderer(_ renderer: RTCVideoRenderer) {
if activeCall?.remoteScreenVideoTrack != nil {
activeCall?.remoteScreenVideoTrack?.add(renderer)
} else {
screenRenderers.append(renderer)
}
}
func removeRemoteScreenRenderer(_ renderer: RTCVideoRenderer) {
if activeCall?.remoteScreenVideoTrack != nil {
activeCall?.remoteScreenVideoTrack?.remove(renderer)
} else {
screenRenderers.removeAll(where: { $0.isEqual(renderer) })
}
}
func startCaptureLocalVideo(_ device: AVCaptureDevice.Position?, _ capturer: RTCVideoCapturer?) {
func startCaptureLocalVideo(_ activeCall: Call) {
#if targetEnvironment(simulator)
guard
let capturer = (activeCall?.localCamera ?? notConnectedCall?.localCameraAndTrack?.0) as? RTCFileVideoCapturer
let capturer = activeCall.localCamera as? RTCFileVideoCapturer
else {
logger.error("Unable to work with a file capturer")
return
@@ -580,10 +348,10 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
capturer.startCapturing(fromFileNamed: "sounds/video.mp4")
#else
guard
let capturer = capturer as? RTCCameraVideoCapturer,
let camera = (RTCCameraVideoCapturer.captureDevices().first { $0.position == device })
let capturer = activeCall.localCamera as? RTCCameraVideoCapturer,
let camera = (RTCCameraVideoCapturer.captureDevices().first { $0.position == activeCall.device })
else {
logger.error("Unable to find a camera or local track")
logger.error("Unable to find a camera")
return
}
@@ -609,6 +377,19 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
#endif
}
private func createAudioSender(_ connection: RTCPeerConnection) {
let streamId = "stream"
let audioTrack = createAudioTrack()
connection.add(audioTrack, streamIds: [streamId])
}
private func createVideoSender(_ connection: RTCPeerConnection) -> (RTCVideoTrack?, RTCVideoTrack?, RTCVideoCapturer?, RTCVideoSource?) {
let streamId = "stream"
let (localVideoTrack, localCamera, localVideoSource) = createVideoTrack()
connection.add(localVideoTrack, streamIds: [streamId])
return (localVideoTrack, connection.transceivers.first { $0.mediaType == .video }?.receiver.track as? RTCVideoTrack, localCamera, localVideoSource)
}
private func createAudioTrack() -> RTCAudioTrack {
let audioConstrains = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: nil)
let audioSource = WebRTCClient.factory.audioSource(with: audioConstrains)
@@ -616,7 +397,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
return audioTrack
}
private func createVideoTrackAndStartCapture(_ device: AVCaptureDevice.Position) -> (RTCVideoCapturer, RTCVideoTrack) {
private func createVideoTrack() -> (RTCVideoTrack, RTCVideoCapturer, RTCVideoSource) {
let localVideoSource = WebRTCClient.factory.videoSource()
#if targetEnvironment(simulator)
@@ -626,8 +407,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
#endif
let localVideoTrack = WebRTCClient.factory.videoTrack(with: localVideoSource, trackId: "video0")
startCaptureLocalVideo(device, localCamera)
return (localCamera, localVideoTrack)
return (localVideoTrack, localCamera, localVideoSource)
}
func endCall() {
@@ -640,16 +420,15 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
}
private func _endCall() {
(notConnectedCall?.localCameraAndTrack?.0 as? RTCCameraVideoCapturer)?.stopCapture()
guard let call = activeCall else { return }
guard let call = activeCall.wrappedValue else { return }
logger.debug("WebRTCClient: ending the call")
activeCall.wrappedValue = nil
(call.localCamera as? RTCCameraVideoCapturer)?.stopCapture()
call.connection.close()
call.connection.delegate = nil
call.frameEncryptor?.delegate = nil
call.frameDecryptor?.delegate = nil
(call.localCamera as? RTCCameraVideoCapturer)?.stopCapture()
audioSessionToDefaults()
activeCall = nil
}
func untilIceComplete(timeoutMs: UInt64, stepMs: UInt64, action: @escaping () async -> Void) async {
@@ -658,7 +437,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
_ = try? await Task.sleep(nanoseconds: stepMs * 1000000)
t += stepMs
await action()
} while t < timeoutMs && activeCall?.connection.iceGatheringState != .complete
} while t < timeoutMs && activeCall.wrappedValue?.connection.iceGatheringState != .complete
}
}
@@ -719,40 +498,11 @@ extension WebRTCClient: RTCPeerConnectionDelegate {
logger.debug("Connection should negotiate")
}
func peerConnection(_ peerConnection: RTCPeerConnection, didStartReceivingOn transceiver: RTCRtpTransceiver) {
if let track = transceiver.receiver.track {
DispatchQueue.main.async {
// Doesn't work for outgoing video call (audio in video call works ok still, same as incoming call)
// if let decryptor = self.activeCall?.frameDecryptor {
// transceiver.receiver.setRtcFrameDecryptor(decryptor)
// }
let source = self.mediaSourceFromTransceiverMid(transceiver.mid)
switch source {
case .mic: self.activeCall?.remoteAudioTrack = track as? RTCAudioTrack
case .camera:
self.activeCall?.remoteVideoTrack = track as? RTCVideoTrack
self.cameraRenderers.forEach({ renderer in
self.activeCall?.remoteVideoTrack?.add(renderer)
})
self.cameraRenderers.removeAll()
case .screenAudio: self.activeCall?.remoteScreenAudioTrack = track as? RTCAudioTrack
case .screenVideo:
self.activeCall?.remoteScreenVideoTrack = track as? RTCVideoTrack
self.screenRenderers.forEach({ renderer in
self.activeCall?.remoteScreenVideoTrack?.add(renderer)
})
self.screenRenderers.removeAll()
case .unknown: ()
}
}
self.setupMuteUnmuteListener(transceiver, track)
}
}
func peerConnection(_ connection: RTCPeerConnection, didChange newState: RTCIceConnectionState) {
debugPrint("Connection new connection state: \(newState.toString() ?? "" + newState.rawValue.description) \(connection.receivers)")
guard let connectionStateString = newState.toString(),
guard let call = activeCall.wrappedValue,
let connectionStateString = newState.toString(),
let iceConnectionStateString = connection.iceConnectionState.toString(),
let iceGatheringStateString = connection.iceGatheringState.toString(),
let signalingStateString = connection.signalingState.toString()
@@ -773,14 +523,18 @@ extension WebRTCClient: RTCPeerConnectionDelegate {
switch newState {
case .checking:
if let frameDecryptor = activeCall?.frameDecryptor {
if let frameDecryptor = activeCall.wrappedValue?.frameDecryptor {
connection.receivers.forEach { $0.setRtcFrameDecryptor(frameDecryptor) }
}
let enableSpeaker: Bool = ChatModel.shared.activeCall?.localMediaSources.hasVideo == true
let enableSpeaker: Bool
switch call.localMedia {
case .video: enableSpeaker = true
default: enableSpeaker = false
}
setSpeakerEnabledAndConfigureSession(enableSpeaker)
case .connected: sendConnectedEvent(connection)
case .disconnected, .failed: endCall()
default: ()
default: do {}
}
}
}
@@ -792,7 +546,7 @@ extension WebRTCClient: RTCPeerConnectionDelegate {
func peerConnection(_ connection: RTCPeerConnection, didGenerate candidate: WebRTC.RTCIceCandidate) {
// logger.debug("Connection generated candidate \(candidate.debugDescription)")
Task {
await self.activeCall?.iceCandidates.append(candidate.toCandidate(nil, nil))
await self.activeCall.wrappedValue?.iceCandidates.append(candidate.toCandidate(nil, nil))
}
}
@@ -847,42 +601,11 @@ extension WebRTCClient: RTCPeerConnectionDelegate {
}
extension WebRTCClient {
static func isAuthorized(for type: AVMediaType) async -> Bool {
let status = AVCaptureDevice.authorizationStatus(for: type)
var isAuthorized = status == .authorized
if status == .notDetermined {
isAuthorized = await AVCaptureDevice.requestAccess(for: type)
}
return isAuthorized
func setAudioEnabled(_ enabled: Bool) {
setTrackEnabled(RTCAudioTrack.self, enabled)
}
static func showUnauthorizedAlert(for type: AVMediaType) {
if type == .audio {
AlertManager.shared.showAlert(Alert(
title: Text("No permission to record speech"),
message: Text("To record speech please grant permission to use Microphone."),
primaryButton: .default(Text("Open Settings")) {
DispatchQueue.main.async {
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
}
},
secondaryButton: .cancel()
))
} else if type == .video {
AlertManager.shared.showAlert(Alert(
title: Text("No permission to record video"),
message: Text("To record video please grant permission to use Camera."),
primaryButton: .default(Text("Open Settings")) {
DispatchQueue.main.async {
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
}
},
secondaryButton: .cancel()
))
}
}
func setSpeakerEnabledAndConfigureSession( _ enabled: Bool, skipExternalDevice: Bool = false) {
func setSpeakerEnabledAndConfigureSession( _ enabled: Bool) {
logger.debug("WebRTCClient: configuring session with speaker enabled \(enabled)")
audioQueue.async { [weak self] in
guard let self = self else { return }
@@ -895,7 +618,7 @@ extension WebRTCClient {
if enabled {
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue, with: [.defaultToSpeaker, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
try self.rtcAudioSession.setMode(AVAudioSession.Mode.videoChat.rawValue)
if hasExternalAudioDevice && !skipExternalDevice, let preferred = self.rtcAudioSession.session.preferredInputDevice() {
if hasExternalAudioDevice, let preferred = self.rtcAudioSession.session.preferredInputDevice() {
try self.rtcAudioSession.setPreferredInput(preferred)
} else {
try self.rtcAudioSession.overrideOutputAudioPort(.speaker)
@@ -905,7 +628,7 @@ extension WebRTCClient {
try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)
try self.rtcAudioSession.overrideOutputAudioPort(.none)
}
if hasExternalAudioDevice && !skipExternalDevice {
if hasExternalAudioDevice {
logger.debug("WebRTCClient: configuring session with external device available, skip configuring speaker")
}
try self.rtcAudioSession.setActive(true)
@@ -936,59 +659,25 @@ extension WebRTCClient {
}
}
@MainActor
func setAudioEnabled(_ enabled: Bool) {
if activeCall != nil {
activeCall?.localAudioTrack = enabled ? createAudioTrack() : nil
activeCall?.connection.transceivers.first(where: { t in mediaSourceFromTransceiverMid(t.mid) == .mic })?.sender.track = activeCall?.localAudioTrack
} else if notConnectedCall != nil {
notConnectedCall?.audioTrack = enabled ? createAudioTrack() : nil
}
ChatModel.shared.activeCall?.localMediaSources.mic = enabled
}
@MainActor
func setCameraEnabled(_ enabled: Bool) {
if let call = activeCall {
if enabled {
if call.localVideoTrack == nil {
let device = activeCall?.device ?? notConnectedCall?.device ?? .front
let (camera, track) = createVideoTrackAndStartCapture(device)
activeCall?.localCamera = camera
activeCall?.localVideoTrack = track
}
} else {
(call.localCamera as? RTCCameraVideoCapturer)?.stopCapture()
activeCall?.localCamera = nil
activeCall?.localVideoTrack = nil
}
call.connection.transceivers
.first(where: { t in mediaSourceFromTransceiverMid(t.mid) == .camera })?
.sender.track = activeCall?.localVideoTrack
ChatModel.shared.activeCall?.localMediaSources.camera = activeCall?.localVideoTrack != nil
} else if let call = notConnectedCall {
if enabled {
let device = activeCall?.device ?? notConnectedCall?.device ?? .front
notConnectedCall?.localCameraAndTrack = createVideoTrackAndStartCapture(device)
} else {
(call.localCameraAndTrack?.0 as? RTCCameraVideoCapturer)?.stopCapture()
notConnectedCall?.localCameraAndTrack = nil
}
ChatModel.shared.activeCall?.localMediaSources.camera = notConnectedCall?.localCameraAndTrack != nil
}
func setVideoEnabled(_ enabled: Bool) {
setTrackEnabled(RTCVideoTrack.self, enabled)
}
func flipCamera() {
let device = activeCall?.device ?? notConnectedCall?.device
if activeCall != nil {
activeCall?.device = device == .front ? .back : .front
} else {
notConnectedCall?.device = device == .front ? .back : .front
switch activeCall.wrappedValue?.device {
case .front: activeCall.wrappedValue?.device = .back
case .back: activeCall.wrappedValue?.device = .front
default: ()
}
startCaptureLocalVideo(
activeCall?.device ?? notConnectedCall?.device,
(activeCall?.localCamera ?? notConnectedCall?.localCameraAndTrack?.0) as? RTCCameraVideoCapturer
)
if let call = activeCall.wrappedValue {
startCaptureLocalVideo(call)
}
}
private func setTrackEnabled<T: RTCMediaStreamTrack>(_ type: T.Type, _ enabled: Bool) {
activeCall.wrappedValue?.connection.transceivers
.compactMap { $0.sender.track as? T }
.forEach { $0.isEnabled = enabled }
}
}
@@ -48,7 +48,7 @@ struct CIRcvDecryptionError: View {
if case let .group(groupInfo) = chat.chatInfo,
case let .groupRcv(groupMember) = chatItem.chatDir {
do {
let (member, stats) = try apiGroupMemberInfoSync(groupInfo.apiId, groupMember.groupMemberId)
let (member, stats) = try apiGroupMemberInfo(groupInfo.apiId, groupMember.groupMemberId)
if let s = stats {
m.updateGroupMemberConnectionStats(groupInfo, member, s)
}
+3 -8
View File
@@ -137,14 +137,6 @@ struct ChatView: View {
}
}
}
// it should be presented on top level in order to prevent a bug in SwiftUI on iOS 16 related to .focused() modifier in AddGroupMembersView's search field
.appSheet(isPresented: $showAddMembersSheet) {
Group {
if case let .group(groupInfo) = cInfo {
AddGroupMembersView(chat: chat, groupInfo: groupInfo)
}
}
}
.sheet(isPresented: Binding(
get: { !forwardedChatItems.isEmpty },
set: { isPresented in
@@ -312,6 +304,9 @@ struct ChatView: View {
}
} else {
addMembersButton()
.appSheet(isPresented: $showAddMembersSheet) {
AddGroupMembersView(chat: chat, groupInfo: groupInfo)
}
}
}
Menu {
@@ -459,7 +459,7 @@ struct ComposeView: View {
Task {
var media: [(String, UploadContent)] = []
for content in selected {
if let img = await resizeImageToStrSize(content.uiImage, maxDataSize: 14000) {
if let img = resizeImageToStrSize(content.uiImage, maxDataSize: 14000) {
media.append((img, content))
await MainActor.run {
composeState = composeState.copy(preview: .mediaPreviews(mediaPreviews: media))
@@ -551,7 +551,7 @@ struct ComposeView: View {
}
private func addMediaContent(_ content: UploadContent) async {
if let img = await resizeImageToStrSize(content.uiImage, maxDataSize: 14000) {
if let img = resizeImageToStrSize(content.uiImage, maxDataSize: 14000) {
var newMedia: [(String, UploadContent?)] = []
if case var .mediaPreviews(media) = composeState.preview {
media.append((img, content))
@@ -18,7 +18,6 @@ struct GroupMemberInfoView: View {
var navigation: Bool = false
@State private var connectionStats: ConnectionStats? = nil
@State private var connectionCode: String? = nil
@State private var connectionLoaded: Bool = false
@State private var newRole: GroupMemberRole = .member
@State private var alert: GroupMemberInfoViewAlert?
@State private var sheet: PlanAndConnectActionSheet?
@@ -95,137 +94,129 @@ struct GroupMemberInfoView: View {
.listRowSeparator(.hidden)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
if connectionLoaded {
if member.memberActive {
Section {
if let code = connectionCode { verifyCodeButton(code) }
if let connStats = connectionStats,
connStats.ratchetSyncAllowed {
synchronizeConnectionButton()
}
// } else if developerTools {
// synchronizeConnectionButtonForce()
// }
if member.memberActive {
Section {
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)
}
} else {
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)
.task {
.onAppear {
if #unavailable(iOS 16) {
// this condition prevents re-setting picker
if !justOpened { return }
}
justOpened = false
newRole = member.memberRole
do {
let (_, stats) = try await apiGroupMemberInfo(groupInfo.apiId, member.groupMemberId)
let (mem, code) = member.memberActive ? try await apiGetGroupMemberCode(groupInfo.apiId, member.groupMemberId) : (member, nil)
await MainActor.run {
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
connectionLoaded = true
} catch let error {
logger.error("apiGroupMemberInfo or apiGetGroupMemberCode error: \(responseError(error))")
}
} catch let error {
await MainActor.run {
connectionLoaded = true
}
logger.error("apiGroupMemberInfo or apiGetGroupMemberCode error: \(responseError(error))")
}
}
.onChange(of: newRole) { newRole in
@@ -110,13 +110,10 @@ struct GroupProfileView: View {
}
}
.onChange(of: chosenImage) { image in
Task {
let resized: String? = if let image {
await resizeImageToStrSize(cropToSquare(image), maxDataSize: 12500)
} else {
nil
}
await MainActor.run { groupProfile.image = resized }
if let image = image {
groupProfile.image = resizeImageToStrSize(cropToSquare(image), maxDataSize: 12500)
} else {
groupProfile.image = nil
}
}
.onAppear {
@@ -41,8 +41,7 @@ struct SelectedItemsBottomToolbar: View {
@State var forwardEnabled: Bool = false
@State var deleteCountProhibited = false
@State var forwardCountProhibited = false
@State var allButtonsDisabled = false
var body: some View {
VStack(spacing: 0) {
@@ -56,9 +55,9 @@ struct SelectedItemsBottomToolbar: View {
.resizable()
.scaledToFit()
.frame(width: 20, height: 20, alignment: .center)
.foregroundColor(!deleteEnabled || deleteCountProhibited ? theme.colors.secondary: .red)
.foregroundColor(!deleteEnabled || allButtonsDisabled ? theme.colors.secondary: .red)
}
.disabled(!deleteEnabled || deleteCountProhibited)
.disabled(!deleteEnabled || allButtonsDisabled)
Spacer()
Button {
@@ -68,9 +67,9 @@ struct SelectedItemsBottomToolbar: View {
.resizable()
.scaledToFit()
.frame(width: 20, height: 20, alignment: .center)
.foregroundColor(!moderateEnabled || deleteCountProhibited ? theme.colors.secondary : .red)
.foregroundColor(!moderateEnabled || allButtonsDisabled ? theme.colors.secondary : .red)
}
.disabled(!moderateEnabled || deleteCountProhibited)
.disabled(!moderateEnabled || allButtonsDisabled)
.opacity(canModerate ? 1 : 0)
Spacer()
@@ -81,9 +80,9 @@ struct SelectedItemsBottomToolbar: View {
.resizable()
.scaledToFit()
.frame(width: 20, height: 20, alignment: .center)
.foregroundColor(!forwardEnabled || forwardCountProhibited ? theme.colors.secondary : theme.colors.primary)
.foregroundColor(!forwardEnabled || allButtonsDisabled ? theme.colors.secondary : theme.colors.primary)
}
.disabled(!forwardEnabled || forwardCountProhibited)
.disabled(!forwardEnabled || allButtonsDisabled)
}
.frame(maxHeight: .infinity)
.padding([.leading, .trailing], 12)
@@ -106,8 +105,7 @@ struct SelectedItemsBottomToolbar: View {
private func recheckItems(_ chatInfo: ChatInfo, _ chatItems: [ChatItem], _ selectedItems: Set<Int64>?) {
let count = selectedItems?.count ?? 0
deleteCountProhibited = count == 0 || count > 200
forwardCountProhibited = count == 0 || count > 20
allButtonsDisabled = count == 0 || count > 20
canModerate = possibleToModerate(chatInfo)
if let selected = selectedItems {
let me: Bool
@@ -437,7 +437,7 @@ struct SubsStatusIndicator: View {
private func startTask() {
task = Task {
while !Task.isCancelled {
if AppChatState.shared.value == .active, ChatModel.shared.chatRunning == true {
if AppChatState.shared.value == .active {
do {
let (subs, hasSess) = try await getAgentSubsTotal()
await MainActor.run {
@@ -33,7 +33,6 @@ struct UserPicker: View {
.sorted(using: KeyPathComparator<UserInfo>(\.user.activeOrder, order: .reverse))
let sectionWidth = max(frameWidth - sectionHorizontalPadding * 2, 0)
let currentUserWidth = max(frameWidth - sectionHorizontalPadding - rowPadding * 2 - 14 - imageSize, 0)
let stopped = m.chatRunning != true
VStack(spacing: sectionSpacing) {
if let user = m.currentUser {
StickyScrollView(resetScroll: $resetScroll) {
@@ -47,14 +46,10 @@ struct UserPicker: View {
.frame(width: otherUsers.isEmpty ? sectionWidth : currentUserWidth, alignment: .leading)
.modifier(ListRow { activeSheet = .currentProfile })
.clipShape(sectionShape)
.disabled(stopped)
.opacity(stopped ? 0.4 : 1)
ForEach(otherUsers) { u in
userView(u, size: imageSize)
.frame(maxWidth: sectionWidth * 0.618)
.fixedSize()
.disabled(stopped)
.opacity(stopped ? 0.4 : 1)
}
}
.padding(.horizontal, sectionHorizontalPadding)
@@ -65,10 +60,10 @@ struct UserPicker: View {
.onPreferenceChange(DetermineWidth.Key.self) { frameWidth = $0 }
}
VStack(spacing: 0) {
openSheetOnTap("qrcode", title: m.userAddress == nil ? "Create SimpleX address" : "Your SimpleX address", sheet: .address, disabled: stopped)
openSheetOnTap("switch.2", title: "Chat preferences", sheet: .chatPreferences, disabled: stopped)
openSheetOnTap("person.crop.rectangle.stack", title: "Your chat profiles", sheet: .chatProfiles, disabled: stopped)
openSheetOnTap("desktopcomputer", title: "Use from desktop", sheet: .useFromDesktop, disabled: stopped)
openSheetOnTap("qrcode", title: m.userAddress == nil ? "Create SimpleX address" : "Your SimpleX address", sheet: .address)
openSheetOnTap("switch.2", title: "Chat preferences", sheet: .chatPreferences)
openSheetOnTap("person.crop.rectangle.stack", title: "Your chat profiles", sheet: .chatProfiles)
openSheetOnTap("desktopcomputer", title: "Use from desktop", sheet: .useFromDesktop)
ZStack(alignment: .trailing) {
openSheetOnTap("gearshape", title: "Settings", sheet: .settings, showDivider: false)
Image(systemName: colorScheme == .light ? "sun.max" : "moon.fill")
@@ -154,16 +149,15 @@ struct UserPicker: View {
.clipShape(sectionShape)
}
private func openSheetOnTap(_ icon: String, title: LocalizedStringKey, sheet: UserPickerSheet, showDivider: Bool = true, disabled: Bool = false) -> some View {
private func openSheetOnTap(_ icon: String, title: LocalizedStringKey, sheet: UserPickerSheet, showDivider: Bool = true) -> some View {
ZStack(alignment: .bottom) {
settingsRow(icon, color: theme.colors.secondary) {
Text(title).foregroundColor(.primary).opacity(disabled ? 0.4 : 1)
Text(title).foregroundColor(.primary)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.horizontal, rowPadding)
.padding(.vertical, rowVerticalPadding)
.modifier(ListRow { activeSheet = sheet })
.disabled(disabled)
if showDivider {
Divider().padding(.leading, 52)
}
@@ -137,13 +137,10 @@ struct AddGroupView: View {
createInvalidNameAlert(mkValidName(profile.displayName), $profile.displayName)
}
.onChange(of: chosenImage) { image in
Task {
let resized: String? = if let image {
await resizeImageToStrSize(cropToSquare(image), maxDataSize: 12500)
} else {
nil
}
await MainActor.run { profile.image = resized }
if let image = image {
profile.image = resizeImageToStrSize(cropToSquare(image), maxDataSize: 12500)
} else {
profile.image = nil
}
}
.modifier(ThemedBackground(grouped: true))
@@ -14,8 +14,7 @@ enum ContactType: Int {
}
struct NewChatMenuButton: View {
// do not use chatModel here because it prevents showing AddGroupMembersView after group creation and QR code after link creation on iOS 16
// @EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var chatModel: ChatModel
@State private var showNewChatSheet = false
@State private var alert: SomeAlert? = nil
@State private var pendingConnection: PendingContactConnection? = nil
@@ -33,7 +32,7 @@ struct NewChatMenuButton: View {
NewChatSheet(pendingConnection: $pendingConnection)
.environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil)
.onDisappear {
alert = cleanupPendingConnection(contactConnection: pendingConnection)
alert = cleanupPendingConnection(chatModel: chatModel, contactConnection: pendingConnection)
pendingConnection = nil
}
}
@@ -45,10 +45,10 @@ enum NewChatOption: Identifiable {
var id: Self { self }
}
func cleanupPendingConnection(contactConnection: PendingContactConnection?) -> SomeAlert? {
func cleanupPendingConnection(chatModel: ChatModel, contactConnection: PendingContactConnection?) -> SomeAlert? {
var alert: SomeAlert? = nil
if !(ChatModel.shared.showingInvitation?.connChatUsed ?? true),
if !(chatModel.showingInvitation?.connChatUsed ?? true),
let conn = contactConnection {
alert = SomeAlert(
alert: Alert(
@@ -68,7 +68,7 @@ func cleanupPendingConnection(contactConnection: PendingContactConnection?) -> S
)
}
ChatModel.shared.showingInvitation = nil
chatModel.showingInvitation = nil
return alert
}
@@ -97,11 +97,6 @@ struct NewChatView: View {
}
.pickerStyle(.segmented)
.padding()
.onChange(of: $selection.wrappedValue) { opt in
if opt == NewChatOption.connect {
showQRCodeScanner = true
}
}
VStack {
// it seems there's a bug in iOS 15 if several views in switch (or if-else) statement have different transitions
@@ -157,7 +152,7 @@ struct NewChatView: View {
}
.onDisappear {
if !choosingProfile {
parentAlert = cleanupPendingConnection(contactConnection: contactConnection)
parentAlert = cleanupPendingConnection(chatModel: m, contactConnection: contactConnection)
contactConnection = nil
}
}
@@ -467,39 +467,6 @@ private let versionDescriptions: [VersionDescription] = [
)
]
),
VersionDescription(
version: "v6.1",
post: URL(string: "https://simplex.chat/blog/20241014-simplex-network-v6-1-security-review-better-calls-user-experience.html"),
features: [
FeatureDescription(
icon: "checkmark.shield",
title: "Better security ✅",
description: "SimpleX protocols reviewed by Trail of Bits."
),
FeatureDescription(
icon: "video",
title: "Better calls",
description: "Switch audio and video during the call."
),
FeatureDescription(
icon: "bolt",
title: "Better notifications",
description: "Improved delivery, reduced traffic usage.\nMore improvements are coming soon!"
),
FeatureDescription(
icon: nil,
title: "Better user experience",
description: nil,
subfeatures: [
("link", "Switch chat profile for 1-time invitations."),
("message", "Customizable message shape."),
("calendar", "Better message dates."),
("arrowshape.turn.up.right", "Forward up to 20 messages at once."),
("flag", "Delete or moderate up to 200 messages.")
]
),
]
),
]
private let lastVersion = versionDescriptions.last!.version
@@ -196,14 +196,11 @@ struct AdvancedNetworkSettings: View {
if developerTools {
Section {
Picker("Transport isolation", selection: $netCfg.sessionMode) {
let modes = TransportSessionMode.values.contains(netCfg.sessionMode)
? TransportSessionMode.values
: TransportSessionMode.values + [netCfg.sessionMode]
ForEach(modes, id: \.self) { Text($0.text) }
ForEach(TransportSessionMode.values, id: \.self) { Text($0.text) }
}
.frame(height: 36)
} footer: {
sessionModeInfo(netCfg.sessionMode)
Text(sessionModeInfo(netCfg.sessionMode))
.foregroundColor(theme.colors.secondary)
}
}
@@ -356,13 +353,10 @@ struct AdvancedNetworkSettings: View {
}
}
private func sessionModeInfo(_ mode: TransportSessionMode) -> Text {
let userMode = Text("A separate TCP connection will be used **for each chat profile you have in the app**.")
return switch mode {
case .user: userMode
case .session: userMode + Text("\n") + Text("New SOCKS credentials will be used every time you start the app.")
case .server: userMode + Text("\n") + Text("New SOCKS credentials will be used for each server.")
case .entity: Text("A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail.")
private func sessionModeInfo(_ mode: TransportSessionMode) -> LocalizedStringKey {
switch mode {
case .user: return "A separate TCP connection will be used **for each chat profile you have in the app**."
case .entity: return "A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail."
}
}
@@ -58,8 +58,6 @@ extension AppSettings {
profileImageCornerRadiusGroupDefault.set(val)
def.setValue(val, forKey: DEFAULT_PROFILE_IMAGE_CORNER_RADIUS)
}
if let val = uiChatItemRoundness { def.setValue(val, forKey: DEFAULT_CHAT_ITEM_ROUNDNESS)}
if let val = uiChatItemTail { def.setValue(val, forKey: DEFAULT_CHAT_ITEM_TAIL)}
if let val = uiColorScheme { currentThemeDefault.set(val) }
if let val = uiDarkColorScheme { systemDarkThemeDefault.set(val) }
if let val = uiCurrentThemeIds { currentThemeIdsDefault.set(val) }
@@ -93,8 +91,6 @@ extension AppSettings {
c.iosCallKitEnabled = callKitEnabledGroupDefault.get()
c.iosCallKitCallsInRecents = def.bool(forKey: DEFAULT_CALL_KIT_CALLS_IN_RECENTS)
c.uiProfileImageCornerRadius = def.double(forKey: DEFAULT_PROFILE_IMAGE_CORNER_RADIUS)
c.uiChatItemRoundness = def.double(forKey: DEFAULT_CHAT_ITEM_ROUNDNESS)
c.uiChatItemTail = def.bool(forKey: DEFAULT_CHAT_ITEM_TAIL)
c.uiColorScheme = currentThemeDefault.get()
c.uiDarkColorScheme = systemDarkThemeDefault.get()
c.uiCurrentThemeIds = currentThemeIdsDefault.get()
@@ -94,13 +94,10 @@ struct UserProfile: View {
}
}
.onChange(of: chosenImage) { image in
Task {
let resized: String? = if let image {
await resizeImageToStrSize(cropToSquare(image), maxDataSize: 12500)
} else {
nil
}
await MainActor.run { profile.image = resized }
if let image {
profile.image = resizeImageToStrSize(cropToSquare(image), maxDataSize: 12500)
} else {
profile.image = nil
}
}
// Modals
@@ -737,7 +737,7 @@
</trans-unit>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -925,10 +925,6 @@
<target>Кода за достъп до приложение се заменя с код за самоунищожение.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>Версия на приложението</target>
@@ -1059,19 +1055,11 @@
<target>Лош хеш на съобщението</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>По-добри групи</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>По-добри съобщения</target>
@@ -1081,18 +1069,6 @@
<source>Better networking</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<note>No comment provided by engineer.</note>
@@ -1366,11 +1342,6 @@
<source>Chat preferences were changed.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Потребителски профил</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<note>No comment provided by engineer.</note>
@@ -1873,10 +1844,6 @@ This is your own one-time link!</source>
<target>Персонализирано време</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<note>No comment provided by engineer.</note>
@@ -2166,10 +2133,6 @@ This is your own one-time link!</source>
<target>Изтрий старата база данни?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Изтрий предстоящата връзка?</target>
@@ -2971,7 +2934,7 @@ This is your own one-time link!</source>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Грешка при смяна на профил!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3016,7 +2979,8 @@ This is your own one-time link!</source>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Грешка: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3252,10 +3216,6 @@ This is your own one-time link!</source>
<source>Forward messages without files?</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Препратено</target>
@@ -3633,11 +3593,6 @@ Error: %2$@</source>
<target>Импортиране на архив</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>Подобрена доставка на съобщения</target>
@@ -4403,14 +4358,6 @@ This is your link for group %@!</source>
<target>Нов kод за достъп</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>Нов чат</target>
@@ -4527,14 +4474,6 @@ This is your link for group %@!</source>
<target>Няма мрежова връзка</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Няма разрешение за запис на гласово съобщение</target>
@@ -5938,10 +5877,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Sent via proxy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<note>No comment provided by engineer.</note>
@@ -6225,10 +6160,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>Еднократна покана за SimpleX</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Опростен режим инкогнито</target>
@@ -6393,14 +6324,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>Подкрепете SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>Системен</target>
@@ -6754,14 +6677,6 @@ You will be prompted to complete authentication before this feature is enabled.<
Ще бъдете подканени да извършите идентификация, преди тази функция да бъде активирана.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>За да запишете гласово съобщение, моля, дайте разрешение за използване на микрофон.</target>
@@ -7086,6 +7001,11 @@ To connect, please ask your contact to create another connection link and check
<source>Use the app with one hand.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Потребителски профил</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<note>No comment provided by engineer.</note>
@@ -7347,6 +7267,11 @@ To connect, please ask your contact to create another connection link and check
<source>XFTP server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Вие</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>**Не трябва** да използвате една и съща база данни на две устройства.</target>
@@ -715,7 +715,7 @@
</trans-unit>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -898,10 +898,6 @@
<target>Přístupový kód aplikace je nahrazen sebedestrukčním přístupovým heslem.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>Verze aplikace</target>
@@ -1028,18 +1024,10 @@
<target>Špatný hash zprávy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Lepší zprávy</target>
@@ -1049,18 +1037,6 @@
<source>Better networking</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<note>No comment provided by engineer.</note>
@@ -1322,11 +1298,6 @@
<source>Chat preferences were changed.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Profil uživatele</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<note>No comment provided by engineer.</note>
@@ -1803,10 +1774,6 @@ This is your own one-time link!</source>
<target>Vlastní čas</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<note>No comment provided by engineer.</note>
@@ -2093,10 +2060,6 @@ This is your own one-time link!</source>
<target>Smazat starou databázi?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Smazat čekající připojení?</target>
@@ -2873,7 +2836,7 @@ This is your own one-time link!</source>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Chyba při přepínání profilu!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -2916,7 +2879,8 @@ This is your own one-time link!</source>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Chyba: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3144,10 +3108,6 @@ This is your own one-time link!</source>
<source>Forward messages without files?</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
@@ -3514,11 +3474,6 @@ Error: %2$@</source>
<source>Importing archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<note>No comment provided by engineer.</note>
@@ -4247,14 +4202,6 @@ This is your link for group %@!</source>
<target>Nové heslo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<note>No comment provided by engineer.</note>
@@ -4369,14 +4316,6 @@ This is your link for group %@!</source>
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Nemáte oprávnění nahrávat hlasové zprávy</target>
@@ -5740,10 +5679,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Sent via proxy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<note>No comment provided by engineer.</note>
@@ -6020,10 +5955,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>Jednorázová pozvánka SimpleX</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Zjednodušený inkognito režim</target>
@@ -6184,14 +6115,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>Podpořte SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>Systém</target>
@@ -6533,14 +6456,6 @@ You will be prompted to complete authentication before this feature is enabled.<
Před zapnutím této funkce budete vyzváni k dokončení ověření.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>Chcete-li nahrávat hlasové zprávy, udělte povolení k použití mikrofonu.</target>
@@ -6851,6 +6766,11 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<source>Use the app with one hand.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Profil uživatele</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<note>No comment provided by engineer.</note>
@@ -7095,6 +7015,11 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<source>XFTP server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Vy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<note>No comment provided by engineer.</note>
@@ -164,22 +164,18 @@
</trans-unit>
<trans-unit id="%d file(s) are still being downloaded." xml:space="preserve">
<source>%d file(s) are still being downloaded.</source>
<target>%d Datei(en) wird/werden immer noch heruntergeladen.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) failed to download." xml:space="preserve">
<source>%d file(s) failed to download.</source>
<target>Bei %d Datei(en) ist das Herunterladen fehlgeschlagen.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were deleted." xml:space="preserve">
<source>%d file(s) were deleted.</source>
<target>%d Datei(en) wurde(n) gelöscht.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were not downloaded." xml:space="preserve">
<source>%d file(s) were not downloaded.</source>
<target>%d Datei(en) wurde(n) nicht heruntergeladen.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d hours" xml:space="preserve">
@@ -189,7 +185,6 @@
</trans-unit>
<trans-unit id="%d messages not forwarded" xml:space="preserve">
<source>%d messages not forwarded</source>
<target>%d Nachrichten wurden nicht weitergeleitet</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="%d min" xml:space="preserve">
@@ -753,7 +748,7 @@
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>Alle Profile</target>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -945,11 +940,6 @@
<target>App-Zugangscode wurde durch den Selbstzerstörungs-Zugangscode ersetzt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<target>App-Sitzung</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>App Version</target>
@@ -1085,19 +1075,11 @@
<target>Ungültiger Nachrichten-Hash</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>Bessere Gruppen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Verbesserungen bei Nachrichten</target>
@@ -1108,18 +1090,6 @@
<target>Kontrollieren Sie Ihr Netzwerk</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Schwarz</target>
@@ -1406,11 +1376,6 @@
<target>Die Chat-Präferenzen wurden geändert.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Benutzerprofil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Chat-Design</target>
@@ -1812,7 +1777,7 @@ Das ist Ihr eigener Einmal-Link!</target>
</trans-unit>
<trans-unit id="Corner" xml:space="preserve">
<source>Corner</source>
<target>Abrundung Ecken</target>
<target>Ecke</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Correct name to %@?" xml:space="preserve">
@@ -1940,10 +1905,6 @@ Das ist Ihr eigener Einmal-Link!</target>
<target>Zeit anpassen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Design anpassen</target>
@@ -2238,10 +2199,6 @@ Das ist Ihr eigener Einmal-Link!</target>
<target>Alte Datenbank löschen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Ausstehende Verbindung löschen?</target>
@@ -2494,7 +2451,6 @@ Das ist Ihr eigener Einmal-Link!</target>
</trans-unit>
<trans-unit id="Do not use credentials with proxy." xml:space="preserve">
<source>Do not use credentials with proxy.</source>
<target>Verwenden Sie keine Anmeldeinformationen mit einem Proxy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't create address" xml:space="preserve">
@@ -2540,7 +2496,6 @@ Das ist Ihr eigener Einmal-Link!</target>
</trans-unit>
<trans-unit id="Download files" xml:space="preserve">
<source>Download files</source>
<target>Dateien herunterladen</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Downloaded" xml:space="preserve">
@@ -3071,7 +3026,7 @@ Das ist Ihr eigener Einmal-Link!</target>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Fehler beim Umschalten des Profils!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3116,7 +3071,8 @@ Das ist Ihr eigener Einmal-Link!</target>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Fehler: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3206,8 +3162,6 @@ Das ist Ihr eigener Einmal-Link!</target>
<trans-unit id="File errors:&#10;%@" xml:space="preserve">
<source>File errors:
%@</source>
<target>Datei-Fehler:
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@@ -3347,7 +3301,6 @@ Das ist Ihr eigener Einmal-Link!</target>
</trans-unit>
<trans-unit id="Forward %d message(s)?" xml:space="preserve">
<source>Forward %d message(s)?</source>
<target>%d Nachricht(en) weiterleiten?</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Forward and save messages" xml:space="preserve">
@@ -3357,18 +3310,12 @@ Das ist Ihr eigener Einmal-Link!</target>
</trans-unit>
<trans-unit id="Forward messages" xml:space="preserve">
<source>Forward messages</source>
<target>Nachrichten weiterleiten</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Forward messages without files?" xml:space="preserve">
<source>Forward messages without files?</source>
<target>Nachrichten ohne Dateien weiterleiten?</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Weitergeleitet</target>
@@ -3381,7 +3328,6 @@ Das ist Ihr eigener Einmal-Link!</target>
</trans-unit>
<trans-unit id="Forwarding %lld messages" xml:space="preserve">
<source>Forwarding %lld messages</source>
<target>%lld Nachricht(en) wird/werden weitergeleitet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarding server %@ failed to connect to destination server %@. Please try later." xml:space="preserve">
@@ -3680,7 +3626,6 @@ Fehler: %2$@</target>
</trans-unit>
<trans-unit id="IP address" xml:space="preserve">
<source>IP address</source>
<target>IP-Adresse</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="If you can't meet in person, show QR code in a video call, or share the link." xml:space="preserve">
@@ -3758,11 +3703,6 @@ Fehler: %2$@</target>
<target>Archiv wird importiert</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>Verbesserte Zustellung von Nachrichten</target>
@@ -4390,7 +4330,6 @@ Das ist Ihr Link für die Gruppe %@!</target>
</trans-unit>
<trans-unit id="Messages were deleted after you selected them." xml:space="preserve">
<source>Messages were deleted after you selected them.</source>
<target>Die Nachrichten wurden gelöscht, nachdem Sie sie ausgewählt hatten.</target>
<note>alert message</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">
@@ -4548,16 +4487,6 @@ Das ist Ihr Link für die Gruppe %@!</target>
<target>Neuer Zugangscode</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<target>Jedes Mal wenn Sie die App starten, werden neue SOCKS-Anmeldeinformationen genutzt</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<target>Für jeden Server werden neue SOCKS-Anmeldeinformationen genutzt</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>Neuer Chat</target>
@@ -4678,16 +4607,6 @@ Das ist Ihr Link für die Gruppe %@!</target>
<target>Keine Netzwerkverbindung</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<target>Keine Genehmigung für Sprach-Aufnahmen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<target>Keine Genehmigung für Video-Aufnahmen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Keine Berechtigung für das Aufnehmen von Sprachnachrichten</target>
@@ -4710,7 +4629,6 @@ Das ist Ihr Link für die Gruppe %@!</target>
</trans-unit>
<trans-unit id="Nothing to forward!" xml:space="preserve">
<source>Nothing to forward!</source>
<target>Es gibt nichts zum Weiterleiten!</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications" xml:space="preserve">
@@ -4939,8 +4857,6 @@ Dies erfordert die Aktivierung eines VPNs.</target>
<trans-unit id="Other file errors:&#10;%@" xml:space="preserve">
<source>Other file errors:
%@</source>
<target>Andere(r) Datei-Fehler:
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
@@ -4980,7 +4896,6 @@ Dies erfordert die Aktivierung eines VPNs.</target>
</trans-unit>
<trans-unit id="Password" xml:space="preserve">
<source>Password</source>
<target>Passwort</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Password to show" xml:space="preserve">
@@ -5134,7 +5049,6 @@ Fehler: %@</target>
</trans-unit>
<trans-unit id="Port" xml:space="preserve">
<source>Port</source>
<target>Port</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Possibly, certificate fingerprint in server address is incorrect" xml:space="preserve">
@@ -5326,7 +5240,6 @@ Aktivieren Sie es in den *Netzwerk &amp; Server* Einstellungen.</target>
</trans-unit>
<trans-unit id="Proxy requires password" xml:space="preserve">
<source>Proxy requires password</source>
<target>Der Proxy benötigt ein Passwort</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Push notifications" xml:space="preserve">
@@ -5737,7 +5650,6 @@ Aktivieren Sie es in den *Netzwerk &amp; Server* Einstellungen.</target>
</trans-unit>
<trans-unit id="SOCKS proxy" xml:space="preserve">
<source>SOCKS proxy</source>
<target>SOCKS-Proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
@@ -5853,7 +5765,6 @@ Aktivieren Sie es in den *Netzwerk &amp; Server* Einstellungen.</target>
</trans-unit>
<trans-unit id="Saving %lld messages" xml:space="preserve">
<source>Saving %lld messages</source>
<target>Es wird/werden %lld Nachricht(en) gesichert</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scale" xml:space="preserve">
@@ -6156,11 +6067,6 @@ Aktivieren Sie es in den *Netzwerk &amp; Server* Einstellungen.</target>
<target>Über einen Proxy gesendet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<target>Server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>Server-Adresse</target>
@@ -6461,10 +6367,6 @@ Aktivieren Sie es in den *Netzwerk &amp; Server* Einstellungen.</target>
<target>SimpleX-Einmal-Einladung</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Vereinfachter Inkognito-Modus</target>
@@ -6640,14 +6542,6 @@ Aktivieren Sie es in den *Netzwerk &amp; Server* Einstellungen.</target>
<target>Unterstützung von SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>System</target>
@@ -6685,7 +6579,7 @@ Aktivieren Sie es in den *Netzwerk &amp; Server* Einstellungen.</target>
</trans-unit>
<trans-unit id="Tail" xml:space="preserve">
<source>Tail</source>
<target>Sprechblasen-Format</target>
<target>Sprechblase</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Take picture" xml:space="preserve">
@@ -7012,16 +6906,6 @@ You will be prompted to complete authentication before this feature is enabled.<
Sie werden aufgefordert, die Authentifizierung abzuschließen, bevor diese Funktion aktiviert wird.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<target>Bitte erteilen Sie für Sprach-Aufnahmen die Genehmigung das Mikrofon zu nutzen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<target>Bitte erteilen Sie für Video-Aufnahmen die Genehmigung die Kamera zu nutzen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>Bitte erlauben Sie die Nutzung des Mikrofons, um Sprachnachrichten aufnehmen zu können.</target>
@@ -7291,7 +7175,6 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
</trans-unit>
<trans-unit id="Use SOCKS proxy" xml:space="preserve">
<source>Use SOCKS proxy</source>
<target>SOCKS-Proxy nutzen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use SimpleX Chat servers?" xml:space="preserve">
@@ -7359,6 +7242,11 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
<target>Die App mit einer Hand bedienen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Benutzerprofil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Benutzer-Auswahl</target>
@@ -7366,7 +7254,6 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
</trans-unit>
<trans-unit id="Username" xml:space="preserve">
<source>Username</source>
<target>Benutzername</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Using SimpleX Chat servers." xml:space="preserve">
@@ -7629,6 +7516,11 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
<target>XFTP-Server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>Sie dürfen die selbe Datenbank **nicht** auf zwei Geräten nutzen.</target>
@@ -8010,7 +7902,6 @@ Verbindungsanfrage wiederholen?</target>
</trans-unit>
<trans-unit id="Your credentials may be sent unencrypted." xml:space="preserve">
<source>Your credentials may be sent unencrypted.</source>
<target>Ihre Anmeldeinformationen können unverschlüsselt versendet werden.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
@@ -8490,7 +8381,7 @@ Verbindungsanfrage wiederholen?</target>
</trans-unit>
<trans-unit id="expired" xml:space="preserve">
<source>expired</source>
<target>Abgelaufen</target>
<target>abgelaufen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
@@ -8722,7 +8613,7 @@ Verbindungsanfrage wiederholen?</target>
</trans-unit>
<trans-unit id="other" xml:space="preserve">
<source>other</source>
<target>Andere</target>
<target>andere</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="other errors" xml:space="preserve">
@@ -4200,7 +4200,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="## In reply to" xml:space="preserve" approved="no">
<source>## In reply to</source>
<target state="translated">## Ως απάντηση σε</target>
<target state="translated">## Ως απαντηση σε</target>
<note>copied message info</note>
</trans-unit>
<trans-unit id="%@ (current)" xml:space="preserve" approved="no">
@@ -753,7 +753,7 @@
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>All profiles</target>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -945,11 +945,6 @@
<target>App passcode is replaced with self-destruct passcode.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<target>App session</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>App version</target>
@@ -1085,21 +1080,11 @@
<target>Bad message hash</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<target>Better calls</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>Better groups</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<target>Better message dates.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Better messages</target>
@@ -1110,21 +1095,6 @@
<target>Better networking</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<target>Better notifications</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<target>Better security ✅</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<target>Better user experience</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Black</target>
@@ -1411,11 +1381,6 @@
<target>Chat preferences were changed.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Chat profile</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Chat theme</target>
@@ -1945,11 +1910,6 @@ This is your own one-time link!</target>
<target>Custom time</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<target>Customizable message shape.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Customize theme</target>
@@ -2244,11 +2204,6 @@ This is your own one-time link!</target>
<target>Delete old database?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<target>Delete or moderate up to 200 messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Delete pending connection?</target>
@@ -3078,7 +3033,7 @@ This is your own one-time link!</target>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Error switching profile!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3123,7 +3078,8 @@ This is your own one-time link!</target>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Error: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3372,11 +3328,6 @@ This is your own one-time link!</target>
<target>Forward messages without files?</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<target>Forward up to 20 messages at once.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Forwarded</target>
@@ -3766,13 +3717,6 @@ Error: %2$@</target>
<target>Importing archive</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<target>Improved delivery, reduced traffic usage.
More improvements are coming soon!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>Improved message delivery</target>
@@ -4558,16 +4502,6 @@ This is your link for group %@!</target>
<target>New Passcode</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<target>New SOCKS credentials will be used every time you start the app.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<target>New SOCKS credentials will be used for each server.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>New chat</target>
@@ -4688,16 +4622,6 @@ This is your link for group %@!</target>
<target>No network connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<target>No permission to record speech</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<target>No permission to record video</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>No permission to record voice message</target>
@@ -6166,11 +6090,6 @@ Enable in *Network &amp; servers* settings.</target>
<target>Sent via proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<target>Server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>Server address</target>
@@ -6471,11 +6390,6 @@ Enable in *Network &amp; servers* settings.</target>
<target>SimpleX one-time invitation</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<target>SimpleX protocols reviewed by Trail of Bits.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Simplified incognito mode</target>
@@ -6651,16 +6565,6 @@ Enable in *Network &amp; servers* settings.</target>
<target>Support SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<target>Switch audio and video during the call.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<target>Switch chat profile for 1-time invitations.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>System</target>
@@ -7025,16 +6929,6 @@ You will be prompted to complete authentication before this feature is enabled.<
You will be prompted to complete authentication before this feature is enabled.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<target>To record speech please grant permission to use Microphone.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<target>To record video please grant permission to use Camera.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>To record voice message please grant permission to use Microphone.</target>
@@ -7372,6 +7266,11 @@ To connect, please ask your contact to create another connection link and check
<target>Use the app with one hand.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>User profile</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>User selection</target>
@@ -7642,6 +7541,11 @@ To connect, please ask your contact to create another connection link and check
<target>XFTP server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>You</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>You **must not** use the same database on two devices.</target>
@@ -139,7 +139,6 @@
</trans-unit>
<trans-unit id="%@, %@" xml:space="preserve">
<source>%1$@, %2$@</source>
<target>%1$@, %2$@</target>
<note>format for date separator in chat</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld members" xml:space="preserve">
@@ -164,22 +163,18 @@
</trans-unit>
<trans-unit id="%d file(s) are still being downloaded." xml:space="preserve">
<source>%d file(s) are still being downloaded.</source>
<target>%d archivo(s) se está(n) descargando todavía.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) failed to download." xml:space="preserve">
<source>%d file(s) failed to download.</source>
<target>La descarga ha fallado para %d archivo(s).</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were deleted." xml:space="preserve">
<source>%d file(s) were deleted.</source>
<target>%d archivo(s) ha(n) sido eliminado(s).</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were not downloaded." xml:space="preserve">
<source>%d file(s) were not downloaded.</source>
<target>%d archivo(s) no se ha(n) descargado.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d hours" xml:space="preserve">
@@ -189,7 +184,6 @@
</trans-unit>
<trans-unit id="%d messages not forwarded" xml:space="preserve">
<source>%d messages not forwarded</source>
<target>%d mensajes no enviados</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="%d min" xml:space="preserve">
@@ -537,7 +531,7 @@
</trans-unit>
<trans-unit id="A new random profile will be shared." xml:space="preserve">
<source>A new random profile will be shared.</source>
<target>Compartirás un perfil nuevo aleatorio.</target>
<target>Se compartirá un perfil nuevo aleatorio.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="A separate TCP connection will be used **for each chat profile you have in the app**." xml:space="preserve">
@@ -753,7 +747,7 @@
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>Todos los perfiles</target>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -945,11 +939,6 @@
<target>El código de acceso será reemplazado por código de autodestrucción.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<target>Sesión de aplicación</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>Versión de la aplicación</target>
@@ -1057,7 +1046,6 @@
</trans-unit>
<trans-unit id="Auto-accept settings" xml:space="preserve">
<source>Auto-accept settings</source>
<target>Auto aceptar configuración</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Back" xml:space="preserve">
@@ -1085,19 +1073,11 @@
<target>Hash de mensaje incorrecto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>Grupos mejorados</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Mensajes mejorados</target>
@@ -1108,18 +1088,6 @@
<target>Uso de red mejorado</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Negro</target>
@@ -1403,14 +1371,8 @@
</trans-unit>
<trans-unit id="Chat preferences were changed." xml:space="preserve">
<source>Chat preferences were changed.</source>
<target>Las preferencias del chat han sido modificadas.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Perfil de usuario</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Tema de chat</target>
@@ -1563,7 +1525,7 @@
</trans-unit>
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
<source>Confirm that you remember database passphrase to migrate it.</source>
<target>Para migrar la base de datos confirma que recuerdas la frase de contraseña.</target>
<target>Para migrar confirma que recuerdas la frase de contraseña de la base de datos.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm upload" xml:space="preserve">
@@ -1812,7 +1774,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Corner" xml:space="preserve">
<source>Corner</source>
<target>Esquina</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Correct name to %@?" xml:space="preserve">
@@ -1940,10 +1901,6 @@ This is your own one-time link!</source>
<target>Tiempo personalizado</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Personalizar tema</target>
@@ -2025,7 +1982,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Database passphrase is different from saved in the keychain." xml:space="preserve">
<source>Database passphrase is different from saved in the keychain.</source>
<target>La contraseña es diferente a la almacenada en Keychain.</target>
<target>La contraseña es distinta a la almacenada en Keychain.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Database passphrase is required to open chat." xml:space="preserve">
@@ -2238,10 +2195,6 @@ This is your own one-time link!</source>
<target>¿Eliminar base de datos antigua?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>¿Eliminar conexión pendiente?</target>
@@ -2454,7 +2407,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<target>¿Desconectar del ordenador?</target>
<target>¿Desconectar ordenador?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
@@ -2494,7 +2447,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Do not use credentials with proxy." xml:space="preserve">
<source>Do not use credentials with proxy.</source>
<target>No uses credenciales con proxy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't create address" xml:space="preserve">
@@ -2509,7 +2461,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Don't show again" xml:space="preserve">
<source>Don't show again</source>
<target>No volver a mostrar</target>
<target>No mostrar de nuevo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Downgrade and open chat" xml:space="preserve">
@@ -2540,7 +2492,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Download files" xml:space="preserve">
<source>Download files</source>
<target>Descargar archivos</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Downloaded" xml:space="preserve">
@@ -2820,7 +2771,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Error changing connection profile" xml:space="preserve">
<source>Error changing connection profile</source>
<target>Error al cambiar el perfil de conexión</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error changing role" xml:space="preserve">
@@ -2835,7 +2785,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Error changing to incognito!" xml:space="preserve">
<source>Error changing to incognito!</source>
<target>¡Error al cambiar a incógnito!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
@@ -2960,7 +2909,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Error migrating settings" xml:space="preserve">
<source>Error migrating settings</source>
<target>Error al migrar la configuración</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error opening chat" xml:space="preserve">
@@ -3065,13 +3013,12 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Error switching profile" xml:space="preserve">
<source>Error switching profile</source>
<target>Error al cambiar perfil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>¡Error al cambiar perfil!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3116,7 +3063,8 @@ This is your own one-time link!</source>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Error: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3206,8 +3154,6 @@ This is your own one-time link!</source>
<trans-unit id="File errors:&#10;%@" xml:space="preserve">
<source>File errors:
%@</source>
<target>Error(es) de archivo
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@@ -3347,7 +3293,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Forward %d message(s)?" xml:space="preserve">
<source>Forward %d message(s)?</source>
<target>¿Reenviar %d mensaje(s)?</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Forward and save messages" xml:space="preserve">
@@ -3357,18 +3302,12 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Forward messages" xml:space="preserve">
<source>Forward messages</source>
<target>Reenviar mensajes</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Forward messages without files?" xml:space="preserve">
<source>Forward messages without files?</source>
<target>¿Reenviar mensajes sin los archivos?</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Reenviado</target>
@@ -3381,7 +3320,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Forwarding %lld messages" xml:space="preserve">
<source>Forwarding %lld messages</source>
<target>Reenviando %lld mensajes</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarding server %@ failed to connect to destination server %@. Please try later." xml:space="preserve">
@@ -3435,12 +3373,12 @@ Error: %2$@</target>
</trans-unit>
<trans-unit id="Fully decentralized visible only to members." xml:space="preserve">
<source>Fully decentralized visible only to members.</source>
<target>Totalmente descentralizado. Visible sólo para los miembros.</target>
<target>Completamente descentralizado y sólo visible para los miembros.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Fully re-implemented - work in background!" xml:space="preserve">
<source>Fully re-implemented - work in background!</source>
<target>Totalmente revisado. ¡Funciona en segundo plano!</target>
<target>Completamente reimplementado: ¡funciona en segundo plano!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Further reduced battery usage" xml:space="preserve">
@@ -3680,7 +3618,6 @@ Error: %2$@</target>
</trans-unit>
<trans-unit id="IP address" xml:space="preserve">
<source>IP address</source>
<target>Dirección IP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="If you can't meet in person, show QR code in a video call, or share the link." xml:space="preserve">
@@ -3758,11 +3695,6 @@ Error: %2$@</target>
<target>Importando archivo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>Entrega de mensajes mejorada</target>
@@ -4165,7 +4097,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Local profile data only" xml:space="preserve">
<source>Local profile data only</source>
<target>Eliminar sólo el perfil</target>
<target>Sólo datos del perfil local</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Lock after" xml:space="preserve">
@@ -4335,7 +4267,6 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Message shape" xml:space="preserve">
<source>Message shape</source>
<target>Forma del mensaje</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -4390,7 +4321,6 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Messages were deleted after you selected them." xml:space="preserve">
<source>Messages were deleted after you selected them.</source>
<target>Los mensajes han sido borrados después de seleccionarlos.</target>
<note>alert message</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">
@@ -4548,16 +4478,6 @@ This is your link for group %@!</source>
<target>Código Nuevo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<target>Se usarán credenciales SOCKS nuevas cada vez que inicies la aplicación.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<target>Se usarán credenciales SOCKS nuevas por cada servidor.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>Nuevo chat</target>
@@ -4678,16 +4598,6 @@ This is your link for group %@!</source>
<target>Sin conexión de red</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<target>Sin permiso para grabación de voz</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<target>Sin permiso para grabación de vídeo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Sin permiso para grabar mensajes de voz</target>
@@ -4710,7 +4620,6 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Nothing to forward!" xml:space="preserve">
<source>Nothing to forward!</source>
<target>¡Nada para reenviar!</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications" xml:space="preserve">
@@ -4939,8 +4848,6 @@ Requiere activación de la VPN.</target>
<trans-unit id="Other file errors:&#10;%@" xml:space="preserve">
<source>Other file errors:
%@</source>
<target>Otro(s) error(es) de archivo.
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
@@ -4980,7 +4887,6 @@ Requiere activación de la VPN.</target>
</trans-unit>
<trans-unit id="Password" xml:space="preserve">
<source>Password</source>
<target>Contraseña</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Password to show" xml:space="preserve">
@@ -5134,12 +5040,11 @@ Error: %@</target>
</trans-unit>
<trans-unit id="Port" xml:space="preserve">
<source>Port</source>
<target>Puerto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Possibly, certificate fingerprint in server address is incorrect" xml:space="preserve">
<source>Possibly, certificate fingerprint in server address is incorrect</source>
<target>Posiblemente la huella del certificado en la dirección del servidor es incorrecta</target>
<target>Posiblemente la huella digital del certificado en la dirección del servidor es incorrecta</target>
<note>server test error</note>
</trans-unit>
<trans-unit id="Preserve the last message draft, with attachments." xml:space="preserve">
@@ -5209,7 +5114,7 @@ Error: %@</target>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
<source>Profile and server connections</source>
<target>Eliminar perfil y conexiones</target>
<target>Datos del perfil y conexiones</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile image" xml:space="preserve">
@@ -5326,7 +5231,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Proxy requires password" xml:space="preserve">
<source>Proxy requires password</source>
<target>El proxy requiere contraseña</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Push notifications" xml:space="preserve">
@@ -5552,7 +5456,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Remove archive?" xml:space="preserve">
<source>Remove archive?</source>
<target>¿Eliminar archivo?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Remove image" xml:space="preserve">
@@ -5737,7 +5640,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="SOCKS proxy" xml:space="preserve">
<source>SOCKS proxy</source>
<target>Proxy SOCKS</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
@@ -5828,7 +5730,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Save your profile?" xml:space="preserve">
<source>Save your profile?</source>
<target>¿Guardar tu perfil?</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Saved" xml:space="preserve">
@@ -5853,7 +5754,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Saving %lld messages" xml:space="preserve">
<source>Saving %lld messages</source>
<target>Guardando %lld mensajes</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scale" xml:space="preserve">
@@ -5938,7 +5838,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Select chat profile" xml:space="preserve">
<source>Select chat profile</source>
<target>Selecciona perfil de chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Selected %lld" xml:space="preserve">
@@ -5988,7 +5887,7 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Send direct message to connect" xml:space="preserve">
<source>Send direct message to connect</source>
<target>Envía un mensaje para conectar</target>
<target>Envia un mensaje para conectar</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send disappearing message" xml:space="preserve">
@@ -6156,11 +6055,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
<target>Mediante proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<target>Servidor</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>Dirección del servidor</target>
@@ -6188,7 +6082,7 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Server test failed!" xml:space="preserve">
<source>Server test failed!</source>
<target>¡Prueba no superada!</target>
<target>¡Error en prueba del servidor!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server type" xml:space="preserve">
@@ -6283,7 +6177,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Settings were changed." xml:space="preserve">
<source>Settings were changed.</source>
<target>La configuración ha sido modificada.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Shape profile images" xml:space="preserve">
@@ -6323,7 +6216,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Share profile" xml:space="preserve">
<source>Share profile</source>
<target>Comparte perfil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share this 1-time invite link" xml:space="preserve">
@@ -6461,10 +6353,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
<target>Invitación SimpleX de un uso</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Modo incógnito simplificado</target>
@@ -6497,7 +6385,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Some app settings were not migrated." xml:space="preserve">
<source>Some app settings were not migrated.</source>
<target>Algunas configuraciones de la app no han sido migradas.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Some file(s) were not exported:" xml:space="preserve">
@@ -6640,14 +6527,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
<target>Soporte SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>Sistema</target>
@@ -6685,7 +6564,6 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Tail" xml:space="preserve">
<source>Tail</source>
<target>Cola</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Take picture" xml:space="preserve">
@@ -6735,7 +6613,7 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Test failed at step %@." xml:space="preserve">
<source>Test failed at step %@.</source>
<target>Prueba no superada en el paso %@.</target>
<target>La prueba ha fallado en el paso %@.</target>
<note>server test failure</note>
</trans-unit>
<trans-unit id="Test server" xml:space="preserve">
@@ -6750,7 +6628,7 @@ Actívalo en ajustes de *Servidores y Redes*.</target>
</trans-unit>
<trans-unit id="Tests failed!" xml:space="preserve">
<source>Tests failed!</source>
<target>¡Pruebas no superadas!</target>
<target>¡Pruebas fallidas!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thank you for installing SimpleX Chat!" xml:space="preserve">
@@ -6882,7 +6760,6 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida.</target>
</trans-unit>
<trans-unit id="The uploaded database archive will be permanently removed from the servers." xml:space="preserve">
<source>The uploaded database archive will be permanently removed from the servers.</source>
<target>El archivo de bases de datos subido será eliminado permanentemente de los servidores.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Themes" xml:space="preserve">
@@ -7012,16 +6889,6 @@ You will be prompted to complete authentication before this feature is enabled.<
Se te pedirá que completes la autenticación antes de activar esta función.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<target>Para grabación de voz, por favor concede el permiso para usar el micrófono.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<target>Para grabación de vídeo, por favor concede el permiso para usar la cámara.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>Para grabar el mensaje de voz concede permiso para usar el micrófono.</target>
@@ -7291,7 +7158,6 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión
</trans-unit>
<trans-unit id="Use SOCKS proxy" xml:space="preserve">
<source>Use SOCKS proxy</source>
<target>Usar proxy SOCKS</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use SimpleX Chat servers?" xml:space="preserve">
@@ -7359,6 +7225,11 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión
<target>Usa la aplicación con una sola mano.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Perfil de usuario</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Selección de usuarios</target>
@@ -7366,7 +7237,6 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión
</trans-unit>
<trans-unit id="Username" xml:space="preserve">
<source>Username</source>
<target>Nombre de usuario</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Using SimpleX Chat servers." xml:space="preserve">
@@ -7629,6 +7499,11 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión
<target>Servidor XFTP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Tú</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>**No debes** usar la misma base de datos en dos dispositivos.</target>
@@ -7980,7 +7855,6 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your chat preferences" xml:space="preserve">
<source>Your chat preferences</source>
<target>Tus preferencias de chat</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Your chat profiles" xml:space="preserve">
@@ -7990,7 +7864,6 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile." xml:space="preserve">
<source>Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile.</source>
<target>Tu conexión ha sido trasladada a %@ pero ha ocurrido un error inesperado al redirigirte al perfil.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contact sent a file that is larger than currently supported maximum size (%@)." xml:space="preserve">
@@ -8010,7 +7883,6 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your credentials may be sent unencrypted." xml:space="preserve">
<source>Your credentials may be sent unencrypted.</source>
<target>Tus credenciales podrían ser enviadas sin cifrar.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
@@ -8050,7 +7922,6 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your profile was changed. If you save it, the updated profile will be sent to all your contacts." xml:space="preserve">
<source>Your profile was changed. If you save it, the updated profile will be sent to all your contacts.</source>
<target>Tu perfil ha sido modificado. Si lo guardas la actualización será enviada a todos tus contactos.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Your profile, contacts and delivered messages are stored on your device." xml:space="preserve">
@@ -8070,7 +7941,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your server address" xml:space="preserve">
<source>Your server address</source>
<target>Dirección del servidor</target>
<target>Dirección de tu servidor</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your settings" xml:space="preserve">
@@ -8782,7 +8653,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="removed profile picture" xml:space="preserve">
<source>removed profile picture</source>
<target>ha eliminado la imagen del perfil</target>
<target>imagen de perfil eliminada</target>
<note>profile update event chat item</note>
</trans-unit>
<trans-unit id="removed you" xml:space="preserve">
@@ -8846,7 +8717,7 @@ last received msg: %2$@</source>
</trans-unit>
<trans-unit id="set new profile picture" xml:space="preserve">
<source>set new profile picture</source>
<target>tiene nueva imagen del perfil</target>
<target>nueva imagen de perfil</target>
<note>profile update event chat item</note>
</trans-unit>
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
@@ -9194,7 +9065,7 @@ last received msg: %2$@</source>
</trans-unit>
<trans-unit id="Database passphrase is different from saved in the keychain." xml:space="preserve">
<source>Database passphrase is different from saved in the keychain.</source>
<target>La contraseña de la base de datos es diferente a la almacenada en keychain.</target>
<target>La contraseña de la base de datos es distinta a la almacenada en keychain.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Database passphrase is required to open chat." xml:space="preserve">
@@ -710,7 +710,7 @@
</trans-unit>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -892,10 +892,6 @@
<target>Sovelluksen pääsykoodi korvataan itsetuhoutuvalla pääsykoodilla.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>Sovellusversio</target>
@@ -1022,18 +1018,10 @@
<target>Virheellinen viestin tarkiste</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Parempia viestejä</target>
@@ -1043,18 +1031,6 @@
<source>Better networking</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<note>No comment provided by engineer.</note>
@@ -1315,11 +1291,6 @@
<source>Chat preferences were changed.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Käyttäjäprofiili</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<note>No comment provided by engineer.</note>
@@ -1796,10 +1767,6 @@ This is your own one-time link!</source>
<target>Mukautettu aika</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<note>No comment provided by engineer.</note>
@@ -2086,10 +2053,6 @@ This is your own one-time link!</source>
<target>Poista vanha tietokanta?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Poistetaanko odottava yhteys?</target>
@@ -2863,7 +2826,7 @@ This is your own one-time link!</source>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Virhe profiilin vaihdossa!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -2906,7 +2869,8 @@ This is your own one-time link!</source>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Virhe: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3134,10 +3098,6 @@ This is your own one-time link!</source>
<source>Forward messages without files?</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
@@ -3504,11 +3464,6 @@ Error: %2$@</source>
<source>Importing archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<note>No comment provided by engineer.</note>
@@ -4237,14 +4192,6 @@ This is your link for group %@!</source>
<target>Uusi pääsykoodi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<note>No comment provided by engineer.</note>
@@ -4358,14 +4305,6 @@ This is your link for group %@!</source>
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Ei lupaa ääniviestin tallentamiseen</target>
@@ -5727,10 +5666,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Sent via proxy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<note>No comment provided by engineer.</note>
@@ -6007,10 +5942,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>SimpleX-kertakutsu</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<note>No comment provided by engineer.</note>
@@ -6170,14 +6101,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>SimpleX Chat tuki</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>Järjestelmä</target>
@@ -6519,14 +6442,6 @@ You will be prompted to complete authentication before this feature is enabled.<
Sinua kehotetaan suorittamaan todennus loppuun, ennen kuin tämä ominaisuus otetaan käyttöön.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>Jos haluat nauhoittaa ääniviestin, anna lupa käyttää mikrofonia.</target>
@@ -6836,6 +6751,11 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<source>Use the app with one hand.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Käyttäjäprofiili</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<note>No comment provided by engineer.</note>
@@ -7080,6 +7000,11 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<source>XFTP server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Sinä</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<note>No comment provided by engineer.</note>
@@ -747,7 +747,7 @@
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>Tous les profiles</target>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -939,10 +939,6 @@
<target>Le code d'accès de l'application est remplacé par un code d'autodestruction.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>Version de l'app</target>
@@ -1077,19 +1073,11 @@
<target>Mauvais hash de message</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>Des groupes plus performants</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Meilleurs messages</target>
@@ -1100,18 +1088,6 @@
<target>Meilleure gestion de réseau</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Noir</target>
@@ -1397,11 +1373,6 @@
<source>Chat preferences were changed.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Profil d'utilisateur</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Thème de chat</target>
@@ -1930,10 +1901,6 @@ Il s'agit de votre propre lien unique !</target>
<target>Délai personnalisé</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Personnaliser le thème</target>
@@ -2228,10 +2195,6 @@ Il s'agit de votre propre lien unique !</target>
<target>Supprimer l'ancienne base de données?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Supprimer la connexion en attente ?</target>
@@ -3055,7 +3018,7 @@ Il s'agit de votre propre lien unique !</target>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Erreur lors du changement de profil !</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3100,7 +3063,8 @@ Il s'agit de votre propre lien unique !</target>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Erreur: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3344,10 +3308,6 @@ Il s'agit de votre propre lien unique !</target>
<source>Forward messages without files?</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Transféré</target>
@@ -3735,11 +3695,6 @@ Erreur: %2$@</target>
<target>Importation de l'archive</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>Amélioration de la transmission des messages</target>
@@ -4523,14 +4478,6 @@ Voici votre lien pour le groupe %@ !</target>
<target>Nouveau code d'accès</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>Nouveau chat</target>
@@ -4651,14 +4598,6 @@ Voici votre lien pour le groupe %@ !</target>
<target>Pas de connexion au réseau</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Pas l'autorisation d'enregistrer un message vocal</target>
@@ -6116,10 +6055,6 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>Envoyé via le proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>Adresse du serveur</target>
@@ -6418,10 +6353,6 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>Invitation unique SimpleX</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Mode incognito simplifié</target>
@@ -6596,14 +6527,6 @@ Activez-le dans les paramètres *Réseau et serveurs*.</target>
<target>Supporter SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>Système</target>
@@ -6966,14 +6889,6 @@ You will be prompted to complete authentication before this feature is enabled.<
Vous serez invité à confirmer l'authentification avant que cette fonction ne soit activée.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>Pour enregistrer un message vocal, veuillez accorder la permission d'utiliser le microphone.</target>
@@ -7310,6 +7225,11 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Utiliser l'application d'une main.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Profil d'utilisateur</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Sélection de l'utilisateur</target>
@@ -7579,6 +7499,11 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Serveur XFTP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Vous</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>Vous **ne devez pas** utiliser la même base de données sur deux appareils.</target>
File diff suppressed because it is too large Load Diff
@@ -164,22 +164,18 @@
</trans-unit>
<trans-unit id="%d file(s) are still being downloaded." xml:space="preserve">
<source>%d file(s) are still being downloaded.</source>
<target>%d file è/sono ancora in scaricamento.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) failed to download." xml:space="preserve">
<source>%d file(s) failed to download.</source>
<target>%d file ha/hanno fallito lo scaricamento.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were deleted." xml:space="preserve">
<source>%d file(s) were deleted.</source>
<target>%d file è/sono stato/i eliminato/i.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were not downloaded." xml:space="preserve">
<source>%d file(s) were not downloaded.</source>
<target>%d file non è/sono stato/i scaricato/i.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d hours" xml:space="preserve">
@@ -189,7 +185,6 @@
</trans-unit>
<trans-unit id="%d messages not forwarded" xml:space="preserve">
<source>%d messages not forwarded</source>
<target>%d messaggi non inoltrati</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="%d min" xml:space="preserve">
@@ -753,7 +748,7 @@
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>Tutti gli profili</target>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -945,11 +940,6 @@
<target>Il codice di accesso dell'app viene sostituito da un codice di autodistruzione.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<target>Sessione dell'app</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>Versione dell'app</target>
@@ -1085,19 +1075,11 @@
<target>Hash del messaggio errato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>Gruppi migliorati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Messaggi migliorati</target>
@@ -1108,18 +1090,6 @@
<target>Rete migliorata</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Nero</target>
@@ -1406,11 +1376,6 @@
<target>Le preferenze della chat sono state cambiate.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Profilo utente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Tema della chat</target>
@@ -1940,10 +1905,6 @@ Questo è il tuo link una tantum!</target>
<target>Tempo personalizzato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Personalizza il tema</target>
@@ -2238,10 +2199,6 @@ Questo è il tuo link una tantum!</target>
<target>Eliminare il database vecchio?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Eliminare la connessione in attesa?</target>
@@ -2494,7 +2451,6 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Do not use credentials with proxy." xml:space="preserve">
<source>Do not use credentials with proxy.</source>
<target>Non usare credenziali con proxy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't create address" xml:space="preserve">
@@ -2540,7 +2496,6 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Download files" xml:space="preserve">
<source>Download files</source>
<target>Scarica i file</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Downloaded" xml:space="preserve">
@@ -3071,7 +3026,7 @@ Questo è il tuo link una tantum!</target>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Errore nel cambio di profilo!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3116,7 +3071,8 @@ Questo è il tuo link una tantum!</target>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Errore: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3206,8 +3162,6 @@ Questo è il tuo link una tantum!</target>
<trans-unit id="File errors:&#10;%@" xml:space="preserve">
<source>File errors:
%@</source>
<target>Errori di file:
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@@ -3347,7 +3301,6 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Forward %d message(s)?" xml:space="preserve">
<source>Forward %d message(s)?</source>
<target>Inoltrare %d messaggio/i?</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Forward and save messages" xml:space="preserve">
@@ -3357,18 +3310,12 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Forward messages" xml:space="preserve">
<source>Forward messages</source>
<target>Inoltra i messaggi</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Forward messages without files?" xml:space="preserve">
<source>Forward messages without files?</source>
<target>Inoltrare i messaggi senza file?</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Inoltrato</target>
@@ -3381,7 +3328,6 @@ Questo è il tuo link una tantum!</target>
</trans-unit>
<trans-unit id="Forwarding %lld messages" xml:space="preserve">
<source>Forwarding %lld messages</source>
<target>Inoltro di %lld messaggi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarding server %@ failed to connect to destination server %@. Please try later." xml:space="preserve">
@@ -3680,7 +3626,6 @@ Errore: %2$@</target>
</trans-unit>
<trans-unit id="IP address" xml:space="preserve">
<source>IP address</source>
<target>Indirizzo IP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="If you can't meet in person, show QR code in a video call, or share the link." xml:space="preserve">
@@ -3758,11 +3703,6 @@ Errore: %2$@</target>
<target>Importazione archivio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>Consegna dei messaggi migliorata</target>
@@ -4390,7 +4330,6 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Messages were deleted after you selected them." xml:space="preserve">
<source>Messages were deleted after you selected them.</source>
<target>I messaggi sono stati eliminati dopo che li hai selezionati.</target>
<note>alert message</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">
@@ -4548,16 +4487,6 @@ Questo è il tuo link per il gruppo %@!</target>
<target>Nuovo codice di accesso</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<target>Le nuove credenziali SOCKS verranno usate ogni volta che avvii l'app.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<target>Le nuove credenziali SOCKS verranno usate per ogni server.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>Nuova chat</target>
@@ -4678,16 +4607,6 @@ Questo è il tuo link per il gruppo %@!</target>
<target>Nessuna connessione di rete</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<target>Nessuna autorizzazione per registrare l'audio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<target>Nessuna autorizzazione per registrare il video</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Nessuna autorizzazione per registrare messaggi vocali</target>
@@ -4710,7 +4629,6 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Nothing to forward!" xml:space="preserve">
<source>Nothing to forward!</source>
<target>Niente da inoltrare!</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications" xml:space="preserve">
@@ -4939,8 +4857,6 @@ Richiede l'attivazione della VPN.</target>
<trans-unit id="Other file errors:&#10;%@" xml:space="preserve">
<source>Other file errors:
%@</source>
<target>Altri errori di file:
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
@@ -4980,7 +4896,6 @@ Richiede l'attivazione della VPN.</target>
</trans-unit>
<trans-unit id="Password" xml:space="preserve">
<source>Password</source>
<target>Password</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Password to show" xml:space="preserve">
@@ -5134,7 +5049,6 @@ Errore: %@</target>
</trans-unit>
<trans-unit id="Port" xml:space="preserve">
<source>Port</source>
<target>Porta</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Possibly, certificate fingerprint in server address is incorrect" xml:space="preserve">
@@ -5326,7 +5240,6 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Proxy requires password" xml:space="preserve">
<source>Proxy requires password</source>
<target>Il proxy richiede una password</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Push notifications" xml:space="preserve">
@@ -5737,7 +5650,6 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="SOCKS proxy" xml:space="preserve">
<source>SOCKS proxy</source>
<target>Proxy SOCKS</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
@@ -5853,7 +5765,6 @@ Attivalo nelle impostazioni *Rete e server*.</target>
</trans-unit>
<trans-unit id="Saving %lld messages" xml:space="preserve">
<source>Saving %lld messages</source>
<target>Salvataggio di %lld messaggi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scale" xml:space="preserve">
@@ -6156,11 +6067,6 @@ Attivalo nelle impostazioni *Rete e server*.</target>
<target>Inviato via proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<target>Server</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>
@@ -6461,10 +6367,6 @@ Attivalo nelle impostazioni *Rete e server*.</target>
<target>Invito SimpleX una tantum</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Modalità incognito semplificata</target>
@@ -6640,14 +6542,6 @@ Attivalo nelle impostazioni *Rete e server*.</target>
<target>Supporta SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>Sistema</target>
@@ -7012,16 +6906,6 @@ You will be prompted to complete authentication before this feature is enabled.<
Ti verrà chiesto di completare l'autenticazione prima di attivare questa funzionalità.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<target>Per registrare l'audio, concedi l'autorizzazione di usare il microfono.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<target>Per registrare il video, concedi l'autorizzazione di usare la fotocamera.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>Per registrare un messaggio vocale, concedi l'autorizzazione all'uso del microfono.</target>
@@ -7291,7 +7175,6 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="Use SOCKS proxy" xml:space="preserve">
<source>Use SOCKS proxy</source>
<target>Usa proxy SOCKS</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use SimpleX Chat servers?" xml:space="preserve">
@@ -7359,6 +7242,11 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
<target>Usa l'app con una mano sola.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Profilo utente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Selezione utente</target>
@@ -7366,7 +7254,6 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="Username" xml:space="preserve">
<source>Username</source>
<target>Nome utente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Using SimpleX Chat servers." xml:space="preserve">
@@ -7629,6 +7516,11 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
<target>Server XFTP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Tu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>**Non devi** usare lo stesso database su due dispositivi.</target>
@@ -8010,7 +7902,6 @@ Ripetere la richiesta di connessione?</target>
</trans-unit>
<trans-unit id="Your credentials may be sent unencrypted." xml:space="preserve">
<source>Your credentials may be sent unencrypted.</source>
<target>Le credenziali potrebbero essere inviate in chiaro.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
@@ -8230,7 +8121,7 @@ Ripetere la richiesta di connessione?</target>
</trans-unit>
<trans-unit id="changed your role to %@" xml:space="preserve">
<source>changed your role to %@</source>
<target>ha cambiato il tuo ruolo in %@</target>
<target>cambiato il tuo ruolo in %@</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="changing address for %@…" xml:space="preserve">
@@ -727,7 +727,7 @@
</trans-unit>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -915,10 +915,6 @@
<target>アプリのパスコードは自己破壊パスコードに置き換えられます。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>アプリのバージョン</target>
@@ -1045,18 +1041,10 @@
<target>メッセージのハッシュ値問題</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>より良いメッセージ</target>
@@ -1066,18 +1054,6 @@
<source>Better networking</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<note>No comment provided by engineer.</note>
@@ -1339,11 +1315,6 @@
<source>Chat preferences were changed.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>ユーザープロフィール</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<note>No comment provided by engineer.</note>
@@ -1820,10 +1791,6 @@ This is your own one-time link!</source>
<target>カスタム時間</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<note>No comment provided by engineer.</note>
@@ -2110,10 +2077,6 @@ This is your own one-time link!</source>
<target>古いデータベースを削除しますか?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>接続待ちの接続を削除しますか?</target>
@@ -2888,7 +2851,7 @@ This is your own one-time link!</source>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>プロフィール切り替えにエラー発生!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -2931,7 +2894,8 @@ This is your own one-time link!</source>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>エラー : %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3159,10 +3123,6 @@ This is your own one-time link!</source>
<source>Forward messages without files?</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
@@ -3529,11 +3489,6 @@ Error: %2$@</source>
<source>Importing archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<note>No comment provided by engineer.</note>
@@ -4261,14 +4216,6 @@ This is your link for group %@!</source>
<target>新しいパスコード</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<note>No comment provided by engineer.</note>
@@ -4383,14 +4330,6 @@ This is your link for group %@!</source>
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>音声メッセージを録音する権限がありません</target>
@@ -5745,10 +5684,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Sent via proxy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<note>No comment provided by engineer.</note>
@@ -6025,10 +5960,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>SimpleX使い捨て招待リンク</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>シークレットモードの簡素化</target>
@@ -6189,14 +6120,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>Simplex Chatを支援</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>システム</target>
@@ -6537,14 +6460,6 @@ You will be prompted to complete authentication before this feature is enabled.<
オンにするには、認証ステップが行われます。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>音声メッセージを録音する場合は、マイクの使用を許可してください。</target>
@@ -6854,6 +6769,11 @@ To connect, please ask your contact to create another connection link and check
<source>Use the app with one hand.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>ユーザープロフィール</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<note>No comment provided by engineer.</note>
@@ -7098,6 +7018,11 @@ To connect, please ask your contact to create another connection link and check
<source>XFTP server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>あなた</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<note>No comment provided by engineer.</note>
@@ -164,22 +164,18 @@
</trans-unit>
<trans-unit id="%d file(s) are still being downloaded." xml:space="preserve">
<source>%d file(s) are still being downloaded.</source>
<target>%d bestand(en) worden nog gedownload.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) failed to download." xml:space="preserve">
<source>%d file(s) failed to download.</source>
<target>%d bestand(en) konden niet worden gedownload.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were deleted." xml:space="preserve">
<source>%d file(s) were deleted.</source>
<target>%d bestand(en) zijn verwijderd.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were not downloaded." xml:space="preserve">
<source>%d file(s) were not downloaded.</source>
<target>%d bestand(en) zijn niet gedownload.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d hours" xml:space="preserve">
@@ -189,7 +185,6 @@
</trans-unit>
<trans-unit id="%d messages not forwarded" xml:space="preserve">
<source>%d messages not forwarded</source>
<target>%d berichten niet doorgestuurd</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="%d min" xml:space="preserve">
@@ -753,7 +748,7 @@
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>Alle profielen</target>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -945,11 +940,6 @@
<target>De app-toegangscode wordt vervangen door een zelfvernietigings wachtwoord.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<target>Appsessie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>App versie</target>
@@ -1085,19 +1075,11 @@
<target>Onjuiste bericht hash</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>Betere groepen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Betere berichten</target>
@@ -1108,18 +1090,6 @@
<target>Beter netwerk</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Zwart</target>
@@ -1406,11 +1376,6 @@
<target>Chatvoorkeuren zijn gewijzigd.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Gebruikers profiel</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Chat thema</target>
@@ -1508,7 +1473,7 @@
</trans-unit>
<trans-unit id="Completed" xml:space="preserve">
<source>Completed</source>
<target>Voltooid</target>
<target>voltooid</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configure ICE servers" xml:space="preserve">
@@ -1940,10 +1905,6 @@ Dit is uw eigen eenmalige link!</target>
<target>Aangepaste tijd</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Thema aanpassen</target>
@@ -2238,10 +2199,6 @@ Dit is uw eigen eenmalige link!</target>
<target>Oude database verwijderen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Wachtende verbinding verwijderen?</target>
@@ -2494,7 +2451,6 @@ Dit is uw eigen eenmalige link!</target>
</trans-unit>
<trans-unit id="Do not use credentials with proxy." xml:space="preserve">
<source>Do not use credentials with proxy.</source>
<target>Gebruik geen inloggegevens met proxy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't create address" xml:space="preserve">
@@ -2540,7 +2496,6 @@ Dit is uw eigen eenmalige link!</target>
</trans-unit>
<trans-unit id="Download files" xml:space="preserve">
<source>Download files</source>
<target>Bestanden downloaden</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Downloaded" xml:space="preserve">
@@ -3071,7 +3026,7 @@ Dit is uw eigen eenmalige link!</target>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Fout bij wisselen van profiel!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3116,7 +3071,8 @@ Dit is uw eigen eenmalige link!</target>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Fout: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3206,8 +3162,6 @@ Dit is uw eigen eenmalige link!</target>
<trans-unit id="File errors:&#10;%@" xml:space="preserve">
<source>File errors:
%@</source>
<target>Bestandsfouten:
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@@ -3347,7 +3301,6 @@ Dit is uw eigen eenmalige link!</target>
</trans-unit>
<trans-unit id="Forward %d message(s)?" xml:space="preserve">
<source>Forward %d message(s)?</source>
<target>%d bericht(en) doorsturen?</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Forward and save messages" xml:space="preserve">
@@ -3357,18 +3310,12 @@ Dit is uw eigen eenmalige link!</target>
</trans-unit>
<trans-unit id="Forward messages" xml:space="preserve">
<source>Forward messages</source>
<target>Berichten doorsturen</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Forward messages without files?" xml:space="preserve">
<source>Forward messages without files?</source>
<target>Berichten doorsturen zonder bestanden?</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Doorgestuurd</target>
@@ -3381,7 +3328,6 @@ Dit is uw eigen eenmalige link!</target>
</trans-unit>
<trans-unit id="Forwarding %lld messages" xml:space="preserve">
<source>Forwarding %lld messages</source>
<target>%lld berichten doorsturen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarding server %@ failed to connect to destination server %@. Please try later." xml:space="preserve">
@@ -3680,7 +3626,6 @@ Fout: %2$@</target>
</trans-unit>
<trans-unit id="IP address" xml:space="preserve">
<source>IP address</source>
<target>IP-adres</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="If you can't meet in person, show QR code in a video call, or share the link." xml:space="preserve">
@@ -3758,11 +3703,6 @@ Fout: %2$@</target>
<target>Archief importeren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>Verbeterde berichtbezorging</target>
@@ -4390,7 +4330,6 @@ Dit is jouw link voor groep %@!</target>
</trans-unit>
<trans-unit id="Messages were deleted after you selected them." xml:space="preserve">
<source>Messages were deleted after you selected them.</source>
<target>Berichten zijn verwijderd nadat u ze had geselecteerd.</target>
<note>alert message</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">
@@ -4548,16 +4487,6 @@ Dit is jouw link voor groep %@!</target>
<target>Nieuwe toegangscode</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<target>Elke keer dat u de app start, worden er nieuwe SOCKS-inloggegevens gebruikt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<target>Voor elke server worden nieuwe SOCKS-inloggegevens gebruikt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>Nieuw gesprek</target>
@@ -4678,16 +4607,6 @@ Dit is jouw link voor groep %@!</target>
<target>Geen netwerkverbinding</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<target>Geen toestemming om spraak op te nemen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<target>Geen toestemming om video op te nemen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Geen toestemming om spraakbericht op te nemen</target>
@@ -4710,7 +4629,6 @@ Dit is jouw link voor groep %@!</target>
</trans-unit>
<trans-unit id="Nothing to forward!" xml:space="preserve">
<source>Nothing to forward!</source>
<target>Niets om door te sturen!</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications" xml:space="preserve">
@@ -4939,8 +4857,6 @@ Vereist het inschakelen van VPN.</target>
<trans-unit id="Other file errors:&#10;%@" xml:space="preserve">
<source>Other file errors:
%@</source>
<target>Andere bestandsfouten:
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
@@ -4980,7 +4896,6 @@ Vereist het inschakelen van VPN.</target>
</trans-unit>
<trans-unit id="Password" xml:space="preserve">
<source>Password</source>
<target>Wachtwoord</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Password to show" xml:space="preserve">
@@ -5134,7 +5049,6 @@ Fout: %@</target>
</trans-unit>
<trans-unit id="Port" xml:space="preserve">
<source>Port</source>
<target>Poort</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Possibly, certificate fingerprint in server address is incorrect" xml:space="preserve">
@@ -5326,7 +5240,6 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
</trans-unit>
<trans-unit id="Proxy requires password" xml:space="preserve">
<source>Proxy requires password</source>
<target>Proxy vereist wachtwoord</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Push notifications" xml:space="preserve">
@@ -5737,7 +5650,6 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
</trans-unit>
<trans-unit id="SOCKS proxy" xml:space="preserve">
<source>SOCKS proxy</source>
<target>SOCKS proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
@@ -5853,7 +5765,6 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
</trans-unit>
<trans-unit id="Saving %lld messages" xml:space="preserve">
<source>Saving %lld messages</source>
<target>%lld berichten opslaan</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scale" xml:space="preserve">
@@ -6156,11 +6067,6 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
<target>Verzonden via proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<target>Server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>Server adres</target>
@@ -6461,10 +6367,6 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
<target>Eenmalige SimpleX uitnodiging</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Vereenvoudigde incognitomodus</target>
@@ -6622,17 +6524,17 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
</trans-unit>
<trans-unit id="Subscribed" xml:space="preserve">
<source>Subscribed</source>
<target>Subscribed</target>
<target>Ingeschreven</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscription errors" xml:space="preserve">
<source>Subscription errors</source>
<target>Subscription fouten</target>
<target>Inschrijving fouten</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Subscriptions ignored" xml:space="preserve">
<source>Subscriptions ignored</source>
<target>Subscriptions genegeerd</target>
<target>Inschrijvingen genegeerd</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Support SimpleX Chat" xml:space="preserve">
@@ -6640,14 +6542,6 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
<target>Ondersteuning van SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>Systeem</target>
@@ -6685,7 +6579,6 @@ Schakel dit in in *Netwerk en servers*-instellingen.</target>
</trans-unit>
<trans-unit id="Tail" xml:space="preserve">
<source>Tail</source>
<target>Staart</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Take picture" xml:space="preserve">
@@ -7012,16 +6905,6 @@ You will be prompted to complete authentication before this feature is enabled.<
U wordt gevraagd de authenticatie te voltooien voordat deze functie wordt ingeschakeld.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<target>Geef toestemming om de microfoon te gebruiken om spraak op te nemen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<target>Om video op te nemen, dient u toestemming te geven om de camera te gebruiken.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>Geef toestemming om de microfoon te gebruiken om een spraakbericht op te nemen.</target>
@@ -7291,7 +7174,6 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
</trans-unit>
<trans-unit id="Use SOCKS proxy" xml:space="preserve">
<source>Use SOCKS proxy</source>
<target>Gebruik SOCKS proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use SimpleX Chat servers?" xml:space="preserve">
@@ -7359,6 +7241,11 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
<target>Gebruik de app met één hand.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Gebruikers profiel</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Gebruikersselectie</target>
@@ -7366,7 +7253,6 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
</trans-unit>
<trans-unit id="Username" xml:space="preserve">
<source>Username</source>
<target>Gebruikersnaam</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Using SimpleX Chat servers." xml:space="preserve">
@@ -7629,6 +7515,11 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
<target>XFTP server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Jij</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>U **mag** niet dezelfde database op twee apparaten gebruiken.</target>
@@ -8010,7 +7901,6 @@ Verbindingsverzoek herhalen?</target>
</trans-unit>
<trans-unit id="Your credentials may be sent unencrypted." xml:space="preserve">
<source>Your credentials may be sent unencrypted.</source>
<target>Uw inloggegevens worden mogelijk niet-versleuteld verzonden.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
@@ -8991,7 +8881,7 @@ laatst ontvangen bericht: %2$@</target>
</trans-unit>
<trans-unit id="you are observer" xml:space="preserve">
<source>you are observer</source>
<target>je bent waarnemer</target>
<target>jij bent waarnemer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you blocked %@" xml:space="preserve">
@@ -9021,7 +8911,7 @@ laatst ontvangen bericht: %2$@</target>
</trans-unit>
<trans-unit id="you left" xml:space="preserve">
<source>you left</source>
<target>je bent vertrokken</target>
<target>jij bent vertrokken</target>
<note>snd group event chat item</note>
</trans-unit>
<trans-unit id="you removed %@" xml:space="preserve">
@@ -139,7 +139,6 @@
</trans-unit>
<trans-unit id="%@, %@" xml:space="preserve">
<source>%1$@, %2$@</source>
<target>%1$@, %2$@</target>
<note>format for date separator in chat</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld members" xml:space="preserve">
@@ -164,22 +163,18 @@
</trans-unit>
<trans-unit id="%d file(s) are still being downloaded." xml:space="preserve">
<source>%d file(s) are still being downloaded.</source>
<target>%d plik(ów) jest dalej pobieranych.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) failed to download." xml:space="preserve">
<source>%d file(s) failed to download.</source>
<target>%d plik(ów) nie udało się pobrać.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were deleted." xml:space="preserve">
<source>%d file(s) were deleted.</source>
<target>%d plik(ów) zostało usuniętych.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were not downloaded." xml:space="preserve">
<source>%d file(s) were not downloaded.</source>
<target>%d plik(ów) nie zostało pobranych.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d hours" xml:space="preserve">
@@ -189,7 +184,6 @@
</trans-unit>
<trans-unit id="%d messages not forwarded" xml:space="preserve">
<source>%d messages not forwarded</source>
<target>%d wiadomości nie przekazanych</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="%d min" xml:space="preserve">
@@ -753,7 +747,7 @@
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>Wszystkie profile</target>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -945,11 +939,6 @@
<target>Pin aplikacji został zastąpiony pinem samozniszczenia.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<target>Sesja aplikacji</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>Wersja aplikacji</target>
@@ -1057,7 +1046,6 @@
</trans-unit>
<trans-unit id="Auto-accept settings" xml:space="preserve">
<source>Auto-accept settings</source>
<target>Ustawienia automatycznej akceptacji</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Back" xml:space="preserve">
@@ -1085,19 +1073,11 @@
<target>Zły hash wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>Lepsze grupy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Lepsze wiadomości</target>
@@ -1108,18 +1088,6 @@
<target>Lepsze sieciowanie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Czarny</target>
@@ -1403,14 +1371,8 @@
</trans-unit>
<trans-unit id="Chat preferences were changed." xml:space="preserve">
<source>Chat preferences were changed.</source>
<target>Preferencje czatu zostały zmienione.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Profil użytkownika</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Motyw czatu</target>
@@ -1812,7 +1774,6 @@ To jest twój jednorazowy link!</target>
</trans-unit>
<trans-unit id="Corner" xml:space="preserve">
<source>Corner</source>
<target>Róg</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Correct name to %@?" xml:space="preserve">
@@ -1940,10 +1901,6 @@ To jest twój jednorazowy link!</target>
<target>Niestandardowy czas</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Dostosuj motyw</target>
@@ -2238,10 +2195,6 @@ To jest twój jednorazowy link!</target>
<target>Usunąć starą bazę danych?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Usunąć oczekujące połączenie?</target>
@@ -2494,7 +2447,6 @@ To jest twój jednorazowy link!</target>
</trans-unit>
<trans-unit id="Do not use credentials with proxy." xml:space="preserve">
<source>Do not use credentials with proxy.</source>
<target>Nie używaj danych logowania do proxy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't create address" xml:space="preserve">
@@ -2540,7 +2492,6 @@ To jest twój jednorazowy link!</target>
</trans-unit>
<trans-unit id="Download files" xml:space="preserve">
<source>Download files</source>
<target>Pobierz pliki</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Downloaded" xml:space="preserve">
@@ -2820,7 +2771,6 @@ To jest twój jednorazowy link!</target>
</trans-unit>
<trans-unit id="Error changing connection profile" xml:space="preserve">
<source>Error changing connection profile</source>
<target>Błąd zmiany połączenia profilu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error changing role" xml:space="preserve">
@@ -2835,7 +2785,6 @@ To jest twój jednorazowy link!</target>
</trans-unit>
<trans-unit id="Error changing to incognito!" xml:space="preserve">
<source>Error changing to incognito!</source>
<target>Błąd zmiany na incognito!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
@@ -2960,7 +2909,6 @@ To jest twój jednorazowy link!</target>
</trans-unit>
<trans-unit id="Error migrating settings" xml:space="preserve">
<source>Error migrating settings</source>
<target>Błąd migracji ustawień</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error opening chat" xml:space="preserve">
@@ -3065,13 +3013,12 @@ To jest twój jednorazowy link!</target>
</trans-unit>
<trans-unit id="Error switching profile" xml:space="preserve">
<source>Error switching profile</source>
<target>Błąd zmiany profilu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Błąd przełączania profilu!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3116,7 +3063,8 @@ To jest twój jednorazowy link!</target>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Błąd: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3206,8 +3154,6 @@ To jest twój jednorazowy link!</target>
<trans-unit id="File errors:&#10;%@" xml:space="preserve">
<source>File errors:
%@</source>
<target>Błędy pliku:
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@@ -3347,7 +3293,6 @@ To jest twój jednorazowy link!</target>
</trans-unit>
<trans-unit id="Forward %d message(s)?" xml:space="preserve">
<source>Forward %d message(s)?</source>
<target>Przekazać %d wiadomość(i)?</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Forward and save messages" xml:space="preserve">
@@ -3357,18 +3302,12 @@ To jest twój jednorazowy link!</target>
</trans-unit>
<trans-unit id="Forward messages" xml:space="preserve">
<source>Forward messages</source>
<target>Przekaż wiadomości</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Forward messages without files?" xml:space="preserve">
<source>Forward messages without files?</source>
<target>Przekazać wiadomości bez plików?</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Przekazane dalej</target>
@@ -3381,7 +3320,6 @@ To jest twój jednorazowy link!</target>
</trans-unit>
<trans-unit id="Forwarding %lld messages" xml:space="preserve">
<source>Forwarding %lld messages</source>
<target>Przekazywanie %lld wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarding server %@ failed to connect to destination server %@. Please try later." xml:space="preserve">
@@ -3680,7 +3618,6 @@ Błąd: %2$@</target>
</trans-unit>
<trans-unit id="IP address" xml:space="preserve">
<source>IP address</source>
<target>Adres IP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="If you can't meet in person, show QR code in a video call, or share the link." xml:space="preserve">
@@ -3758,11 +3695,6 @@ Błąd: %2$@</target>
<target>Importowanie archiwum</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>Ulepszona dostawa wiadomości</target>
@@ -4335,7 +4267,6 @@ To jest twój link do grupy %@!</target>
</trans-unit>
<trans-unit id="Message shape" xml:space="preserve">
<source>Message shape</source>
<target>Kształt wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -4390,7 +4321,6 @@ To jest twój link do grupy %@!</target>
</trans-unit>
<trans-unit id="Messages were deleted after you selected them." xml:space="preserve">
<source>Messages were deleted after you selected them.</source>
<target>Wiadomości zostały usunięte po wybraniu ich.</target>
<note>alert message</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">
@@ -4548,16 +4478,6 @@ To jest twój link do grupy %@!</target>
<target>Nowy Pin</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<target>Nowe poświadczenia SOCKS będą używane przy każdym uruchomieniu aplikacji.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<target>Dla każdego serwera zostaną użyte nowe poświadczenia SOCKS.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>Nowy czat</target>
@@ -4678,16 +4598,6 @@ To jest twój link do grupy %@!</target>
<target>Brak połączenia z siecią</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<target>Brak zezwoleń do nagrania rozmowy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<target>Brak zezwoleń do nagrania wideo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Brak uprawnień do nagrywania wiadomości głosowej</target>
@@ -4710,7 +4620,6 @@ To jest twój link do grupy %@!</target>
</trans-unit>
<trans-unit id="Nothing to forward!" xml:space="preserve">
<source>Nothing to forward!</source>
<target>Nic do przekazania!</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications" xml:space="preserve">
@@ -4939,8 +4848,6 @@ Wymaga włączenia VPN.</target>
<trans-unit id="Other file errors:&#10;%@" xml:space="preserve">
<source>Other file errors:
%@</source>
<target>Inne błędy pliku:
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
@@ -4980,7 +4887,6 @@ Wymaga włączenia VPN.</target>
</trans-unit>
<trans-unit id="Password" xml:space="preserve">
<source>Password</source>
<target>Hasło</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Password to show" xml:space="preserve">
@@ -5134,7 +5040,6 @@ Błąd: %@</target>
</trans-unit>
<trans-unit id="Port" xml:space="preserve">
<source>Port</source>
<target>Port</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Possibly, certificate fingerprint in server address is incorrect" xml:space="preserve">
@@ -5326,7 +5231,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
</trans-unit>
<trans-unit id="Proxy requires password" xml:space="preserve">
<source>Proxy requires password</source>
<target>Proxy wymaga hasła</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Push notifications" xml:space="preserve">
@@ -5552,7 +5456,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
</trans-unit>
<trans-unit id="Remove archive?" xml:space="preserve">
<source>Remove archive?</source>
<target>Usunąć archiwum?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Remove image" xml:space="preserve">
@@ -5737,7 +5640,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
</trans-unit>
<trans-unit id="SOCKS proxy" xml:space="preserve">
<source>SOCKS proxy</source>
<target>Proxy SOCKS</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
@@ -5828,7 +5730,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
</trans-unit>
<trans-unit id="Save your profile?" xml:space="preserve">
<source>Save your profile?</source>
<target>Zapisać Twój profil?</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Saved" xml:space="preserve">
@@ -5853,7 +5754,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
</trans-unit>
<trans-unit id="Saving %lld messages" xml:space="preserve">
<source>Saving %lld messages</source>
<target>Zapisywanie %lld wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scale" xml:space="preserve">
@@ -5938,7 +5838,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
</trans-unit>
<trans-unit id="Select chat profile" xml:space="preserve">
<source>Select chat profile</source>
<target>Wybierz profil czatu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Selected %lld" xml:space="preserve">
@@ -6156,11 +6055,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Wysłano przez proxy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<target>Serwer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>Adres serwera</target>
@@ -6283,7 +6177,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
</trans-unit>
<trans-unit id="Settings were changed." xml:space="preserve">
<source>Settings were changed.</source>
<target>Ustawienia zostały zmienione.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Shape profile images" xml:space="preserve">
@@ -6323,7 +6216,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
</trans-unit>
<trans-unit id="Share profile" xml:space="preserve">
<source>Share profile</source>
<target>Udostępnij profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share this 1-time invite link" xml:space="preserve">
@@ -6461,10 +6353,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Zaproszenie jednorazowe SimpleX</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Uproszczony tryb incognito</target>
@@ -6497,7 +6385,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
</trans-unit>
<trans-unit id="Some app settings were not migrated." xml:space="preserve">
<source>Some app settings were not migrated.</source>
<target>Niektóre ustawienia aplikacji nie zostały zmigrowane.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Some file(s) were not exported:" xml:space="preserve">
@@ -6640,14 +6527,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
<target>Wspieraj SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>System</target>
@@ -6685,7 +6564,6 @@ Włącz w ustawianiach *Sieć i serwery* .</target>
</trans-unit>
<trans-unit id="Tail" xml:space="preserve">
<source>Tail</source>
<target>Ogon</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Take picture" xml:space="preserve">
@@ -6882,7 +6760,6 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom
</trans-unit>
<trans-unit id="The uploaded database archive will be permanently removed from the servers." xml:space="preserve">
<source>The uploaded database archive will be permanently removed from the servers.</source>
<target>Przesłane archiwum bazy danych zostanie trwale usunięte z serwerów.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Themes" xml:space="preserve">
@@ -7012,16 +6889,6 @@ You will be prompted to complete authentication before this feature is enabled.<
Przed włączeniem tej funkcji zostanie wyświetlony monit uwierzytelniania.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<target>Aby nagrać rozmowę, proszę zezwolić na użycie Mikrofonu.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<target>Aby nagrać wideo, proszę zezwolić na użycie Aparatu.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>Aby nagrać wiadomość głosową należy udzielić zgody na użycie Mikrofonu.</target>
@@ -7291,7 +7158,6 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
</trans-unit>
<trans-unit id="Use SOCKS proxy" xml:space="preserve">
<source>Use SOCKS proxy</source>
<target>Użyj proxy SOCKS</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use SimpleX Chat servers?" xml:space="preserve">
@@ -7359,6 +7225,11 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
<target>Korzystaj z aplikacji jedną ręką.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Profil użytkownika</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Wybór użytkownika</target>
@@ -7366,7 +7237,6 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
</trans-unit>
<trans-unit id="Username" xml:space="preserve">
<source>Username</source>
<target>Nazwa użytkownika</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Using SimpleX Chat servers." xml:space="preserve">
@@ -7629,6 +7499,11 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
<target>Serwer XFTP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Ty</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>**Nie możesz** używać tej samej bazy na dwóch urządzeniach.</target>
@@ -7980,7 +7855,6 @@ Powtórzyć prośbę połączenia?</target>
</trans-unit>
<trans-unit id="Your chat preferences" xml:space="preserve">
<source>Your chat preferences</source>
<target>Twoje preferencje czatu</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Your chat profiles" xml:space="preserve">
@@ -7990,7 +7864,6 @@ Powtórzyć prośbę połączenia?</target>
</trans-unit>
<trans-unit id="Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile." xml:space="preserve">
<source>Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile.</source>
<target>Twoje połączenie zostało przeniesione do %@, ale podczas przekierowywania do profilu wystąpił nieoczekiwany błąd.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contact sent a file that is larger than currently supported maximum size (%@)." xml:space="preserve">
@@ -8010,7 +7883,6 @@ Powtórzyć prośbę połączenia?</target>
</trans-unit>
<trans-unit id="Your credentials may be sent unencrypted." xml:space="preserve">
<source>Your credentials may be sent unencrypted.</source>
<target>Twoje poświadczenia mogą zostać wysłane niezaszyfrowane.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
@@ -8050,7 +7922,6 @@ Powtórzyć prośbę połączenia?</target>
</trans-unit>
<trans-unit id="Your profile was changed. If you save it, the updated profile will be sent to all your contacts." xml:space="preserve">
<source>Your profile was changed. If you save it, the updated profile will be sent to all your contacts.</source>
<target>Twój profil został zmieniony. Jeśli go zapiszesz, zaktualizowany profil zostanie wysłany do wszystkich kontaktów.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Your profile, contacts and delivered messages are stored on your device." xml:space="preserve">
@@ -5502,74 +5502,6 @@ Isso pode acontecer por causa de algum bug ou quando a conexão está comprometi
<source>Archived contacts</source>
<target state="translated">Contatos arquivados</target>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve" approved="no">
<source>Cellular</source>
<target state="translated">Rede móvel</target>
</trans-unit>
<trans-unit id="%d file(s) failed to download." xml:space="preserve" approved="no">
<source>%d file(s) failed to download.</source>
<target state="translated">%d arquivo(s) falharam ao ser baixados.</target>
</trans-unit>
<trans-unit id="%d file(s) were deleted." xml:space="preserve" approved="no">
<source>%d file(s) were deleted.</source>
<target state="translated">%d arquivo(s) foram apagados.</target>
</trans-unit>
<trans-unit id="%d messages not forwarded" xml:space="preserve" approved="no">
<source>%d messages not forwarded</source>
<target state="translated">%d mensagens não encaminhadas</target>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve" approved="no">
<source>Bad desktop address</source>
<target state="translated">Endereço de desktop incorreto</target>
</trans-unit>
<trans-unit id="Blur for better privacy." xml:space="preserve" approved="no">
<source>Blur for better privacy.</source>
<target state="translated">Borrar para melhor privacidade.</target>
</trans-unit>
<trans-unit id="%d file(s) are still being downloaded." xml:space="preserve" approved="no">
<source>%d file(s) are still being downloaded.</source>
<target state="translated">%d arquivo(s) ainda estão sendo baixados.</target>
</trans-unit>
<trans-unit id="%d file(s) were not downloaded." xml:space="preserve" approved="no">
<source>%d file(s) were not downloaded.</source>
<target state="translated">%d arquivo(s) não foram baixados.</target>
</trans-unit>
<trans-unit id="Chat colors" xml:space="preserve" approved="no">
<source>Chat colors</source>
<target state="translated">Cores do chat</target>
</trans-unit>
<trans-unit id="%lld group events" xml:space="preserve" approved="no">
<source>%lld group events</source>
<target state="translated">%lld eventos do grupo</target>
</trans-unit>
<trans-unit id="%lld messages moderated by %@" xml:space="preserve" approved="no">
<source>%lld messages moderated by %@</source>
<target state="translated">%lld mensagens moderadas por %@</target>
</trans-unit>
<trans-unit id="%@, %@" xml:space="preserve" approved="no">
<source>%1$@, %2$@</source>
<target state="translated">%1$@, %2$@</target>
</trans-unit>
<trans-unit id="%lld new interface languages" xml:space="preserve" approved="no">
<source>%lld new interface languages</source>
<target state="translated">%lld novos idiomas de interface</target>
</trans-unit>
<trans-unit id="Better networking" xml:space="preserve" approved="no">
<source>Better networking</source>
<target state="translated">Melhores redes</target>
</trans-unit>
<trans-unit id="Bulgarian, Finnish, Thai and Ukrainian - thanks to the users and [Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" xml:space="preserve" approved="no">
<source>Bulgarian, Finnish, Thai and Ukrainian - thanks to the users and [Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</source>
<target state="translated">Búlgaro, Finlandês, Tailandês e Ucraniano - obrigado aos usuários e [Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!</target>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve" approved="no">
<source>Better groups</source>
<target state="translated">Melhores grupos</target>
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve" approved="no">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target state="translated">Capacidade excedida - o destinatário não recebeu as mensagens enviadas anteriormente.</target>
</trans-unit>
</body>
</file>
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="pt-BR" datatype="plaintext">
@@ -163,22 +163,18 @@
</trans-unit>
<trans-unit id="%d file(s) are still being downloaded." xml:space="preserve">
<source>%d file(s) are still being downloaded.</source>
<target>%d файл(ов) загружаются.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) failed to download." xml:space="preserve">
<source>%d file(s) failed to download.</source>
<target>%d файл(ов) не удалось загрузить.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were deleted." xml:space="preserve">
<source>%d file(s) were deleted.</source>
<target>%d файлов было удалено.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d file(s) were not downloaded." xml:space="preserve">
<source>%d file(s) were not downloaded.</source>
<target>%d файлов не было загружено.</target>
<note>forward confirmation reason</note>
</trans-unit>
<trans-unit id="%d hours" xml:space="preserve">
@@ -188,7 +184,6 @@
</trans-unit>
<trans-unit id="%d messages not forwarded" xml:space="preserve">
<source>%d messages not forwarded</source>
<target>%d сообщений не переслано</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="%d min" xml:space="preserve">
@@ -752,7 +747,7 @@
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>Все профили</target>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -944,11 +939,6 @@
<target>Код доступа в приложение будет заменен кодом самоуничтожения.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<target>Сессия приложения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>Версия приложения</target>
@@ -1056,7 +1046,6 @@
</trans-unit>
<trans-unit id="Auto-accept settings" xml:space="preserve">
<source>Auto-accept settings</source>
<target>Настройки автоприема</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Back" xml:space="preserve">
@@ -1084,19 +1073,11 @@
<target>Ошибка хэш сообщения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>Улучшенные группы</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Улучшенные сообщения</target>
@@ -1107,18 +1088,6 @@
<target>Улучшенные сетевые функции</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Черная</target>
@@ -1402,14 +1371,8 @@
</trans-unit>
<trans-unit id="Chat preferences were changed." xml:space="preserve">
<source>Chat preferences were changed.</source>
<target>Настройки чата были изменены.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Профиль чата</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Тема чата</target>
@@ -1811,7 +1774,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Corner" xml:space="preserve">
<source>Corner</source>
<target>Угол</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Correct name to %@?" xml:space="preserve">
@@ -1939,10 +1901,6 @@ This is your own one-time link!</source>
<target>Пользовательское время</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Настроить тему</target>
@@ -2237,10 +2195,6 @@ This is your own one-time link!</source>
<target>Удалить предыдущую версию данных?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Удалить ожидаемое соединение?</target>
@@ -2493,7 +2447,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Do not use credentials with proxy." xml:space="preserve">
<source>Do not use credentials with proxy.</source>
<target>Не использовать учетные данные с прокси.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Don't create address" xml:space="preserve">
@@ -2539,7 +2492,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Download files" xml:space="preserve">
<source>Download files</source>
<target>Загрузить файлы</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Downloaded" xml:space="preserve">
@@ -2819,7 +2771,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Error changing connection profile" xml:space="preserve">
<source>Error changing connection profile</source>
<target>Ошибка при изменении профиля соединения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error changing role" xml:space="preserve">
@@ -2834,7 +2785,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Error changing to incognito!" xml:space="preserve">
<source>Error changing to incognito!</source>
<target>Ошибка при смене на Инкогнито!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error connecting to forwarding server %@. Please try later." xml:space="preserve">
@@ -2959,7 +2909,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Error migrating settings" xml:space="preserve">
<source>Error migrating settings</source>
<target>Ошибка миграции настроек</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error opening chat" xml:space="preserve">
@@ -3064,13 +3013,12 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Error switching profile" xml:space="preserve">
<source>Error switching profile</source>
<target>Ошибка переключения профиля</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Ошибка выбора профиля!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3115,7 +3063,8 @@ This is your own one-time link!</source>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Ошибка: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3205,8 +3154,6 @@ This is your own one-time link!</source>
<trans-unit id="File errors:&#10;%@" xml:space="preserve">
<source>File errors:
%@</source>
<target>Ошибки файлов:
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="File not found - most likely file was deleted or cancelled." xml:space="preserve">
@@ -3346,7 +3293,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Forward %d message(s)?" xml:space="preserve">
<source>Forward %d message(s)?</source>
<target>Переслать %d сообщение(й)?</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Forward and save messages" xml:space="preserve">
@@ -3356,18 +3302,12 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Forward messages" xml:space="preserve">
<source>Forward messages</source>
<target>Переслать сообщения</target>
<note>alert action</note>
</trans-unit>
<trans-unit id="Forward messages without files?" xml:space="preserve">
<source>Forward messages without files?</source>
<target>Переслать сообщения без файлов?</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Переслано</target>
@@ -3380,7 +3320,6 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Forwarding %lld messages" xml:space="preserve">
<source>Forwarding %lld messages</source>
<target>Пересылка %lld сообщений</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarding server %@ failed to connect to destination server %@. Please try later." xml:space="preserve">
@@ -3679,7 +3618,6 @@ Error: %2$@</source>
</trans-unit>
<trans-unit id="IP address" xml:space="preserve">
<source>IP address</source>
<target>IP адрес</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="If you can't meet in person, show QR code in a video call, or share the link." xml:space="preserve">
@@ -3757,11 +3695,6 @@ Error: %2$@</source>
<target>Импорт архива</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>Улучшенная доставка сообщений</target>
@@ -4334,7 +4267,6 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Message shape" xml:space="preserve">
<source>Message shape</source>
<target>Форма сообщений</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -4389,7 +4321,6 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Messages were deleted after you selected them." xml:space="preserve">
<source>Messages were deleted after you selected them.</source>
<target>Сообщения были удалены после того, как вы их выбрали.</target>
<note>alert message</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">
@@ -4547,16 +4478,6 @@ This is your link for group %@!</source>
<target>Новый Код</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<target>Новые учетные данные SOCKS будут использоваться при каждом запуске приложения.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<target>Новые учетные данные SOCKS будут использоваться для каждого сервера.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>Новый чат</target>
@@ -4677,16 +4598,6 @@ This is your link for group %@!</source>
<target>Нет интернет-соединения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<target>Нет разрешения на запись речи</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<target>Нет разрешения на запись видео</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Нет разрешения для записи голосового сообщения</target>
@@ -4709,7 +4620,6 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Nothing to forward!" xml:space="preserve">
<source>Nothing to forward!</source>
<target>Нет сообщений, которые можно переслать!</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Notifications" xml:space="preserve">
@@ -4938,8 +4848,6 @@ Requires compatible VPN.</source>
<trans-unit id="Other file errors:&#10;%@" xml:space="preserve">
<source>Other file errors:
%@</source>
<target>Другие ошибки файлов:
%@</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
@@ -4979,7 +4887,6 @@ Requires compatible VPN.</source>
</trans-unit>
<trans-unit id="Password" xml:space="preserve">
<source>Password</source>
<target>Пароль</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Password to show" xml:space="preserve">
@@ -5133,7 +5040,6 @@ Error: %@</source>
</trans-unit>
<trans-unit id="Port" xml:space="preserve">
<source>Port</source>
<target>Порт</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Possibly, certificate fingerprint in server address is incorrect" xml:space="preserve">
@@ -5325,7 +5231,6 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Proxy requires password" xml:space="preserve">
<source>Proxy requires password</source>
<target>Прокси требует пароль</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Push notifications" xml:space="preserve">
@@ -5551,7 +5456,6 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Remove archive?" xml:space="preserve">
<source>Remove archive?</source>
<target>Удалить архив?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Remove image" xml:space="preserve">
@@ -5736,7 +5640,6 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="SOCKS proxy" xml:space="preserve">
<source>SOCKS proxy</source>
<target>SOCKS прокси</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
@@ -5827,7 +5730,6 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Save your profile?" xml:space="preserve">
<source>Save your profile?</source>
<target>Сохранить ваш профиль?</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Saved" xml:space="preserve">
@@ -5852,7 +5754,6 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Saving %lld messages" xml:space="preserve">
<source>Saving %lld messages</source>
<target>Сохранение %lld сообщений</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scale" xml:space="preserve">
@@ -5937,7 +5838,6 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Select chat profile" xml:space="preserve">
<source>Select chat profile</source>
<target>Выберите профиль чата</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Selected %lld" xml:space="preserve">
@@ -6155,11 +6055,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>Отправлено через прокси</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<target>Сервер</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>Адрес сервера</target>
@@ -6282,7 +6177,6 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Settings were changed." xml:space="preserve">
<source>Settings were changed.</source>
<target>Настройки были изменены.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Shape profile images" xml:space="preserve">
@@ -6322,7 +6216,6 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Share profile" xml:space="preserve">
<source>Share profile</source>
<target>Поделиться профилем</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share this 1-time invite link" xml:space="preserve">
@@ -6460,10 +6353,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>SimpleX одноразовая ссылка</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Упрощенный режим Инкогнито</target>
@@ -6496,7 +6385,6 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Some app settings were not migrated." xml:space="preserve">
<source>Some app settings were not migrated.</source>
<target>Некоторые настройки приложения не были перенесены.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Some file(s) were not exported:" xml:space="preserve">
@@ -6639,14 +6527,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>Поддержать SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>Системная</target>
@@ -6684,7 +6564,6 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Tail" xml:space="preserve">
<source>Tail</source>
<target>Хвост</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Take picture" xml:space="preserve">
@@ -6881,7 +6760,6 @@ It can happen because of some bug or when the connection is compromised.</source
</trans-unit>
<trans-unit id="The uploaded database archive will be permanently removed from the servers." xml:space="preserve">
<source>The uploaded database archive will be permanently removed from the servers.</source>
<target>Загруженный архив базы данных будет навсегда удален с серверов.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Themes" xml:space="preserve">
@@ -7011,16 +6889,6 @@ You will be prompted to complete authentication before this feature is enabled.<
Вам будет нужно пройти аутентификацию для включения блокировки.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<target>Для записи речи, пожалуйста, дайте разрешение на использование микрофона.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<target>Для записи видео, пожалуйста, дайте разрешение на использование камеры.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>Для записи голосового сообщения, пожалуйста разрешите доступ к микрофону.</target>
@@ -7290,7 +7158,6 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="Use SOCKS proxy" xml:space="preserve">
<source>Use SOCKS proxy</source>
<target>Использовать SOCKS прокси</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use SimpleX Chat servers?" xml:space="preserve">
@@ -7358,6 +7225,11 @@ To connect, please ask your contact to create another connection link and check
<target>Используйте приложение одной рукой.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Профиль чата</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Выбор пользователя</target>
@@ -7365,7 +7237,6 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="Username" xml:space="preserve">
<source>Username</source>
<target>Имя пользователя</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Using SimpleX Chat servers." xml:space="preserve">
@@ -7628,6 +7499,11 @@ To connect, please ask your contact to create another connection link and check
<target>XFTP сервер</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Вы</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>Вы **не должны** использовать одну и ту же базу данных на двух устройствах.</target>
@@ -7979,7 +7855,6 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your chat preferences" xml:space="preserve">
<source>Your chat preferences</source>
<target>Ваши настройки чата</target>
<note>alert title</note>
</trans-unit>
<trans-unit id="Your chat profiles" xml:space="preserve">
@@ -7989,7 +7864,6 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile." xml:space="preserve">
<source>Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile.</source>
<target>Соединение было перемещено на %@, но при смене профиля произошла неожиданная ошибка.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contact sent a file that is larger than currently supported maximum size (%@)." xml:space="preserve">
@@ -8009,7 +7883,6 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your credentials may be sent unencrypted." xml:space="preserve">
<source>Your credentials may be sent unencrypted.</source>
<target>Ваши учетные данные могут быть отправлены в незашифрованном виде.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your current chat database will be DELETED and REPLACED with the imported one." xml:space="preserve">
@@ -8049,7 +7922,6 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your profile was changed. If you save it, the updated profile will be sent to all your contacts." xml:space="preserve">
<source>Your profile was changed. If you save it, the updated profile will be sent to all your contacts.</source>
<target>Ваш профиль был изменен. Если вы сохраните его, обновленный профиль будет отправлен всем вашим контактам.</target>
<note>alert message</note>
</trans-unit>
<trans-unit id="Your profile, contacts and delivered messages are stored on your device." xml:space="preserve">
@@ -702,7 +702,7 @@
</trans-unit>
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -884,10 +884,6 @@
<target>รหัสผ่านแอปจะถูกแทนที่ด้วยรหัสผ่านที่ทำลายตัวเอง</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>เวอร์ชันแอป</target>
@@ -1014,18 +1010,10 @@
<target>แฮชข้อความไม่ดี</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>ข้อความที่ดีขึ้น</target>
@@ -1035,18 +1023,6 @@
<source>Better networking</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<note>No comment provided by engineer.</note>
@@ -1307,11 +1283,6 @@
<source>Chat preferences were changed.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>โปรไฟล์ผู้ใช้</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<note>No comment provided by engineer.</note>
@@ -1785,10 +1756,6 @@ This is your own one-time link!</source>
<target>เวลาที่กําหนดเอง</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<note>No comment provided by engineer.</note>
@@ -2075,10 +2042,6 @@ This is your own one-time link!</source>
<target>ลบฐานข้อมูลเก่า?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>ลบการเชื่อมต่อที่รอดำเนินการหรือไม่?</target>
@@ -2848,7 +2811,7 @@ This is your own one-time link!</source>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>เกิดข้อผิดพลาดในการเปลี่ยนโปรไฟล์!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -2891,7 +2854,8 @@ This is your own one-time link!</source>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>ข้อผิดพลาด: % @</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3119,10 +3083,6 @@ This is your own one-time link!</source>
<source>Forward messages without files?</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
@@ -3489,11 +3449,6 @@ Error: %2$@</source>
<source>Importing archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<note>No comment provided by engineer.</note>
@@ -4219,14 +4174,6 @@ This is your link for group %@!</source>
<target>รหัสผ่านใหม่</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<note>No comment provided by engineer.</note>
@@ -4339,14 +4286,6 @@ This is your link for group %@!</source>
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>ไม่อนุญาตให้บันทึกข้อความเสียง</target>
@@ -5702,10 +5641,6 @@ Enable in *Network &amp; servers* settings.</source>
<source>Sent via proxy</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<note>No comment provided by engineer.</note>
@@ -5981,10 +5916,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>คำเชิญ SimpleX แบบครั้งเดียว</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<note>No comment provided by engineer.</note>
@@ -6143,14 +6074,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>สนับสนุน SimpleX แชท</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>ระบบ</target>
@@ -6491,14 +6414,6 @@ You will be prompted to complete authentication before this feature is enabled.<
คุณจะได้รับแจ้งให้ยืนยันตัวตนให้เสร็จสมบูรณ์ก่อนที่จะเปิดใช้งานคุณลักษณะนี้</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>ในการบันทึกข้อความเสียง โปรดให้สิทธิ์ในการใช้ไมโครโฟน</target>
@@ -6806,6 +6721,11 @@ To connect, please ask your contact to create another connection link and check
<source>Use the app with one hand.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>โปรไฟล์ผู้ใช้</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<note>No comment provided by engineer.</note>
@@ -7050,6 +6970,11 @@ To connect, please ask your contact to create another connection link and check
<source>XFTP server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>คุณ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<note>No comment provided by engineer.</note>
File diff suppressed because it is too large Load Diff
@@ -747,7 +747,7 @@
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>Всі профілі</target>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -939,10 +939,6 @@
<target>Пароль програми замінено на пароль самознищення.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>Версія програми</target>
@@ -1077,19 +1073,11 @@
<target>Поганий хеш повідомлення</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>Кращі групи</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>Кращі повідомлення</target>
@@ -1100,18 +1088,6 @@
<target>Краща мережа</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>Чорний</target>
@@ -1397,11 +1373,6 @@
<source>Chat preferences were changed.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>Профіль користувача</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>Тема чату</target>
@@ -1930,10 +1901,6 @@ This is your own one-time link!</source>
<target>Індивідуальний час</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>Налаштувати тему</target>
@@ -2228,10 +2195,6 @@ This is your own one-time link!</source>
<target>Видалити стару базу даних?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>Видалити очікуване з'єднання?</target>
@@ -3055,7 +3018,7 @@ This is your own one-time link!</source>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>Помилка перемикання профілю!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3100,7 +3063,8 @@ This is your own one-time link!</source>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>Помилка: %@</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3344,10 +3308,6 @@ This is your own one-time link!</source>
<source>Forward messages without files?</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Переслано</target>
@@ -3735,11 +3695,6 @@ Error: %2$@</source>
<target>Імпорт архіву</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>Покращена доставка повідомлень</target>
@@ -4523,14 +4478,6 @@ This is your link for group %@!</source>
<target>Новий пароль</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>Новий чат</target>
@@ -4651,14 +4598,6 @@ This is your link for group %@!</source>
<target>Немає підключення до мережі</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>Немає дозволу на запис голосового повідомлення</target>
@@ -6116,10 +6055,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>Відправлено через проксі</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>Адреса сервера</target>
@@ -6418,10 +6353,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>Одноразове запрошення SimpleX</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>Спрощений режим інкогніто</target>
@@ -6596,14 +6527,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>Підтримка чату SimpleX</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>Система</target>
@@ -6966,14 +6889,6 @@ You will be prompted to complete authentication before this feature is enabled.<
Перед увімкненням цієї функції вам буде запропоновано пройти автентифікацію.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>Щоб записати голосове повідомлення, будь ласка, надайте дозвіл на використання мікрофону.</target>
@@ -7310,6 +7225,11 @@ To connect, please ask your contact to create another connection link and check
<target>Використовуйте додаток однією рукою.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>Профіль користувача</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>Вибір користувача</target>
@@ -7579,6 +7499,11 @@ To connect, please ask your contact to create another connection link and check
<target>XFTP-сервер</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Ти</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>Ви **не повинні використовувати** одну і ту ж базу даних на двох пристроях.</target>
@@ -747,7 +747,7 @@
<trans-unit id="All profiles" xml:space="preserve">
<source>All profiles</source>
<target>所有配置文件</target>
<note>profile dropdown</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
<source>All your contacts will remain connected.</source>
@@ -939,10 +939,6 @@
<target>应用程序密码被替换为自毁密码。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App session" xml:space="preserve">
<source>App session</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App version" xml:space="preserve">
<source>App version</source>
<target>应用程序版本</target>
@@ -1077,19 +1073,11 @@
<target>错误消息散列</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better calls" xml:space="preserve">
<source>Better calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better groups" xml:space="preserve">
<source>Better groups</source>
<target>更佳的群组</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better message dates." xml:space="preserve">
<source>Better message dates.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better messages" xml:space="preserve">
<source>Better messages</source>
<target>更好的消息</target>
@@ -1100,18 +1088,6 @@
<target>更好的网络</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better notifications" xml:space="preserve">
<source>Better notifications</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better security ✅" xml:space="preserve">
<source>Better security ✅</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Better user experience" xml:space="preserve">
<source>Better user experience</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Black" xml:space="preserve">
<source>Black</source>
<target>黑色</target>
@@ -1397,11 +1373,6 @@
<source>Chat preferences were changed.</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Chat profile" xml:space="preserve">
<source>Chat profile</source>
<target>用户资料</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat theme" xml:space="preserve">
<source>Chat theme</source>
<target>聊天主题</target>
@@ -1930,10 +1901,6 @@ This is your own one-time link!</source>
<target>自定义时间</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customizable message shape." xml:space="preserve">
<source>Customizable message shape.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Customize theme" xml:space="preserve">
<source>Customize theme</source>
<target>自定义主题</target>
@@ -2228,10 +2195,6 @@ This is your own one-time link!</source>
<target>删除旧数据库吗?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete or moderate up to 200 messages." xml:space="preserve">
<source>Delete or moderate up to 200 messages.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete pending connection?" xml:space="preserve">
<source>Delete pending connection?</source>
<target>删除待定连接?</target>
@@ -3055,7 +3018,7 @@ This is your own one-time link!</source>
<trans-unit id="Error switching profile!" xml:space="preserve">
<source>Error switching profile!</source>
<target>切换资料错误!</target>
<note>alertTitle</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error synchronizing connection" xml:space="preserve">
<source>Error synchronizing connection</source>
@@ -3100,7 +3063,8 @@ This is your own one-time link!</source>
<trans-unit id="Error: %@" xml:space="preserve">
<source>Error: %@</source>
<target>错误: @</target>
<note>alert message</note>
<note>file error text
snd error text</note>
</trans-unit>
<trans-unit id="Error: URL is invalid" xml:space="preserve">
<source>Error: URL is invalid</source>
@@ -3344,10 +3308,6 @@ This is your own one-time link!</source>
<source>Forward messages without files?</source>
<note>alert message</note>
</trans-unit>
<trans-unit id="Forward up to 20 messages at once." xml:space="preserve">
<source>Forward up to 20 messages at once.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>已转发</target>
@@ -3735,11 +3695,6 @@ Error: %2$@</source>
<target>正在导入存档</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved delivery, reduced traffic usage.&#10;More improvements are coming soon!" xml:space="preserve">
<source>Improved delivery, reduced traffic usage.
More improvements are coming soon!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source>
<target>改进了消息传递</target>
@@ -4523,14 +4478,6 @@ This is your link for group %@!</source>
<target>新密码</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used every time you start the app." xml:space="preserve">
<source>New SOCKS credentials will be used every time you start the app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New SOCKS credentials will be used for each server." xml:space="preserve">
<source>New SOCKS credentials will be used for each server.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="New chat" xml:space="preserve">
<source>New chat</source>
<target>新聊天</target>
@@ -4651,14 +4598,6 @@ This is your link for group %@!</source>
<target>无网络连接</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record speech" xml:space="preserve">
<source>No permission to record speech</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record video" xml:space="preserve">
<source>No permission to record video</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source>
<target>没有录制语音消息的权限</target>
@@ -6116,10 +6055,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>通过代理发送</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Server address" xml:space="preserve">
<source>Server address</source>
<target>服务器地址</target>
@@ -6418,10 +6353,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>SimpleX 一次性邀请</target>
<note>simplex link type</note>
</trans-unit>
<trans-unit id="SimpleX protocols reviewed by Trail of Bits." xml:space="preserve">
<source>SimpleX protocols reviewed by Trail of Bits.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Simplified incognito mode" xml:space="preserve">
<source>Simplified incognito mode</source>
<target>简化的隐身模式</target>
@@ -6596,14 +6527,6 @@ Enable in *Network &amp; servers* settings.</source>
<target>支持 SimpleX Chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch audio and video during the call." xml:space="preserve">
<source>Switch audio and video during the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Switch chat profile for 1-time invitations." xml:space="preserve">
<source>Switch chat profile for 1-time invitations.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="System" xml:space="preserve">
<source>System</source>
<target>系统</target>
@@ -6966,14 +6889,6 @@ You will be prompted to complete authentication before this feature is enabled.<
在启用此功能之前,系统将提示您完成身份验证。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record speech please grant permission to use Microphone." xml:space="preserve">
<source>To record speech please grant permission to use Microphone.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record video please grant permission to use Camera." xml:space="preserve">
<source>To record video please grant permission to use Camera.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To record voice message please grant permission to use Microphone." xml:space="preserve">
<source>To record voice message please grant permission to use Microphone.</source>
<target>请授权使用麦克风以录制语音消息。</target>
@@ -7310,6 +7225,11 @@ To connect, please ask your contact to create another connection link and check
<target>用一只手使用应用程序。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve">
<source>User profile</source>
<target>用户资料</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User selection" xml:space="preserve">
<source>User selection</source>
<target>用户选择</target>
@@ -7579,6 +7499,11 @@ To connect, please ask your contact to create another connection link and check
<target>XFTP 服务器</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>您</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<target>您 **不得** 在两台设备上使用相同的数据库。</target>
+14 -46
View File
@@ -26,7 +26,7 @@ enum NSENotification {
case nse(UNMutableNotificationContent)
case callkit(RcvCallInvitation)
case empty
case msgInfo(NtfMsgAckInfo)
case msgInfo(NtfMsgInfo)
var isCallInvitation: Bool {
switch self {
@@ -119,9 +119,7 @@ class NotificationService: UNNotificationServiceExtension {
var threadId: UUID? = NSEThreads.shared.newThread()
var notificationInfo: NtfMessages?
var receiveEntityId: String?
var receiveConnId: String?
var expectedMessage: String?
var allowedGetNextAttempts: Int = 3
// return true if the message is taken - it prevents sending it to another NotificationService instance for processing
var shouldProcessNtf = false
var appSubscriber: AppSubscriber?
@@ -193,21 +191,17 @@ 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.receivedMsg_ == nil ? 0 : 1))")
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfInfo.ntfMessage_ == nil ? 0 : 1))")
if let connEntity = ntfInfo.connEntity_ {
setBestAttemptNtf(
ntfInfo.ntfsEnabled
? .nse(createConnectionEventNtf(ntfInfo.user, connEntity))
: .empty
)
if let id = connEntity.id, ntfInfo.expectedMsg_ != nil {
if let id = connEntity.id, ntfInfo.msgTs != nil {
notificationInfo = ntfInfo
receiveEntityId = id
receiveConnId = connEntity.conn.agentConnId
let expectedMsgId = ntfInfo.expectedMsg_?.msgId
let receivedMsgId = ntfInfo.receivedMsg_?.msgId
logger.debug("NotificationService: receiveNtfMessages: expectedMsgId = \(expectedMsgId ?? "nil", privacy: .private), receivedMsgId = \(receivedMsgId ?? "nil", privacy: .private)")
expectedMessage = expectedMsgId
expectedMessage = ntfInfo.ntfMessage_.flatMap { $0.msgId }
shouldProcessNtf = true
return
}
@@ -225,34 +219,22 @@ class NotificationService: UNNotificationServiceExtension {
}
func processReceivedNtf(_ ntf: NSENotification) -> Bool {
guard let ntfInfo = notificationInfo, let expectedMsgTs = ntfInfo.expectedMsg_?.msgTs else { return false }
guard let ntfInfo = notificationInfo, let msgTs = ntfInfo.msgTs else { return false }
if !ntfInfo.user.showNotifications {
self.setBestAttemptNtf(.empty)
}
if case let .msgInfo(info) = ntf {
if info.msgId == expectedMessage {
expectedMessage = nil
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): expected")
logger.debug("NotificationService processNtf: msgInfo")
self.deliverBestAttemptNtf()
return true
} else if let msgTs = info.msgTs_, msgTs > expectedMsgTs {
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): unexpected msgInfo, let other instance to process it, stopping this one")
} else if info.msgTs > msgTs {
logger.debug("NotificationService processNtf: unexpected msgInfo, let other instance to process it, stopping this one")
self.deliverBestAttemptNtf()
return false
} else if allowedGetNextAttempts > 0, let receiveConnId = receiveConnId {
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): unexpected msgInfo, get next message")
allowedGetNextAttempts -= 1
if let receivedMsg = apiGetConnNtfMessage(connId: receiveConnId) {
logger.debug("NotificationService processNtf, on apiGetConnNtfMessage: msgInfo msgId = \(info.msgId, privacy: .private), receivedMsg msgId = \(receivedMsg.msgId, privacy: .private)")
return true
} else {
logger.debug("NotificationService processNtf, on apiGetConnNtfMessage: msgInfo msgId = \(info.msgId, privacy: .private): no next message, deliver best attempt")
self.deliverBestAttemptNtf()
return false
}
} else {
logger.debug("NotificationService processNtf: msgInfo msgId = \(info.msgId, privacy: .private): unknown message, let other instance to process it")
self.deliverBestAttemptNtf()
logger.debug("NotificationService processNtf: unknown message, let other instance to process it")
return false
}
} else if ntfInfo.user.showNotifications {
@@ -710,9 +692,9 @@ func apiGetNtfMessage(nonce: String, encNtfInfo: String) -> NtfMessages? {
return nil
}
let r = sendSimpleXCmd(.apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo))
if case let .ntfMessages(user, connEntity_, expectedMsg_, receivedMsg_) = r, let user = user {
logger.debug("apiGetNtfMessage response ntfMessages: \(receivedMsg_ == nil ? 0 : 1)")
return NtfMessages(user: user, connEntity_: connEntity_, expectedMsg_: expectedMsg_, receivedMsg_: receivedMsg_)
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 {
@@ -721,20 +703,6 @@ func apiGetNtfMessage(nonce: String, encNtfInfo: String) -> NtfMessages? {
return nil
}
func apiGetConnNtfMessage(connId: String) -> NtfMsgInfo? {
guard apiGetActiveUser() != nil else {
logger.debug("no active user")
return nil
}
let r = sendSimpleXCmd(.apiGetConnNtfMessage(connId: connId))
if case let .connNtfMessage(receivedMsg_) = r {
logger.debug("apiGetConnNtfMessage response receivedMsg_: \(receivedMsg_ == nil ? 0 : 1)")
return receivedMsg_
}
logger.debug("apiGetConnNtfMessage error: \(responseError(r))")
return nil
}
func apiReceiveFile(fileId: Int64, encrypted: Bool, inline: Bool? = nil) -> AChatItem? {
let userApprovedRelays = !privacyAskToApproveRelaysGroupDefault.get()
let r = sendSimpleXCmd(.receiveFile(fileId: fileId, userApprovedRelays: userApprovedRelays, encrypted: encrypted, inline: inline))
@@ -772,8 +740,8 @@ func setNetworkConfig(_ cfg: NetCfg) throws {
struct NtfMessages {
var user: User
var connEntity_: ConnectionEntity?
var expectedMsg_: NtfMsgInfo?
var receivedMsg_: NtfMsgInfo?
var msgTs: Date?
var ntfMessage_: NtfMsgInfo?
var ntfsEnabled: Bool {
user.showNotifications && (connEntity_?.ntfsEnabled ?? false)
+3 -3
View File
@@ -417,7 +417,7 @@ fileprivate func getSharedContent(_ ip: NSItemProvider) async -> Result<SharedCo
let data = try? Data(contentsOf: url),
let image = UIImage(data: data),
let cryptoFile = saveFile(data, generateNewFileName("IMG", "gif"), encrypted: privacyEncryptLocalFilesGroupDefault.get()),
let preview = await resizeImageToStrSize(image, maxDataSize: MAX_DATA_SIZE) {
let preview = resizeImageToStrSize(image, maxDataSize: MAX_DATA_SIZE) {
.success(.image(preview: preview, cryptoFile: cryptoFile))
} else { .failure(ErrorAlert("Error preparing message")) }
@@ -425,7 +425,7 @@ fileprivate func getSharedContent(_ ip: NSItemProvider) async -> Result<SharedCo
} else {
if let image = await staticImage(),
let cryptoFile = saveImage(image),
let preview = await resizeImageToStrSize(image, maxDataSize: MAX_DATA_SIZE) {
let preview = resizeImageToStrSize(image, maxDataSize: MAX_DATA_SIZE) {
.success(.image(preview: preview, cryptoFile: cryptoFile))
} else { .failure(ErrorAlert("Error preparing message")) }
}
@@ -435,7 +435,7 @@ fileprivate func getSharedContent(_ ip: NSItemProvider) async -> Result<SharedCo
if let url = try? await inPlaceUrl(type: type),
let trancodedUrl = await transcodeVideo(from: url),
let (image, duration) = AVAsset(url: trancodedUrl).generatePreview(),
let preview = await resizeImageToStrSize(image, maxDataSize: MAX_DATA_SIZE),
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))
@@ -29,7 +29,7 @@
"Database error" = "Error en base de datos";
/* No comment provided by engineer. */
"Database passphrase is different from saved in the keychain." = "La contraseña de la base de datos es diferente a la almacenada en keychain.";
"Database passphrase is different from saved in the keychain." = "La contraseña de la base de datos es distinta a la almacenada en keychain.";
/* No comment provided by engineer. */
"Database passphrase is required to open chat." = "Se requiere la contraseña de la base de datos para abrir la aplicación.";
@@ -26,13 +26,13 @@
"Database encrypted!" = "Adatbázis titkosítva!";
/* No comment provided by engineer. */
"Database error" = "Adatbázishiba";
"Database error" = "Adatbázis hiba";
/* No comment provided by engineer. */
"Database passphrase is different from saved in the keychain." = "Az adatbázis jelmondata eltér a kulcstartóban lévőtől.";
/* No comment provided by engineer. */
"Database passphrase is required to open chat." = "Adatbázis-jelmondat szükséges a csevegés megnyitásához.";
"Database passphrase is required to open chat." = "Adatbázis jelmondat szükséges a csevegés megnyitásához.";
/* No comment provided by engineer. */
"Database upgrade required" = "Adatbázis fejlesztése szükséges";
@@ -50,13 +50,13 @@
"File error" = "Fájlhiba";
/* No comment provided by engineer. */
"Incompatible database version" = "Nem kompatibilis adatbázis-verzió";
"Incompatible database version" = "Nem kompatibilis adatbázis verzió";
/* No comment provided by engineer. */
"Invalid migration confirmation" = "Érvénytelen átköltöztetési visszaigazolás";
/* No comment provided by engineer. */
"Keychain error" = "Kulcstartóhiba";
"Keychain error" = "Kulcstartó hiba";
/* No comment provided by engineer. */
"Large file!" = "Nagy fájl!";
@@ -95,7 +95,7 @@
"Slow network?" = "Lassú internetkapcsolat?";
/* No comment provided by engineer. */
"Unknown database error: %@" = "Ismeretlen adatbázishiba: %@";
"Unknown database error: %@" = "Ismeretlen adatbázis hiba: %@";
/* No comment provided by engineer. */
"Unsupported format" = "Nem támogatott formátum";
@@ -104,7 +104,7 @@
"Wait" = "Várjon";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Hibás adatbázis-jelmondat";
"Wrong database passphrase" = "Hibás adatbázis jelmondat";
/* No comment provided by engineer. */
"You can allow sharing in Privacy & Security / SimpleX Lock settings." = "A megosztást az Adatvédelem és biztonság / SimpleX-zár menüben engedélyezheti.";
@@ -1,9 +1,7 @@
/* Bundle display name */
"CFBundleDisplayName" = "SimpleX SE";
/* Bundle name */
"CFBundleName" = "SimpleX SE";
/* Copyright (human-readable) */
"NSHumanReadableCopyright" = "Telif Hakkı © 2024 SimpleX Chat. Tüm hakları saklıdır.";
/*
InfoPlist.strings
SimpleX
Created by EP on 30/07/2024.
Copyright © 2024 SimpleX Chat. All rights reserved.
*/
@@ -1,111 +1,7 @@
/* No comment provided by engineer. */
"%@" = "%@";
/* No comment provided by engineer. */
"App is locked!" = "Uygulama kilitlendi!";
/* No comment provided by engineer. */
"Cancel" = "İptal et";
/* No comment provided by engineer. */
"Cannot access keychain to save database password" = "Veritabanı şifresini kaydetmek için Anahtar Zinciri'ne erişilemiyor";
/* No comment provided by engineer. */
"Cannot forward message" = "Mesaj iletilemiyor";
/* No comment provided by engineer. */
"Comment" = "Yorum";
/* No comment provided by engineer. */
"Currently maximum supported file size is %@." = "Şu anki maksimum desteklenen dosya boyutu %@ kadardır.";
/* No comment provided by engineer. */
"Database downgrade required" = "Veritabanı sürüm düşürme gerekli";
/* No comment provided by engineer. */
"Database encrypted!" = "Veritabanı şifrelendi!";
/* No comment provided by engineer. */
"Database error" = "Veritabanı hatası";
/* No comment provided by engineer. */
"Database passphrase is different from saved in the keychain." = "Veritabanı parolası Anahtar Zinciri'nde kayıtlı olandan farklıdır.";
/* No comment provided by engineer. */
"Database passphrase is required to open chat." = "Konuşmayı açmak için veri tabanı parolası gerekli.";
/* No comment provided by engineer. */
"Database upgrade required" = "Veritabanı yükseltmesi gerekli";
/* No comment provided by engineer. */
"Error preparing file" = "Dosya hazırlanırken hata oluştu";
/* No comment provided by engineer. */
"Error preparing message" = "Mesaj hazırlanırken hata oluştu";
/* No comment provided by engineer. */
"Error: %@" = "Hata: %@";
/* No comment provided by engineer. */
"File error" = "Dosya hatası";
/* No comment provided by engineer. */
"Incompatible database version" = "Uyumsuz veritabanı sürümü";
/* No comment provided by engineer. */
"Invalid migration confirmation" = "Geçerli olmayan taşıma onayı";
/* No comment provided by engineer. */
"Keychain error" = "Anahtarlık hatası";
/* No comment provided by engineer. */
"Large file!" = "Büyük dosya!";
/* No comment provided by engineer. */
"No active profile" = "Aktif profil yok";
/* No comment provided by engineer. */
"Ok" = "Tamam";
/* No comment provided by engineer. */
"Open the app to downgrade the database." = "Veritabanının sürümünü düşürmek için uygulamayı açın.";
/* No comment provided by engineer. */
"Open the app to upgrade the database." = "Veritabanını güncellemek için uygulamayı açın.";
/* No comment provided by engineer. */
"Passphrase" = "Parola";
/* No comment provided by engineer. */
"Please create a profile in the SimpleX app" = "Lütfen SimpleX uygulamasında bir profil oluşturun";
/* No comment provided by engineer. */
"Selected chat preferences prohibit this message." = "Seçilen sohbet tercihleri bu mesajı yasakladı.";
/* No comment provided by engineer. */
"Sending a message takes longer than expected." = "Mesaj göndermek beklenenden daha uzun sürüyor.";
/* No comment provided by engineer. */
"Sending message…" = "Mesaj gönderiliyor…";
/* No comment provided by engineer. */
"Share" = "Paylaş";
/* No comment provided by engineer. */
"Slow network?" = "Ağ yavaş mı?";
/* No comment provided by engineer. */
"Unknown database error: %@" = "Bilinmeyen veritabanı hatası: %@";
/* No comment provided by engineer. */
"Unsupported format" = "Desteklenmeyen format";
/* No comment provided by engineer. */
"Wait" = "Bekleyin";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Yanlış veritabanı parolası";
/* No comment provided by engineer. */
"You can allow sharing in Privacy & Security / SimpleX Lock settings." = "Gizlilik ve Güvenlik / SimpleX Lock ayarlarından paylaşıma izin verebilirsiniz.";
/*
Localizable.strings
SimpleX
Created by EP on 30/07/2024.
Copyright © 2024 SimpleX Chat. All rights reserved.
*/
+30 -30
View File
@@ -144,11 +144,6 @@
5CFE0922282EEAF60002594B /* ZoomableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */; };
640417CD2B29B8C200CCB412 /* NewChatMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640417CB2B29B8C200CCB412 /* NewChatMenuButton.swift */; };
640417CE2B29B8C200CCB412 /* NewChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640417CC2B29B8C200CCB412 /* NewChatView.swift */; };
640548A32CB56735005DE1E4 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6405489E2CB56735005DE1E4 /* libgmpxx.a */; };
640548A42CB56735005DE1E4 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6405489F2CB56735005DE1E4 /* libgmp.a */; };
640548A52CB56735005DE1E4 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 640548A02CB56735005DE1E4 /* libffi.a */; };
640548A62CB56735005DE1E4 /* libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 640548A12CB56735005DE1E4 /* libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv-ghc9.6.3.a */; };
640548A72CB56735005DE1E4 /* libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 640548A22CB56735005DE1E4 /* libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv.a */; };
6407BA83295DA85D0082BA18 /* CIInvalidJSONView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */; };
6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */; };
6419EC582AB97507004A607A /* CIMemberCreatedContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */; };
@@ -223,6 +218,11 @@
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 */; };
E51B923B2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */; };
E51B923C2CAB2B8800C212F2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92372CAB2B8800C212F2 /* libgmp.a */; };
E51B923D2CAB2B8800C212F2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92382CAB2B8800C212F2 /* libffi.a */; };
E51B923E2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */; };
E51B923F2CAB2B8800C212F2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B923A2CAB2B8800C212F2 /* libgmpxx.a */; };
E51CC1E62C62085600DB91FE /* OneHandUICard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51CC1E52C62085600DB91FE /* OneHandUICard.swift */; };
E5DCF8DB2C56FAC1007928CC /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; };
E5DCF9712C590272007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF96F2C590272007928CC /* Localizable.strings */; };
@@ -486,11 +486,6 @@
5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ZoomableScrollView.swift; path = Shared/Views/ZoomableScrollView.swift; sourceTree = SOURCE_ROOT; };
640417CB2B29B8C200CCB412 /* NewChatMenuButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewChatMenuButton.swift; sourceTree = "<group>"; };
640417CC2B29B8C200CCB412 /* NewChatView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewChatView.swift; sourceTree = "<group>"; };
6405489E2CB56735005DE1E4 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
6405489F2CB56735005DE1E4 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
640548A02CB56735005DE1E4 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
640548A12CB56735005DE1E4 /* libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv-ghc9.6.3.a"; sourceTree = "<group>"; };
640548A22CB56735005DE1E4 /* libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv.a"; sourceTree = "<group>"; };
6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIInvalidJSONView.swift; sourceTree = "<group>"; };
6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextInvitingContactMemberView.swift; sourceTree = "<group>"; };
6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMemberCreatedContactView.swift; sourceTree = "<group>"; };
@@ -564,6 +559,11 @@
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; };
E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a"; sourceTree = "<group>"; };
E51B92372CAB2B8800C212F2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
E51B92382CAB2B8800C212F2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a"; sourceTree = "<group>"; };
E51B923A2CAB2B8800C212F2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
E51CC1E52C62085600DB91FE /* OneHandUICard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OneHandUICard.swift; sourceTree = "<group>"; };
E5DCF9702C590272007928CC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
E5DCF9722C590274007928CC /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -655,14 +655,14 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
640548A32CB56735005DE1E4 /* libgmpxx.a in Frameworks */,
640548A72CB56735005DE1E4 /* libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv.a in Frameworks */,
640548A52CB56735005DE1E4 /* libffi.a in Frameworks */,
640548A42CB56735005DE1E4 /* libgmp.a in Frameworks */,
E51B923B2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a in Frameworks */,
E51B923D2CAB2B8800C212F2 /* libffi.a in Frameworks */,
E51B923C2CAB2B8800C212F2 /* libgmp.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
640548A62CB56735005DE1E4 /* libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv-ghc9.6.3.a in Frameworks */,
E51B923F2CAB2B8800C212F2 /* libgmpxx.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
E51B923E2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -739,11 +739,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
640548A02CB56735005DE1E4 /* libffi.a */,
6405489F2CB56735005DE1E4 /* libgmp.a */,
6405489E2CB56735005DE1E4 /* libgmpxx.a */,
640548A12CB56735005DE1E4 /* libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv-ghc9.6.3.a */,
640548A22CB56735005DE1E4 /* libHSsimplex-chat-6.1.0.7-EtclnBf7vnkLnhnDA1lixv.a */,
E51B92382CAB2B8800C212F2 /* libffi.a */,
E51B92372CAB2B8800C212F2 /* libgmp.a */,
E51B923A2CAB2B8800C212F2 /* libgmpxx.a */,
E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */,
E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -1899,7 +1899,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 242;
CURRENT_PROJECT_VERSION = 241;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1948,7 +1948,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 242;
CURRENT_PROJECT_VERSION = 241;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1989,7 +1989,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 242;
CURRENT_PROJECT_VERSION = 241;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@@ -2009,7 +2009,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 242;
CURRENT_PROJECT_VERSION = 241;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@@ -2034,7 +2034,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 242;
CURRENT_PROJECT_VERSION = 241;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
@@ -2071,7 +2071,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 242;
CURRENT_PROJECT_VERSION = 241;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
@@ -2108,7 +2108,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 242;
CURRENT_PROJECT_VERSION = 241;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -2159,7 +2159,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 242;
CURRENT_PROJECT_VERSION = 241;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -2210,7 +2210,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 242;
CURRENT_PROJECT_VERSION = 241;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -2244,7 +2244,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 242;
CURRENT_PROJECT_VERSION = 241;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
+6 -22
View File
@@ -56,7 +56,6 @@ public enum ChatCommand {
case apiVerifyToken(token: DeviceToken, nonce: String, code: String)
case apiDeleteToken(token: DeviceToken)
case apiGetNtfMessage(nonce: String, encNtfInfo: String)
case apiGetConnNtfMessage(connId: String)
case apiNewGroup(userId: Int64, incognito: Bool, groupProfile: GroupProfile)
case apiAddMember(groupId: Int64, contactId: Int64, memberRole: GroupMemberRole)
case apiJoinGroup(groupId: Int64)
@@ -215,7 +214,6 @@ public enum ChatCommand {
case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)"
case let .apiDeleteToken(token): return "/_ntf delete \(token.cmdString)"
case let .apiGetNtfMessage(nonce, encNtfInfo): return "/_ntf message \(nonce) \(encNtfInfo)"
case let .apiGetConnNtfMessage(connId): return "/_ntf conn message \(connId)"
case let .apiNewGroup(userId, incognito, groupProfile): return "/_group \(userId) incognito=\(onOff(incognito)) \(encodeJSON(groupProfile))"
case let .apiAddMember(groupId, contactId, memberRole): return "/_add #\(groupId) \(contactId) \(memberRole)"
case let .apiJoinGroup(groupId): return "/_join #\(groupId)"
@@ -370,7 +368,6 @@ public enum ChatCommand {
case .apiVerifyToken: return "apiVerifyToken"
case .apiDeleteToken: return "apiDeleteToken"
case .apiGetNtfMessage: return "apiGetNtfMessage"
case .apiGetConnNtfMessage: return "apiGetConnNtfMessage"
case .apiNewGroup: return "apiNewGroup"
case .apiAddMember: return "apiAddMember"
case .apiJoinGroup: return "apiJoinGroup"
@@ -682,9 +679,8 @@ 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?, expectedMsg_: NtfMsgInfo?, receivedMsg_: NtfMsgInfo?)
case connNtfMessage(receivedMsg_: NtfMsgInfo?)
case ntfMessage(user: UserRef, connEntity: ConnectionEntity, ntfMessage: NtfMsgAckInfo)
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)
// remote desktop responses/events
@@ -852,7 +848,6 @@ public enum ChatResponse: Decodable, Error {
case .ntfTokenStatus: return "ntfTokenStatus"
case .ntfToken: return "ntfToken"
case .ntfMessages: return "ntfMessages"
case .connNtfMessage: return "connNtfMessage"
case .ntfMessage: return "ntfMessage"
case .contactConnectionDeleted: return "contactConnectionDeleted"
case .contactDisabled: return "contactDisabled"
@@ -1029,8 +1024,7 @@ public enum ChatResponse: Decodable, Error {
case let .callInvitations(invs): return String(describing: invs)
case let .ntfTokenStatus(status): return String(describing: status)
case let .ntfToken(token, status, ntfMode, ntfServer): return "token: \(token)\nstatus: \(status.rawValue)\nntfMode: \(ntfMode.rawValue)\nntfServer: \(ntfServer)"
case let .ntfMessages(u, connEntity, expectedMsg_, receivedMsg_): return withUser(u, "connEntity: \(String(describing: connEntity))\nexpectedMsg_: \(String(describing: expectedMsg_))\nreceivedMsg_: \(String(describing: receivedMsg_))")
case let .connNtfMessage(receivedMsg_): return "receivedMsg_: \(String(describing: receivedMsg_))"
case let .ntfMessages(u, connEntity, msgTs, ntfMessages): return withUser(u, "connEntity: \(String(describing: connEntity))\nmsgTs: \(String(describing: msgTs))\nntfMessages: \(String(describing: ntfMessages))")
case let .ntfMessage(u, connEntity, ntfMessage): return withUser(u, "connEntity: \(String(describing: connEntity))\nntfMessage: \(String(describing: ntfMessage))")
case let .contactConnectionDeleted(u, connection): return withUser(u, String(describing: connection))
case let .contactDisabled(u, contact): return withUser(u, String(describing: contact))
@@ -1359,7 +1353,7 @@ public struct NetCfg: Codable, Equatable {
public var sessionMode = TransportSessionMode.user
public var smpProxyMode: SMPProxyMode = .unknown
public var smpProxyFallback: SMPProxyFallback = .allowProtected
public var smpWebPort = false
var smpWebPort = false
public var tcpConnectTimeout: Int // microseconds
public var tcpTimeout: Int // microseconds
public var tcpTimeoutPerKb: Int // microseconds
@@ -1491,22 +1485,18 @@ public enum OnionHosts: String, Identifiable {
public enum TransportSessionMode: String, Codable, Identifiable {
case user
case session
case server
case entity
public var text: LocalizedStringKey {
switch self {
case .user: return "Chat profile"
case .session: return "App session"
case .server: return "Server"
case .user: return "User profile"
case .entity: return "Connection"
}
}
public var id: TransportSessionMode { self }
public static let values: [TransportSessionMode] = [.user, .session, .server, .entity]
public static let values: [TransportSessionMode] = [.user, .entity]
}
public struct KeepAliveOpts: Codable, Equatable {
@@ -2261,8 +2251,6 @@ public struct AppSettings: Codable, Equatable {
public var iosCallKitEnabled: Bool? = nil
public var iosCallKitCallsInRecents: Bool? = nil
public var uiProfileImageCornerRadius: Double? = nil
public var uiChatItemRoundness: Double? = nil
public var uiChatItemTail: Bool? = nil
public var uiColorScheme: String? = nil
public var uiDarkColorScheme: String? = nil
public var uiCurrentThemeIds: [String: String]? = nil
@@ -2295,8 +2283,6 @@ public struct AppSettings: Codable, Equatable {
if iosCallKitEnabled != def.iosCallKitEnabled { empty.iosCallKitEnabled = iosCallKitEnabled }
if iosCallKitCallsInRecents != def.iosCallKitCallsInRecents { empty.iosCallKitCallsInRecents = iosCallKitCallsInRecents }
if uiProfileImageCornerRadius != def.uiProfileImageCornerRadius { empty.uiProfileImageCornerRadius = uiProfileImageCornerRadius }
if uiChatItemRoundness != def.uiChatItemRoundness { empty.uiChatItemRoundness = uiChatItemRoundness }
if uiChatItemTail != def.uiChatItemTail { empty.uiChatItemTail = uiChatItemTail }
if uiColorScheme != def.uiColorScheme { empty.uiColorScheme = uiColorScheme }
if uiDarkColorScheme != def.uiDarkColorScheme { empty.uiDarkColorScheme = uiDarkColorScheme }
if uiCurrentThemeIds != def.uiCurrentThemeIds { empty.uiCurrentThemeIds = uiCurrentThemeIds }
@@ -2330,8 +2316,6 @@ public struct AppSettings: Codable, Equatable {
iosCallKitEnabled: true,
iosCallKitCallsInRecents: false,
uiProfileImageCornerRadius: 22.5,
uiChatItemRoundness: 0.75,
uiChatItemTail: true,
uiColorScheme: DefaultTheme.SYSTEM_THEME_NAME,
uiDarkColorScheme: DefaultTheme.SIMPLEX.themeName,
uiCurrentThemeIds: nil as [String: String]?,
+2 -3
View File
@@ -67,7 +67,7 @@ public func registerGroupDefaults() {
GROUP_DEFAULT_NTF_ENABLE_LOCAL: false,
GROUP_DEFAULT_NTF_ENABLE_PERIODIC: false,
GROUP_DEFAULT_NETWORK_USE_ONION_HOSTS: OnionHosts.no.rawValue,
GROUP_DEFAULT_NETWORK_SESSION_MODE: TransportSessionMode.session.rawValue,
GROUP_DEFAULT_NETWORK_SESSION_MODE: TransportSessionMode.user.rawValue,
GROUP_DEFAULT_NETWORK_SMP_PROXY_MODE: SMPProxyMode.unknown.rawValue,
GROUP_DEFAULT_NETWORK_SMP_PROXY_FALLBACK: SMPProxyFallback.allowProtected.rawValue,
GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT: NetCfg.defaults.tcpConnectTimeout,
@@ -232,7 +232,7 @@ public let networkUseOnionHostsGroupDefault = EnumDefault<OnionHosts>(
public let networkSessionModeGroupDefault = EnumDefault<TransportSessionMode>(
defaults: groupDefaults,
forKey: GROUP_DEFAULT_NETWORK_SESSION_MODE,
withDefault: .session
withDefault: .user
)
public let networkSMPProxyModeGroupDefault = EnumDefault<SMPProxyMode>(
@@ -357,7 +357,6 @@ public func getNetCfg() -> NetCfg {
sessionMode: sessionMode,
smpProxyMode: smpProxyMode,
smpProxyFallback: smpProxyFallback,
smpWebPort: false,
tcpConnectTimeout: tcpConnectTimeout,
tcpTimeout: tcpTimeout,
tcpTimeoutPerKb: tcpTimeoutPerKb,
-8
View File
@@ -80,14 +80,6 @@ public enum CallMediaType: String, Codable, Equatable {
case audio = "audio"
}
public enum CallMediaSource: String, Codable, Equatable {
case mic = "mic"
case camera = "camera"
case screenAudio = "screenAudio"
case screenVideo = "screenVideo"
case unknown = "unknown"
}
public enum VideoCamera: String, Codable, Equatable {
case user = "user"
case environment = "environment"
+11 -26
View File
@@ -2240,42 +2240,32 @@ public struct MemberSubError: Decodable, Hashable {
}
public enum ConnectionEntity: Decodable, Hashable {
case rcvDirectMsgConnection(entityConnection: Connection, contact: Contact?)
case rcvGroupMsgConnection(entityConnection: Connection, groupInfo: GroupInfo, groupMember: GroupMember)
case sndFileConnection(entityConnection: Connection, sndFileTransfer: SndFileTransfer)
case rcvFileConnection(entityConnection: Connection, rcvFileTransfer: RcvFileTransfer)
case userContactConnection(entityConnection: Connection, userContact: UserContact)
case rcvDirectMsgConnection(contact: Contact?)
case rcvGroupMsgConnection(groupInfo: GroupInfo, groupMember: GroupMember)
case sndFileConnection(sndFileTransfer: SndFileTransfer)
case rcvFileConnection(rcvFileTransfer: RcvFileTransfer)
case userContactConnection(userContact: UserContact)
public var id: String? {
switch self {
case let .rcvDirectMsgConnection(_, contact):
case let .rcvDirectMsgConnection(contact):
return contact?.id
case let .rcvGroupMsgConnection(_, _, groupMember):
case let .rcvGroupMsgConnection(_, groupMember):
return groupMember.id
case let .userContactConnection(_, userContact):
case let .userContactConnection(userContact):
return userContact.id
default:
return nil
}
}
public var conn: Connection {
switch self {
case let .rcvDirectMsgConnection(entityConnection, _): entityConnection
case let .rcvGroupMsgConnection(entityConnection, _, _): entityConnection
case let .sndFileConnection(entityConnection, _): entityConnection
case let .rcvFileConnection(entityConnection, _): entityConnection
case let .userContactConnection(entityConnection, _): entityConnection
}
}
public var ntfsEnabled: Bool {
switch self {
case let .rcvDirectMsgConnection(_, contact): return contact?.chatSettings.enableNtfs == .all
case let .rcvGroupMsgConnection(_, groupInfo, _): return groupInfo.chatSettings.enableNtfs == .all
case let .rcvDirectMsgConnection(contact): return contact?.chatSettings.enableNtfs == .all
case let .rcvGroupMsgConnection(groupInfo, _): return groupInfo.chatSettings.enableNtfs == .all
case .sndFileConnection: return false
case .rcvFileConnection: return false
case let .userContactConnection(_, userContact): return userContact.groupId == nil
case let .userContactConnection(userContact): return userContact.groupId == nil
}
}
}
@@ -2285,11 +2275,6 @@ public struct NtfMsgInfo: Decodable, Hashable {
public var msgTs: Date
}
public struct NtfMsgAckInfo: Decodable, Hashable {
public var msgId: String
public var msgTs_: Date?
}
public struct ChatItemDeletion: Decodable, Hashable {
public var deletedChatItem: AChatItem
public var toChatItem: AChatItem? = nil
+2 -10
View File
@@ -100,7 +100,7 @@ public func resizeImageToDataSize(_ image: UIImage, maxDataSize: Int64, hasAlpha
return data
}
public func resizeImageToStrSizeSync(_ image: UIImage, maxDataSize: Int64) -> String? {
public func resizeImageToStrSize(_ image: UIImage, maxDataSize: Int64) -> String? {
var img = image
let hasAlpha = imageHasAlpha(image)
var str = compressImageStr(img, hasAlpha: hasAlpha)
@@ -116,15 +116,7 @@ public func resizeImageToStrSizeSync(_ image: UIImage, maxDataSize: Int64) -> St
return str
}
public func resizeImageToStrSize(_ image: UIImage, maxDataSize: Int64) async -> String? {
resizeImageToStrSizeSync(image, maxDataSize: maxDataSize)
}
public func compressImageStr(_ image: UIImage, _ compressionQuality: CGFloat = 0.85, hasAlpha: Bool) -> String? {
// // Heavy workload to verify if UI gets blocked by the call
// for i in 0..<100 {
// print(image.jpegData(compressionQuality: Double(i) / 100)?.count ?? 0, terminator: ", ")
// }
let ext = hasAlpha ? "png" : "jpg"
if let data = hasAlpha ? image.pngData() : image.jpegData(compressionQuality: compressionQuality) {
return "data:image/\(ext);base64,\(data.base64EncodedString())"
@@ -434,7 +426,7 @@ public func getLinkPreview(url: URL, cb: @escaping (LinkPreview?) -> Void) {
logger.error("Couldn't load image preview from link metadata with error: \(error.localizedDescription)")
} else {
if let image = object as? UIImage,
let resized = resizeImageToStrSizeSync(image, maxDataSize: 14000),
let resized = resizeImageToStrSize(image, maxDataSize: 14000),
let title = metadata.title,
let uri = metadata.originalURL {
linkPreview = LinkPreview(uri: uri, title: title, image: resized)
+2 -2
View File
@@ -94,7 +94,7 @@ public func createConnectionEventNtf(_ user: User, _ connEntity: ConnectionEntit
var body: String? = nil
var targetContentIdentifier: String? = nil
switch connEntity {
case let .rcvDirectMsgConnection(_, contact):
case let .rcvDirectMsgConnection(contact):
if let contact = contact {
title = hideContent ? contactHidden : "\(contact.chatViewName):"
targetContentIdentifier = contact.id
@@ -102,7 +102,7 @@ public func createConnectionEventNtf(_ user: User, _ connEntity: ConnectionEntit
title = NSLocalizedString("New contact:", comment: "notification")
}
body = NSLocalizedString("message received", comment: "notification")
case let .rcvGroupMsgConnection(_, groupInfo, groupMember):
case let .rcvGroupMsgConnection(groupInfo, groupMember):
title = groupMsgNtfTitle(groupInfo, groupMember, hideContent: hideContent)
body = NSLocalizedString("message received", comment: "notification")
targetContentIdentifier = groupInfo.id
+9 -5
View File
@@ -791,9 +791,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "Чат настройки";
/* No comment provided by engineer. */
"Chat profile" = "Потребителски профил";
/* No comment provided by engineer. */
"Chats" = "Чатове";
@@ -1735,7 +1732,7 @@
/* No comment provided by engineer. */
"Error stopping chat" = "Грешка при спиране на чата";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "Грешка при смяна на профил!";
/* No comment provided by engineer. */
@@ -1762,7 +1759,8 @@
/* No comment provided by engineer. */
"Error: " = "Грешка: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Грешка: %@";
/* No comment provided by engineer. */
@@ -3992,6 +3990,9 @@
/* No comment provided by engineer. */
"Use the app while in the call." = "Използвайте приложението по време на разговора.";
/* No comment provided by engineer. */
"User profile" = "Потребителски профил";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "Използват се сървърите на SimpleX Chat.";
@@ -4166,6 +4167,9 @@
/* No comment provided by engineer. */
"you" = "вие";
/* No comment provided by engineer. */
"You" = "Вие";
/* No comment provided by engineer. */
"You **must not** use the same database on two devices." = "**Не трябва** да използвате една и съща база данни на две устройства.";
+9 -5
View File
@@ -644,9 +644,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "Předvolby chatu";
/* No comment provided by engineer. */
"Chat profile" = "Profil uživatele";
/* No comment provided by engineer. */
"Chats" = "Chaty";
@@ -1425,7 +1422,7 @@
/* No comment provided by engineer. */
"Error stopping chat" = "Chyba při zastavení chatu";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "Chyba při přepínání profilu!";
/* No comment provided by engineer. */
@@ -1446,7 +1443,8 @@
/* No comment provided by engineer. */
"Error: " = "Chyba: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Chyba: %@";
/* No comment provided by engineer. */
@@ -3232,6 +3230,9 @@
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "Používat servery SimpleX Chat?";
/* No comment provided by engineer. */
"User profile" = "Profil uživatele";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "Používat servery SimpleX Chat.";
@@ -3349,6 +3350,9 @@
/* pref value */
"yes" = "ano";
/* No comment provided by engineer. */
"You" = "Vy";
/* No comment provided by engineer. */
"You accepted connection" = "Přijali jste spojení";
+13 -105
View File
@@ -175,24 +175,9 @@
/* time interval */
"%d days" = "%d Tage";
/* forward confirmation reason */
"%d file(s) are still being downloaded." = "%d Datei(en) wird/werden immer noch heruntergeladen.";
/* forward confirmation reason */
"%d file(s) failed to download." = "Bei %d Datei(en) ist das Herunterladen fehlgeschlagen.";
/* forward confirmation reason */
"%d file(s) were deleted." = "%d Datei(en) wurde(n) gelöscht.";
/* forward confirmation reason */
"%d file(s) were not downloaded." = "%d Datei(en) wurde(n) nicht heruntergeladen.";
/* time interval */
"%d hours" = "%d Stunden";
/* alert title */
"%d messages not forwarded" = "%d Nachrichten wurden nicht weitergeleitet";
/* time interval */
"%d min" = "%d min";
@@ -472,7 +457,7 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Von %@ werden alle neuen Nachrichten ausgeblendet!";
/* profile dropdown */
/* No comment provided by engineer. */
"All profiles" = "Alle Profile";
/* No comment provided by engineer. */
@@ -595,9 +580,6 @@
/* No comment provided by engineer. */
"App passcode is replaced with self-destruct passcode." = "App-Zugangscode wurde durch den Selbstzerstörungs-Zugangscode ersetzt.";
/* No comment provided by engineer. */
"App session" = "App-Sitzung";
/* No comment provided by engineer. */
"App version" = "App Version";
@@ -917,9 +899,6 @@
/* alert message */
"Chat preferences were changed." = "Die Chat-Präferenzen wurden geändert.";
/* No comment provided by engineer. */
"Chat profile" = "Benutzerprofil";
/* No comment provided by engineer. */
"Chat theme" = "Chat-Design";
@@ -1209,7 +1188,7 @@
"Core version: v%@" = "Core Version: v%@";
/* No comment provided by engineer. */
"Corner" = "Abrundung Ecken";
"Corner" = "Ecke";
/* No comment provided by engineer. */
"Correct name to %@?" = "Richtiger Name für %@?";
@@ -1644,9 +1623,6 @@
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "Nachrichten werden nicht direkt versendet, selbst wenn Ihr oder der Zielserver kein privates Routing unterstützt.";
/* No comment provided by engineer. */
"Do not use credentials with proxy." = "Verwenden Sie keine Anmeldeinformationen mit einem Proxy.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "Sie nutzen KEIN privates Routing.";
@@ -1678,9 +1654,6 @@
/* server test step */
"Download file" = "Datei herunterladen";
/* alert action */
"Download files" = "Dateien herunterladen";
/* No comment provided by engineer. */
"Downloaded" = "Heruntergeladen";
@@ -2047,7 +2020,7 @@
/* No comment provided by engineer. */
"Error switching profile" = "Fehler beim Wechseln des Profils";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "Fehler beim Umschalten des Profils!";
/* No comment provided by engineer. */
@@ -2074,7 +2047,8 @@
/* No comment provided by engineer. */
"Error: " = "Fehler: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Fehler: %@";
/* No comment provided by engineer. */
@@ -2099,7 +2073,7 @@
"Expand" = "Erweitern";
/* No comment provided by engineer. */
"expired" = "Abgelaufen";
"expired" = "abgelaufen";
/* No comment provided by engineer. */
"Export database" = "Datenbank exportieren";
@@ -2134,9 +2108,6 @@
/* No comment provided by engineer. */
"File error" = "Datei-Fehler";
/* alert message */
"File errors:\n%@" = "Datei-Fehler:\n%@";
/* file error text */
"File not found - most likely file was deleted or cancelled." = "Datei nicht gefunden - höchstwahrscheinlich wurde die Datei gelöscht oder der Transfer abgebrochen.";
@@ -2218,18 +2189,9 @@
/* chat item action */
"Forward" = "Weiterleiten";
/* alert title */
"Forward %d message(s)?" = "%d Nachricht(en) weiterleiten?";
/* No comment provided by engineer. */
"Forward and save messages" = "Nachrichten weiterleiten und speichern";
/* alert action */
"Forward messages" = "Nachrichten weiterleiten";
/* alert message */
"Forward messages without files?" = "Nachrichten ohne Dateien weiterleiten?";
/* No comment provided by engineer. */
"forwarded" = "weitergeleitet";
@@ -2239,9 +2201,6 @@
/* No comment provided by engineer. */
"Forwarded from" = "Weitergeleitet aus";
/* No comment provided by engineer. */
"Forwarding %lld messages" = "%lld Nachricht(en) wird/werden weitergeleitet";
/* No comment provided by engineer. */
"Forwarding server %@ failed to connect to destination server %@. Please try later." = "Weiterleitungsserver %@ konnte sich nicht mit dem Zielserver %@ verbinden. Bitte versuchen Sie es später erneut.";
@@ -2629,9 +2588,6 @@
/* No comment provided by engineer. */
"iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications." = "Für die sichere Speicherung des Passworts nach dem Neustart der App und dem Wechsel des Passworts wird der iOS Schlüsselbund verwendet - dies erlaubt den Empfang von Push-Benachrichtigungen.";
/* No comment provided by engineer. */
"IP address" = "IP-Adresse";
/* No comment provided by engineer. */
"Irreversible message deletion" = "Unwiederbringliches löschen einer Nachricht";
@@ -2917,9 +2873,6 @@
/* No comment provided by engineer. */
"Messages sent" = "Gesendete Nachrichten";
/* alert message */
"Messages were deleted after you selected them." = "Die Nachrichten wurden gelöscht, nachdem Sie sie ausgewählt hatten.";
/* 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." = "Nachrichten, Dateien und Anrufe sind durch **Ende-zu-Ende-Verschlüsselung** mit Perfect Forward Secrecy, Ablehnung und Einbruchs-Wiederherstellung geschützt.";
@@ -3073,12 +3026,6 @@
/* No comment provided by engineer. */
"New passphrase…" = "Neues Passwort…";
/* No comment provided by engineer. */
"New SOCKS credentials will be used every time you start the app." = "Jedes Mal wenn Sie die App starten, werden neue SOCKS-Anmeldeinformationen genutzt";
/* No comment provided by engineer. */
"New SOCKS credentials will be used for each server." = "Für jeden Server werden neue SOCKS-Anmeldeinformationen genutzt";
/* pref value */
"no" = "Nein";
@@ -3121,12 +3068,6 @@
/* No comment provided by engineer. */
"No network connection" = "Keine Netzwerkverbindung";
/* No comment provided by engineer. */
"No permission to record speech" = "Keine Genehmigung für Sprach-Aufnahmen";
/* No comment provided by engineer. */
"No permission to record video" = "Keine Genehmigung für Video-Aufnahmen";
/* No comment provided by engineer. */
"No permission to record voice message" = "Keine Berechtigung für das Aufnehmen von Sprachnachrichten";
@@ -3142,9 +3083,6 @@
/* No comment provided by engineer. */
"Nothing selected" = "Nichts ausgewählt";
/* alert title */
"Nothing to forward!" = "Es gibt nichts zum Weiterleiten!";
/* No comment provided by engineer. */
"Notifications" = "Benachrichtigungen";
@@ -3286,7 +3224,7 @@
"Or show this code" = "Oder diesen QR-Code anzeigen";
/* No comment provided by engineer. */
"other" = "Andere";
"other" = "andere";
/* No comment provided by engineer. */
"Other" = "Andere";
@@ -3297,9 +3235,6 @@
/* No comment provided by engineer. */
"other errors" = "Andere Fehler";
/* alert message */
"Other file errors:\n%@" = "Andere(r) Datei-Fehler:\n%@";
/* member role */
"owner" = "Eigentümer";
@@ -3321,9 +3256,6 @@
/* No comment provided by engineer. */
"Passcode set!" = "Zugangscode eingestellt!";
/* No comment provided by engineer. */
"Password" = "Passwort";
/* No comment provided by engineer. */
"Password to show" = "Passwort anzeigen";
@@ -3420,9 +3352,6 @@
/* No comment provided by engineer. */
"Polish interface" = "Polnische Bedienoberfläche";
/* No comment provided by engineer. */
"Port" = "Port";
/* server test error */
"Possibly, certificate fingerprint in server address is incorrect" = "Der Fingerabdruck des Zertifikats in der Serveradresse ist wahrscheinlich ungültig";
@@ -3534,9 +3463,6 @@
/* No comment provided by engineer. */
"Proxied servers" = "Proxy-Server";
/* No comment provided by engineer. */
"Proxy requires password" = "Der Proxy benötigt ein Passwort";
/* No comment provided by engineer. */
"Push notifications" = "Push-Benachrichtigungen";
@@ -3878,9 +3804,6 @@
/* No comment provided by engineer. */
"Saved WebRTC ICE servers will be removed" = "Gespeicherte WebRTC ICE-Server werden entfernt";
/* No comment provided by engineer. */
"Saving %lld messages" = "Es wird/werden %lld Nachricht(en) gesichert";
/* No comment provided by engineer. */
"Scale" = "Skalieren";
@@ -4079,9 +4002,6 @@
/* No comment provided by engineer. */
"Sent via proxy" = "Über einen Proxy gesendet";
/* No comment provided by engineer. */
"Server" = "Server";
/* No comment provided by engineer. */
"Server address" = "Server-Adresse";
@@ -4289,9 +4209,6 @@
/* No comment provided by engineer. */
"SMP server" = "SMP-Server";
/* No comment provided by engineer. */
"SOCKS proxy" = "SOCKS-Proxy";
/* blur media */
"Soft" = "Weich";
@@ -4398,7 +4315,7 @@
"System authentication" = "System-Authentifizierung";
/* No comment provided by engineer. */
"Tail" = "Sprechblasen-Format";
"Tail" = "Sprechblase";
/* No comment provided by engineer. */
"Take picture" = "Machen Sie ein Foto";
@@ -4610,12 +4527,6 @@
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Zum Schutz Ihrer IP-Adresse, wird für die Nachrichten-Auslieferung privates Routing über Ihre konfigurierten SMP-Server genutzt.";
/* No comment provided by engineer. */
"To record speech please grant permission to use Microphone." = "Bitte erteilen Sie für Sprach-Aufnahmen die Genehmigung das Mikrofon zu nutzen.";
/* No comment provided by engineer. */
"To record video please grant permission to use Camera." = "Bitte erteilen Sie für Video-Aufnahmen die Genehmigung die Kamera zu nutzen.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Bitte erlauben Sie die Nutzung des Mikrofons, um Sprachnachrichten aufnehmen zu können.";
@@ -4832,9 +4743,6 @@
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "Verwenden Sie SimpleX-Chat-Server?";
/* No comment provided by engineer. */
"Use SOCKS proxy" = "SOCKS-Proxy nutzen";
/* No comment provided by engineer. */
"Use the app while in the call." = "Die App kann während eines Anrufs genutzt werden.";
@@ -4842,10 +4750,10 @@
"Use the app with one hand." = "Die App mit einer Hand bedienen.";
/* No comment provided by engineer. */
"User selection" = "Benutzer-Auswahl";
"User profile" = "Benutzerprofil";
/* No comment provided by engineer. */
"Username" = "Benutzername";
"User selection" = "Benutzer-Auswahl";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "Verwendung von SimpleX-Chat-Servern.";
@@ -5048,6 +4956,9 @@
/* No comment provided by engineer. */
"you" = "Profil";
/* No comment provided by engineer. */
"You" = "Profil";
/* No comment provided by engineer. */
"You **must not** use the same database on two devices." = "Sie dürfen die selbe Datenbank **nicht** auf zwei Geräten nutzen.";
@@ -5300,9 +5211,6 @@
/* No comment provided by engineer. */
"Your contacts will remain connected." = "Ihre Kontakte bleiben weiterhin verbunden.";
/* No comment provided by engineer. */
"Your credentials may be sent unencrypted." = "Ihre Anmeldeinformationen können unverschlüsselt versendet werden.";
/* No comment provided by engineer. */
"Your current chat database will be DELETED and REPLACED with the imported one." = "Ihre aktuelle Chat-Datenbank wird GELÖSCHT und durch die Importierte ERSETZT.";
+25 -177
View File
@@ -160,9 +160,6 @@
/* notification title */
"%@ wants to connect!" = "¡ %@ quiere contactar!";
/* format for date separator in chat */
"%@, %@" = "%1$@, %2$@";
/* No comment provided by engineer. */
"%@, %@ and %lld members" = "%@, %@ y %lld miembro(s) más";
@@ -175,24 +172,9 @@
/* time interval */
"%d days" = "%d días";
/* forward confirmation reason */
"%d file(s) are still being downloaded." = "%d archivo(s) se está(n) descargando todavía.";
/* forward confirmation reason */
"%d file(s) failed to download." = "La descarga ha fallado para %d archivo(s).";
/* forward confirmation reason */
"%d file(s) were deleted." = "%d archivo(s) ha(n) sido eliminado(s).";
/* forward confirmation reason */
"%d file(s) were not downloaded." = "%d archivo(s) no se ha(n) descargado.";
/* time interval */
"%d hours" = "%d horas";
/* alert title */
"%d messages not forwarded" = "%d mensajes no enviados";
/* time interval */
"%d min" = "%d minutos";
@@ -323,7 +305,7 @@
"A new contact" = "Contacto nuevo";
/* No comment provided by engineer. */
"A new random profile will be shared." = "Compartirás un perfil nuevo aleatorio.";
"A new random profile will be shared." = "Se compartirá un perfil nuevo aleatorio.";
/* No comment provided by engineer. */
"A separate TCP connection will be used **for each chat profile you have in the app**." = "Se usará una conexión TCP independiente **por cada perfil que tengas en la aplicación**.";
@@ -472,7 +454,7 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "¡Los mensajes nuevos de %@ estarán ocultos!";
/* profile dropdown */
/* No comment provided by engineer. */
"All profiles" = "Todos los perfiles";
/* No comment provided by engineer. */
@@ -595,9 +577,6 @@
/* No comment provided by engineer. */
"App passcode is replaced with self-destruct passcode." = "El código de acceso será reemplazado por código de autodestrucción.";
/* No comment provided by engineer. */
"App session" = "Sesión de aplicación";
/* No comment provided by engineer. */
"App version" = "Versión de la aplicación";
@@ -670,9 +649,6 @@
/* No comment provided by engineer. */
"Auto-accept images" = "Aceptar imágenes automáticamente";
/* alert title */
"Auto-accept settings" = "Auto aceptar configuración";
/* No comment provided by engineer. */
"Back" = "Volver";
@@ -914,12 +890,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "Preferencias de Chat";
/* alert message */
"Chat preferences were changed." = "Las preferencias del chat han sido modificadas.";
/* No comment provided by engineer. */
"Chat profile" = "Perfil de usuario";
/* No comment provided by engineer. */
"Chat theme" = "Tema de chat";
@@ -1017,7 +987,7 @@
"Confirm password" = "Confirmar contraseña";
/* No comment provided by engineer. */
"Confirm that you remember database passphrase to migrate it." = "Para migrar la base de datos confirma que recuerdas la frase de contraseña.";
"Confirm that you remember database passphrase to migrate it." = "Para migrar confirma que recuerdas la frase de contraseña de la base de datos.";
/* No comment provided by engineer. */
"Confirm upload" = "Confirmar subida";
@@ -1208,9 +1178,6 @@
/* No comment provided by engineer. */
"Core version: v%@" = "Versión Core: v%@";
/* No comment provided by engineer. */
"Corner" = "Esquina";
/* No comment provided by engineer. */
"Correct name to %@?" = "¿Corregir el nombre a %@?";
@@ -1338,7 +1305,7 @@
"Database passphrase & export" = "Base de datos y contraseña";
/* No comment provided by engineer. */
"Database passphrase is different from saved in the keychain." = "La contraseña es diferente a la almacenada en Keychain.";
"Database passphrase is different from saved in the keychain." = "La contraseña es distinta a la almacenada en Keychain.";
/* No comment provided by engineer. */
"Database passphrase is required to open chat." = "Para abrir la aplicación se requiere la contraseña de la base de datos.";
@@ -1627,7 +1594,7 @@
"Disconnect" = "Desconectar";
/* No comment provided by engineer. */
"Disconnect desktop?" = "¿Desconectar del ordenador?";
"Disconnect desktop?" = "¿Desconectar ordenador?";
/* No comment provided by engineer. */
"Discover and join groups" = "Descubre y únete a grupos";
@@ -1644,9 +1611,6 @@
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "NO enviar mensajes directamente incluso si tu servidor o el de destino no soportan enrutamiento privado.";
/* No comment provided by engineer. */
"Do not use credentials with proxy." = "No uses credenciales con proxy.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "NO usar enrutamiento privado.";
@@ -1660,7 +1624,7 @@
"Don't enable" = "No activar";
/* No comment provided by engineer. */
"Don't show again" = "No volver a mostrar";
"Don't show again" = "No mostrar de nuevo";
/* No comment provided by engineer. */
"Downgrade and open chat" = "Degradar y abrir Chat";
@@ -1678,9 +1642,6 @@
/* server test step */
"Download file" = "Descargar archivo";
/* alert action */
"Download files" = "Descargar archivos";
/* No comment provided by engineer. */
"Downloaded" = "Descargado";
@@ -1897,18 +1858,12 @@
/* No comment provided by engineer. */
"Error changing address" = "Error al cambiar servidor";
/* No comment provided by engineer. */
"Error changing connection profile" = "Error al cambiar el perfil de conexión";
/* No comment provided by engineer. */
"Error changing role" = "Error al cambiar rol";
/* No comment provided by engineer. */
"Error changing setting" = "Error cambiando configuración";
/* No comment provided by engineer. */
"Error changing to incognito!" = "¡Error al cambiar a incógnito!";
/* No comment provided by engineer. */
"Error connecting to forwarding server %@. Please try later." = "Error al conectar con el servidor de reenvío %@. Por favor, inténtalo más tarde.";
@@ -1981,9 +1936,6 @@
/* No comment provided by engineer. */
"Error loading %@ servers" = "Error al cargar servidores %@";
/* No comment provided by engineer. */
"Error migrating settings" = "Error al migrar la configuración";
/* No comment provided by engineer. */
"Error opening chat" = "Error al abrir chat";
@@ -2045,9 +1997,6 @@
"Error stopping chat" = "Error al parar SimpleX";
/* No comment provided by engineer. */
"Error switching profile" = "Error al cambiar perfil";
/* alertTitle */
"Error switching profile!" = "¡Error al cambiar perfil!";
/* No comment provided by engineer. */
@@ -2074,7 +2023,8 @@
/* No comment provided by engineer. */
"Error: " = "Error: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Error: %@";
/* No comment provided by engineer. */
@@ -2134,9 +2084,6 @@
/* No comment provided by engineer. */
"File error" = "Error de archivo";
/* alert message */
"File errors:\n%@" = "Error(es) de archivo\n%@";
/* file error text */
"File not found - most likely file was deleted or cancelled." = "Archivo no encontrado, probablemente haya sido borrado o cancelado.";
@@ -2218,18 +2165,9 @@
/* chat item action */
"Forward" = "Reenviar";
/* alert title */
"Forward %d message(s)?" = "¿Reenviar %d mensaje(s)?";
/* No comment provided by engineer. */
"Forward and save messages" = "Reenviar y guardar mensajes";
/* alert action */
"Forward messages" = "Reenviar mensajes";
/* alert message */
"Forward messages without files?" = "¿Reenviar mensajes sin los archivos?";
/* No comment provided by engineer. */
"forwarded" = "reenviado";
@@ -2239,9 +2177,6 @@
/* No comment provided by engineer. */
"Forwarded from" = "Reenviado por";
/* No comment provided by engineer. */
"Forwarding %lld messages" = "Reenviando %lld mensajes";
/* No comment provided by engineer. */
"Forwarding server %@ failed to connect to destination server %@. Please try later." = "El servidor de reenvío %@ no ha podido conectarse al servidor de destino %@. Por favor, intentalo más tarde.";
@@ -2270,10 +2205,10 @@
"Full name (optional)" = "Nombre completo (opcional)";
/* No comment provided by engineer. */
"Fully decentralized visible only to members." = "Totalmente descentralizado. Visible sólo para los miembros.";
"Fully decentralized visible only to members." = "Completamente descentralizado y sólo visible para los miembros.";
/* No comment provided by engineer. */
"Fully re-implemented - work in background!" = "Totalmente revisado. ¡Funciona en segundo plano!";
"Fully re-implemented - work in background!" = "Completamente reimplementado: ¡funciona en segundo plano!";
/* No comment provided by engineer. */
"Further reduced battery usage" = "Reducción consumo de batería";
@@ -2629,9 +2564,6 @@
/* No comment provided by engineer. */
"iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications." = "iOS Keychain se usará para almacenar la contraseña de forma segura después de reiniciar la aplicación o cambiar la contraseña. Esto permitirá recibir notificaciones automáticas.";
/* No comment provided by engineer. */
"IP address" = "Dirección IP";
/* No comment provided by engineer. */
"Irreversible message deletion" = "Eliminación irreversible del mensaje";
@@ -2765,7 +2697,7 @@
"Local name" = "Nombre local";
/* No comment provided by engineer. */
"Local profile data only" = "Eliminar sólo el perfil";
"Local profile data only" = "Sólo datos del perfil local";
/* No comment provided by engineer. */
"Lock after" = "Bloquear en";
@@ -2884,9 +2816,6 @@
/* No comment provided by engineer. */
"Message servers" = "Servidores de mensajes";
/* No comment provided by engineer. */
"Message shape" = "Forma del mensaje";
/* No comment provided by engineer. */
"Message source remains private." = "El autor del mensaje se mantiene privado.";
@@ -2917,9 +2846,6 @@
/* No comment provided by engineer. */
"Messages sent" = "Mensajes enviados";
/* alert message */
"Messages were deleted after you selected them." = "Los mensajes han sido borrados después de seleccionarlos.";
/* 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." = "Los mensajes, archivos y llamadas están protegidos mediante **cifrado de extremo a extremo** con secreto perfecto hacía adelante, repudio y recuperación tras ataque.";
@@ -3073,12 +2999,6 @@
/* No comment provided by engineer. */
"New passphrase…" = "Contraseña nueva…";
/* No comment provided by engineer. */
"New SOCKS credentials will be used every time you start the app." = "Se usarán credenciales SOCKS nuevas cada vez que inicies la aplicación.";
/* No comment provided by engineer. */
"New SOCKS credentials will be used for each server." = "Se usarán credenciales SOCKS nuevas por cada servidor.";
/* pref value */
"no" = "no";
@@ -3121,12 +3041,6 @@
/* No comment provided by engineer. */
"No network connection" = "Sin conexión de red";
/* No comment provided by engineer. */
"No permission to record speech" = "Sin permiso para grabación de voz";
/* No comment provided by engineer. */
"No permission to record video" = "Sin permiso para grabación de vídeo";
/* No comment provided by engineer. */
"No permission to record voice message" = "Sin permiso para grabar mensajes de voz";
@@ -3142,9 +3056,6 @@
/* No comment provided by engineer. */
"Nothing selected" = "Nada seleccionado";
/* alert title */
"Nothing to forward!" = "¡Nada para reenviar!";
/* No comment provided by engineer. */
"Notifications" = "Notificaciones";
@@ -3297,9 +3208,6 @@
/* No comment provided by engineer. */
"other errors" = "otros errores";
/* alert message */
"Other file errors:\n%@" = "Otro(s) error(es) de archivo.\n%@";
/* member role */
"owner" = "propietario";
@@ -3321,9 +3229,6 @@
/* No comment provided by engineer. */
"Passcode set!" = "¡Código de acceso guardado!";
/* No comment provided by engineer. */
"Password" = "Contraseña";
/* No comment provided by engineer. */
"Password to show" = "Contraseña para hacerlo visible";
@@ -3420,11 +3325,8 @@
/* No comment provided by engineer. */
"Polish interface" = "Interfaz en polaco";
/* No comment provided by engineer. */
"Port" = "Puerto";
/* server test error */
"Possibly, certificate fingerprint in server address is incorrect" = "Posiblemente la huella del certificado en la dirección del servidor es incorrecta";
"Possibly, certificate fingerprint in server address is incorrect" = "Posiblemente la huella digital del certificado en la dirección del servidor es incorrecta";
/* No comment provided by engineer. */
"Preserve the last message draft, with attachments." = "Conserva el último borrador del mensaje con los datos adjuntos.";
@@ -3466,7 +3368,7 @@
"Private routing error" = "Error de enrutamiento privado";
/* No comment provided by engineer. */
"Profile and server connections" = "Eliminar perfil y conexiones";
"Profile and server connections" = "Datos del perfil y conexiones";
/* No comment provided by engineer. */
"Profile image" = "Imagen del perfil";
@@ -3534,9 +3436,6 @@
/* No comment provided by engineer. */
"Proxied servers" = "Servidores con proxy";
/* No comment provided by engineer. */
"Proxy requires password" = "El proxy requiere contraseña";
/* No comment provided by engineer. */
"Push notifications" = "Notificaciones automáticas";
@@ -3682,9 +3581,6 @@
/* No comment provided by engineer. */
"Remove" = "Eliminar";
/* No comment provided by engineer. */
"Remove archive?" = "¿Eliminar archivo?";
/* No comment provided by engineer. */
"Remove image" = "Eliminar imagen";
@@ -3707,7 +3603,7 @@
"removed contact address" = "dirección de contacto eliminada";
/* profile update event chat item */
"removed profile picture" = "ha eliminado la imagen del perfil";
"removed profile picture" = "imagen de perfil eliminada";
/* rcv group event chat item */
"removed you" = "te ha expulsado";
@@ -3857,9 +3753,6 @@
/* No comment provided by engineer. */
"Save welcome message?" = "¿Guardar mensaje de bienvenida?";
/* alert title */
"Save your profile?" = "¿Guardar tu perfil?";
/* No comment provided by engineer. */
"saved" = "guardado";
@@ -3878,9 +3771,6 @@
/* No comment provided by engineer. */
"Saved WebRTC ICE servers will be removed" = "Los servidores WebRTC ICE guardados serán eliminados";
/* No comment provided by engineer. */
"Saving %lld messages" = "Guardando %lld mensajes";
/* No comment provided by engineer. */
"Scale" = "Escala";
@@ -3944,9 +3834,6 @@
/* chat item action */
"Select" = "Seleccionar";
/* No comment provided by engineer. */
"Select chat profile" = "Selecciona perfil de chat";
/* No comment provided by engineer. */
"Selected %lld" = "Seleccionados %lld";
@@ -3978,7 +3865,7 @@
"send direct message" = "Enviar mensaje directo";
/* No comment provided by engineer. */
"Send direct message to connect" = "Envía un mensaje para conectar";
"Send direct message to connect" = "Envia un mensaje para conectar";
/* No comment provided by engineer. */
"Send disappearing message" = "Enviar mensaje temporal";
@@ -4079,9 +3966,6 @@
/* No comment provided by engineer. */
"Sent via proxy" = "Mediante proxy";
/* No comment provided by engineer. */
"Server" = "Servidor";
/* No comment provided by engineer. */
"Server address" = "Dirección del servidor";
@@ -4101,7 +3985,7 @@
"Server requires authorization to upload, check password" = "El servidor requiere autorización para subir, comprueba la contraseña";
/* No comment provided by engineer. */
"Server test failed!" = "¡Prueba no superada!";
"Server test failed!" = "¡Error en prueba del servidor!";
/* No comment provided by engineer. */
"Server type" = "Tipo de servidor";
@@ -4143,7 +4027,7 @@
"set new contact address" = "nueva dirección de contacto";
/* profile update event chat item */
"set new profile picture" = "tiene nueva imagen del perfil";
"set new profile picture" = "nueva imagen de perfil";
/* No comment provided by engineer. */
"Set passcode" = "Código autodestrucción";
@@ -4163,9 +4047,6 @@
/* No comment provided by engineer. */
"Settings" = "Configuración";
/* alert message */
"Settings were changed." = "La configuración ha sido modificada.";
/* No comment provided by engineer. */
"Shape profile images" = "Dar forma a las imágenes de perfil";
@@ -4187,9 +4068,6 @@
/* No comment provided by engineer. */
"Share link" = "Compartir enlace";
/* No comment provided by engineer. */
"Share profile" = "Comparte perfil";
/* No comment provided by engineer. */
"Share this 1-time invite link" = "Comparte este enlace de un solo uso";
@@ -4289,15 +4167,9 @@
/* No comment provided by engineer. */
"SMP server" = "Servidor SMP";
/* No comment provided by engineer. */
"SOCKS proxy" = "Proxy SOCKS";
/* blur media */
"Soft" = "Suave";
/* No comment provided by engineer. */
"Some app settings were not migrated." = "Algunas configuraciones de la app no han sido migradas.";
/* No comment provided by engineer. */
"Some file(s) were not exported:" = "Algunos archivos no han sido exportados:";
@@ -4397,9 +4269,6 @@
/* No comment provided by engineer. */
"System authentication" = "Autenticación del sistema";
/* No comment provided by engineer. */
"Tail" = "Cola";
/* No comment provided by engineer. */
"Take picture" = "Tomar foto";
@@ -4443,7 +4312,7 @@
"Temporary file error" = "Error en archivo temporal";
/* server test failure */
"Test failed at step %@." = "Prueba no superada en el paso %@.";
"Test failed at step %@." = "La prueba ha fallado en el paso %@.";
/* No comment provided by engineer. */
"Test server" = "Probar servidor";
@@ -4452,7 +4321,7 @@
"Test servers" = "Probar servidores";
/* No comment provided by engineer. */
"Tests failed!" = "¡Pruebas no superadas!";
"Tests failed!" = "¡Pruebas fallidas!";
/* No comment provided by engineer. */
"Thank you for installing SimpleX Chat!" = "¡Gracias por instalar SimpleX Chat!";
@@ -4529,9 +4398,6 @@
/* No comment provided by engineer. */
"The text you pasted is not a SimpleX link." = "El texto pegado no es un enlace SimpleX.";
/* No comment provided by engineer. */
"The uploaded database archive will be permanently removed from the servers." = "El archivo de bases de datos subido será eliminado permanentemente de los servidores.";
/* No comment provided by engineer. */
"Themes" = "Temas";
@@ -4610,12 +4476,6 @@
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Para proteger tu dirección IP, el enrutamiento privado usa tu lista de servidores SMP para enviar mensajes.";
/* No comment provided by engineer. */
"To record speech please grant permission to use Microphone." = "Para grabación de voz, por favor concede el permiso para usar el micrófono.";
/* No comment provided by engineer. */
"To record video please grant permission to use Camera." = "Para grabación de vídeo, por favor concede el permiso para usar la cámara.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Para grabar el mensaje de voz concede permiso para usar el micrófono.";
@@ -4832,9 +4692,6 @@
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "¿Usar servidores SimpleX Chat?";
/* No comment provided by engineer. */
"Use SOCKS proxy" = "Usar proxy SOCKS";
/* No comment provided by engineer. */
"Use the app while in the call." = "Usar la aplicación durante la llamada.";
@@ -4842,10 +4699,10 @@
"Use the app with one hand." = "Usa la aplicación con una sola mano.";
/* No comment provided by engineer. */
"User selection" = "Selección de usuarios";
"User profile" = "Perfil de usuario";
/* No comment provided by engineer. */
"Username" = "Nombre de usuario";
"User selection" = "Selección de usuarios";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "Usar servidores SimpleX Chat.";
@@ -5048,6 +4905,9 @@
/* No comment provided by engineer. */
"you" = "tu";
/* No comment provided by engineer. */
"You" = "Tú";
/* No comment provided by engineer. */
"You **must not** use the same database on two devices." = "**No debes** usar la misma base de datos en dos dispositivos.";
@@ -5282,15 +5142,9 @@
/* No comment provided by engineer. */
"Your chat database is not encrypted - set passphrase to encrypt it." = "La base de datos no está cifrada - establece una contraseña para cifrarla.";
/* alert title */
"Your chat preferences" = "Tus preferencias de chat";
/* No comment provided by engineer. */
"Your chat profiles" = "Mis perfiles";
/* No comment provided by engineer. */
"Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile." = "Tu conexión ha sido trasladada a %@ pero ha ocurrido un error inesperado al redirigirte al perfil.";
/* No comment provided by engineer. */
"Your contact sent a file that is larger than currently supported maximum size (%@)." = "El contacto ha enviado un archivo mayor al máximo admitido (%@).";
@@ -5300,9 +5154,6 @@
/* No comment provided by engineer. */
"Your contacts will remain connected." = "Tus contactos permanecerán conectados.";
/* No comment provided by engineer. */
"Your credentials may be sent unencrypted." = "Tus credenciales podrían ser enviadas sin cifrar.";
/* No comment provided by engineer. */
"Your current chat database will be DELETED and REPLACED with the imported one." = "La base de datos actual será ELIMINADA y SUSTITUIDA por la importada.";
@@ -5327,9 +5178,6 @@
/* No comment provided by engineer. */
"Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile." = "Tu perfil es almacenado en tu dispositivo y solamente se comparte con tus contactos. Los servidores SimpleX no pueden ver tu perfil.";
/* alert message */
"Your profile was changed. If you save it, the updated profile will be sent to all your contacts." = "Tu perfil ha sido modificado. Si lo guardas la actualización será enviada a todos tus contactos.";
/* No comment provided by engineer. */
"Your profile, contacts and delivered messages are stored on your device." = "Tu perfil, contactos y mensajes se almacenan en tu dispositivo.";
@@ -5340,7 +5188,7 @@
"Your server" = "Tu servidor";
/* No comment provided by engineer. */
"Your server address" = "Dirección del servidor";
"Your server address" = "Dirección de tu servidor";
/* No comment provided by engineer. */
"Your settings" = "Configuración";
+9 -5
View File
@@ -629,9 +629,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "Chat-asetukset";
/* No comment provided by engineer. */
"Chat profile" = "Käyttäjäprofiili";
/* No comment provided by engineer. */
"Chats" = "Keskustelut";
@@ -1398,7 +1395,7 @@
/* No comment provided by engineer. */
"Error stopping chat" = "Virhe keskustelun lopettamisessa";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "Virhe profiilin vaihdossa!";
/* No comment provided by engineer. */
@@ -1419,7 +1416,8 @@
/* No comment provided by engineer. */
"Error: " = "Virhe: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Virhe: %@";
/* No comment provided by engineer. */
@@ -3190,6 +3188,9 @@
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "Käytä SimpleX Chat palvelimia?";
/* No comment provided by engineer. */
"User profile" = "Käyttäjäprofiili";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "Käyttää SimpleX Chat -palvelimia.";
@@ -3307,6 +3308,9 @@
/* pref value */
"yes" = "kyllä";
/* No comment provided by engineer. */
"You" = "Sinä";
/* No comment provided by engineer. */
"You accepted connection" = "Hyväksyit yhteyden";
+10 -6
View File
@@ -454,7 +454,7 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Tous les nouveaux messages de %@ seront cachés !";
/* profile dropdown */
/* No comment provided by engineer. */
"All profiles" = "Tous les profiles";
/* No comment provided by engineer. */
@@ -890,9 +890,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "Préférences de chat";
/* No comment provided by engineer. */
"Chat profile" = "Profil d'utilisateur";
/* No comment provided by engineer. */
"Chat theme" = "Thème de chat";
@@ -1999,7 +1996,7 @@
/* No comment provided by engineer. */
"Error stopping chat" = "Erreur lors de l'arrêt du chat";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "Erreur lors du changement de profil !";
/* No comment provided by engineer. */
@@ -2026,7 +2023,8 @@
/* No comment provided by engineer. */
"Error: " = "Erreur : ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Erreur: %@";
/* No comment provided by engineer. */
@@ -4700,6 +4698,9 @@
/* No comment provided by engineer. */
"Use the app with one hand." = "Utiliser l'application d'une main.";
/* No comment provided by engineer. */
"User profile" = "Profil d'utilisateur";
/* No comment provided by engineer. */
"User selection" = "Sélection de l'utilisateur";
@@ -4904,6 +4905,9 @@
/* No comment provided by engineer. */
"you" = "vous";
/* No comment provided by engineer. */
"You" = "Vous";
/* No comment provided by engineer. */
"You **must not** use the same database on two devices." = "Vous **ne devez pas** utiliser la même base de données sur deux appareils.";
File diff suppressed because it is too large Load Diff
+10 -102
View File
@@ -175,24 +175,9 @@
/* time interval */
"%d days" = "%d giorni";
/* forward confirmation reason */
"%d file(s) are still being downloaded." = "%d file è/sono ancora in scaricamento.";
/* forward confirmation reason */
"%d file(s) failed to download." = "%d file ha/hanno fallito lo scaricamento.";
/* forward confirmation reason */
"%d file(s) were deleted." = "%d file è/sono stato/i eliminato/i.";
/* forward confirmation reason */
"%d file(s) were not downloaded." = "%d file non è/sono stato/i scaricato/i.";
/* time interval */
"%d hours" = "%d ore";
/* alert title */
"%d messages not forwarded" = "%d messaggi non inoltrati";
/* time interval */
"%d min" = "%d min";
@@ -472,7 +457,7 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Tutti i nuovi messaggi da %@ verrranno nascosti!";
/* profile dropdown */
/* No comment provided by engineer. */
"All profiles" = "Tutti gli profili";
/* No comment provided by engineer. */
@@ -595,9 +580,6 @@
/* No comment provided by engineer. */
"App passcode is replaced with self-destruct passcode." = "Il codice di accesso dell'app viene sostituito da un codice di autodistruzione.";
/* No comment provided by engineer. */
"App session" = "Sessione dell'app";
/* No comment provided by engineer. */
"App version" = "Versione dell'app";
@@ -867,7 +849,7 @@
"changed role of %@ to %@" = "ha cambiato il ruolo di %1$@ in %2$@";
/* rcv group event chat item */
"changed your role to %@" = "ha cambiato il tuo ruolo in %@";
"changed your role to %@" = "cambiato il tuo ruolo in %@";
/* chat item text */
"changing address for %@…" = "cambio indirizzo per %@…";
@@ -917,9 +899,6 @@
/* alert message */
"Chat preferences were changed." = "Le preferenze della chat sono state cambiate.";
/* No comment provided by engineer. */
"Chat profile" = "Profilo utente";
/* No comment provided by engineer. */
"Chat theme" = "Tema della chat";
@@ -1644,9 +1623,6 @@
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "NON inviare messaggi direttamente, anche se il tuo server o quello di destinazione non supporta l'instradamento privato.";
/* No comment provided by engineer. */
"Do not use credentials with proxy." = "Non usare credenziali con proxy.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "NON usare l'instradamento privato.";
@@ -1678,9 +1654,6 @@
/* server test step */
"Download file" = "Scarica file";
/* alert action */
"Download files" = "Scarica i file";
/* No comment provided by engineer. */
"Downloaded" = "Scaricato";
@@ -2047,7 +2020,7 @@
/* No comment provided by engineer. */
"Error switching profile" = "Errore nel cambio di profilo";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "Errore nel cambio di profilo!";
/* No comment provided by engineer. */
@@ -2074,7 +2047,8 @@
/* No comment provided by engineer. */
"Error: " = "Errore: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Errore: %@";
/* No comment provided by engineer. */
@@ -2134,9 +2108,6 @@
/* No comment provided by engineer. */
"File error" = "Errore del file";
/* alert message */
"File errors:\n%@" = "Errori di file:\n%@";
/* file error text */
"File not found - most likely file was deleted or cancelled." = "File non trovato - probabilmente è stato eliminato o annullato.";
@@ -2218,18 +2189,9 @@
/* chat item action */
"Forward" = "Inoltra";
/* alert title */
"Forward %d message(s)?" = "Inoltrare %d messaggio/i?";
/* No comment provided by engineer. */
"Forward and save messages" = "Inoltra e salva i messaggi";
/* alert action */
"Forward messages" = "Inoltra i messaggi";
/* alert message */
"Forward messages without files?" = "Inoltrare i messaggi senza file?";
/* No comment provided by engineer. */
"forwarded" = "inoltrato";
@@ -2239,9 +2201,6 @@
/* No comment provided by engineer. */
"Forwarded from" = "Inoltrato da";
/* No comment provided by engineer. */
"Forwarding %lld messages" = "Inoltro di %lld messaggi";
/* No comment provided by engineer. */
"Forwarding server %@ failed to connect to destination server %@. Please try later." = "Il server di inoltro %@ non è riuscito a connettersi al server di destinazione %@. Riprova più tardi.";
@@ -2629,9 +2588,6 @@
/* No comment provided by engineer. */
"iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications." = "Il portachiavi di iOS verrà usato per archiviare in modo sicuro la password dopo il riavvio dell'app o la modifica della password; consentirà di ricevere notifiche push.";
/* No comment provided by engineer. */
"IP address" = "Indirizzo IP";
/* No comment provided by engineer. */
"Irreversible message deletion" = "Eliminazione irreversibile del messaggio";
@@ -2917,9 +2873,6 @@
/* No comment provided by engineer. */
"Messages sent" = "Messaggi inviati";
/* alert message */
"Messages were deleted after you selected them." = "I messaggi sono stati eliminati dopo che li hai selezionati.";
/* 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.";
@@ -3073,12 +3026,6 @@
/* No comment provided by engineer. */
"New passphrase…" = "Nuova password…";
/* No comment provided by engineer. */
"New SOCKS credentials will be used every time you start the app." = "Le nuove credenziali SOCKS verranno usate ogni volta che avvii l'app.";
/* No comment provided by engineer. */
"New SOCKS credentials will be used for each server." = "Le nuove credenziali SOCKS verranno usate per ogni server.";
/* pref value */
"no" = "no";
@@ -3121,12 +3068,6 @@
/* No comment provided by engineer. */
"No network connection" = "Nessuna connessione di rete";
/* No comment provided by engineer. */
"No permission to record speech" = "Nessuna autorizzazione per registrare l'audio";
/* No comment provided by engineer. */
"No permission to record video" = "Nessuna autorizzazione per registrare il video";
/* No comment provided by engineer. */
"No permission to record voice message" = "Nessuna autorizzazione per registrare messaggi vocali";
@@ -3142,9 +3083,6 @@
/* No comment provided by engineer. */
"Nothing selected" = "Nessuna selezione";
/* alert title */
"Nothing to forward!" = "Niente da inoltrare!";
/* No comment provided by engineer. */
"Notifications" = "Notifiche";
@@ -3297,9 +3235,6 @@
/* No comment provided by engineer. */
"other errors" = "altri errori";
/* alert message */
"Other file errors:\n%@" = "Altri errori di file:\n%@";
/* member role */
"owner" = "proprietario";
@@ -3321,9 +3256,6 @@
/* No comment provided by engineer. */
"Passcode set!" = "Codice di accesso impostato!";
/* No comment provided by engineer. */
"Password" = "Password";
/* No comment provided by engineer. */
"Password to show" = "Password per mostrare";
@@ -3420,9 +3352,6 @@
/* No comment provided by engineer. */
"Polish interface" = "Interfaccia polacca";
/* No comment provided by engineer. */
"Port" = "Porta";
/* server test error */
"Possibly, certificate fingerprint in server address is incorrect" = "Probabilmente l'impronta del certificato nell'indirizzo del server è sbagliata";
@@ -3534,9 +3463,6 @@
/* No comment provided by engineer. */
"Proxied servers" = "Server via proxy";
/* No comment provided by engineer. */
"Proxy requires password" = "Il proxy richiede una password";
/* No comment provided by engineer. */
"Push notifications" = "Notifiche push";
@@ -3878,9 +3804,6 @@
/* No comment provided by engineer. */
"Saved WebRTC ICE servers will be removed" = "I server WebRTC ICE salvati verranno rimossi";
/* No comment provided by engineer. */
"Saving %lld messages" = "Salvataggio di %lld messaggi";
/* No comment provided by engineer. */
"Scale" = "Scala";
@@ -4079,9 +4002,6 @@
/* No comment provided by engineer. */
"Sent via proxy" = "Inviato via proxy";
/* No comment provided by engineer. */
"Server" = "Server";
/* No comment provided by engineer. */
"Server address" = "Indirizzo server";
@@ -4289,9 +4209,6 @@
/* No comment provided by engineer. */
"SMP server" = "Server SMP";
/* No comment provided by engineer. */
"SOCKS proxy" = "Proxy SOCKS";
/* blur media */
"Soft" = "Leggera";
@@ -4610,12 +4527,6 @@
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Per proteggere il tuo indirizzo IP, l'instradamento privato usa i tuoi server SMP per consegnare i messaggi.";
/* No comment provided by engineer. */
"To record speech please grant permission to use Microphone." = "Per registrare l'audio, concedi l'autorizzazione di usare il microfono.";
/* No comment provided by engineer. */
"To record video please grant permission to use Camera." = "Per registrare il video, concedi l'autorizzazione di usare la fotocamera.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Per registrare un messaggio vocale, concedi l'autorizzazione all'uso del microfono.";
@@ -4832,9 +4743,6 @@
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "Usare i server di SimpleX Chat?";
/* No comment provided by engineer. */
"Use SOCKS proxy" = "Usa proxy SOCKS";
/* No comment provided by engineer. */
"Use the app while in the call." = "Usa l'app mentre sei in chiamata.";
@@ -4842,10 +4750,10 @@
"Use the app with one hand." = "Usa l'app con una mano sola.";
/* No comment provided by engineer. */
"User selection" = "Selezione utente";
"User profile" = "Profilo utente";
/* No comment provided by engineer. */
"Username" = "Nome utente";
"User selection" = "Selezione utente";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "Utilizzo dei server SimpleX Chat.";
@@ -5048,6 +4956,9 @@
/* No comment provided by engineer. */
"you" = "tu";
/* No comment provided by engineer. */
"You" = "Tu";
/* No comment provided by engineer. */
"You **must not** use the same database on two devices." = "**Non devi** usare lo stesso database su due dispositivi.";
@@ -5300,9 +5211,6 @@
/* No comment provided by engineer. */
"Your contacts will remain connected." = "I tuoi contatti resteranno connessi.";
/* No comment provided by engineer. */
"Your credentials may be sent unencrypted." = "Le credenziali potrebbero essere inviate in chiaro.";
/* No comment provided by engineer. */
"Your current chat database will be DELETED and REPLACED with the imported one." = "Il tuo attuale database della chat verrà ELIMINATO e SOSTITUITO con quello importato.";
+9 -5
View File
@@ -701,9 +701,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "チャット設定";
/* No comment provided by engineer. */
"Chat profile" = "ユーザープロフィール";
/* No comment provided by engineer. */
"Chats" = "チャット";
@@ -1473,7 +1470,7 @@
/* No comment provided by engineer. */
"Error stopping chat" = "チャット停止にエラー発生";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "プロフィール切り替えにエラー発生!";
/* No comment provided by engineer. */
@@ -1494,7 +1491,8 @@
/* No comment provided by engineer. */
"Error: " = "エラー : ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "エラー : %@";
/* No comment provided by engineer. */
@@ -3244,6 +3242,9 @@
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "SimpleX チャット サーバーを使用しますか?";
/* No comment provided by engineer. */
"User profile" = "ユーザープロフィール";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "SimpleX チャット サーバーを使用する。";
@@ -3361,6 +3362,9 @@
/* pref value */
"yes" = "はい";
/* No comment provided by engineer. */
"You" = "あなた";
/* No comment provided by engineer. */
"You accepted connection" = "接続を承認しました";
+15 -110
View File
@@ -175,24 +175,9 @@
/* time interval */
"%d days" = "%d dagen";
/* forward confirmation reason */
"%d file(s) are still being downloaded." = "%d bestand(en) worden nog gedownload.";
/* forward confirmation reason */
"%d file(s) failed to download." = "%d bestand(en) konden niet worden gedownload.";
/* forward confirmation reason */
"%d file(s) were deleted." = "%d bestand(en) zijn verwijderd.";
/* forward confirmation reason */
"%d file(s) were not downloaded." = "%d bestand(en) zijn niet gedownload.";
/* time interval */
"%d hours" = "%d uren";
/* alert title */
"%d messages not forwarded" = "%d berichten niet doorgestuurd";
/* time interval */
"%d min" = "%d min";
@@ -472,7 +457,7 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Alle nieuwe berichten van %@ worden verborgen!";
/* profile dropdown */
/* No comment provided by engineer. */
"All profiles" = "Alle profielen";
/* No comment provided by engineer. */
@@ -595,9 +580,6 @@
/* No comment provided by engineer. */
"App passcode is replaced with self-destruct passcode." = "De app-toegangscode wordt vervangen door een zelfvernietigings wachtwoord.";
/* No comment provided by engineer. */
"App session" = "Appsessie";
/* No comment provided by engineer. */
"App version" = "App versie";
@@ -917,9 +899,6 @@
/* alert message */
"Chat preferences were changed." = "Chatvoorkeuren zijn gewijzigd.";
/* No comment provided by engineer. */
"Chat profile" = "Gebruikers profiel";
/* No comment provided by engineer. */
"Chat theme" = "Chat thema";
@@ -984,7 +963,7 @@
"complete" = "compleet";
/* No comment provided by engineer. */
"Completed" = "Voltooid";
"Completed" = "voltooid";
/* No comment provided by engineer. */
"Configure ICE servers" = "ICE servers configureren";
@@ -1644,9 +1623,6 @@
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "Stuur GEEN berichten rechtstreeks, zelfs als uw of de bestemmingsserver geen privéroutering ondersteunt.";
/* No comment provided by engineer. */
"Do not use credentials with proxy." = "Gebruik geen inloggegevens met proxy.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "Gebruik GEEN privéroutering.";
@@ -1678,9 +1654,6 @@
/* server test step */
"Download file" = "Download bestand";
/* alert action */
"Download files" = "Bestanden downloaden";
/* No comment provided by engineer. */
"Downloaded" = "Gedownload";
@@ -2047,7 +2020,7 @@
/* No comment provided by engineer. */
"Error switching profile" = "Fout bij wisselen van profiel";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "Fout bij wisselen van profiel!";
/* No comment provided by engineer. */
@@ -2074,7 +2047,8 @@
/* No comment provided by engineer. */
"Error: " = "Fout: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Fout: %@";
/* No comment provided by engineer. */
@@ -2134,9 +2108,6 @@
/* No comment provided by engineer. */
"File error" = "Bestandsfout";
/* alert message */
"File errors:\n%@" = "Bestandsfouten:\n%@";
/* file error text */
"File not found - most likely file was deleted or cancelled." = "Bestand niet gevonden - hoogstwaarschijnlijk is het bestand verwijderd of geannuleerd.";
@@ -2218,18 +2189,9 @@
/* chat item action */
"Forward" = "Doorsturen";
/* alert title */
"Forward %d message(s)?" = "%d bericht(en) doorsturen?";
/* No comment provided by engineer. */
"Forward and save messages" = "Berichten doorsturen en opslaan";
/* alert action */
"Forward messages" = "Berichten doorsturen";
/* alert message */
"Forward messages without files?" = "Berichten doorsturen zonder bestanden?";
/* No comment provided by engineer. */
"forwarded" = "doorgestuurd";
@@ -2239,9 +2201,6 @@
/* No comment provided by engineer. */
"Forwarded from" = "Doorgestuurd vanuit";
/* No comment provided by engineer. */
"Forwarding %lld messages" = "%lld berichten doorsturen";
/* No comment provided by engineer. */
"Forwarding server %@ failed to connect to destination server %@. Please try later." = "De doorstuurserver %@ kon geen verbinding maken met de bestemmingsserver %@. Probeer het later opnieuw.";
@@ -2629,9 +2588,6 @@
/* No comment provided by engineer. */
"iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications." = "iOS-keychain wordt gebruikt om het wachtwoord veilig op te slaan nadat u de app opnieuw hebt opgestart of het wachtwoord hebt gewijzigd, hiermee kunt u push meldingen ontvangen.";
/* No comment provided by engineer. */
"IP address" = "IP-adres";
/* No comment provided by engineer. */
"Irreversible message deletion" = "Onomkeerbare berichtverwijdering";
@@ -2917,9 +2873,6 @@
/* No comment provided by engineer. */
"Messages sent" = "Berichten verzonden";
/* alert message */
"Messages were deleted after you selected them." = "Berichten zijn verwijderd nadat u ze had geselecteerd.";
/* 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." = "Berichten, bestanden en oproepen worden beschermd door **end-to-end codering** met perfecte voorwaartse geheimhouding, afwijzing en inbraakherstel.";
@@ -3073,12 +3026,6 @@
/* No comment provided by engineer. */
"New passphrase…" = "Nieuw wachtwoord…";
/* No comment provided by engineer. */
"New SOCKS credentials will be used every time you start the app." = "Elke keer dat u de app start, worden er nieuwe SOCKS-inloggegevens gebruikt.";
/* No comment provided by engineer. */
"New SOCKS credentials will be used for each server." = "Voor elke server worden nieuwe SOCKS-inloggegevens gebruikt.";
/* pref value */
"no" = "Nee";
@@ -3121,12 +3068,6 @@
/* No comment provided by engineer. */
"No network connection" = "Geen netwerkverbinding";
/* No comment provided by engineer. */
"No permission to record speech" = "Geen toestemming om spraak op te nemen";
/* No comment provided by engineer. */
"No permission to record video" = "Geen toestemming om video op te nemen";
/* No comment provided by engineer. */
"No permission to record voice message" = "Geen toestemming om spraakbericht op te nemen";
@@ -3142,9 +3083,6 @@
/* No comment provided by engineer. */
"Nothing selected" = "Niets geselecteerd";
/* alert title */
"Nothing to forward!" = "Niets om door te sturen!";
/* No comment provided by engineer. */
"Notifications" = "Meldingen";
@@ -3297,9 +3235,6 @@
/* No comment provided by engineer. */
"other errors" = "overige fouten";
/* alert message */
"Other file errors:\n%@" = "Andere bestandsfouten:\n%@";
/* member role */
"owner" = "Eigenaar";
@@ -3321,9 +3256,6 @@
/* No comment provided by engineer. */
"Passcode set!" = "Toegangscode ingesteld!";
/* No comment provided by engineer. */
"Password" = "Wachtwoord";
/* No comment provided by engineer. */
"Password to show" = "Wachtwoord om weer te geven";
@@ -3420,9 +3352,6 @@
/* No comment provided by engineer. */
"Polish interface" = "Poolse interface";
/* No comment provided by engineer. */
"Port" = "Poort";
/* server test error */
"Possibly, certificate fingerprint in server address is incorrect" = "Mogelijk is de certificaat vingerafdruk in het server adres onjuist";
@@ -3534,9 +3463,6 @@
/* No comment provided by engineer. */
"Proxied servers" = "Proxied servers";
/* No comment provided by engineer. */
"Proxy requires password" = "Proxy vereist wachtwoord";
/* No comment provided by engineer. */
"Push notifications" = "Push meldingen";
@@ -3878,9 +3804,6 @@
/* No comment provided by engineer. */
"Saved WebRTC ICE servers will be removed" = "Opgeslagen WebRTC ICE servers worden verwijderd";
/* No comment provided by engineer. */
"Saving %lld messages" = "%lld berichten opslaan";
/* No comment provided by engineer. */
"Scale" = "Schaal";
@@ -4079,9 +4002,6 @@
/* No comment provided by engineer. */
"Sent via proxy" = "Verzonden via proxy";
/* No comment provided by engineer. */
"Server" = "Server";
/* No comment provided by engineer. */
"Server address" = "Server adres";
@@ -4289,9 +4209,6 @@
/* No comment provided by engineer. */
"SMP server" = "SMP server";
/* No comment provided by engineer. */
"SOCKS proxy" = "SOCKS proxy";
/* blur media */
"Soft" = "Soft";
@@ -4380,13 +4297,13 @@
"Submit" = "Indienen";
/* No comment provided by engineer. */
"Subscribed" = "Subscribed";
"Subscribed" = "Ingeschreven";
/* No comment provided by engineer. */
"Subscription errors" = "Subscription fouten";
"Subscription errors" = "Inschrijving fouten";
/* No comment provided by engineer. */
"Subscriptions ignored" = "Subscriptions genegeerd";
"Subscriptions ignored" = "Inschrijvingen genegeerd";
/* No comment provided by engineer. */
"Support SimpleX Chat" = "Ondersteuning van SimpleX Chat";
@@ -4397,9 +4314,6 @@
/* No comment provided by engineer. */
"System authentication" = "Systeem authenticatie";
/* No comment provided by engineer. */
"Tail" = "Staart";
/* No comment provided by engineer. */
"Take picture" = "Foto nemen";
@@ -4610,12 +4524,6 @@
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Om uw IP-adres te beschermen, gebruikt privéroutering uw SMP-servers om berichten te bezorgen.";
/* No comment provided by engineer. */
"To record speech please grant permission to use Microphone." = "Geef toestemming om de microfoon te gebruiken om spraak op te nemen.";
/* No comment provided by engineer. */
"To record video please grant permission to use Camera." = "Om video op te nemen, dient u toestemming te geven om de camera te gebruiken.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Geef toestemming om de microfoon te gebruiken om een spraakbericht op te nemen.";
@@ -4832,9 +4740,6 @@
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "SimpleX Chat servers gebruiken?";
/* No comment provided by engineer. */
"Use SOCKS proxy" = "Gebruik SOCKS proxy";
/* No comment provided by engineer. */
"Use the app while in the call." = "Gebruik de app tijdens het gesprek.";
@@ -4842,10 +4747,10 @@
"Use the app with one hand." = "Gebruik de app met één hand.";
/* No comment provided by engineer. */
"User selection" = "Gebruikersselectie";
"User profile" = "Gebruikers profiel";
/* No comment provided by engineer. */
"Username" = "Gebruikersnaam";
"User selection" = "Gebruikersselectie";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "SimpleX Chat servers gebruiken.";
@@ -5048,6 +4953,9 @@
/* No comment provided by engineer. */
"you" = "jij";
/* No comment provided by engineer. */
"You" = "Jij";
/* No comment provided by engineer. */
"You **must not** use the same database on two devices." = "U **mag** niet dezelfde database op twee apparaten gebruiken.";
@@ -5097,7 +5005,7 @@
"You are not connected to these servers. Private routing is used to deliver messages to them." = "U bent niet verbonden met deze servers. Privéroutering wordt gebruikt om berichten bij hen af te leveren.";
/* No comment provided by engineer. */
"you are observer" = "je bent waarnemer";
"you are observer" = "jij bent waarnemer";
/* snd group event chat item */
"you blocked %@" = "je hebt %@ geblokkeerd";
@@ -5199,7 +5107,7 @@
"You joined this group. Connecting to inviting group member." = "Je bent lid geworden van deze groep. Verbinding maken met uitnodigend groepslid.";
/* snd group event chat item */
"you left" = "je bent vertrokken";
"you left" = "jij bent vertrokken";
/* No comment provided by engineer. */
"You may migrate the exported database." = "U kunt de geëxporteerde database migreren.";
@@ -5300,9 +5208,6 @@
/* No comment provided by engineer. */
"Your contacts will remain connected." = "Uw contacten blijven verbonden.";
/* No comment provided by engineer. */
"Your credentials may be sent unencrypted." = "Uw inloggegevens worden mogelijk niet-versleuteld verzonden.";
/* No comment provided by engineer. */
"Your current chat database will be DELETED and REPLACED with the imported one." = "Uw huidige chat database wordt VERWIJDERD en VERVANGEN door de geïmporteerde.";
+8 -160
View File
@@ -160,9 +160,6 @@
/* notification title */
"%@ wants to connect!" = "%@ chce się połączyć!";
/* format for date separator in chat */
"%@, %@" = "%1$@, %2$@";
/* No comment provided by engineer. */
"%@, %@ and %lld members" = "%@, %@ i %lld członków";
@@ -175,24 +172,9 @@
/* time interval */
"%d days" = "%d dni";
/* forward confirmation reason */
"%d file(s) are still being downloaded." = "%d plik(ów) jest dalej pobieranych.";
/* forward confirmation reason */
"%d file(s) failed to download." = "%d plik(ów) nie udało się pobrać.";
/* forward confirmation reason */
"%d file(s) were deleted." = "%d plik(ów) zostało usuniętych.";
/* forward confirmation reason */
"%d file(s) were not downloaded." = "%d plik(ów) nie zostało pobranych.";
/* time interval */
"%d hours" = "%d godzin";
/* alert title */
"%d messages not forwarded" = "%d wiadomości nie przekazanych";
/* time interval */
"%d min" = "%d min";
@@ -472,7 +454,7 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Wszystkie nowe wiadomości z %@ zostaną ukryte!";
/* profile dropdown */
/* No comment provided by engineer. */
"All profiles" = "Wszystkie profile";
/* No comment provided by engineer. */
@@ -595,9 +577,6 @@
/* No comment provided by engineer. */
"App passcode is replaced with self-destruct passcode." = "Pin aplikacji został zastąpiony pinem samozniszczenia.";
/* No comment provided by engineer. */
"App session" = "Sesja aplikacji";
/* No comment provided by engineer. */
"App version" = "Wersja aplikacji";
@@ -670,9 +649,6 @@
/* No comment provided by engineer. */
"Auto-accept images" = "Automatyczne akceptowanie obrazów";
/* alert title */
"Auto-accept settings" = "Ustawienia automatycznej akceptacji";
/* No comment provided by engineer. */
"Back" = "Wstecz";
@@ -914,12 +890,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "Preferencje czatu";
/* alert message */
"Chat preferences were changed." = "Preferencje czatu zostały zmienione.";
/* No comment provided by engineer. */
"Chat profile" = "Profil użytkownika";
/* No comment provided by engineer. */
"Chat theme" = "Motyw czatu";
@@ -1208,9 +1178,6 @@
/* No comment provided by engineer. */
"Core version: v%@" = "Wersja rdzenia: v%@";
/* No comment provided by engineer. */
"Corner" = "Róg";
/* No comment provided by engineer. */
"Correct name to %@?" = "Poprawić imię na %@?";
@@ -1644,9 +1611,6 @@
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "NIE wysyłaj wiadomości bezpośrednio, nawet jeśli serwer docelowy nie obsługuje prywatnego trasowania.";
/* No comment provided by engineer. */
"Do not use credentials with proxy." = "Nie używaj danych logowania do proxy.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "NIE używaj prywatnego trasowania.";
@@ -1678,9 +1642,6 @@
/* server test step */
"Download file" = "Pobierz plik";
/* alert action */
"Download files" = "Pobierz pliki";
/* No comment provided by engineer. */
"Downloaded" = "Pobrane";
@@ -1897,18 +1858,12 @@
/* No comment provided by engineer. */
"Error changing address" = "Błąd zmiany adresu";
/* No comment provided by engineer. */
"Error changing connection profile" = "Błąd zmiany połączenia profilu";
/* No comment provided by engineer. */
"Error changing role" = "Błąd zmiany roli";
/* No comment provided by engineer. */
"Error changing setting" = "Błąd zmiany ustawienia";
/* No comment provided by engineer. */
"Error changing to incognito!" = "Błąd zmiany na incognito!";
/* No comment provided by engineer. */
"Error connecting to forwarding server %@. Please try later." = "Błąd połączenia z serwerem przekierowania %@. Spróbuj ponownie później.";
@@ -1981,9 +1936,6 @@
/* No comment provided by engineer. */
"Error loading %@ servers" = "Błąd ładowania %@ serwerów";
/* No comment provided by engineer. */
"Error migrating settings" = "Błąd migracji ustawień";
/* No comment provided by engineer. */
"Error opening chat" = "Błąd otwierania czatu";
@@ -2045,9 +1997,6 @@
"Error stopping chat" = "Błąd zatrzymania czatu";
/* No comment provided by engineer. */
"Error switching profile" = "Błąd zmiany profilu";
/* alertTitle */
"Error switching profile!" = "Błąd przełączania profilu!";
/* No comment provided by engineer. */
@@ -2074,7 +2023,8 @@
/* No comment provided by engineer. */
"Error: " = "Błąd: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Błąd: %@";
/* No comment provided by engineer. */
@@ -2134,9 +2084,6 @@
/* No comment provided by engineer. */
"File error" = "Błąd pliku";
/* alert message */
"File errors:\n%@" = "Błędy pliku:\n%@";
/* file error text */
"File not found - most likely file was deleted or cancelled." = "Nie odnaleziono pliku - najprawdopodobniej plik został usunięty lub anulowany.";
@@ -2218,18 +2165,9 @@
/* chat item action */
"Forward" = "Przekaż dalej";
/* alert title */
"Forward %d message(s)?" = "Przekazać %d wiadomość(i)?";
/* No comment provided by engineer. */
"Forward and save messages" = "Przesyłaj dalej i zapisuj wiadomości";
/* alert action */
"Forward messages" = "Przekaż wiadomości";
/* alert message */
"Forward messages without files?" = "Przekazać wiadomości bez plików?";
/* No comment provided by engineer. */
"forwarded" = "przekazane dalej";
@@ -2239,9 +2177,6 @@
/* No comment provided by engineer. */
"Forwarded from" = "Przekazane dalej od";
/* No comment provided by engineer. */
"Forwarding %lld messages" = "Przekazywanie %lld wiadomości";
/* No comment provided by engineer. */
"Forwarding server %@ failed to connect to destination server %@. Please try later." = "Serwer przekazujący %@ nie mógł połączyć się z serwerem docelowym %@. Spróbuj ponownie później.";
@@ -2629,9 +2564,6 @@
/* No comment provided by engineer. */
"iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications." = "iOS Keychain będzie używany do bezpiecznego przechowywania hasła po ponownym uruchomieniu aplikacji lub zmianie hasła - pozwoli to na otrzymywanie powiadomień push.";
/* No comment provided by engineer. */
"IP address" = "Adres IP";
/* No comment provided by engineer. */
"Irreversible message deletion" = "Nieodwracalne usuwanie wiadomości";
@@ -2884,9 +2816,6 @@
/* No comment provided by engineer. */
"Message servers" = "Serwery wiadomości";
/* No comment provided by engineer. */
"Message shape" = "Kształt wiadomości";
/* No comment provided by engineer. */
"Message source remains private." = "Źródło wiadomości pozostaje prywatne.";
@@ -2917,9 +2846,6 @@
/* No comment provided by engineer. */
"Messages sent" = "Wysłane wiadomości";
/* alert message */
"Messages were deleted after you selected them." = "Wiadomości zostały usunięte po wybraniu ich.";
/* 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." = "Wiadomości, pliki i połączenia są chronione przez **szyfrowanie end-to-end** z doskonałym utajnianiem z wyprzedzeniem i odzyskiem po złamaniu.";
@@ -3073,12 +2999,6 @@
/* No comment provided by engineer. */
"New passphrase…" = "Nowe hasło…";
/* No comment provided by engineer. */
"New SOCKS credentials will be used every time you start the app." = "Nowe poświadczenia SOCKS będą używane przy każdym uruchomieniu aplikacji.";
/* No comment provided by engineer. */
"New SOCKS credentials will be used for each server." = "Dla każdego serwera zostaną użyte nowe poświadczenia SOCKS.";
/* pref value */
"no" = "nie";
@@ -3121,12 +3041,6 @@
/* No comment provided by engineer. */
"No network connection" = "Brak połączenia z siecią";
/* No comment provided by engineer. */
"No permission to record speech" = "Brak zezwoleń do nagrania rozmowy";
/* No comment provided by engineer. */
"No permission to record video" = "Brak zezwoleń do nagrania wideo";
/* No comment provided by engineer. */
"No permission to record voice message" = "Brak uprawnień do nagrywania wiadomości głosowej";
@@ -3142,9 +3056,6 @@
/* No comment provided by engineer. */
"Nothing selected" = "Nic nie jest zaznaczone";
/* alert title */
"Nothing to forward!" = "Nic do przekazania!";
/* No comment provided by engineer. */
"Notifications" = "Powiadomienia";
@@ -3297,9 +3208,6 @@
/* No comment provided by engineer. */
"other errors" = "inne błędy";
/* alert message */
"Other file errors:\n%@" = "Inne błędy pliku:\n%@";
/* member role */
"owner" = "właściciel";
@@ -3321,9 +3229,6 @@
/* No comment provided by engineer. */
"Passcode set!" = "Pin ustawiony!";
/* No comment provided by engineer. */
"Password" = "Hasło";
/* No comment provided by engineer. */
"Password to show" = "Hasło do wyświetlenia";
@@ -3420,9 +3325,6 @@
/* No comment provided by engineer. */
"Polish interface" = "Polski interfejs";
/* No comment provided by engineer. */
"Port" = "Port";
/* server test error */
"Possibly, certificate fingerprint in server address is incorrect" = "Możliwe, że odcisk palca certyfikatu w adresie serwera jest nieprawidłowy";
@@ -3534,9 +3436,6 @@
/* No comment provided by engineer. */
"Proxied servers" = "Serwery trasowane przez proxy";
/* No comment provided by engineer. */
"Proxy requires password" = "Proxy wymaga hasła";
/* No comment provided by engineer. */
"Push notifications" = "Powiadomienia push";
@@ -3682,9 +3581,6 @@
/* No comment provided by engineer. */
"Remove" = "Usuń";
/* No comment provided by engineer. */
"Remove archive?" = "Usunąć archiwum?";
/* No comment provided by engineer. */
"Remove image" = "Usuń obraz";
@@ -3857,9 +3753,6 @@
/* No comment provided by engineer. */
"Save welcome message?" = "Zapisać wiadomość powitalną?";
/* alert title */
"Save your profile?" = "Zapisać Twój profil?";
/* No comment provided by engineer. */
"saved" = "zapisane";
@@ -3878,9 +3771,6 @@
/* No comment provided by engineer. */
"Saved WebRTC ICE servers will be removed" = "Zapisane serwery WebRTC ICE zostaną usunięte";
/* No comment provided by engineer. */
"Saving %lld messages" = "Zapisywanie %lld wiadomości";
/* No comment provided by engineer. */
"Scale" = "Skaluj";
@@ -3944,9 +3834,6 @@
/* chat item action */
"Select" = "Wybierz";
/* No comment provided by engineer. */
"Select chat profile" = "Wybierz profil czatu";
/* No comment provided by engineer. */
"Selected %lld" = "Zaznaczono %lld";
@@ -4079,9 +3966,6 @@
/* No comment provided by engineer. */
"Sent via proxy" = "Wysłano przez proxy";
/* No comment provided by engineer. */
"Server" = "Serwer";
/* No comment provided by engineer. */
"Server address" = "Adres serwera";
@@ -4163,9 +4047,6 @@
/* No comment provided by engineer. */
"Settings" = "Ustawienia";
/* alert message */
"Settings were changed." = "Ustawienia zostały zmienione.";
/* No comment provided by engineer. */
"Shape profile images" = "Kształtuj obrazy profilowe";
@@ -4187,9 +4068,6 @@
/* No comment provided by engineer. */
"Share link" = "Udostępnij link";
/* No comment provided by engineer. */
"Share profile" = "Udostępnij profil";
/* No comment provided by engineer. */
"Share this 1-time invite link" = "Udostępnij ten jednorazowy link";
@@ -4289,15 +4167,9 @@
/* No comment provided by engineer. */
"SMP server" = "Serwer SMP";
/* No comment provided by engineer. */
"SOCKS proxy" = "Proxy SOCKS";
/* blur media */
"Soft" = "Łagodny";
/* No comment provided by engineer. */
"Some app settings were not migrated." = "Niektóre ustawienia aplikacji nie zostały zmigrowane.";
/* No comment provided by engineer. */
"Some file(s) were not exported:" = "Niektóre plik(i) nie zostały wyeksportowane:";
@@ -4397,9 +4269,6 @@
/* No comment provided by engineer. */
"System authentication" = "Uwierzytelnianie systemu";
/* No comment provided by engineer. */
"Tail" = "Ogon";
/* No comment provided by engineer. */
"Take picture" = "Zrób zdjęcie";
@@ -4529,9 +4398,6 @@
/* No comment provided by engineer. */
"The text you pasted is not a SimpleX link." = "Tekst, który wkleiłeś nie jest linkiem SimpleX.";
/* No comment provided by engineer. */
"The uploaded database archive will be permanently removed from the servers." = "Przesłane archiwum bazy danych zostanie trwale usunięte z serwerów.";
/* No comment provided by engineer. */
"Themes" = "Motywy";
@@ -4610,12 +4476,6 @@
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Aby chronić Twój adres IP, prywatne trasowanie używa Twoich serwerów SMP, aby dostarczyć wiadomości.";
/* No comment provided by engineer. */
"To record speech please grant permission to use Microphone." = "Aby nagrać rozmowę, proszę zezwolić na użycie Mikrofonu.";
/* No comment provided by engineer. */
"To record video please grant permission to use Camera." = "Aby nagrać wideo, proszę zezwolić na użycie Aparatu.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Aby nagrać wiadomość głosową należy udzielić zgody na użycie Mikrofonu.";
@@ -4832,9 +4692,6 @@
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "Użyć serwerów SimpleX Chat?";
/* No comment provided by engineer. */
"Use SOCKS proxy" = "Użyj proxy SOCKS";
/* No comment provided by engineer. */
"Use the app while in the call." = "Używaj aplikacji podczas połączenia.";
@@ -4842,10 +4699,10 @@
"Use the app with one hand." = "Korzystaj z aplikacji jedną ręką.";
/* No comment provided by engineer. */
"User selection" = "Wybór użytkownika";
"User profile" = "Profil użytkownika";
/* No comment provided by engineer. */
"Username" = "Nazwa użytkownika";
"User selection" = "Wybór użytkownika";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "Używanie serwerów SimpleX Chat.";
@@ -5048,6 +4905,9 @@
/* No comment provided by engineer. */
"you" = "Ty";
/* No comment provided by engineer. */
"You" = "Ty";
/* No comment provided by engineer. */
"You **must not** use the same database on two devices." = "**Nie możesz** używać tej samej bazy na dwóch urządzeniach.";
@@ -5282,15 +5142,9 @@
/* No comment provided by engineer. */
"Your chat database is not encrypted - set passphrase to encrypt it." = "Baza danych czatu nie jest szyfrowana - ustaw hasło, aby ją zaszyfrować.";
/* alert title */
"Your chat preferences" = "Twoje preferencje czatu";
/* No comment provided by engineer. */
"Your chat profiles" = "Twoje profile czatu";
/* No comment provided by engineer. */
"Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile." = "Twoje połączenie zostało przeniesione do %@, ale podczas przekierowywania do profilu wystąpił nieoczekiwany błąd.";
/* No comment provided by engineer. */
"Your contact sent a file that is larger than currently supported maximum size (%@)." = "Twój kontakt wysłał plik, który jest większy niż obecnie obsługiwany maksymalny rozmiar (%@).";
@@ -5300,9 +5154,6 @@
/* No comment provided by engineer. */
"Your contacts will remain connected." = "Twoje kontakty pozostaną połączone.";
/* No comment provided by engineer. */
"Your credentials may be sent unencrypted." = "Twoje poświadczenia mogą zostać wysłane niezaszyfrowane.";
/* No comment provided by engineer. */
"Your current chat database will be DELETED and REPLACED with the imported one." = "Twoja obecna baza danych czatu zostanie usunięta i zastąpiona zaimportowaną.";
@@ -5327,9 +5178,6 @@
/* No comment provided by engineer. */
"Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile." = "Twój profil jest przechowywany na urządzeniu i udostępniany tylko Twoim kontaktom. Serwery SimpleX nie mogą zobaczyć Twojego profilu.";
/* alert message */
"Your profile was changed. If you save it, the updated profile will be sent to all your contacts." = "Twój profil został zmieniony. Jeśli go zapiszesz, zaktualizowany profil zostanie wysłany do wszystkich kontaktów.";
/* No comment provided by engineer. */
"Your profile, contacts and delivered messages are stored on your device." = "Twój profil, kontakty i dostarczone wiadomości są przechowywane na Twoim urządzeniu.";
+8 -157
View File
@@ -172,24 +172,9 @@
/* time interval */
"%d days" = "%d дней";
/* forward confirmation reason */
"%d file(s) are still being downloaded." = "%d файл(ов) загружаются.";
/* forward confirmation reason */
"%d file(s) failed to download." = "%d файл(ов) не удалось загрузить.";
/* forward confirmation reason */
"%d file(s) were deleted." = "%d файлов было удалено.";
/* forward confirmation reason */
"%d file(s) were not downloaded." = "%d файлов не было загружено.";
/* time interval */
"%d hours" = "%d ч.";
/* alert title */
"%d messages not forwarded" = "%d сообщений не переслано";
/* time interval */
"%d min" = "%d мин";
@@ -469,7 +454,7 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Все новые сообщения от %@ будут скрыты!";
/* profile dropdown */
/* No comment provided by engineer. */
"All profiles" = "Все профили";
/* No comment provided by engineer. */
@@ -592,9 +577,6 @@
/* No comment provided by engineer. */
"App passcode is replaced with self-destruct passcode." = "Код доступа в приложение будет заменен кодом самоуничтожения.";
/* No comment provided by engineer. */
"App session" = "Сессия приложения";
/* No comment provided by engineer. */
"App version" = "Версия приложения";
@@ -667,9 +649,6 @@
/* No comment provided by engineer. */
"Auto-accept images" = "Автоприем изображений";
/* alert title */
"Auto-accept settings" = "Настройки автоприема";
/* No comment provided by engineer. */
"Back" = "Назад";
@@ -911,12 +890,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "Предпочтения";
/* alert message */
"Chat preferences were changed." = "Настройки чата были изменены.";
/* No comment provided by engineer. */
"Chat profile" = "Профиль чата";
/* No comment provided by engineer. */
"Chat theme" = "Тема чата";
@@ -1205,9 +1178,6 @@
/* No comment provided by engineer. */
"Core version: v%@" = "Версия ядра: v%@";
/* No comment provided by engineer. */
"Corner" = "Угол";
/* No comment provided by engineer. */
"Correct name to %@?" = "Исправить имя на %@?";
@@ -1641,9 +1611,6 @@
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "Не отправлять сообщения напрямую, даже если сервер получателя не поддерживает конфиденциальную доставку.";
/* No comment provided by engineer. */
"Do not use credentials with proxy." = "Не использовать учетные данные с прокси.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "Не использовать конфиденциальную доставку.";
@@ -1675,9 +1642,6 @@
/* server test step */
"Download file" = "Загрузка файла";
/* alert action */
"Download files" = "Загрузить файлы";
/* No comment provided by engineer. */
"Downloaded" = "Принято";
@@ -1894,18 +1858,12 @@
/* No comment provided by engineer. */
"Error changing address" = "Ошибка при изменении адреса";
/* No comment provided by engineer. */
"Error changing connection profile" = "Ошибка при изменении профиля соединения";
/* No comment provided by engineer. */
"Error changing role" = "Ошибка при изменении роли";
/* No comment provided by engineer. */
"Error changing setting" = "Ошибка при изменении настройки";
/* No comment provided by engineer. */
"Error changing to incognito!" = "Ошибка при смене на Инкогнито!";
/* No comment provided by engineer. */
"Error connecting to forwarding server %@. Please try later." = "Ошибка подключения к пересылающему серверу %@. Попробуйте позже.";
@@ -1978,9 +1936,6 @@
/* No comment provided by engineer. */
"Error loading %@ servers" = "Ошибка загрузки %@ серверов";
/* No comment provided by engineer. */
"Error migrating settings" = "Ошибка миграции настроек";
/* No comment provided by engineer. */
"Error opening chat" = "Ошибка доступа к чату";
@@ -2042,9 +1997,6 @@
"Error stopping chat" = "Ошибка при остановке чата";
/* No comment provided by engineer. */
"Error switching profile" = "Ошибка переключения профиля";
/* alertTitle */
"Error switching profile!" = "Ошибка выбора профиля!";
/* No comment provided by engineer. */
@@ -2071,7 +2023,8 @@
/* No comment provided by engineer. */
"Error: " = "Ошибка: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Ошибка: %@";
/* No comment provided by engineer. */
@@ -2131,9 +2084,6 @@
/* No comment provided by engineer. */
"File error" = "Ошибка файла";
/* alert message */
"File errors:\n%@" = "Ошибки файлов:\n%@";
/* file error text */
"File not found - most likely file was deleted or cancelled." = "Файл не найден - скорее всего, файл был удален или отменен.";
@@ -2215,18 +2165,9 @@
/* chat item action */
"Forward" = "Переслать";
/* alert title */
"Forward %d message(s)?" = "Переслать %d сообщение(й)?";
/* No comment provided by engineer. */
"Forward and save messages" = "Переслать и сохранить сообщение";
/* alert action */
"Forward messages" = "Переслать сообщения";
/* alert message */
"Forward messages without files?" = "Переслать сообщения без файлов?";
/* No comment provided by engineer. */
"forwarded" = "переслано";
@@ -2236,9 +2177,6 @@
/* No comment provided by engineer. */
"Forwarded from" = "Переслано из";
/* No comment provided by engineer. */
"Forwarding %lld messages" = "Пересылка %lld сообщений";
/* No comment provided by engineer. */
"Forwarding server %@ failed to connect to destination server %@. Please try later." = "Пересылающий сервер %@ не смог подключиться к серверу назначения %@. Попробуйте позже.";
@@ -2626,9 +2564,6 @@
/* No comment provided by engineer. */
"iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications." = "Пароль базы данных будет безопасно сохранен в iOS Keychain после запуска чата или изменения пароля - это позволит получать мгновенные уведомления.";
/* No comment provided by engineer. */
"IP address" = "IP адрес";
/* No comment provided by engineer. */
"Irreversible message deletion" = "Окончательное удаление сообщений";
@@ -2881,9 +2816,6 @@
/* No comment provided by engineer. */
"Message servers" = "Серверы сообщений";
/* No comment provided by engineer. */
"Message shape" = "Форма сообщений";
/* No comment provided by engineer. */
"Message source remains private." = "Источник сообщения остаётся конфиденциальным.";
@@ -2914,9 +2846,6 @@
/* No comment provided by engineer. */
"Messages sent" = "Сообщений отправлено";
/* alert message */
"Messages were deleted after you selected them." = "Сообщения были удалены после того, как вы их выбрали.";
/* 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." = "Сообщения, файлы и звонки защищены **end-to-end шифрованием** с прямой секретностью (PFS), правдоподобным отрицанием и восстановлением от взлома.";
@@ -3070,12 +2999,6 @@
/* No comment provided by engineer. */
"New passphrase…" = "Новый пароль…";
/* No comment provided by engineer. */
"New SOCKS credentials will be used every time you start the app." = "Новые учетные данные SOCKS будут использоваться при каждом запуске приложения.";
/* No comment provided by engineer. */
"New SOCKS credentials will be used for each server." = "Новые учетные данные SOCKS будут использоваться для каждого сервера.";
/* pref value */
"no" = "нет";
@@ -3118,12 +3041,6 @@
/* No comment provided by engineer. */
"No network connection" = "Нет интернет-соединения";
/* No comment provided by engineer. */
"No permission to record speech" = "Нет разрешения на запись речи";
/* No comment provided by engineer. */
"No permission to record video" = "Нет разрешения на запись видео";
/* No comment provided by engineer. */
"No permission to record voice message" = "Нет разрешения для записи голосового сообщения";
@@ -3139,9 +3056,6 @@
/* No comment provided by engineer. */
"Nothing selected" = "Ничего не выбрано";
/* alert title */
"Nothing to forward!" = "Нет сообщений, которые можно переслать!";
/* No comment provided by engineer. */
"Notifications" = "Уведомления";
@@ -3294,9 +3208,6 @@
/* No comment provided by engineer. */
"other errors" = "другие ошибки";
/* alert message */
"Other file errors:\n%@" = "Другие ошибки файлов:\n%@";
/* member role */
"owner" = "владелец";
@@ -3318,9 +3229,6 @@
/* No comment provided by engineer. */
"Passcode set!" = "Код доступа установлен!";
/* No comment provided by engineer. */
"Password" = "Пароль";
/* No comment provided by engineer. */
"Password to show" = "Пароль чтобы раскрыть";
@@ -3417,9 +3325,6 @@
/* No comment provided by engineer. */
"Polish interface" = "Польский интерфейс";
/* No comment provided by engineer. */
"Port" = "Порт";
/* server test error */
"Possibly, certificate fingerprint in server address is incorrect" = "Возможно, хэш сертификата в адресе сервера неверный";
@@ -3531,9 +3436,6 @@
/* No comment provided by engineer. */
"Proxied servers" = "Проксированные серверы";
/* No comment provided by engineer. */
"Proxy requires password" = "Прокси требует пароль";
/* No comment provided by engineer. */
"Push notifications" = "Доставка уведомлений";
@@ -3679,9 +3581,6 @@
/* No comment provided by engineer. */
"Remove" = "Удалить";
/* No comment provided by engineer. */
"Remove archive?" = "Удалить архив?";
/* No comment provided by engineer. */
"Remove image" = "Удалить изображение";
@@ -3854,9 +3753,6 @@
/* No comment provided by engineer. */
"Save welcome message?" = "Сохранить приветственное сообщение?";
/* alert title */
"Save your profile?" = "Сохранить ваш профиль?";
/* No comment provided by engineer. */
"saved" = "сохранено";
@@ -3875,9 +3771,6 @@
/* No comment provided by engineer. */
"Saved WebRTC ICE servers will be removed" = "Сохраненные WebRTC ICE серверы будут удалены";
/* No comment provided by engineer. */
"Saving %lld messages" = "Сохранение %lld сообщений";
/* No comment provided by engineer. */
"Scale" = "Масштаб";
@@ -3941,9 +3834,6 @@
/* chat item action */
"Select" = "Выбрать";
/* No comment provided by engineer. */
"Select chat profile" = "Выберите профиль чата";
/* No comment provided by engineer. */
"Selected %lld" = "Выбрано %lld";
@@ -4076,9 +3966,6 @@
/* No comment provided by engineer. */
"Sent via proxy" = "Отправлено через прокси";
/* No comment provided by engineer. */
"Server" = "Сервер";
/* No comment provided by engineer. */
"Server address" = "Адрес сервера";
@@ -4160,9 +4047,6 @@
/* No comment provided by engineer. */
"Settings" = "Настройки";
/* alert message */
"Settings were changed." = "Настройки были изменены.";
/* No comment provided by engineer. */
"Shape profile images" = "Форма картинок профилей";
@@ -4184,9 +4068,6 @@
/* No comment provided by engineer. */
"Share link" = "Поделиться ссылкой";
/* No comment provided by engineer. */
"Share profile" = "Поделиться профилем";
/* No comment provided by engineer. */
"Share this 1-time invite link" = "Поделиться одноразовой ссылкой-приглашением";
@@ -4286,15 +4167,9 @@
/* No comment provided by engineer. */
"SMP server" = "SMP сервер";
/* No comment provided by engineer. */
"SOCKS proxy" = "SOCKS прокси";
/* blur media */
"Soft" = "Слабое";
/* No comment provided by engineer. */
"Some app settings were not migrated." = "Некоторые настройки приложения не были перенесены.";
/* No comment provided by engineer. */
"Some file(s) were not exported:" = "Некоторые файл(ы) не были экспортированы:";
@@ -4394,9 +4269,6 @@
/* No comment provided by engineer. */
"System authentication" = "Системная аутентификация";
/* No comment provided by engineer. */
"Tail" = "Хвост";
/* No comment provided by engineer. */
"Take picture" = "Сделать фото";
@@ -4526,9 +4398,6 @@
/* No comment provided by engineer. */
"The text you pasted is not a SimpleX link." = "Вставленный текст не является SimpleX-ссылкой.";
/* No comment provided by engineer. */
"The uploaded database archive will be permanently removed from the servers." = "Загруженный архив базы данных будет навсегда удален с серверов.";
/* No comment provided by engineer. */
"Themes" = "Темы";
@@ -4607,12 +4476,6 @@
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Чтобы защитить ваш IP адрес, приложение использует Ваши SMP серверы для конфиденциальной доставки сообщений.";
/* No comment provided by engineer. */
"To record speech please grant permission to use Microphone." = "Для записи речи, пожалуйста, дайте разрешение на использование микрофона.";
/* No comment provided by engineer. */
"To record video please grant permission to use Camera." = "Для записи видео, пожалуйста, дайте разрешение на использование камеры.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Для записи голосового сообщения, пожалуйста разрешите доступ к микрофону.";
@@ -4829,9 +4692,6 @@
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "Использовать серверы предосталенные SimpleX Chat?";
/* No comment provided by engineer. */
"Use SOCKS proxy" = "Использовать SOCKS прокси";
/* No comment provided by engineer. */
"Use the app while in the call." = "Используйте приложение во время звонка.";
@@ -4839,10 +4699,10 @@
"Use the app with one hand." = "Используйте приложение одной рукой.";
/* No comment provided by engineer. */
"User selection" = "Выбор пользователя";
"User profile" = "Профиль чата";
/* No comment provided by engineer. */
"Username" = "Имя пользователя";
"User selection" = "Выбор пользователя";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "Используются серверы, предоставленные SimpleX Chat.";
@@ -5045,6 +4905,9 @@
/* No comment provided by engineer. */
"you" = "Вы";
/* No comment provided by engineer. */
"You" = "Вы";
/* No comment provided by engineer. */
"You **must not** use the same database on two devices." = "Вы **не должны** использовать одну и ту же базу данных на двух устройствах.";
@@ -5279,15 +5142,9 @@
/* No comment provided by engineer. */
"Your chat database is not encrypted - set passphrase to encrypt it." = "База данных НЕ зашифрована. Установите пароль, чтобы защитить Ваши данные.";
/* alert title */
"Your chat preferences" = "Ваши настройки чата";
/* No comment provided by engineer. */
"Your chat profiles" = "Ваши профили чата";
/* No comment provided by engineer. */
"Your connection was moved to %@ but an unexpected error occurred while redirecting you to the profile." = "Соединение было перемещено на %@, но при смене профиля произошла неожиданная ошибка.";
/* No comment provided by engineer. */
"Your contact sent a file that is larger than currently supported maximum size (%@)." = "Ваш контакт отправил файл, размер которого превышает максимальный размер (%@).";
@@ -5297,9 +5154,6 @@
/* No comment provided by engineer. */
"Your contacts will remain connected." = "Ваши контакты сохранятся.";
/* No comment provided by engineer. */
"Your credentials may be sent unencrypted." = "Ваши учетные данные могут быть отправлены в незашифрованном виде.";
/* No comment provided by engineer. */
"Your current chat database will be DELETED and REPLACED with the imported one." = "Текущие данные Вашего чата будет УДАЛЕНЫ и ЗАМЕНЕНЫ импортированными.";
@@ -5324,9 +5178,6 @@
/* No comment provided by engineer. */
"Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile." = "Ваш профиль хранится на Вашем устройстве и отправляется только Вашим контактам. SimpleX серверы не могут получить доступ к Вашему профилю.";
/* alert message */
"Your profile was changed. If you save it, the updated profile will be sent to all your contacts." = "Ваш профиль был изменен. Если вы сохраните его, обновленный профиль будет отправлен всем вашим контактам.";
/* No comment provided by engineer. */
"Your profile, contacts and delivered messages are stored on your device." = "Ваш профиль, контакты и доставленные сообщения хранятся на Вашем устройстве.";
+9 -5
View File
@@ -605,9 +605,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "ค่ากําหนดในการแชท";
/* No comment provided by engineer. */
"Chat profile" = "โปรไฟล์ผู้ใช้";
/* No comment provided by engineer. */
"Chats" = "แชท";
@@ -1350,7 +1347,7 @@
/* No comment provided by engineer. */
"Error stopping chat" = "เกิดข้อผิดพลาดในการหยุดแชท";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "เกิดข้อผิดพลาดในการเปลี่ยนโปรไฟล์!";
/* No comment provided by engineer. */
@@ -1371,7 +1368,8 @@
/* No comment provided by engineer. */
"Error: " = "ผิดพลาด: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "ข้อผิดพลาด: % @";
/* No comment provided by engineer. */
@@ -3097,6 +3095,9 @@
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "ใช้เซิร์ฟเวอร์ SimpleX Chat ไหม?";
/* No comment provided by engineer. */
"User profile" = "โปรไฟล์ผู้ใช้";
/* No comment provided by engineer. */
"Using SimpleX Chat servers." = "กำลังใช้เซิร์ฟเวอร์ SimpleX Chat อยู่";
@@ -3214,6 +3215,9 @@
/* pref value */
"yes" = "ใช่";
/* No comment provided by engineer. */
"You" = "คุณ";
/* No comment provided by engineer. */
"You accepted connection" = "คุณยอมรับการเชื่อมต่อ";
File diff suppressed because it is too large Load Diff
+10 -6
View File
@@ -454,7 +454,7 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Всі нові повідомлення від %@ будуть приховані!";
/* profile dropdown */
/* No comment provided by engineer. */
"All profiles" = "Всі профілі";
/* No comment provided by engineer. */
@@ -890,9 +890,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "Налаштування чату";
/* No comment provided by engineer. */
"Chat profile" = "Профіль користувача";
/* No comment provided by engineer. */
"Chat theme" = "Тема чату";
@@ -1999,7 +1996,7 @@
/* No comment provided by engineer. */
"Error stopping chat" = "Помилка зупинки чату";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "Помилка перемикання профілю!";
/* No comment provided by engineer. */
@@ -2026,7 +2023,8 @@
/* No comment provided by engineer. */
"Error: " = "Помилка: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "Помилка: %@";
/* No comment provided by engineer. */
@@ -4700,6 +4698,9 @@
/* No comment provided by engineer. */
"Use the app with one hand." = "Використовуйте додаток однією рукою.";
/* No comment provided by engineer. */
"User profile" = "Профіль користувача";
/* No comment provided by engineer. */
"User selection" = "Вибір користувача";
@@ -4904,6 +4905,9 @@
/* No comment provided by engineer. */
"you" = "ти";
/* No comment provided by engineer. */
"You" = "Ти";
/* No comment provided by engineer. */
"You **must not** use the same database on two devices." = "Ви **не повинні використовувати** одну і ту ж базу даних на двох пристроях.";
+10 -6
View File
@@ -454,7 +454,7 @@
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "来自 %@ 的所有新消息都将被隐藏!";
/* profile dropdown */
/* No comment provided by engineer. */
"All profiles" = "所有配置文件";
/* No comment provided by engineer. */
@@ -890,9 +890,6 @@
/* No comment provided by engineer. */
"Chat preferences" = "聊天偏好设置";
/* No comment provided by engineer. */
"Chat profile" = "用户资料";
/* No comment provided by engineer. */
"Chat theme" = "聊天主题";
@@ -1999,7 +1996,7 @@
/* No comment provided by engineer. */
"Error stopping chat" = "停止聊天错误";
/* alertTitle */
/* No comment provided by engineer. */
"Error switching profile!" = "切换资料错误!";
/* No comment provided by engineer. */
@@ -2026,7 +2023,8 @@
/* No comment provided by engineer. */
"Error: " = "错误: ";
/* alert message */
/* file error text
snd error text */
"Error: %@" = "错误: @";
/* No comment provided by engineer. */
@@ -4700,6 +4698,9 @@
/* No comment provided by engineer. */
"Use the app with one hand." = "用一只手使用应用程序。";
/* No comment provided by engineer. */
"User profile" = "用户资料";
/* No comment provided by engineer. */
"User selection" = "用户选择";
@@ -4904,6 +4905,9 @@
/* No comment provided by engineer. */
"you" = "您";
/* No comment provided by engineer. */
"You" = "您";
/* No comment provided by engineer. */
"You **must not** use the same database on two devices." = "您 **不得** 在两台设备上使用相同的数据库。";
@@ -7,12 +7,9 @@ import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.runtime.*
import chat.simplex.common.platform.*
import chat.simplex.common.views.helpers.withBGApi
import dev.icerock.moko.resources.ImageResource
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import java.util.concurrent.Executors
interface CallAudioDeviceManagerInterface {
@@ -22,7 +19,6 @@ interface CallAudioDeviceManagerInterface {
fun stop()
// AudioDeviceInfo.AudioDeviceType
fun selectLastExternalDeviceOrDefault(speaker: Boolean, keepAnyExternal: Boolean)
fun selectSameDeviceOnWebViewChange()
// AudioDeviceInfo.AudioDeviceType
fun selectDevice(id: Int)
@@ -39,15 +35,12 @@ interface CallAudioDeviceManagerInterface {
@RequiresApi(Build.VERSION_CODES.S)
class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
private val am = androidAppContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
private var resetCurrentToDevice: AudioDeviceInfo? = null
private var resetCurrentToDeviceJob: Job = Job()
override val devices: MutableState<List<AudioDeviceInfo>> = mutableStateOf(emptyList())
override val currentDevice: MutableState<AudioDeviceInfo?> = mutableStateOf(null)
private val audioCallback = object: AudioDeviceCallback() {
override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>) {
Log.d(TAG, "Added audio devices: ${addedDevices.map { it.type }}")
resetCurrentToDevice = null
super.onAudioDevicesAdded(addedDevices)
val oldDevices = devices.value
devices.value = am.availableCommunicationDevices
@@ -60,21 +53,13 @@ class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>) {
Log.d(TAG, "Removed audio devices: ${removedDevices.map { it.type }}")
resetCurrentToDevice = null
super.onAudioDevicesRemoved(removedDevices)
devices.value = am.availableCommunicationDevices
}
}
private val listener: OnCommunicationDeviceChangedListener = OnCommunicationDeviceChangedListener { device ->
val resetTo = resetCurrentToDevice
if (resetTo != null && device != null && resetTo.id != device.id) {
Log.w(TAG, "Resetting device that was set by WebView ${device.name?.localized()} to previously set device ${resetTo.name?.localized()}")
selectDevice(resetTo.id)
return@OnCommunicationDeviceChangedListener
}
devices.value = am.availableCommunicationDevices
//Log.d(TAG, "Devices changed ${device?.details()} | ${devices.value.map { it.details() }}")
currentDevice.value = device
}
@@ -113,18 +98,7 @@ class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
}
}
// WebView modifies speaker when muting/unmuting microphone. It's not needed at all, returning back current device if it will be changed
override fun selectSameDeviceOnWebViewChange() {
resetCurrentToDevice = currentDevice.value
resetCurrentToDeviceJob.cancel()
resetCurrentToDeviceJob = withBGApi {
delay(5000)
resetCurrentToDevice = null
}
}
override fun selectDevice(id: Int) {
resetCurrentToDevice = null
val device = devices.value.lastOrNull { it.id == id }
if (device != null && am.communicationDevice?.id != id ) {
am.setCommunicationDevice(device)
@@ -134,14 +108,12 @@ class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
class PreSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
private val am = androidAppContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
private var resetCurrentToDeviceJob: Job = Job()
override val devices: MutableState<List<AudioDeviceInfo>> = mutableStateOf(emptyList())
override val currentDevice: MutableState<AudioDeviceInfo?> = mutableStateOf(null)
private val audioCallback = object: AudioDeviceCallback() {
override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>) {
Log.d(TAG, "Added audio devices: ${addedDevices.map { it.type }}")
resetCurrentToDeviceJob.cancel()
super.onAudioDevicesAdded(addedDevices)
devices.value = am.getDevices(AudioManager.GET_DEVICES_OUTPUTS).filter { it.hasSupportedType() }.excludeSameType().excludeEarpieceIfWired()
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.hasVideo == true, false)
@@ -149,7 +121,6 @@ class PreSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>) {
Log.d(TAG, "Removed audio devices: ${removedDevices.map { it.type }}")
resetCurrentToDeviceJob.cancel()
super.onAudioDevicesRemoved(removedDevices)
devices.value = am.getDevices(AudioManager.GET_DEVICES_OUTPUTS).filter { it.hasSupportedType() }.excludeSameType().excludeEarpieceIfWired()
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.hasVideo == true, true)
@@ -182,22 +153,7 @@ class PreSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
}
}
override fun selectSameDeviceOnWebViewChange() {
val current = currentDevice.value ?: return
resetCurrentToDeviceJob.cancel()
resetCurrentToDeviceJob = withBGApi {
// select old device manually because WebView will change it for sure.
// smaller delay first if it's possible to make the switch less noticeable
delay(300)
selectDevice(current.id)
// and in order to be sure that it will be selected even if WebView will be slow in changing its device
delay(700)
selectDevice(current.id)
}
}
override fun selectDevice(id: Int) {
resetCurrentToDeviceJob.cancel()
val device = devices.value.lastOrNull { it.id == id }
val isExternalDevice = device != null && device.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE && device.type != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER
if (isExternalDevice) {
@@ -260,8 +216,6 @@ val AudioDeviceInfo.icon: ImageResource
else -> MR.images.ic_brand_awareness_filled
}
private fun AudioDeviceInfo.details(): String = "$productName id:$id name:${name?.localized()} type:$type sink:$isSink source:$isSource"
val AudioDeviceInfo.name: StringResource?
get() = when (this.type) {
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> MR.strings.audio_device_earpiece
@@ -202,7 +202,6 @@ actual fun ActiveCallView() {
is WCallCommand.Camera -> {
updateActiveCall(call) { it.copy(localCamera = cmd.camera) }
if (!call.localMediaSources.mic) {
callAudioDeviceManager.selectSameDeviceOnWebViewChange()
chatModel.callCommand.add(WCallCommand.Media(CallMediaSource.Mic, enable = false))
}
}
@@ -227,9 +226,8 @@ actual fun ActiveCallView() {
ActiveCallOverlay(call, chatModel, callAudioDeviceManager)
}
}
KeyChangeEffect(call?.localMediaSources?.hasVideo) {
if (call != null && call.hasVideo && callAudioDeviceManager.currentDevice.value?.type == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) {
// enabling speaker on user action (peer action ignored) and not disabling it again
KeyChangeEffect(call?.hasVideo) {
if (call != null) {
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.hasVideo, true)
}
}
@@ -262,10 +260,7 @@ private fun ActiveCallOverlay(call: Call, chatModel: ChatModel, callAudioDeviceM
devices = remember { callAudioDeviceManager.devices }.value,
currentDevice = remember { callAudioDeviceManager.currentDevice },
dismiss = { withBGApi { chatModel.callManager.endCall(call) } },
toggleAudio = {
callAudioDeviceManager.selectSameDeviceOnWebViewChange()
chatModel.callCommand.add(WCallCommand.Media(CallMediaSource.Mic, enable = !call.localMediaSources.mic))
},
toggleAudio = { chatModel.callCommand.add(WCallCommand.Media(CallMediaSource.Mic, enable = !call.localMediaSources.mic)) },
selectDevice = { callAudioDeviceManager.selectDevice(it.id) },
toggleVideo = {
if (ContextCompat.checkSelfPermission(androidAppContext, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
@@ -115,9 +115,6 @@ fun AppearanceScope.AppearanceLayout(
SectionDividerSpaced()
ThemesSection(systemDarkTheme)
SectionDividerSpaced()
MessageShapeSection()
SectionDividerSpaced()
ProfileImageSection()
@@ -71,9 +71,6 @@ object ChatModel {
val groupMembers = mutableStateListOf<GroupMember>()
val groupMembersIndexes = mutableStateMapOf<Long, Int>()
// false: default placement, true: floating window.
// Used for deciding to add terminal items on main thread or not. Floating means appPrefs.terminalAlwaysVisible
var terminalsVisible = setOf<Boolean>()
val terminalItems = mutableStateOf<List<TerminalItem>>(listOf())
val userAddress = mutableStateOf<UserContactLinkRec?>(null)
val chatItemTTL = mutableStateOf<ChatItemTTL>(ChatItemTTL.None)
@@ -775,16 +772,6 @@ object ChatModel {
fun addTerminalItem(item: TerminalItem) {
val maxItems = if (appPreferences.developerTools.get()) 500 else 200
if (terminalsVisible.isNotEmpty()) {
withApi {
addTerminalItem(item, maxItems)
}
} else {
addTerminalItem(item, maxItems)
}
}
private fun addTerminalItem(item: TerminalItem, maxItems: Int) {
if (terminalItems.value.size >= maxItems) {
terminalItems.value = terminalItems.value.subList(1, terminalItems.value.size)
}
@@ -219,8 +219,6 @@ class AppPreferences {
}, settingsThemes)
val themeOverrides = mkThemeOverridesPreference()
val profileImageCornerRadius = mkFloatPreference(SHARED_PREFS_PROFILE_IMAGE_CORNER_RADIUS, 22.5f)
val chatItemRoundness = mkFloatPreference(SHARED_PREFS_CHAT_ITEM_ROUNDNESS, 0.75f)
val chatItemTail = mkBoolPreference(SHARED_PREFS_CHAT_ITEM_TAIL, true)
val fontScale = mkFloatPreference(SHARED_PREFS_FONT_SCALE, 1f)
val densityScale = mkFloatPreference(SHARED_PREFS_DENSITY_SCALE, 1f)
@@ -424,8 +422,6 @@ class AppPreferences {
private const val SHARED_PREFS_THEMES_OLD = "Themes"
private const val SHARED_PREFS_THEME_OVERRIDES = "ThemeOverrides"
private const val SHARED_PREFS_PROFILE_IMAGE_CORNER_RADIUS = "ProfileImageCornerRadius"
private const val SHARED_PREFS_CHAT_ITEM_ROUNDNESS = "ChatItemRoundness"
private const val SHARED_PREFS_CHAT_ITEM_TAIL = "ChatItemTail"
private const val SHARED_PREFS_FONT_SCALE = "FontScale"
private const val SHARED_PREFS_DENSITY_SCALE = "DensityScale"
private const val SHARED_PREFS_WHATS_NEW_VERSION = "WhatsNewVersion"
@@ -3654,7 +3650,7 @@ data class NetCfg(
val socksMode: SocksMode = SocksMode.Always,
val hostMode: HostMode = HostMode.OnionViaSocks,
val requiredHostMode: Boolean = false,
val sessionMode: TransportSessionMode = TransportSessionMode.default,
val sessionMode: TransportSessionMode = TransportSessionMode.User,
val smpProxyMode: SMPProxyMode = SMPProxyMode.Unknown,
val smpProxyFallback: SMPProxyFallback = SMPProxyFallback.AllowProtected,
val smpWebPort: Boolean = false,
@@ -3781,13 +3777,10 @@ enum class SMPProxyFallback {
@Serializable
enum class TransportSessionMode {
@SerialName("user") User,
@SerialName("session") Session,
@SerialName("server") Server,
@SerialName("entity") Entity;
companion object {
val default = Session
val safeValues = arrayOf(User, Session, Server)
val default = User
}
}
@@ -6341,8 +6334,6 @@ data class AppSettings(
var iosCallKitEnabled: Boolean? = null,
var iosCallKitCallsInRecents: Boolean? = null,
var uiProfileImageCornerRadius: Float? = null,
var uiChatItemRoundness: Float? = null,
var uiChatItemTail: Boolean? = null,
var uiColorScheme: String? = null,
var uiDarkColorScheme: String? = null,
var uiCurrentThemeIds: Map<String, String>? = null,
@@ -6375,8 +6366,6 @@ data class AppSettings(
if (iosCallKitEnabled != def.iosCallKitEnabled) { empty.iosCallKitEnabled = iosCallKitEnabled }
if (iosCallKitCallsInRecents != def.iosCallKitCallsInRecents) { empty.iosCallKitCallsInRecents = iosCallKitCallsInRecents }
if (uiProfileImageCornerRadius != def.uiProfileImageCornerRadius) { empty.uiProfileImageCornerRadius = uiProfileImageCornerRadius }
if (uiChatItemRoundness != def.uiChatItemRoundness) { empty.uiChatItemRoundness = uiChatItemRoundness }
if (uiChatItemTail != def.uiChatItemTail) { empty.uiChatItemTail = uiChatItemTail }
if (uiColorScheme != def.uiColorScheme) { empty.uiColorScheme = uiColorScheme }
if (uiDarkColorScheme != def.uiDarkColorScheme) { empty.uiDarkColorScheme = uiDarkColorScheme }
if (uiCurrentThemeIds != def.uiCurrentThemeIds) { empty.uiCurrentThemeIds = uiCurrentThemeIds }
@@ -6420,8 +6409,6 @@ data class AppSettings(
iosCallKitEnabled?.let { def.iosCallKitEnabled.set(it) }
iosCallKitCallsInRecents?.let { def.iosCallKitCallsInRecents.set(it) }
uiProfileImageCornerRadius?.let { def.profileImageCornerRadius.set(it) }
uiChatItemRoundness?.let { def.chatItemRoundness.set(it) }
uiChatItemTail?.let { def.chatItemTail.set(it) }
uiColorScheme?.let { def.currentTheme.set(it) }
uiDarkColorScheme?.let { def.systemDarkTheme.set(it) }
uiCurrentThemeIds?.let { def.currentThemeIds.set(it) }
@@ -6455,8 +6442,6 @@ data class AppSettings(
iosCallKitEnabled = true,
iosCallKitCallsInRecents = false,
uiProfileImageCornerRadius = 22.5f,
uiChatItemRoundness = 0.75f,
uiChatItemTail = true,
uiColorScheme = DefaultTheme.SYSTEM_THEME_NAME,
uiDarkColorScheme = DefaultTheme.SIMPLEX.themeName,
uiCurrentThemeIds = null,
@@ -6491,8 +6476,6 @@ data class AppSettings(
iosCallKitEnabled = def.iosCallKitEnabled.get(),
iosCallKitCallsInRecents = def.iosCallKitCallsInRecents.get(),
uiProfileImageCornerRadius = def.profileImageCornerRadius.get(),
uiChatItemRoundness = def.chatItemRoundness.get(),
uiChatItemTail = def.chatItemTail.get(),
uiColorScheme = def.currentTheme.get() ?: DefaultTheme.SYSTEM_THEME_NAME,
uiDarkColorScheme = def.systemDarkTheme.get() ?: DefaultTheme.SIMPLEX.themeName,
uiCurrentThemeIds = def.currentThemeIds.get(),
@@ -20,12 +20,11 @@ import chat.simplex.common.views.chat.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.ChatModel
import chat.simplex.common.platform.*
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
import chat.simplex.res.MR
import dev.icerock.moko.resources.compose.stringResource
@Composable
fun TerminalView(floating: Boolean = false, close: () -> Unit) {
fun TerminalView(chatModel: ChatModel, close: () -> Unit) {
val composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = false)) }
val close = {
close()
@@ -38,7 +37,6 @@ fun TerminalView(floating: Boolean = false, close: () -> Unit) {
})
TerminalLayout(
composeState,
floating,
sendCommand = { sendCommand(chatModel, composeState) },
close
)
@@ -67,7 +65,6 @@ private fun sendCommand(chatModel: ChatModel, composeState: MutableState<Compose
@Composable
fun TerminalLayout(
composeState: MutableState<ComposeState>,
floating: Boolean,
sendCommand: () -> Unit,
close: () -> Unit
) {
@@ -121,40 +118,19 @@ fun TerminalLayout(
color = MaterialTheme.colors.background,
contentColor = LocalContentColor.current
) {
TerminalLog(floating)
TerminalLog()
}
}
}
}
@Composable
fun TerminalLog(floating: Boolean) {
fun TerminalLog() {
val reversedTerminalItems by remember {
derivedStateOf { chatModel.terminalItems.value.asReversed() }
}
val clipboard = LocalClipboardManager.current
val listState = LocalAppBarHandler.current?.listState ?: rememberLazyListState()
LaunchedEffect(Unit) {
var autoScrollToBottom = true
launch {
snapshotFlow { listState.layoutInfo.totalItemsCount }
.filter { autoScrollToBottom }
.collect {
try {
listState.scrollToItem(0)
} catch (e: Exception) {
Log.e(TAG, e.stackTraceToString())
}
}
}
launch {
snapshotFlow { listState.firstVisibleItemIndex }
.collect {
autoScrollToBottom = listState.firstVisibleItemIndex == 0
}
}
}
LazyColumnWithScrollBar(reverseLayout = true, state = listState) {
LazyColumnWithScrollBar(reverseLayout = true) {
items(reversedTerminalItems, key = { item -> item.id to item.createdAtNanos }) { item ->
val rhId = item.remoteHostId
val rhIdStr = if (rhId == null) "" else "$rhId "
@@ -166,12 +142,7 @@ fun TerminalLog(floating: Boolean) {
modifier = Modifier
.fillMaxWidth()
.clickable {
val modalPlace = if (floating) {
ModalManager.floatingTerminal
} else {
ModalManager.start
}
modalPlace.showModal(endButtons = { ShareButton { clipboard.shareText(item.details) } }) {
ModalManager.start.showModal(endButtons = { ShareButton { clipboard.shareText(item.details) } }) {
SelectionContainer(modifier = Modifier.verticalScroll(rememberScrollState())) {
val details = item.details
.let {
@@ -185,16 +156,6 @@ fun TerminalLog(floating: Boolean) {
)
}
}
DisposableEffect(Unit) {
val terminals = chatModel.terminalsVisible.toMutableSet()
terminals += floating
chatModel.terminalsVisible = terminals
onDispose {
val terminals = chatModel.terminalsVisible.toMutableSet()
terminals -= floating
chatModel.terminalsVisible = terminals
}
}
}
@Preview/*(
@@ -208,7 +169,6 @@ fun PreviewTerminalLayout() {
TerminalLayout(
composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = false)) },
sendCommand = {},
floating = false,
close = {}
)
}
@@ -83,7 +83,6 @@ enum class CallState {
@Serializable
sealed class WCallCommand {
@Serializable @SerialName("capabilities") data class Capabilities(val media: CallMediaType): WCallCommand()
@Serializable @SerialName("permission") data class Permission(val title: String, val chrome: String, val safari: String): WCallCommand()
@Serializable @SerialName("start") data class Start(val media: CallMediaType, val aesKey: String? = null, val iceServers: List<RTCIceServer>? = null, val relay: Boolean? = null): WCallCommand()
@Serializable @SerialName("offer") data class Offer(val offer: String, val iceCandidates: String, val media: CallMediaType, val aesKey: String? = null, val iceServers: List<RTCIceServer>? = null, val relay: Boolean? = null): WCallCommand()
@Serializable @SerialName("answer") data class Answer (val answer: String, val iceCandidates: String): WCallCommand()
@@ -24,10 +24,11 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.*
import chat.simplex.common.platform.*
import chat.simplex.common.views.chat.item.ItemAction
import chat.simplex.common.views.chat.item.MarkdownText
import chat.simplex.common.views.helpers.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chat.group.MemberProfileImage
import chat.simplex.common.views.chat.item.*
import chat.simplex.common.views.chatlist.*
import chat.simplex.res.MR
import dev.icerock.moko.resources.ImageResource
@@ -74,7 +75,7 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
Column {
Box(
Modifier.clipChatItem().background(itemColor).padding(bottom = 3.dp)
Modifier.clip(RoundedCornerShape(18.dp)).background(itemColor).padding(bottom = 3.dp)
.combinedClickable(onLongClick = { showMenu.value = true }, onClick = {})
.onRightClick { showMenu.value = true }
) {
@@ -121,7 +122,7 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
Column {
Box(
Modifier.clipChatItem().background(quoteColor).padding(bottom = 3.dp)
Modifier.clip(RoundedCornerShape(18.dp)).background(quoteColor).padding(bottom = 3.dp)
.combinedClickable(onLongClick = { showMenu.value = true }, onClick = {})
.onRightClick { showMenu.value = true }
) {
@@ -1036,7 +1036,7 @@ fun BoxWithConstraintsScope.ChatItemsList(
tryOrShowError("${cItem.id}ChatItem", error = {
CIBrokenComposableView(if (cItem.chatDir.sent) Alignment.CenterEnd else Alignment.CenterStart)
}) {
ChatItemView(remoteHostId, chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, revealed = revealed, range = range, fillMaxWidth = fillMaxWidth, selectedChatItems = selectedChatItems, selectChatItem = { selectUnselectChatItem(true, cItem, revealed, selectedChatItems) }, deleteMessage = deleteMessage, deleteMessages = deleteMessages, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, openDirectChat = openDirectChat, forwardItem = forwardItem, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember, scrollToItem = scrollToItem, setReaction = setReaction, showItemDetails = showItemDetails, developerTools = developerTools, showViaProxy = showViaProxy, itemSeparation = itemSeparation, showTimestamp = itemSeparation.timestamp)
ChatItemView(remoteHostId, chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, revealed = revealed, range = range, fillMaxWidth = fillMaxWidth, selectedChatItems = selectedChatItems, selectChatItem = { selectUnselectChatItem(true, cItem, revealed, selectedChatItems) }, deleteMessage = deleteMessage, deleteMessages = deleteMessages, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, openDirectChat = openDirectChat, forwardItem = forwardItem, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember, scrollToItem = scrollToItem, setReaction = setReaction, showItemDetails = showItemDetails, developerTools = developerTools, showViaProxy = showViaProxy, showTimestamp = itemSeparation.timestamp)
}
}
@@ -1081,15 +1081,6 @@ fun BoxWithConstraintsScope.ChatItemsList(
}
}
@Composable
fun adjustTailPaddingOffset(originalPadding: Dp, start: Boolean): Dp {
val chatItemTail = remember { appPreferences.chatItemTail.state }
val style = shapeStyle(cItem, chatItemTail.value, itemSeparation.largeGap, true)
val tailRendered = style is ShapeStyle.Bubble && style.tailVisible
return originalPadding + (if (tailRendered) 0.dp else if (start) msgTailWidthDp * 2 else msgTailWidthDp)
}
Box {
val voiceWithTransparentBack = cItem.content.msgContent is MsgContent.MCVoice && cItem.content.text.isEmpty() && cItem.quotedItem == null && cItem.meta.itemForwarded == null
val selectionVisible = selectedChatItems.value != null && cItem.canBeDeletedForSelf
@@ -1108,7 +1099,7 @@ fun BoxWithConstraintsScope.ChatItemsList(
Column(
Modifier
.padding(top = 8.dp)
.padding(start = 8.dp, end = if (voiceWithTransparentBack) 12.dp else adjustTailPaddingOffset(66.dp, start = false))
.padding(start = 8.dp, end = if (voiceWithTransparentBack) 12.dp else 66.dp)
.fillMaxWidth()
.then(swipeableModifier),
verticalArrangement = Arrangement.spacedBy(4.dp),
@@ -1120,7 +1111,7 @@ fun BoxWithConstraintsScope.ChatItemsList(
Text(
memberNames(member, prevMember, memCount),
Modifier
.padding(start = (MEMBER_IMAGE_SIZE * fontSizeSqrtMultiplier) + DEFAULT_PADDING_HALF)
.padding(start = MEMBER_IMAGE_SIZE + DEFAULT_PADDING_HALF)
.weight(1f, false),
fontSize = 13.5.sp,
color = MaterialTheme.colors.secondary,
@@ -1128,13 +1119,9 @@ fun BoxWithConstraintsScope.ChatItemsList(
maxLines = 1
)
if (memCount == 1 && member.memberRole > GroupMemberRole.Member) {
val chatItemTail = remember { appPreferences.chatItemTail.state }
val style = shapeStyle(cItem, chatItemTail.value, itemSeparation.largeGap, true)
val tailRendered = style is ShapeStyle.Bubble && style.tailVisible
Text(
member.memberRole.text,
Modifier.padding(start = DEFAULT_PADDING_HALF * 1.5f, end = DEFAULT_PADDING_HALF + if (tailRendered) msgTailWidthDp else 0.dp),
Modifier.padding(start = DEFAULT_PADDING_HALF * 1.5f, end = DEFAULT_PADDING_HALF),
fontSize = 13.5.sp,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colors.secondary,
@@ -1150,11 +1137,12 @@ fun BoxWithConstraintsScope.ChatItemsList(
androidx.compose.animation.AnimatedVisibility(selectionVisible, enter = fadeIn(), exit = fadeOut()) {
SelectedChatItem(Modifier, cItem.id, selectedChatItems)
}
Row(Modifier.graphicsLayer { translationX = selectionOffset.toPx() }) {
Row(Modifier.graphicsLayer { translationX = selectionOffset.toPx() },
horizontalArrangement = Arrangement.spacedBy(4.dp)) {
Box(Modifier.clickable { showMemberInfo(chatInfo.groupInfo, member) }) {
MemberImage(member)
}
Box(modifier = Modifier.padding(top = 2.dp, start = 4.dp).chatItemOffset(cItem, itemSeparation.largeGap, revealed = revealed.value)) {
Box(modifier = Modifier.padding(top = 2.dp)) {
ChatItemViewShortHand(cItem, itemSeparation, range, false)
}
}
@@ -1176,8 +1164,7 @@ fun BoxWithConstraintsScope.ChatItemsList(
}
Row(
Modifier
.padding(start = 8.dp + (MEMBER_IMAGE_SIZE * fontSizeSqrtMultiplier) + 4.dp, end = if (voiceWithTransparentBack) 12.dp else adjustTailPaddingOffset(66.dp, start = false))
.chatItemOffset(cItem, itemSeparation.largeGap, revealed = revealed.value)
.padding(start = 8.dp + MEMBER_IMAGE_SIZE + 4.dp, end = if (voiceWithTransparentBack) 12.dp else 66.dp)
.then(swipeableOrSelectionModifier)
) {
ChatItemViewShortHand(cItem, itemSeparation, range)
@@ -1191,8 +1178,7 @@ fun BoxWithConstraintsScope.ChatItemsList(
}
Box(
Modifier
.padding(start = if (voiceWithTransparentBack) 12.dp else adjustTailPaddingOffset(104.dp, start = true), end = 12.dp)
.chatItemOffset(cItem, itemSeparation.largeGap, revealed = revealed.value)
.padding(start = if (voiceWithTransparentBack) 12.dp else 104.dp, end = 12.dp)
.then(if (selectionVisible) Modifier else swipeableModifier)
) {
ChatItemViewShortHand(cItem, itemSeparation, range)
@@ -1204,14 +1190,11 @@ fun BoxWithConstraintsScope.ChatItemsList(
AnimatedVisibility (selectionVisible, enter = fadeIn(), exit = fadeOut()) {
SelectedChatItem(Modifier.padding(start = 8.dp), cItem.id, selectedChatItems)
}
Box(
Modifier.padding(
start = if (sent && !voiceWithTransparentBack) adjustTailPaddingOffset(76.dp, start = true) else 12.dp,
end = if (sent || voiceWithTransparentBack) 12.dp else adjustTailPaddingOffset(76.dp, start = false),
)
.chatItemOffset(cItem, itemSeparation.largeGap, revealed = revealed.value)
.then(if (!selectionVisible || !sent) swipeableOrSelectionModifier else Modifier)
start = if (sent && !voiceWithTransparentBack) 76.dp else 12.dp,
end = if (sent || voiceWithTransparentBack) 12.dp else 76.dp,
).then(if (!selectionVisible || !sent) swipeableOrSelectionModifier else Modifier)
) {
ChatItemViewShortHand(cItem, itemSeparation, range)
}
@@ -59,8 +59,7 @@ fun SelectedItemsBottomToolbar(
val canModerate = remember { mutableStateOf(false) }
val moderateEnabled = remember { mutableStateOf(false) }
val forwardEnabled = remember { mutableStateOf(false) }
val deleteCountProhibited = remember { mutableStateOf(false) }
val forwardCountProhibited = remember { mutableStateOf(false) }
val allButtonsDisabled = remember { mutableStateOf(false) }
Box {
// It's hard to measure exact height of ComposeView with different fontSizes. Better to depend on actual ComposeView, even empty
ComposeView(chatModel = chatModel, Chat.sampleData, remember { mutableStateOf(ComposeState(useLinkPreviews = false)) }, remember { mutableStateOf(null) }, {})
@@ -76,36 +75,36 @@ fun SelectedItemsBottomToolbar(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
IconButton({ deleteItems(deleteForEveryoneEnabled.value) }, enabled = deleteEnabled.value && !deleteCountProhibited.value) {
IconButton({ deleteItems(deleteForEveryoneEnabled.value) }, enabled = deleteEnabled.value && !allButtonsDisabled.value) {
Icon(
painterResource(MR.images.ic_delete),
null,
Modifier.size(22.dp),
tint = if (!deleteEnabled.value || deleteCountProhibited.value) MaterialTheme.colors.secondary else MaterialTheme.colors.error
tint = if (!deleteEnabled.value || allButtonsDisabled.value) MaterialTheme.colors.secondary else MaterialTheme.colors.error
)
}
IconButton({ moderateItems() }, Modifier.alpha(if (canModerate.value) 1f else 0f), enabled = moderateEnabled.value && !deleteCountProhibited.value) {
IconButton({ moderateItems() }, Modifier.alpha(if (canModerate.value) 1f else 0f), enabled = moderateEnabled.value && !allButtonsDisabled.value) {
Icon(
painterResource(MR.images.ic_flag),
null,
Modifier.size(22.dp),
tint = if (!moderateEnabled.value || deleteCountProhibited.value) MaterialTheme.colors.secondary else MaterialTheme.colors.error
tint = if (!moderateEnabled.value || allButtonsDisabled.value) MaterialTheme.colors.secondary else MaterialTheme.colors.error
)
}
IconButton({ forwardItems() }, enabled = forwardEnabled.value && !forwardCountProhibited.value) {
IconButton({ forwardItems() }, enabled = forwardEnabled.value && !allButtonsDisabled.value) {
Icon(
painterResource(MR.images.ic_forward),
null,
Modifier.size(22.dp),
tint = if (!forwardEnabled.value || forwardCountProhibited.value) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
tint = if (!forwardEnabled.value || allButtonsDisabled.value) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
)
}
}
}
LaunchedEffect(chatInfo, chatItems, selectedChatItems.value) {
recheckItems(chatInfo, chatItems, selectedChatItems, deleteEnabled, deleteForEveryoneEnabled, canModerate, moderateEnabled, forwardEnabled, deleteCountProhibited, forwardCountProhibited)
recheckItems(chatInfo, chatItems, selectedChatItems, deleteEnabled, deleteForEveryoneEnabled, canModerate, moderateEnabled, forwardEnabled, allButtonsDisabled)
}
}
@@ -117,12 +116,10 @@ private fun recheckItems(chatInfo: ChatInfo,
canModerate: MutableState<Boolean>,
moderateEnabled: MutableState<Boolean>,
forwardEnabled: MutableState<Boolean>,
deleteCountProhibited: MutableState<Boolean>,
forwardCountProhibited: MutableState<Boolean>
allButtonsDisabled: MutableState<Boolean>
) {
val count = selectedChatItems.value?.size ?: 0
deleteCountProhibited.value = count == 0 || count > 200
forwardCountProhibited.value = count == 0 || count > 20
allButtonsDisabled.value = count == 0 || count > 20
canModerate.value = possibleToModerate(chatInfo)
val selected = selectedChatItems.value ?: return
var rDeleteEnabled = true
@@ -3,14 +3,13 @@ package chat.simplex.common.views.chat.item
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.*
@@ -27,16 +26,9 @@ import chat.simplex.common.views.chat.*
import chat.simplex.common.views.helpers.*
import chat.simplex.res.MR
import kotlinx.datetime.Clock
import kotlin.math.*
// TODO refactor so that FramedItemView can show all CIContent items if they're deleted (see Swift code)
private val msgRectMaxRadius = 18.dp
private val msgBubbleMaxRadius = msgRectMaxRadius * 1.2f
val msgTailWidthDp = 9.dp
private val msgTailMinHeightDp = msgTailWidthDp * 1.254f // ~56deg
private val msgTailMaxHeightDp = msgTailWidthDp * 1.732f // 60deg
val chatEventStyle = SpanStyle(fontSize = 12.sp, fontWeight = FontWeight.Light, color = CurrentColors.value.colors.secondary)
fun chatEventText(ci: ChatItem): AnnotatedString =
@@ -82,7 +74,6 @@ fun ChatItemView(
developerTools: Boolean,
showViaProxy: Boolean,
showTimestamp: Boolean,
itemSeparation: ItemSeparation,
preview: Boolean = false,
) {
val uriHandler = LocalUriHandler.current
@@ -109,7 +100,7 @@ fun ChatItemView(
@Composable
fun ChatItemReactions() {
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.chatItemOffset(cItem, itemSeparation.largeGap, inverted = true, revealed = true)) {
Row(verticalAlignment = Alignment.CenterVertically) {
cItem.reactions.forEach { r ->
var modifier = Modifier.padding(horizontal = 5.dp, vertical = 2.dp).clip(RoundedCornerShape(8.dp))
if (cInfo.featureEnabled(ChatFeature.Reactions) && (cItem.allowAddReaction || r.userReacted)) {
@@ -136,13 +127,13 @@ fun ChatItemView(
Column(horizontalAlignment = if (cItem.chatDir.sent) Alignment.End else Alignment.Start) {
Column(
Modifier
.clipChatItem(cItem, itemSeparation.largeGap, revealed.value)
.clip(RoundedCornerShape(18.dp))
.combinedClickable(onLongClick = { showMenu.value = true }, onClick = onClick)
.onRightClick { showMenu.value = true },
) {
@Composable
fun framedItemView() {
FramedItemView(cInfo, cItem, uriHandler, imageProvider, linkMode = linkMode, showViaProxy = showViaProxy, showMenu, showTimestamp = showTimestamp, tailVisible = itemSeparation.largeGap, receiveFile, onLinkLongClick, scrollToItem)
FramedItemView(cInfo, cItem, uriHandler, imageProvider, linkMode = linkMode, showViaProxy = showViaProxy, showMenu, showTimestamp = showTimestamp, receiveFile, onLinkLongClick, scrollToItem)
}
fun deleteMessageQuestionText(): String {
@@ -804,154 +795,6 @@ fun ItemAction(text: String, color: Color = Color.Unspecified, onClick: () -> Un
}
}
@Composable
fun Modifier.chatItemOffset(cItem: ChatItem, tailVisible: Boolean, inverted: Boolean = false, revealed: Boolean): Modifier {
val chatItemTail = remember { appPreferences.chatItemTail.state }
val style = shapeStyle(cItem, chatItemTail.value, tailVisible, revealed)
val offset = if (style is ShapeStyle.Bubble) {
if (style.tailVisible) {
if (cItem.chatDir.sent) msgTailWidthDp else -msgTailWidthDp
} else {
0.dp
}
} else 0.dp
return this.offset(x = if (inverted) (-1f * offset) else offset)
}
@Composable
fun Modifier.clipChatItem(chatItem: ChatItem? = null, tailVisible: Boolean = false, revealed: Boolean = false): Modifier {
val chatItemRoundness = remember { appPreferences.chatItemRoundness.state }
val chatItemTail = remember { appPreferences.chatItemTail.state }
val style = shapeStyle(chatItem, chatItemTail.value, tailVisible, revealed)
val cornerRoundness = chatItemRoundness.value.coerceIn(0f, 1f)
val shape = when (style) {
is ShapeStyle.Bubble -> chatItemShape(cornerRoundness, LocalDensity.current, style.tailVisible, chatItem?.chatDir?.sent == true)
is ShapeStyle.RoundRect -> RoundedCornerShape(style.radius * cornerRoundness)
}
return this.clip(shape)
}
private fun chatItemShape(roundness: Float, density: Density, tailVisible: Boolean, sent: Boolean = false): GenericShape = GenericShape { size, _ ->
val (msgTailWidth, msgBubbleMaxRadius) = with(density) { Pair(msgTailWidthDp.toPx(), msgBubbleMaxRadius.toPx()) }
val width = if (sent && tailVisible) size.width - msgTailWidth else size.width
val height = size.height
val rxMax = min(msgBubbleMaxRadius, width / 2)
val ryMax = min(msgBubbleMaxRadius, height / 2)
val rx = roundness * rxMax
val ry = roundness * ryMax
val tailHeight = with(density) {
min(
msgTailMinHeightDp.toPx() + roundness * (msgTailMaxHeightDp.toPx() - msgTailMinHeightDp.toPx()),
height / 2
)
}
moveTo(rx, 0f)
lineTo(width - rx, 0f) // Top Line
if (roundness > 0) {
quadraticBezierTo(width, 0f, width, ry) // Top-right corner
}
if (height > 2 * ry) {
lineTo(width, height - ry) // Right side
}
if (roundness > 0) {
quadraticBezierTo(width, height, width - rx, height) // Bottom-right corner
}
if (tailVisible) {
lineTo(0f, height) // Bottom line
if (roundness > 0) {
val d = tailHeight - msgTailWidth * msgTailWidth / tailHeight
val controlPoint = Offset(msgTailWidth, height - tailHeight + d * sqrt(roundness))
quadraticBezierTo(controlPoint.x, controlPoint.y, msgTailWidth, height - tailHeight)
} else {
lineTo(msgTailWidth, height - tailHeight)
}
if (height > ry + tailHeight) {
lineTo(msgTailWidth, ry)
}
} else {
lineTo(rx, height) // Bottom line
if (roundness > 0) {
quadraticBezierTo(0f, height, 0f, height - ry) // Bottom-left corner
}
if (height > 2 * ry) {
lineTo(0f, ry) // Left side
}
}
if (roundness > 0) {
val bubbleInitialX = if (tailVisible) msgTailWidth else 0f
quadraticBezierTo(bubbleInitialX, 0f, bubbleInitialX + rx, 0f) // Top-left corner
}
if (sent) {
val matrix = Matrix()
matrix.scale(-1f, 1f)
this.transform(matrix)
this.translate(Offset(size.width, 0f))
}
}
sealed class ShapeStyle {
data class Bubble(val tailVisible: Boolean, val startPadding: Boolean) : ShapeStyle()
data class RoundRect(val radius: Dp) : ShapeStyle()
}
fun shapeStyle(chatItem: ChatItem? = null, tailEnabled: Boolean, tailVisible: Boolean, revealed: Boolean): ShapeStyle {
if (chatItem == null) {
return ShapeStyle.RoundRect(msgRectMaxRadius)
}
when (chatItem.content) {
is CIContent.SndMsgContent,
is CIContent.RcvMsgContent,
is CIContent.RcvDecryptionError,
is CIContent.SndDeleted,
is CIContent.RcvDeleted,
is CIContent.RcvIntegrityError,
is CIContent.SndModerated,
is CIContent.RcvModerated,
is CIContent.RcvBlocked,
is CIContent.InvalidJSON -> {
if (chatItem.meta.itemDeleted != null && (!revealed || chatItem.isDeletedContent)) {
return ShapeStyle.RoundRect(msgRectMaxRadius)
}
val tail = when (val content = chatItem.content.msgContent) {
is MsgContent.MCImage,
is MsgContent.MCVideo,
is MsgContent.MCVoice -> {
if (content.text.isEmpty()) {
false
} else {
tailVisible
}
}
is MsgContent.MCText -> {
if (isShortEmoji(content.text)) {
false
} else {
tailVisible
}
}
else -> tailVisible
}
return if (tailEnabled) {
ShapeStyle.Bubble(tail, !chatItem.chatDir.sent)
} else {
ShapeStyle.RoundRect(msgRectMaxRadius)
}
}
is CIContent.RcvGroupInvitation,
is CIContent.SndGroupInvitation -> return ShapeStyle.RoundRect(msgRectMaxRadius)
else -> return ShapeStyle.RoundRect(8.dp)
}
}
fun cancelFileAlertDialog(fileId: Long, cancelFile: (Long) -> Unit, cancelAction: CancelAction) {
AlertManager.shared.showAlertDialog(
title = generalGetString(cancelAction.alert.titleId),
@@ -1088,7 +931,6 @@ fun PreviewChatItemView(
showViaProxy = false,
showTimestamp = true,
preview = true,
itemSeparation = ItemSeparation(timestamp = true, largeGap = true, null)
)
}
@@ -1128,8 +970,7 @@ fun PreviewChatItemViewDeletedContent() {
developerTools = false,
showViaProxy = false,
preview = true,
showTimestamp = true,
itemSeparation = ItemSeparation(timestamp = true, largeGap = true, null)
showTimestamp = true
)
}
}
@@ -2,10 +2,12 @@ package chat.simplex.common.views.chat.item
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
@@ -34,7 +36,6 @@ fun FramedItemView(
showViaProxy: Boolean,
showMenu: MutableState<Boolean>,
showTimestamp: Boolean,
tailVisible: Boolean = false,
receiveFile: (Long) -> Unit,
onLinkLongClick: (link: String) -> Unit = {},
scrollToItem: (Long) -> Unit = {},
@@ -189,7 +190,7 @@ fun FramedItemView(
val sentColor = MaterialTheme.appColors.sentMessage
val receivedColor = MaterialTheme.appColors.receivedMessage
Box(Modifier
.clipChatItem(ci, tailVisible, revealed = true)
.clip(RoundedCornerShape(18.dp))
.background(
when {
transparentBackground -> Color.Transparent
@@ -199,14 +200,7 @@ fun FramedItemView(
)) {
var metaColor = MaterialTheme.colors.secondary
Box(contentAlignment = Alignment.BottomEnd) {
val chatItemTail = remember { appPreferences.chatItemTail.state }
val style = shapeStyle(ci, chatItemTail.value, tailVisible, revealed = true)
val tailRendered = style is ShapeStyle.Bubble && style.tailVisible
Column(
Modifier
.width(IntrinsicSize.Max)
.padding(start = if (tailRendered) msgTailWidthDp else 0.dp, end = if (sent && tailRendered) msgTailWidthDp else 0.dp)
) {
Column(Modifier.width(IntrinsicSize.Max)) {
PriorityLayout(Modifier, CHAT_IMAGE_LAYOUT_ID) {
if (ci.meta.itemDeleted != null) {
when (ci.meta.itemDeleted) {
@@ -285,13 +279,7 @@ fun FramedItemView(
}
}
}
Box(
Modifier
.padding(
bottom = 6.dp,
end = 12.dp + if (tailRendered && sent) msgTailWidthDp else 0.dp,
)
) {
Box(Modifier.padding(bottom = 6.dp, end = 12.dp)) {
CIMetaView(ci, chatTTL, metaColor, showViaProxy = showViaProxy, showTimestamp = showTimestamp)
}
}
@@ -341,8 +341,7 @@ private fun GlobalSettingsSection(
ModalManager.start.showCustomModal { close ->
ConnectDesktopView(close)
}
},
disabled = stopped
}
)
} else {
UserPickerOptionRow(
@@ -2,8 +2,10 @@ package chat.simplex.common.views.helpers
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
@@ -207,14 +209,11 @@ class ModalManager(private val placement: ModalPlacement? = null) {
val end = if (appPlatform.isAndroid) shared else ModalManager(ModalPlacement.END)
val fullscreen = if (appPlatform.isAndroid) shared else ModalManager(ModalPlacement.FULLSCREEN)
val floatingTerminal = if (appPlatform.isAndroid) shared else ModalManager(ModalPlacement.START)
fun closeAllModalsEverywhere() {
start.closeModals()
center.closeModals()
end.closeModals()
fullscreen.closeModals()
floatingTerminal.closeModals()
}
@OptIn(ExperimentalAnimationApi::class)
@@ -321,19 +321,17 @@ fun ActiveProfilePicker(
}
}
if ((contactConnection != null && updatedConn != null) || contactConnection == null) {
controller.changeActiveUser_(
rhId = user.remoteHostId,
toUserId = user.userId,
viewPwd = if (user.hidden) searchTextOrPassword.value else null
)
controller.changeActiveUser_(
rhId = user.remoteHostId,
toUserId = user.userId,
viewPwd = if (user.hidden) searchTextOrPassword.value else null
)
if (chatModel.currentUser.value?.userId != user.userId) {
AlertManager.shared.showAlertMsg(generalGetString(
MR.strings.switching_profile_error_title),
String.format(generalGetString(MR.strings.switching_profile_error_message), user.chatViewName)
)
}
if (chatModel.currentUser.value?.userId != user.userId) {
AlertManager.shared.showAlertMsg(generalGetString(
MR.strings.switching_profile_error_title),
String.format(generalGetString(MR.strings.switching_profile_error_message), user.chatViewName)
)
}
if (updatedConn != null) {
@@ -53,8 +53,7 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
maxLines = 2,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.h4,
fontWeight = FontWeight.Medium,
modifier = Modifier.padding(bottom = 6.dp)
fontWeight = FontWeight.Medium
)
if (link != null) {
linkButton(link)
@@ -65,7 +64,7 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.padding(bottom = 6.dp)
modifier = Modifier.padding(bottom = 4.dp)
) {
Icon(painterResource(si), stringResource(sd), tint = MaterialTheme.colors.secondary)
Text(generalGetString(sd), fontSize = 15.sp)
@@ -649,36 +648,7 @@ private val versionDescriptions: List<VersionDescription> = listOf(
show = appPlatform.isDesktop
),
),
),
VersionDescription(
version = "v6.1",
post = "https://simplex.chat/blog/20241014-simplex-network-v6-1-security-review-better-calls-user-experience.html",
features = listOf(
FeatureDescription(
icon = MR.images.ic_verified_user,
titleId = MR.strings.v6_1_better_security,
descrId = MR.strings.v6_1_better_security_descr,
link = "https://simplex.chat/blog/20241014-simplex-network-v6-1-security-review-better-calls-user-experience.html"
),
FeatureDescription(
icon = MR.images.ic_videocam,
titleId = MR.strings.v6_1_better_calls,
descrId = MR.strings.v6_1_better_calls_descr
),
FeatureDescription(
icon = null,
titleId = MR.strings.v6_1_better_user_experience,
descrId = null,
subfeatures = listOf(
MR.images.ic_link to MR.strings.v6_1_switch_chat_profile_descr,
MR.images.ic_chat to MR.strings.v6_1_customizable_message_descr,
MR.images.ic_calendar to MR.strings.v6_1_message_dates_descr,
MR.images.ic_forward to MR.strings.v6_1_forward_many_messages_descr,
MR.images.ic_delete to MR.strings.v6_1_delete_many_messages_descr
)
),
),
),
)
)
private val lastVersion = versionDescriptions.last().version
@@ -218,7 +218,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U
SectionDividerSpaced(maxTopPadding = true)
}
if (currentRemoteHost == null) {
if (currentRemoteHost == null && developerTools) {
SectionView(stringResource(MR.strings.network_session_mode_transport_isolation).uppercase()) {
SessionModePicker(sessionMode, showModal, updateSessionMode)
}
@@ -35,7 +35,6 @@ import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.ThemeManager.colorFromReadableHex
import chat.simplex.common.ui.theme.ThemeManager.toReadableHex
import chat.simplex.common.views.chat.item.PreviewChatItemView
import chat.simplex.common.views.chat.item.msgTailWidthDp
import chat.simplex.res.MR
import com.godaddy.android.colorpicker.ClassicColorPicker
import com.godaddy.android.colorpicker.HsvColor
@@ -85,31 +84,6 @@ object AppearanceScope {
}
}
@Composable
fun MessageShapeSection() {
SectionView(stringResource(MR.strings.settings_section_title_message_shape).uppercase(), contentPadding = PaddingValues()) {
Row(modifier = Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING + 4.dp ) ,verticalAlignment = Alignment.CenterVertically) {
Text(stringResource(MR.strings.settings_message_shape_corner), color = colors.onBackground)
Spacer(Modifier.width(10.dp))
Slider(
remember { appPreferences.chatItemRoundness.state }.value,
valueRange = 0f..1f,
steps = 20,
onValueChange = {
val diff = it % 0.05f
appPreferences.chatItemRoundness.set(it + (if (diff >= 0.025f) -diff + 0.05f else -diff))
saveThemeToDatabase(null)
},
colors = SliderDefaults.colors(
activeTickColor = Color.Transparent,
inactiveTickColor = Color.Transparent,
)
)
}
SettingsPreferenceItem(icon = null, stringResource(MR.strings.settings_message_shape_tail), appPreferences.chatItemTail)
}
}
@Composable
fun FontScaleSection() {
val localFontScale = remember { mutableStateOf(appPrefs.fontScale.get()) }
@@ -195,17 +169,13 @@ object AppearanceScope {
.padding(DEFAULT_PADDING_HALF)
) {
if (withMessages) {
val chatItemTail = remember { appPreferences.chatItemTail.state }
Column(verticalArrangement = Arrangement.spacedBy(4.dp), modifier = if (chatItemTail.value) Modifier else Modifier.padding(horizontal = msgTailWidthDp)) {
val alice = remember { ChatItem.getSampleData(1, CIDirection.DirectRcv(), Clock.System.now(), generalGetString(MR.strings.wallpaper_preview_hello_bob)) }
PreviewChatItemView(alice)
PreviewChatItemView(
ChatItem.getSampleData(2, CIDirection.DirectSnd(), Clock.System.now(), stringResource(MR.strings.wallpaper_preview_hello_alice),
quotedItem = CIQuote(alice.chatDir, alice.id, sentAt = alice.meta.itemTs, formattedText = alice.formattedText, content = MsgContent.MCText(alice.content.text))
)
)
}
val alice = remember { ChatItem.getSampleData(1, CIDirection.DirectRcv(), Clock.System.now(), generalGetString(MR.strings.wallpaper_preview_hello_bob)) }
PreviewChatItemView(alice)
PreviewChatItemView(
ChatItem.getSampleData(2, CIDirection.DirectSnd(), Clock.System.now(), stringResource(MR.strings.wallpaper_preview_hello_alice),
quotedItem = CIQuote(alice.chatDir, alice.id, sentAt = alice.meta.itemTs, formattedText = alice.formattedText, content = MsgContent.MCText(alice.content.text))
)
)
} else {
Box(Modifier.fillMaxSize())
}
@@ -35,7 +35,7 @@ fun DeveloperView(
val unchangedHints = mutableStateOf(unchangedHintPreferences())
SectionView {
InstallTerminalAppItem(uriHandler)
ChatConsoleItem { withAuth(generalGetString(MR.strings.auth_open_chat_console), generalGetString(MR.strings.auth_log_in_using_credential), showCustomModal { it, close -> TerminalView(false, close) }) }
ChatConsoleItem { withAuth(generalGetString(MR.strings.auth_open_chat_console), generalGetString(MR.strings.auth_log_in_using_credential), showCustomModal { it, close -> TerminalView(it, close) }) }
ResetHintsItem(unchangedHints)
SettingsPreferenceItem(painterResource(MR.images.ic_code), stringResource(MR.strings.show_developer_options), developerTools)
SectionTextFooter(
@@ -164,7 +164,9 @@ fun NetworkAndServersView() {
val showCustomModal = { it: @Composable (close: () -> Unit) -> Unit -> ModalManager.fullscreen.showCustomModal { close -> it(close) }}
UseSocksProxySwitch(networkUseSocksProxy, toggleSocksProxy)
SettingsActionItem(painterResource(MR.images.ic_settings_ethernet), stringResource(MR.strings.network_socks_proxy_settings), { showCustomModal { SocksProxySettings(networkUseSocksProxy.value, networkProxy, onionHosts, sessionMode.value, true, it) } })
SessionModePicker(sessionMode, showModal, updateSessionMode)
if (developerTools) {
SessionModePicker(sessionMode, showModal, updateSessionMode)
}
}
@Composable
@@ -456,17 +458,9 @@ fun SessionModePicker(
) {
val density = LocalDensity.current
val values = remember {
val safeModes = TransportSessionMode.safeValues
val modes: Array<TransportSessionMode> =
if (appPrefs.developerTools.get()) TransportSessionMode.values()
else if (safeModes.contains(sessionMode.value)) safeModes
else safeModes + sessionMode.value
modes.map {
val userModeDescr: AnnotatedString = escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_session_mode_user_description), density)
TransportSessionMode.values().map {
when (it) {
TransportSessionMode.User -> ValueTitleDesc(TransportSessionMode.User, generalGetString(MR.strings.network_session_mode_user), userModeDescr)
TransportSessionMode.Session -> ValueTitleDesc(TransportSessionMode.Session, generalGetString(MR.strings.network_session_mode_session), userModeDescr + AnnotatedString("\n") + escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_session_mode_session_description), density))
TransportSessionMode.Server -> ValueTitleDesc(TransportSessionMode.Server, generalGetString(MR.strings.network_session_mode_server), userModeDescr + AnnotatedString("\n") + escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_session_mode_server_description), density))
TransportSessionMode.User -> ValueTitleDesc(TransportSessionMode.User, generalGetString(MR.strings.network_session_mode_user), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_session_mode_user_description), density))
TransportSessionMode.Entity -> ValueTitleDesc(TransportSessionMode.Entity, generalGetString(MR.strings.network_session_mode_entity), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_session_mode_entity_description), density))
}
}
@@ -1265,8 +1265,8 @@
<string name="you_can_share_your_address">يمكنك مشاركة عنوانك كرابط أو رمز QR - يمكن لأي شخص الاتصال بك.</string>
<string name="you_can_create_it_later">يمكنك إنشاؤه لاحقًا</string>
<string name="invite_prohibited_description">أنت تحاول دعوة جهة اتصال قمت بمشاركة ملف تعريف متخفي معها إلى المجموعة التي تستخدم فيها ملفك الشخصي الرئيسي</string>
<string name="user_unmute">ألغِ الكتم</string>
<string name="unmute_chat">ألغِ الكتم</string>
<string name="user_unmute">إلغاء الكتم</string>
<string name="unmute_chat">إلغاء الكتم</string>
<string name="you_accepted_connection">لقد قبلت الاتصال</string>
<string name="unhide_profile">إلغاء إخفاء ملف تعريف</string>
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">يجب أن تكون جهة الاتصال متصلة بالإنترنت حتى يكتمل الاتصال.
@@ -2090,39 +2090,4 @@
<string name="switching_profile_error_title">خطأ في تبديل الملف الشخصي</string>
<string name="select_chat_profile">حدد ملف تعريف الدردشة</string>
<string name="switching_profile_error_message">لقد تم نقل اتصالك إلى %s ولكن حدث خطأ غير متوقع أثناء إعادة توجيهك إلى الملف الشخصي.</string>
<string name="forward_alert_title_messages_to_forward">تحويل %1$s رسالة؟</string>
<string name="forward_files_messages_deleted_after_selection_title">لم يحوّل %1$s من الرسائل</string>
<string name="compose_forward_messages_n">جارِ تحويل %1$s رسالة</string>
<string name="forward_multiple">حوّل الرسائل…</string>
<string name="forward_alert_forward_messages_without_files">تحويل الرسائل بدون ملفات؟</string>
<string name="compose_save_messages_n">جارِ حفظ %1$s رسالة</string>
<string name="network_proxy_incorrect_config_desc">تأكد من صحة تضبيط الوكيل.</string>
<string name="n_other_file_errors">%1$d خطأ في ملف آخر.</string>
<string name="forward_files_messages_deleted_after_selection_desc">حُذفت الرسائل بعد تحديدها.</string>
<string name="forward_alert_title_nothing_to_forward">لا يوجد شيء لتحويله!</string>
<string name="network_proxy_password">كلمة المرور</string>
<string name="network_proxy_auth">استيثاق الوكيل</string>
<string name="delete_messages_cannot_be_undone_warning">سيتم حذف الرسائل - لا يمكن التراجع عن هذا!</string>
<string name="icon_descr_sound_muted">الصوت مكتوم</string>
<string name="error_initializing_web_view_wrong_arch">حدث خطأ أثناء تهيئة WebView. تأكد من تثبيت WebView وأن بنيته المدعومة هي arm64.\nالخطأ: %s</string>
<string name="settings_section_title_message_shape">شكل الرسالة</string>
<string name="settings_message_shape_tail">ذيل</string>
<string name="settings_message_shape_corner">ركن</string>
<string name="network_session_mode_session">جلسة التطبيق</string>
<string name="network_session_mode_server">الخادم</string>
<string name="network_session_mode_session_description">سيتم استخدام بيانات اعتماد SOCKS الجديدة في كل مرة تبدأ فيها تشغيل التطبيق.</string>
<string name="network_session_mode_server_description">سيتم استخدام بيانات اعتماد SOCKS الجديدة لكل خادم.</string>
<string name="call_desktop_permission_denied_chrome">انقر فوق زر المعلومات الموجود بالقرب من حقل العنوان للسماح باستخدام الميكروفون.</string>
<string name="call_desktop_permission_denied_safari">افتح إعدادات Safari / مواقع الويب / الميكروفون، ثم اختر السماح لـ localhost.</string>
<string name="call_desktop_permission_denied_title">لإجراء مكالمات، اسمح باستخدام الميكروفون. أنهِ المكالمة وحاول الاتصال مرة أخرى.</string>
<string name="v6_1_better_user_experience">تجربة مستخدم أفضل</string>
<string name="v6_1_customizable_message_descr">شكل الرسالة قابل للتخصيص.</string>
<string name="v6_1_better_calls_descr">تبديل الصوت والفيديو أثناء المكالمة.</string>
<string name="v6_1_delete_many_messages_descr">حذف أو إشراف ما يصل إلى 200 رسالة.</string>
<string name="v6_1_forward_many_messages_descr">حوّل ما يصل إلى 20 رسالة آن واحد.</string>
<string name="v6_1_better_calls">مكالمات أفضل</string>
<string name="v6_1_message_dates_descr">تواريخ أفضل للرسائل.</string>
<string name="v6_1_better_security">أمان أفضل ✅</string>
<string name="v6_1_better_security_descr">بروتوكولات SimpleX تمت مراجعتها بواسطة Trail of Bits.</string>
<string name="v6_1_switch_chat_profile_descr">تبديل ملف تعريف الدردشة لدعوات لمرة واحدة.</string>
</resources>
@@ -811,12 +811,8 @@
<string name="network_use_onion_hosts_required_desc">Onion hosts will be required for connection.\nPlease note: you will not be able to connect to the servers without .onion address.</string>
<string name="network_session_mode_transport_isolation">Transport isolation</string>
<string name="network_session_mode_user">Chat profile</string>
<string name="network_session_mode_session">App session</string>
<string name="network_session_mode_server">Server</string>
<string name="network_session_mode_entity">Connection</string>
<string name="network_session_mode_user_description"><![CDATA[A separate TCP connection (and SOCKS credential) will be used <b>for each chat profile you have in the app</b>.]]></string>
<string name="network_session_mode_session_description">New SOCKS credentials will be used every time you start the app.</string>
<string name="network_session_mode_server_description">New SOCKS credentials will be used for each server.</string>
<string name="network_session_mode_entity_description"><![CDATA[A separate TCP connection (and SOCKS credential) will be used <b>for each contact and group member</b>.\n<b>Please note</b>: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail.]]></string>
<string name="update_network_session_mode_question">Update transport isolation mode?</string>
<string name="disable_onion_hosts_when_not_supported"><![CDATA[Set <i>Use .onion hosts</i> to No if SOCKS proxy does not support them.]]></string>
@@ -1047,9 +1043,6 @@
<string name="call_already_ended">Call already ended!</string>
<string name="icon_descr_video_call">video call</string>
<string name="icon_descr_audio_call">audio call</string>
<string name="call_desktop_permission_denied_title">To make calls, allow to use your microphone. End the call and try to call again.</string>
<string name="call_desktop_permission_denied_chrome">Click info button near address field to allow using microphone.</string>
<string name="call_desktop_permission_denied_safari">Open Safari Settings / Websites / Microphone, then choose Allow for localhost.</string>
<!-- Call settings -->
<string name="settings_audio_video_calls">Audio &amp; video calls</string>
@@ -1203,9 +1196,6 @@
<string name="settings_section_title_icon">APP ICON</string>
<string name="settings_section_title_themes">THEMES</string>
<string name="settings_section_title_profile_images">Profile images</string>
<string name="settings_section_title_message_shape">Message shape</string>
<string name="settings_message_shape_corner">Corner</string>
<string name="settings_message_shape_tail">Tail</string>
<string name="settings_section_title_chat_theme">Chat theme</string>
<string name="settings_section_title_user_theme">Profile theme</string>
<string name="settings_section_title_chat_colors">Chat colors</string>
@@ -2041,16 +2031,6 @@
<string name="v6_0_upgrade_app_descr">Download new versions from GitHub.</string>
<string name="v6_0_connection_servers_status">Control your network</string>
<string name="v6_0_connection_servers_status_descr">Connection and servers status.</string>
<string name="v6_1_better_security">Better security ✅</string>
<string name="v6_1_better_security_descr">SimpleX protocols reviewed by Trail of Bits.</string>
<string name="v6_1_better_calls">Better calls</string>
<string name="v6_1_better_calls_descr">Switch audio and video during the call.</string>
<string name="v6_1_better_user_experience">Better user experience</string>
<string name="v6_1_switch_chat_profile_descr">Switch chat profile for 1-time invitations.</string>
<string name="v6_1_customizable_message_descr">Customizable message shape.</string>
<string name="v6_1_message_dates_descr">Better message dates.</string>
<string name="v6_1_forward_many_messages_descr">Forward up to 20 messages at once.</string>
<string name="v6_1_delete_many_messages_descr">Delete or moderate up to 200 messages.</string>
<!-- CustomTimePicker -->
<string name="custom_time_unit_seconds">seconds</string>
@@ -1990,7 +1990,7 @@
<string name="downloaded_files">Heruntergeladene Dateien</string>
<string name="download_errors">Fehler beim Herunterladen</string>
<string name="duplicates_label">Duplikate</string>
<string name="expired_label">Abgelaufen</string>
<string name="expired_label">abgelaufen</string>
<string name="open_server_settings_button">Server-Einstellungen öffnen</string>
<string name="other_errors">Andere Fehler</string>
<string name="proxied">Proxy</string>
@@ -2170,43 +2170,4 @@
<string name="network_proxy_auth_mode_isolate_by_auth_user">Verwenden Sie für jedes Profil unterschiedliche Proxy-Anmeldeinformationen.</string>
<string name="network_proxy_random_credentials">Verwenden Sie zufällige Anmeldeinformationen</string>
<string name="network_proxy_username">Benutzername</string>
<string name="n_file_errors">%1$d Datei-Fehler:
\n%2$s</string>
<string name="forward_files_in_progress_desc">%1$d Datei(en) wird/werden immer noch heruntergeladen.</string>
<string name="forward_files_failed_to_receive_desc">Bei %1$d Datei(en) ist das Herunterladen fehlgeschlagen.</string>
<string name="error_forwarding_messages">Fehler beim Weiterleiten der Nachrichten</string>
<string name="forward_files_messages_deleted_after_selection_desc">Die Nachrichten wurden gelöscht, nachdem Sie sie ausgewählt hatten.</string>
<string name="forward_alert_title_nothing_to_forward">Es gibt nichts zum Weiterleiten!</string>
<string name="n_other_file_errors">%1$d andere(r) Datei-Fehler.</string>
<string name="forward_alert_title_messages_to_forward">%1$s Nachricht(en) weiterleiten?</string>
<string name="forward_files_missing_desc">%1$d Datei(en) wurde(n) gelöscht.</string>
<string name="forward_files_not_accepted_desc">%1$d Datei(en) wurde(n) nicht heruntergeladen.</string>
<string name="forward_alert_forward_messages_without_files">Nachrichten ohne Dateien weiterleiten?</string>
<string name="forward_files_messages_deleted_after_selection_title">%1$s Nachrichten wurden nicht weitergeleitet</string>
<string name="forward_files_not_accepted_receive_files">Herunterladen</string>
<string name="compose_forward_messages_n">Es wird/werden %1$s Nachricht(en) weitergeleitet</string>
<string name="forward_multiple">Nachrichten werden weitergeleitet…</string>
<string name="compose_save_messages_n">Es wird/werden %1$s Nachricht(en) gesichert</string>
<string name="icon_descr_sound_muted">Ton stummgeschaltet</string>
<string name="error_initializing_web_view_wrong_arch">Fehler bei der Initialisierung von WebView. Stellen Sie sicher, dass Sie WebView installiert haben, und es die ARM64-Architektur unterstützt.\nFehler: %s</string>
<string name="settings_section_title_message_shape">Form der Nachricht</string>
<string name="settings_message_shape_tail">Sprechblase</string>
<string name="settings_message_shape_corner">Abrundung Ecken</string>
<string name="network_session_mode_session">App-Sitzung</string>
<string name="network_session_mode_server_description">Für jeden Server werden neue SOCKS-Anmeldeinformationen genutzt</string>
<string name="network_session_mode_server">Server</string>
<string name="call_desktop_permission_denied_chrome">Klicken Sie auf die Info-Schaltfläche neben dem Adressfeld, um die Verwendung des Mikrofons zu erlauben.</string>
<string name="call_desktop_permission_denied_title">Um Anrufe durchzuführen, erlauben Sie die Nutzung Ihres Mikrofons. Beenden Sie den Anruf und versuchen Sie es erneut.</string>
<string name="call_desktop_permission_denied_safari">Öffnen Sie die Safari-Einstellungen / Webseiten / Mikrofon und wählen Sie dann \"Für Localhost erlauben\".</string>
<string name="v6_1_better_calls">Verbesserte Anrufe</string>
<string name="v6_1_customizable_message_descr">Anpassbares Format des Nachrichtenfelds</string>
<string name="v6_1_delete_many_messages_descr">Bis zu 200 Nachrichten löschen oder moderieren</string>
<string name="v6_1_forward_many_messages_descr">Bis zu 20 Nachrichten auf einmal weiterleiten</string>
<string name="v6_1_better_security_descr">Die SimpleX-Protokolle wurden von Trail of Bits überprüft.</string>
<string name="v6_1_better_calls_descr">Während des Anrufs zwischen Audio und Video wechseln</string>
<string name="v6_1_switch_chat_profile_descr">Das Chat-Profil für Einmal-Einladungen wechseln</string>
<string name="network_session_mode_session_description">Jedes Mal wenn Sie die App starten, werden neue SOCKS-Anmeldeinformationen genutzt</string>
<string name="v6_1_better_security">Verbesserte Sicherheit ✅</string>
<string name="v6_1_message_dates_descr">Verbesserte Nachrichten-Datumsinformation</string>
<string name="v6_1_better_user_experience">Verbesserte Nutzer-Erfahrung</string>
</resources>
@@ -227,20 +227,4 @@
<string name="deleted_description">διαγράφτηκε</string>
<string name="moderated_item_description">με συντονιστή %s</string>
<string name="blocked_item_description">φραγμένος</string>
<string name="learn_more_about_address">Σχετικά με τη διεύθυνση SimpleX</string>
<string name="conn_event_ratchet_sync_started">συμφωνία κρυπτογράφησης…</string>
<string name="chat_theme_apply_to_all_modes">Όλες οι χρωματικές λειτουργίες</string>
<string name="abort_switch_receiving_address_desc">Η αλλαγή διεύθυνσης θα ακυρωθεί. Θα χρησιμοποιηθεί η παλιά διεύθυνση παραλαβής.</string>
<string name="servers_info_subscriptions_connections_subscribed">Ενεργές συνδέσεις</string>
<string name="network_settings_title">Προχωρημένες ρυθμίσεις</string>
<string name="color_primary_variant">Πρόσθετη προφορά</string>
<string name="add_contact_tab">Προσθήκη επαφής</string>
<string name="abort_switch_receiving_address">Διακοπή αλλαγής διεύθυνσης</string>
<string name="wallpaper_advanced_settings">Προχωρημένες ρυθμίσεις</string>
<string name="v5_6_safer_groups_descr">Οι διαχειριστές μπορούν να αποκλείσουν ένα μέλος για όλους.</string>
<string name="acknowledged">Αναγνωρισμένο</string>
<string name="above_then_preposition_continuation">παραπάνω, λοιπόν:</string>
<string name="add_address_to_your_profile">Προσθέστε τη διεύθυνση στο προφίλ σας, έτσι ώστε οι επαφές σας να μπορούν να τη μοιραστούν με άλλα άτομα. Το ενημέρωμένο προφίλ θα σταλεί στις επαφές σας.</string>
<string name="feature_roles_admins">διαχειριστές</string>
<string name="acknowledgement_errors">Λάθη αναγνώρισης</string>
</resources>
@@ -83,7 +83,7 @@
<string name="database_passphrase_will_be_updated">La contraseña de cifrado de la base de datos será actualizada.</string>
<string name="info_row_database_id">ID base de datos</string>
<string name="direct_messages_are_prohibited_in_chat">Los mensajes directos entre miembros del grupo no están permitidos.</string>
<string name="passphrase_is_different">La contraseña de la base de datos es diferente a la almacenada en Keystore.</string>
<string name="passphrase_is_different">La contraseña de la base de datos es distinta a la almacenada en Keystore.</string>
<string name="database_will_be_encrypted_and_passphrase_stored">La base de datos será cifrada y la contraseña se guardará en Keystore.</string>
<string name="delete_contact_question">¿Eliminar contacto\?</string>
<string name="delete_message__question">¿Eliminar mensaje\?</string>
@@ -366,7 +366,7 @@
<string name="description_via_contact_address_link_incognito">en modo incógnito mediante enlace de dirección del contacto</string>
<string name="failed_to_create_user_title">¡Error al crear perfil!</string>
<string name="failed_to_parse_chat_title">No se pudo cargar el chat</string>
<string name="failed_to_parse_chats_title">Fallo en la carga de chats</string>
<string name="failed_to_parse_chats_title">No se pudieron cargar los chats</string>
<string name="simplex_link_mode_full">Enlace completo</string>
<string name="error_deleting_contact">Error al eliminar contacto</string>
<string name="error_joining_group">Error al unirte al grupo</string>
@@ -562,7 +562,7 @@
<string name="rcv_group_event_member_left">ha salido</string>
<string name="button_leave_group">Salir del grupo</string>
<string name="only_group_owners_can_change_prefs">Sólo los propietarios pueden modificar las preferencias del grupo.</string>
<string name="users_delete_data_only">Eliminar sólo el perfil</string>
<string name="users_delete_data_only">Sólo datos del perfil</string>
<string name="chat_preferences_no">no</string>
<string name="thousand_abbreviation">k</string>
<string name="marked_deleted_description">marcado eliminado</string>
@@ -579,7 +579,7 @@
<string name="make_private_connection">Establecer una conexión privada</string>
<string name="network_error_desc">Comprueba tu conexión de red con %1$s e inténtalo de nuevo.</string>
<string name="sender_may_have_deleted_the_connection_request">El remitente puede haber eliminado la solicitud de conexión.</string>
<string name="error_smp_test_certificate">Posiblemente la huella del certificado en la dirección del servidor es incorrecta</string>
<string name="error_smp_test_certificate">Posiblemente la huella digital del certificado en la dirección del servidor es incorrecta</string>
<string name="reply_verb">Responder</string>
<string name="save_passphrase_in_keychain">Guardar contraseña en Keystore</string>
<string name="database_restore_error">Error al restaurar base de datos</string>
@@ -668,7 +668,7 @@
<string name="receiving_via">Recibiendo vía</string>
<string name="network_option_protocol_timeout">Timeout protocolo</string>
<string name="network_option_seconds_label">seg</string>
<string name="users_delete_with_connections">Eliminar perfil y conexiones</string>
<string name="users_delete_with_connections">Datos del perfil y conexiones</string>
<string name="prohibit_sending_disappearing_messages">No se permiten mensajes temporales.</string>
<string name="only_you_can_send_voice">Sólo tú puedes enviar mensajes de voz.</string>
<string name="only_your_contact_can_send_voice">Sólo tu contacto puede enviar mensajes de voz.</string>
@@ -820,7 +820,7 @@
<string name="trying_to_connect_to_server_to_receive_messages">Intentando conectar con el servidor para recibir mensajes de este contacto.</string>
<string name="unknown_message_format">formato de mensaje desconocido</string>
<string name="trying_to_connect_to_server_to_receive_messages_with_error">Intentando conectar con el servidor para recibir mensajes de este contacto (error: %1$s).</string>
<string name="error_smp_test_failed_at_step">Prueba no superada en el paso %s.</string>
<string name="error_smp_test_failed_at_step">Prueba fallida en el paso %s.</string>
<string name="tap_to_start_new_chat">Pulsa para iniciar chat nuevo</string>
<string name="share_message">Compartir mensaje…</string>
<string name="share_image">Compartir medios…</string>
@@ -830,10 +830,10 @@
<string name="chat_help_tap_button">Pulsa el botón</string>
<string name="to_start_a_new_chat_help_header">Para iniciar un chat nuevo</string>
<string name="switch_receiving_address">Cambiar servidor de recepción</string>
<string name="group_is_decentralized">Totalmente descentralizado. Visible sólo para los miembros.</string>
<string name="group_is_decentralized">Completamente descentralizado y sólo visible para los miembros.</string>
<string name="to_connect_via_link_title">Para conectarte mediante enlace</string>
<string name="smp_servers_test_failed">¡Prueba no superada!</string>
<string name="smp_servers_test_some_failed">Algunos servidores no han superado la prueba:</string>
<string name="smp_servers_test_failed">¡Error en prueba del servidor!</string>
<string name="smp_servers_test_some_failed">Algunos servidores no superaron la prueba:</string>
<string name="smp_servers_use_server">Usar servidor</string>
<string name="smp_servers_use_server_for_new_conn">Usar para conexiones nuevas</string>
<string name="theme_system">Sistema</string>
@@ -949,7 +949,7 @@
<string name="your_chat_profiles">Mis perfiles</string>
<string name="your_simplex_contact_address">Mi dirección SimpleX</string>
<string name="smp_servers_your_server">Tu servidor</string>
<string name="smp_servers_your_server_address">Dirección del servidor</string>
<string name="smp_servers_your_server_address">Dirección de tu servidor</string>
<string name="your_current_profile">Tu perfil actual</string>
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Tu perfil es almacenado en tu dispositivo y solamente se comparte con tus contactos. Los servidores SimpleX no pueden ver tu perfil.</string>
<string name="language_system">Sistema</string>
@@ -971,7 +971,7 @@
<string name="button_welcome_message">Mensaje de bienvenida</string>
<string name="group_welcome_title">Mensaje de bienvenida</string>
<string name="make_profile_private">¡Hacer perfil privado!</string>
<string name="dont_show_again">No volver a mostrar</string>
<string name="dont_show_again">No mostrar de nuevo</string>
<string name="muted_when_inactive">¡Silenciado cuando está inactivo!</string>
<string name="v4_6_group_moderation">Moderación de grupos</string>
<string name="v4_6_hidden_chat_profiles">Perfiles ocultos</string>
@@ -1347,7 +1347,7 @@
<string name="connect_via_link_incognito">Conectar en incógnito</string>
<string name="turn_off_battery_optimization_button">Permitir</string>
<string name="turn_off_system_restriction_button">Abrir configuración</string>
<string name="connect__a_new_random_profile_will_be_shared">Compartirás un perfil nuevo aleatorio.</string>
<string name="connect__a_new_random_profile_will_be_shared">Se compartirá un perfil nuevo aleatorio.</string>
<string name="paste_the_link_you_received_to_connect_with_your_contact">Pega el enlace recibido para conectar con tu contacto…</string>
<string name="connect__your_profile_will_be_shared">El perfil %1$s será compartido.</string>
<string name="disable_notifications_button">Desactivar notificaciones</string>
@@ -1383,7 +1383,7 @@
<string name="v5_3_new_desktop_app">Nueva aplicación para ordenador!</string>
<string name="v5_3_new_interface_languages">6 idiomas nuevos para el interfaz</string>
<string name="v5_3_encrypt_local_files_descr">Cifrado de los nuevos archivos locales (excepto vídeos).</string>
<string name="compose_send_direct_message_to_connect">Envía un mensaje para conectar</string>
<string name="compose_send_direct_message_to_connect">Enviar mensaje directo para conectar</string>
<string name="v5_3_discover_join_groups">Descubre y únete a grupos</string>
<string name="v5_3_simpler_incognito_mode">Modo incógnito simplificado</string>
<string name="v5_3_new_interface_languages_descr">Árabe, Búlgaro, Finlandés, Hebreo, Tailandés y Ucraniano - gracias a los usuarios y Weblate.</string>
@@ -1450,7 +1450,7 @@
<string name="bad_desktop_address">Dirección ordenador incorrecta</string>
<string name="devices">Dispositivo</string>
<string name="non_content_uri_alert_title">Ruta archivo no valida.</string>
<string name="disconnect_desktop_question">¿Desconectar del ordenador?</string>
<string name="disconnect_desktop_question">¿Desconectar ordenador?</string>
<string name="block_member_desc">¡Los mensajes nuevos de %s estarán ocultos!</string>
<string name="desktop_app_version_is_incompatible">La versión de aplicación del ordenador %s no es compatible con esta aplicación.</string>
<string name="blocked_item_description">bloqueado</string>
@@ -1627,9 +1627,9 @@
<string name="past_member_vName">Miembro pasado %1$s</string>
<string name="profile_update_event_member_name_changed">el miembro %1$s ha cambiado a %2$s</string>
<string name="profile_update_event_removed_address">dirección de contacto eliminada</string>
<string name="profile_update_event_removed_picture">ha eliminado la imagen del perfil</string>
<string name="profile_update_event_removed_picture">imagen de perfil eliminada</string>
<string name="profile_update_event_set_new_address">nueva dirección de contacto</string>
<string name="profile_update_event_set_new_picture">tiene nueva imagen del perfil</string>
<string name="profile_update_event_set_new_picture">nueva imagen de perfil</string>
<string name="call_service_notification_audio_call">Llamada</string>
<string name="call_service_notification_end_call">Llamada finalizada</string>
<string name="call_service_notification_video_call">Videollamada</string>
@@ -1686,7 +1686,7 @@
<string name="migrate_from_device_finalize_migration">Finalizar migración</string>
<string name="migrate_from_device_archive_will_be_deleted"><![CDATA[<b>Atención</b>: el archivo será eliminado.]]></string>
<string name="migrate_from_device_check_connection_and_try_again">Comprueba tu conexión a internet y vuelve a intentarlo</string>
<string name="migrate_from_device_confirm_you_remember_passphrase">Para migrar la base de datos confirma que recuerdas la frase de contraseña.</string>
<string name="migrate_from_device_confirm_you_remember_passphrase">Para migrar confirma que recuerdas la frase de contraseña de la base de datos.</string>
<string name="migrate_from_device_error_verifying_passphrase">Error al verificar la frase de contraseña:</string>
<string name="migrate_from_device_using_on_two_device_breaks_encryption"><![CDATA[<b>Recuerda</b>: usar la misma base de datos en dos dispositivos hará que falle el descifrado de mensajes como protección de seguridad.]]></string>
<string name="migrate_from_device_choose_migrate_from_another_device"><![CDATA[En el nuevo dispositivo selecciona <i>Migrar desde otro dispositivo</i> y escanea el código QR.]]></string>
@@ -2070,62 +2070,4 @@
<string name="new_message">Nuevo mensaje</string>
<string name="error_parsing_uri_title">Enlace no válido</string>
<string name="error_parsing_uri_desc">Por favor, comprueba que el enlace SimpleX es correcto.</string>
<string name="forward_files_in_progress_desc">%1$d archivo(s) se está(n) descargando todavía.</string>
<string name="n_other_file_errors">%1$d otro(s) error(es) de archivo.</string>
<string name="settings_section_title_chat_database">BASE DE DATOS</string>
<string name="error_forwarding_messages">Error en reenvío de mensajes</string>
<string name="forward_alert_title_messages_to_forward">¿Reenviar %1$s mensaje(s)?</string>
<string name="forward_multiple">Reenviar mensajes…</string>
<string name="system_mode_toast">Modo de sistema</string>
<string name="forward_alert_forward_messages_without_files">¿Reenviar mensajes sin los archivos?</string>
<string name="network_proxy_incorrect_config_desc">Asegúrate de que la configuración del proxy es correcta.</string>
<string name="forward_files_missing_desc">%1$d archivo(s) ha(n) sido eliminado(s).</string>
<string name="n_file_errors">%1$d error(es) de archivo
\n%2$s</string>
<string name="forward_files_failed_to_receive_desc">La descarga ha fallado para %1$d archivo(s).</string>
<string name="forward_files_not_accepted_desc">%1$d archivo(s) no se ha(n) descargado.</string>
<string name="forward_files_messages_deleted_after_selection_title">%1$s mensajes no enviados</string>
<string name="forward_files_not_accepted_receive_files">Descargar</string>
<string name="compose_forward_messages_n">Reenviando %1$s mensajes</string>
<string name="forward_files_messages_deleted_after_selection_desc">Los mensajes han sido borrados después de seleccionarlos.</string>
<string name="forward_alert_title_nothing_to_forward">¡Nada para reenviar!</string>
<string name="compose_save_messages_n">Guardando %1$s mensajes</string>
<string name="network_proxy_auth_mode_no_auth">No uses credenciales con proxy.</string>
<string name="network_proxy_incorrect_config_title">Error guardando proxy</string>
<string name="network_proxy_password">Contraseña</string>
<string name="network_proxy_auth">Autenticación proxy</string>
<string name="network_proxy_auth_mode_isolate_by_auth_entity">Credenciales proxy diferentes para cada conexión.</string>
<string name="network_proxy_auth_mode_isolate_by_auth_user">Credenciales proxy diferentes para cada perfil.</string>
<string name="network_proxy_random_credentials">Credenciales aleatorias</string>
<string name="network_proxy_username">Nombre de usuario</string>
<string name="network_proxy_auth_mode_username_password">Tus credenciales podrían ser enviadas sin cifrar.</string>
<string name="migrate_from_device_remove_archive_question">¿Eliminar archivo?</string>
<string name="migrate_from_device_uploaded_archive_will_be_removed">El archivo de bases de datos subido será eliminado permanentemente de los servidores.</string>
<string name="delete_messages_cannot_be_undone_warning">Los mensajes serán eliminados. ¡No podrá deshacerse!</string>
<string name="switching_profile_error_title">Error al cambiar perfil</string>
<string name="select_chat_profile">Selecciona perfil de chat</string>
<string name="new_chat_share_profile">Comparte perfil</string>
<string name="switching_profile_error_message">Tu conexión ha sido trasladada a %s pero ha ocurrido un error inesperado al redirigirte al perfil.</string>
<string name="icon_descr_sound_muted">Sonido silenciado</string>
<string name="error_initializing_web_view_wrong_arch">Error al iniciar WebView. Asegúrate de tener WebView instalado y que sea compatible con la arquitectura amr64.\nError: %s</string>
<string name="settings_section_title_message_shape">Forma del mensaje</string>
<string name="settings_message_shape_corner">Esquinas</string>
<string name="settings_message_shape_tail">Cola</string>
<string name="network_session_mode_session_description">Se usarán credenciales SOCKS nuevas cada vez que inicies la aplicación.</string>
<string name="network_session_mode_session">Sesión de aplicación</string>
<string name="call_desktop_permission_denied_safari">Abre la configuración de Safari / Sitios Web / Micrófono y a continuación selecciona Permitir para localhost.</string>
<string name="call_desktop_permission_denied_chrome">Pulsa el botón info del campo dirección para permitir el uso del micrófono.</string>
<string name="call_desktop_permission_denied_title">Para hacer llamadas, permite el uso del micrófono. Cuelga e intenta llamar de nuevo.</string>
<string name="network_session_mode_server_description">Se usarán credenciales SOCKS nuevas por cada servidor.</string>
<string name="network_session_mode_server">Servidor</string>
<string name="v6_1_better_calls">Llamadas mejoradas</string>
<string name="v6_1_message_dates_descr">Mensajes mejor datados.</string>
<string name="v6_1_better_user_experience">Experiencia de usuario mejorada</string>
<string name="v6_1_customizable_message_descr">Forma personalizable de los mensajes.</string>
<string name="v6_1_forward_many_messages_descr">Desplazamiento de hasta 20 mensajes.</string>
<string name="v6_1_better_security_descr">Protocolos de SimpleX auditados por Trail of Bits.</string>
<string name="v6_1_better_calls_descr">Intercambia audio y video durante la llamada.</string>
<string name="v6_1_better_security">Seguridad mejorada ✅</string>
<string name="v6_1_delete_many_messages_descr">Borrar o moderar hasta 200 mensajes.</string>
<string name="v6_1_switch_chat_profile_descr">Cambia el perfil de chat para invitaciones de un solo uso.</string>
</resources>
File diff suppressed because it is too large Load Diff
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#000000"><path d="M182-85q-22.97 0-40.23-17.27-17.27-17.26-17.27-40.23v-616q0-22.97 17.27-40.23Q159.03-816 182-816h67.5v-60H312v60h336v-60h62.5v60H778q22.97 0 40.23 17.27 17.27 17.26 17.27 40.23v616q0 22.97-17.27 40.23Q800.97-85 778-85H182Zm0-57.5h596V-569H182v426.5Zm0-484h596v-132H182v132Zm0 0v-132 132Zm298.05 226q-16.76 0-28.16-11.34-11.39-11.34-11.39-28.11 0-16.76 11.34-28.16 11.34-11.39 28.11-11.39 16.76 0 28.16 11.34 11.39 11.34 11.39 28.11 0 16.76-11.34 28.16-11.34 11.39-28.11 11.39Zm-160 0q-16.76 0-28.16-11.34-11.39-11.34-11.39-28.11 0-16.76 11.34-28.16 11.34-11.39 28.11-11.39 16.76 0 28.16 11.34 11.39 11.34 11.39 28.11 0 16.76-11.34 28.16-11.34 11.39-28.11 11.39Zm320 0q-16.76 0-28.16-11.34-11.39-11.34-11.39-28.11 0-16.76 11.34-28.16 11.34-11.39 28.11-11.39 16.76 0 28.16 11.34 11.39 11.34 11.39 28.11 0 16.76-11.34 28.16-11.34 11.39-28.11 11.39Zm-160 160q-16.76 0-28.16-11.34-11.39-11.34-11.39-28.11 0-16.76 11.34-28.16 11.34-11.39 28.11-11.39 16.76 0 28.16 11.34 11.39 11.34 11.39 28.11 0 16.76-11.34 28.16-11.34 11.39-28.11 11.39Zm-160 0q-16.76 0-28.16-11.34-11.39-11.34-11.39-28.11 0-16.76 11.34-28.16 11.34-11.39 28.11-11.39 16.76 0 28.16 11.34 11.39 11.34 11.39 28.11 0 16.76-11.34 28.16-11.34 11.39-28.11 11.39Zm320 0q-16.76 0-28.16-11.34-11.39-11.34-11.39-28.11 0-16.76 11.34-28.16 11.34-11.39 28.11-11.39 16.76 0 28.16 11.34 11.39 11.34 11.39 28.11 0 16.76-11.34 28.16-11.34 11.39-28.11 11.39Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

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