Compare commits

...

28 Commits

Author SHA1 Message Date
Moritz Angermann d438cec674 Disable i686-linux-static build 2024-04-21 10:09:25 +00:00
Moritz Angermann e4c5dbdb08 Disable aarch64-linux-static build. 2024-04-21 10:09:04 +00:00
Moritz Angermann 5d1a393131 Disable windows builds 2024-04-21 10:08:09 +00:00
Evgeny Poberezkin 8e3a713a49 ui: limit max size of events, sort members by role (#4058) 2024-04-21 10:57:54 +01:00
Evgeny Poberezkin 7cec79e79b 5.7-beta.1: ios 208, android 197, desktop 38 2024-04-20 22:07:04 +01:00
Evgeny Poberezkin e9db7e8e58 ios: export translations 2024-04-20 19:57:40 +01:00
Evgeny Poberezkin f53882049f ios: update core library 2024-04-20 19:54:47 +01:00
Evgeny Poberezkin 8f4c9a673a core: 5.7.0.1 2024-04-20 19:39:20 +01:00
Evgeny Poberezkin 02f980e968 core: update simplexmq (better newtork congestion handling, larger connection timeouts) (#4055)
* core: update simplexmq (better newtork congestion handling, larger connection timeouts)

* ui: update default TCP connect timeout, add receiving concurrency

* update simplexmq
2024-04-20 19:35:11 +01:00
Stanislav Dmitrenko 412f75219a android: select audio source (#4040)
* android, desktop: select audio source

* improvements

* fix possible crash

* changes
2024-04-20 19:19:37 +01:00
Evgeny Poberezkin c8c81a840b core: revert build to use two branches (#4052)
* Revert "scripts: ghc version update (#4010)"

This reverts commit 35b7f2cb1c.

* Revert "Force include hs_init_with_rtsopts (#4028)"

This reverts commit 76a33a3743.

* Revert "core: fix nix config (#4003)"

This reverts commit f8e6a78a3b.

* Revert "ci: build armv7a with 8.10.7 in the main branches (master, stable) (#3733)"

This reverts commit 0d7a32877f.
2024-04-19 21:17:22 +01:00
Stanislav Dmitrenko 925cb39397 desktop: using system sound in screenshare (#4035)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-19 17:37:47 +01:00
Stanislav Dmitrenko f6ceb89c4b android, desktop: forward ui (#4039)
* android, desktop: forward ui

* changes

* attachment icon

* reorder lines

* reorder lines

* change

* inline content + formatted text

* fix header padding

* fix

* fix2

* Revert "fix header padding"

This reverts commit 63f2b15f02.

* broken default parameter

* changes

* more checks for file forwarding

* paddings

* padding

* padding and fix

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-04-19 17:36:32 +01:00
Evgeny Poberezkin a35d392f76 core: update simplexmq 2024-04-19 17:25:34 +01:00
spaced4ndy 1306c84938 ios: in item context menu don't show forward button if file doesn't exist, add download button (#4048) 2024-04-19 17:21:35 +01:00
Stanislav Dmitrenko 6484e36b82 ios: fix mute/unmute button state (#4046) 2024-04-19 17:20:31 +01:00
Stanislav Dmitrenko 918be31f2c desktop: fix freeze that happened when new chat items arrives while scrolling via scrollbar (#4050) 2024-04-19 15:57:00 +01:00
spaced4ndy 648884044f core: prohibit forwarding file if it's not found (#4047) 2024-04-19 11:31:44 +04:00
Stanislav Dmitrenko 505c6cb062 ios: prevent a crash when exiting the app (#4041)
* ios: prevent a crash when exiting the app

* log
2024-04-19 07:23:13 +01:00
Stanislav Dmitrenko 065c8f8861 ios: fix typing using keyboard suggestions (#4045) 2024-04-19 07:17:17 +01:00
spaced4ndy 6c509027f7 docs: IP address protection rfc (#4036) 2024-04-17 13:53:45 +04:00
Evgeny Poberezkin 4eafdc3723 blog: metadata in messengers (#4038)
* blog: metadata in messengers

* readme

* call.js

* picture

* revert call.js
2024-04-16 20:18:22 +01:00
spaced4ndy 77f5c678d5 ios: forward ui (#4024)
* wip

* wip

* fixes

* improvements

* info

* fix

* dont cleanup file

* info design, text

* text

* rework with LazyVStack

* delay

* refactor

* move delay

* fix

* refactor

* refactor 2

* keep current message

* forward with quote, context icons

* info

* preserve draft

* remove newline

* improve search

* info

* layout

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-16 09:28:39 +01:00
Stanislav Dmitrenko 5e71d00ace android, desktop: workaround of missing stuns support in calls (#4033)
* android, desktop: workaround of missing stuns support in calls

* const
2024-04-16 08:38:46 +01:00
Stanislav Dmitrenko c2169f7813 desktop: fix video calls in Firefox (#4034)
* desktop: fix video calls in Firefox

* one more play()
2024-04-16 08:22:40 +01:00
spaced4ndy 7ff4b05c90 core: remember new origin for received forwarded messages (#4032) 2024-04-15 17:19:37 +04:00
Evgeny Poberezkin d7f8bff957 Merge branch 'stable' 2024-04-15 11:16:33 +01:00
sh bda0917787 github: fix cla action (#4030) 2024-04-15 10:51:24 +01:00
93 changed files with 3691 additions and 529 deletions
+4 -4
View File
@@ -55,22 +55,22 @@ jobs:
ghc: "8.10.7" ghc: "8.10.7"
cache_path: ~/.cabal/store cache_path: ~/.cabal/store
- os: ubuntu-20.04 - os: ubuntu-20.04
ghc: "9.6.4" ghc: "9.6.3"
cache_path: ~/.cabal/store cache_path: ~/.cabal/store
asset_name: simplex-chat-ubuntu-20_04-x86-64 asset_name: simplex-chat-ubuntu-20_04-x86-64
desktop_asset_name: simplex-desktop-ubuntu-20_04-x86_64.deb desktop_asset_name: simplex-desktop-ubuntu-20_04-x86_64.deb
- os: ubuntu-22.04 - os: ubuntu-22.04
ghc: "9.6.4" ghc: "9.6.3"
cache_path: ~/.cabal/store cache_path: ~/.cabal/store
asset_name: simplex-chat-ubuntu-22_04-x86-64 asset_name: simplex-chat-ubuntu-22_04-x86-64
desktop_asset_name: simplex-desktop-ubuntu-22_04-x86_64.deb desktop_asset_name: simplex-desktop-ubuntu-22_04-x86_64.deb
- os: macos-latest - os: macos-latest
ghc: "9.6.4" ghc: "9.6.3"
cache_path: ~/.cabal/store cache_path: ~/.cabal/store
asset_name: simplex-chat-macos-x86-64 asset_name: simplex-chat-macos-x86-64
desktop_asset_name: simplex-desktop-macos-x86_64.dmg desktop_asset_name: simplex-desktop-macos-x86_64.dmg
- os: windows-latest - os: windows-latest
ghc: "9.6.4" ghc: "9.6.3"
cache_path: C:/cabal cache_path: C:/cabal
asset_name: simplex-chat-windows-x86-64 asset_name: simplex-chat-windows-x86-64
desktop_asset_name: simplex-desktop-windows-x86_64.msi desktop_asset_name: simplex-desktop-windows-x86_64.msi
+9 -3
View File
@@ -5,14 +5,20 @@ on:
pull_request_target: pull_request_target:
types: [opened, closed, synchronize] types: [opened, closed, synchronize]
permissions:
actions: write
contents: write
pull-requests: write
statuses: write
jobs: jobs:
CLAssistant: CLAssistant:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: "CLA Assistant" - name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request' if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
# Beta Release # Beta Release
uses: cla-assistant/github-action@v2.1.3-beta uses: cla-assistant/github-action@v2.3.0
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret # the below token should have repo scope and must be manually added by you in the repository's secret
@@ -33,4 +39,4 @@ jobs:
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA' #custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.' #custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true) #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
#use-dco-flag: true - If you are using DCO instead of CLA #use-dco-flag: true - If you are using DCO instead of CLA
+1 -1
View File
@@ -8,7 +8,7 @@ FROM ubuntu:${TAG} AS build
RUN apt-get update && apt-get install -y curl git build-essential libgmp3-dev zlib1g-dev llvm-12 llvm-12-dev libnuma-dev libssl-dev RUN apt-get update && apt-get install -y curl git build-essential libgmp3-dev zlib1g-dev llvm-12 llvm-12-dev libnuma-dev libssl-dev
# Specify bootstrap Haskell versions # Specify bootstrap Haskell versions
ENV BOOTSTRAP_HASKELL_GHC_VERSION=9.6.4 ENV BOOTSTRAP_HASKELL_GHC_VERSION=9.6.3
ENV BOOTSTRAP_HASKELL_CABAL_VERSION=3.10.1.0 ENV BOOTSTRAP_HASKELL_CABAL_VERSION=3.10.1.0
# Install ghcup # Install ghcup
+12 -4
View File
@@ -353,11 +353,20 @@ func apiGetChatItemInfo(type: ChatType, id: Int64, itemId: Int64) async throws -
throw r throw r
} }
func apiForwardChatItem(toChatType: ChatType, toChatId: Int64, fromChatType: ChatType, fromChatId: Int64, itemId: Int64) async -> ChatItem? {
let cmd: ChatCommand = .apiForwardChatItem(toChatType: toChatType, toChatId: toChatId, fromChatType: fromChatType, fromChatId: fromChatId, itemId: itemId)
return await processSendMessageCmd(toChatType: toChatType, cmd: cmd)
}
func apiSendMessage(type: ChatType, id: Int64, file: CryptoFile?, quotedItemId: Int64?, msg: MsgContent, live: Bool = false, ttl: Int? = nil) async -> ChatItem? { func apiSendMessage(type: ChatType, id: Int64, file: CryptoFile?, quotedItemId: Int64?, msg: MsgContent, live: Bool = false, ttl: Int? = nil) async -> ChatItem? {
let chatModel = ChatModel.shared
let cmd: ChatCommand = .apiSendMessage(type: type, id: id, file: file, quotedItemId: quotedItemId, msg: msg, live: live, ttl: ttl) let cmd: ChatCommand = .apiSendMessage(type: type, id: id, file: file, quotedItemId: quotedItemId, msg: msg, live: live, ttl: ttl)
return await processSendMessageCmd(toChatType: type, cmd: cmd)
}
private func processSendMessageCmd(toChatType: ChatType, cmd: ChatCommand) async -> ChatItem? {
let chatModel = ChatModel.shared
let r: ChatResponse let r: ChatResponse
if type == .direct { if toChatType == .direct {
var cItem: ChatItem? = nil var cItem: ChatItem? = nil
let endTask = beginBGTask({ let endTask = beginBGTask({
if let cItem = cItem { if let cItem = cItem {
@@ -397,7 +406,7 @@ func apiCreateChatItem(noteFolderId: Int64, file: CryptoFile?, msg: MsgContent)
} }
private func sendMessageErrorAlert(_ r: ChatResponse) { private func sendMessageErrorAlert(_ r: ChatResponse) {
logger.error("apiSendMessage error: \(String(describing: r))") logger.error("send message error: \(String(describing: r))")
AlertManager.shared.showAlertMsg( AlertManager.shared.showAlertMsg(
title: "Error sending message", title: "Error sending message",
message: "Error: \(String(describing: r))" message: "Error: \(String(describing: r))"
@@ -1803,7 +1812,6 @@ func processReceivedMsg(_ res: ChatResponse) async {
} }
case let .sndFileCompleteXFTP(user, aChatItem, _): case let .sndFileCompleteXFTP(user, aChatItem, _):
await chatItemSimpleUpdate(user, aChatItem) await chatItemSimpleUpdate(user, aChatItem)
Task { cleanupFile(aChatItem) }
case let .sndFileError(user, aChatItem, _): case let .sndFileError(user, aChatItem, _):
if let aChatItem = aChatItem { if let aChatItem = aChatItem {
await chatItemSimpleUpdate(user, aChatItem) await chatItemSimpleUpdate(user, aChatItem)
@@ -17,6 +17,7 @@ struct CIEventView: View {
.padding(.horizontal, 6) .padding(.horizontal, 6)
.padding(.vertical, 4) .padding(.vertical, 4)
.textSelection(.disabled) .textSelection(.disabled)
.lineLimit(3)
} }
} }
@@ -69,19 +69,12 @@ struct CIFileView: View {
return false return false
} }
private func fileSizeValid() -> Bool {
if let file = file {
return file.fileSize <= getMaxFileSize(file.fileProtocol)
}
return false
}
private func fileAction() { private func fileAction() {
logger.debug("CIFileView fileAction") logger.debug("CIFileView fileAction")
if let file = file { if let file = file {
switch (file.fileStatus) { switch (file.fileStatus) {
case .rcvInvitation: case .rcvInvitation:
if fileSizeValid() { if fileSizeValid(file) {
Task { Task {
logger.debug("CIFileView fileAction - in .rcvInvitation, in Task") logger.debug("CIFileView fileAction - in .rcvInvitation, in Task")
if let user = m.currentUser { if let user = m.currentUser {
@@ -143,7 +136,7 @@ struct CIFileView: View {
case .sndCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10) case .sndCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .sndError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10) case .sndError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .rcvInvitation: case .rcvInvitation:
if fileSizeValid() { if fileSizeValid(file) {
fileIcon("arrow.down.doc.fill", color: .accentColor) fileIcon("arrow.down.doc.fill", color: .accentColor)
} else { } else {
fileIcon("doc.fill", color: .orange, innerIcon: "exclamationmark", innerIconSize: 12) fileIcon("doc.fill", color: .orange, innerIcon: "exclamationmark", innerIconSize: 12)
@@ -201,6 +194,13 @@ struct CIFileView: View {
} }
} }
func fileSizeValid(_ file: CIFile?) -> Bool {
if let file = file {
return file.fileSize <= getMaxFileSize(file.fileProtocol)
}
return false
}
func saveCryptoFile(_ fileSource: CryptoFile) { func saveCryptoFile(_ fileSource: CryptoFile) {
if let cfArgs = fileSource.cryptoArgs { if let cfArgs = fileSource.cryptoArgs {
let url = getAppFilePath(fileSource.filePath) let url = getAppFilePath(fileSource.filePath)
@@ -65,8 +65,8 @@ struct FramedItemView: View {
} }
} }
} }
} else if chatItem.meta.itemForwarded != nil { } else if let itemForwarded = chatItem.meta.itemForwarded {
framedItemHeader(icon: "arrowshape.turn.up.forward", caption: Text("forwarded").italic()) framedItemHeader(icon: "arrowshape.turn.up.forward", caption: Text(itemForwarded.text(chat.chatInfo.chatType)).italic(), pad: true)
} }
ChatItemContentView(chat: chat, chatItem: chatItem, revealed: $revealed, msgContentView: framedMsgContentView) ChatItemContentView(chat: chat, chatItem: chatItem, revealed: $revealed, msgContentView: framedMsgContentView)
@@ -165,7 +165,7 @@ struct FramedItemView: View {
) )
} }
@ViewBuilder func framedItemHeader(icon: String? = nil, caption: Text) -> some View { @ViewBuilder func framedItemHeader(icon: String? = nil, caption: Text, pad: Bool = false) -> some View {
let v = HStack(spacing: 6) { let v = HStack(spacing: 6) {
if let icon = icon { if let icon = icon {
Image(systemName: icon) Image(systemName: icon)
@@ -180,7 +180,7 @@ struct FramedItemView: View {
.foregroundColor(.secondary) .foregroundColor(.secondary)
.padding(.horizontal, 12) .padding(.horizontal, 12)
.padding(.top, 6) .padding(.top, 6)
.padding(.bottom, chatItem.quotedItem == nil ? 6 : 0) // TODO think how to regroup .padding(.bottom, pad || (chatItem.quotedItem == nil && chatItem.meta.itemForwarded == nil) ? 6 : 0)
.overlay(DetermineWidth()) .overlay(DetermineWidth())
.frame(minWidth: msgWidth, alignment: .leading) .frame(minWidth: msgWidth, alignment: .leading)
.background(chatItemFrameContextColor(chatItem, colorScheme)) .background(chatItemFrameContextColor(chatItem, colorScheme))
@@ -0,0 +1,152 @@
//
// ChatItemForwardingView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 12.04.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct ChatItemForwardingView: View {
@EnvironmentObject var chatModel: ChatModel
@Environment(\.dismiss) var dismiss
var ci: ChatItem
var fromChatInfo: ChatInfo
@Binding var composeState: ComposeState
@State private var searchText: String = ""
@FocusState private var searchFocused
var body: some View {
NavigationView {
forwardListView()
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Cancel") {
dismiss()
}
}
ToolbarItem(placement: .principal) {
Text("Forward")
.bold()
}
}
}
}
@ViewBuilder private func forwardListView() -> some View {
VStack(alignment: .leading) {
let chatsToForwardTo = filterChatsToForwardTo()
if !chatsToForwardTo.isEmpty {
ScrollView {
LazyVStack(alignment: .leading, spacing: 8) {
searchFieldView(text: $searchText, focussed: $searchFocused)
.padding(.leading, 2)
let s = searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
let chats = s == "" ? chatsToForwardTo : chatsToForwardTo.filter { filterChatSearched($0, s) }
ForEach(chats) { chat in
Divider()
forwardListNavLinkView(chat)
.disabled(chatModel.deletedChats.contains(chat.chatInfo.id))
}
}
.padding(.horizontal)
.padding(.vertical, 8)
.background(Color(uiColor: .systemBackground))
.cornerRadius(12)
.padding(.horizontal)
}
.background(Color(.systemGroupedBackground))
} else {
emptyList()
}
}
}
private func filterChatsToForwardTo() -> [Chat] {
var filteredChats = chatModel.chats.filter({ canForwardToChat($0) })
if let index = filteredChats.firstIndex(where: { $0.chatInfo.chatType == .local }) {
let privateNotes = filteredChats.remove(at: index)
filteredChats.insert(privateNotes, at: 0)
}
return filteredChats
}
private func filterChatSearched(_ chat: Chat, _ searchStr: String) -> Bool {
let cInfo = chat.chatInfo
return switch cInfo {
case let .direct(contact):
viewNameContains(cInfo, searchStr) ||
contact.profile.displayName.localizedLowercase.contains(searchStr) ||
contact.fullName.localizedLowercase.contains(searchStr)
default:
viewNameContains(cInfo, searchStr)
}
func viewNameContains(_ cInfo: ChatInfo, _ s: String) -> Bool {
cInfo.chatViewName.localizedLowercase.contains(s)
}
}
private func canForwardToChat(_ chat: Chat) -> Bool {
switch chat.chatInfo {
case let .direct(contact): contact.sendMsgEnabled && !contact.nextSendGrpInv
case let .group(groupInfo): groupInfo.sendMsgEnabled
case let .local(noteFolder): noteFolder.sendMsgEnabled
case .contactRequest: false
case .contactConnection: false
case .invalidJSON: false
}
}
private func emptyList() -> some View {
Text("No filtered chats")
.foregroundColor(.secondary)
.frame(maxWidth: .infinity)
}
@ViewBuilder private func forwardListNavLinkView(_ chat: Chat) -> some View {
Button {
dismiss()
if chat.id == fromChatInfo.id {
composeState = ComposeState(
message: composeState.message,
preview: composeState.linkPreview != nil ? composeState.preview : .noPreview,
contextItem: .forwardingItem(chatItem: ci, fromChatInfo: fromChatInfo)
)
} else {
composeState = ComposeState.init(forwardingItem: ci, fromChatInfo: fromChatInfo)
chatModel.chatId = chat.id
}
} label: {
HStack {
ChatInfoImage(chat: chat)
.frame(width: 30, height: 30)
.padding(.trailing, 2)
Text(chat.chatInfo.chatViewName)
.foregroundColor(.primary)
.lineLimit(1)
if chat.chatInfo.incognito {
Spacer()
Image(systemName: "theatermasks")
.resizable()
.scaledToFit()
.frame(width: 22, height: 22)
.foregroundColor(.secondary)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}
#Preview {
ChatItemForwardingView(
ci: ChatItem.getSample(1, .directSnd, .now, "hello"),
fromChatInfo: .direct(contact: Contact.sampleData),
composeState: Binding.constant(ComposeState(message: "hello"))
)
}
@@ -11,6 +11,7 @@ import SimpleXChat
struct ChatItemInfoView: View { struct ChatItemInfoView: View {
@EnvironmentObject var chatModel: ChatModel @EnvironmentObject var chatModel: ChatModel
@Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
var ci: ChatItem var ci: ChatItem
@Binding var chatItemInfo: ChatItemInfo? @Binding var chatItemInfo: ChatItemInfo?
@@ -21,6 +22,7 @@ struct ChatItemInfoView: View {
enum CIInfoTab { enum CIInfoTab {
case history case history
case quote case quote
case forwarded
case delivery case delivery
} }
@@ -68,9 +70,20 @@ struct ChatItemInfoView: View {
if ci.quotedItem != nil { if ci.quotedItem != nil {
numTabs += 1 numTabs += 1
} }
if chatItemInfo?.forwardedFromChatItem != nil {
numTabs += 1
}
return numTabs return numTabs
} }
private var local: Bool {
switch ci.chatDir {
case .localSnd: true
case .localRcv: true
default: false
}
}
@ViewBuilder private func itemInfoView() -> some View { @ViewBuilder private func itemInfoView() -> some View {
if numTabs > 1 { if numTabs > 1 {
TabView(selection: $selection) { TabView(selection: $selection) {
@@ -93,6 +106,13 @@ struct ChatItemInfoView: View {
} }
.tag(CIInfoTab.quote) .tag(CIInfoTab.quote)
} }
if let forwardedFromItem = chatItemInfo?.forwardedFromChatItem {
forwardedFromTab(forwardedFromItem)
.tabItem {
Label(local ? "Saved" : "Forwarded", systemImage: "arrowshape.turn.up.forward")
}
.tag(CIInfoTab.forwarded)
}
} }
.onAppear { .onAppear {
if chatItemInfo?.memberDeliveryStatuses != nil { if chatItemInfo?.memberDeliveryStatuses != nil {
@@ -275,6 +295,75 @@ struct ChatItemInfoView: View {
: Color(uiColor: .tertiarySystemGroupedBackground) : Color(uiColor: .tertiarySystemGroupedBackground)
} }
@ViewBuilder private func forwardedFromTab(_ forwardedFromItem: AChatItem) -> some View {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
details()
Divider().padding(.vertical)
Text(local ? "Saved from" : "Forwarded from")
.font(.title2)
.padding(.bottom, 4)
forwardedFromView(forwardedFromItem)
}
.padding()
}
.frame(maxHeight: .infinity, alignment: .top)
}
private func forwardedFromView(_ forwardedFromItem: AChatItem) -> some View {
VStack(alignment: .leading, spacing: 8) {
Button {
Task {
await MainActor.run {
chatModel.chatId = forwardedFromItem.chatInfo.id
dismiss()
}
}
} label: {
forwardedFromSender(forwardedFromItem)
}
if !local {
Divider().padding(.top, 32)
Text("Recipient(s) can't see who this message is from.")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
@ViewBuilder private func forwardedFromSender(_ forwardedFromItem: AChatItem) -> some View {
HStack {
ChatInfoImage(chat: Chat(chatInfo: forwardedFromItem.chatInfo))
.frame(width: 48, height: 48)
.padding(.trailing, 6)
if forwardedFromItem.chatItem.chatDir.sent {
VStack(alignment: .leading) {
Text("you")
.italic()
.foregroundColor(.primary)
Text(forwardedFromItem.chatInfo.chatViewName)
.foregroundColor(.secondary)
.lineLimit(1)
}
} else if case let .groupRcv(groupMember) = forwardedFromItem.chatItem.chatDir {
VStack(alignment: .leading) {
Text(groupMember.chatViewName)
.foregroundColor(.primary)
.lineLimit(1)
Text(forwardedFromItem.chatInfo.chatViewName)
.foregroundColor(.secondary)
.lineLimit(1)
}
} else {
Text(forwardedFromItem.chatInfo.chatViewName)
.foregroundColor(.primary)
.lineLimit(1)
}
}
}
@ViewBuilder private func deliveryTab(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View { @ViewBuilder private func deliveryTab(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View {
ScrollView { ScrollView {
VStack(alignment: .leading, spacing: 16) { VStack(alignment: .leading, spacing: 16) {
+63 -15
View File
@@ -83,7 +83,11 @@ struct ChatView: View {
initChatView() initChatView()
} }
.onChange(of: chatModel.chatId) { cId in .onChange(of: chatModel.chatId) { cId in
if cId != nil { showChatInfoSheet = false
if let cId {
if let c = chatModel.getChat(cId) {
chat = c
}
initChatView() initChatView()
} else { } else {
dismiss() dismiss()
@@ -179,7 +183,7 @@ struct ChatView: View {
.disabled(!contact.ready || !contact.active) .disabled(!contact.ready || !contact.active)
} }
searchButton() searchButton()
toggleNtfsButton(chat) ToggleNtfsButton(chat: chat)
.disabled(!contact.ready || !contact.active) .disabled(!contact.ready || !contact.active)
} label: { } label: {
Image(systemName: "ellipsis") Image(systemName: "ellipsis")
@@ -208,7 +212,7 @@ struct ChatView: View {
} }
Menu { Menu {
searchButton() searchButton()
toggleNtfsButton(chat) ToggleNtfsButton(chat: chat)
} label: { } label: {
Image(systemName: "ellipsis") Image(systemName: "ellipsis")
} }
@@ -251,7 +255,8 @@ struct ChatView: View {
} }
} }
} }
if chatModel.draftChatId == cInfo.id, let draft = chatModel.draft { if chatModel.draftChatId == cInfo.id && !composeState.forwarding,
let draft = chatModel.draft {
composeState = draft composeState = draft
} }
if chat.chatStats.unreadChat { if chat.chatStats.unreadChat {
@@ -342,8 +347,8 @@ struct ChatView: View {
.onChange(of: searchText) { _ in .onChange(of: searchText) { _ in
loadChat(chat: chat, search: searchText) loadChat(chat: chat, search: searchText)
} }
.onChange(of: chatModel.chatId) { _ in .onChange(of: chatModel.chatId) { chatId in
if let chatId = chatModel.chatId, let c = chatModel.getChat(chatId) { if let chatId, let c = chatModel.getChat(chatId) {
chat = c chat = c
showChatInfoSheet = false showChatInfoSheet = false
loadChat(chat: c) loadChat(chat: c)
@@ -539,6 +544,7 @@ struct ChatView: View {
@State private var revealed = false @State private var revealed = false
@State private var showChatItemInfoSheet: Bool = false @State private var showChatItemInfoSheet: Bool = false
@State private var chatItemInfo: ChatItemInfo? @State private var chatItemInfo: ChatItemInfo?
@State private var showForwardingSheet: Bool = false
@State private var allowMenu: Bool = true @State private var allowMenu: Bool = true
@@ -693,6 +699,14 @@ struct ChatView: View {
}) { }) {
ChatItemInfoView(ci: ci, chatItemInfo: $chatItemInfo) ChatItemInfoView(ci: ci, chatItemInfo: $chatItemInfo)
} }
.sheet(isPresented: $showForwardingSheet) {
if #available(iOS 16.0, *) {
ChatItemForwardingView(ci: ci, fromChatInfo: chat.chatInfo, composeState: $composeState)
.presentationDetents([.fraction(0.8)])
} else {
ChatItemForwardingView(ci: ci, fromChatInfo: chat.chatInfo, composeState: $composeState)
}
}
} }
private func showMemberImage(_ member: GroupMember, _ prevItem: ChatItem?) -> Bool { private func showMemberImage(_ member: GroupMember, _ prevItem: ChatItem?) -> Bool {
@@ -771,10 +785,17 @@ struct ChatView: View {
} else { } else {
menu.append(saveFileAction(fileSource)) menu.append(saveFileAction(fileSource))
} }
} else if let file = ci.file, case .rcvInvitation = file.fileStatus, fileSizeValid(file) {
menu.append(downloadFileAction(file))
} }
if ci.meta.editable && !mc.isVoice && !live { if ci.meta.editable && !mc.isVoice && !live {
menu.append(editAction(ci)) menu.append(editAction(ci))
} }
if ci.meta.itemDeleted == nil
&& (ci.file == nil || (fileSource != nil && fileExists))
&& !ci.isLiveDummy && !live {
menu.append(forwardUIAction(ci))
}
if !ci.isLiveDummy { if !ci.isLiveDummy {
menu.append(viewInfoUIAction(ci)) menu.append(viewInfoUIAction(ci))
} }
@@ -826,6 +847,15 @@ struct ChatView: View {
} }
} }
private func forwardUIAction(_ ci: ChatItem) -> UIAction {
UIAction(
title: NSLocalizedString("Forward", comment: "chat item action"),
image: UIImage(systemName: "arrowshape.turn.up.forward")
) { _ in
showForwardingSheet = true
}
}
private func reactionUIMenuPreiOS16(_ rs: [UIAction]) -> UIMenu { private func reactionUIMenuPreiOS16(_ rs: [UIAction]) -> UIMenu {
UIMenu( UIMenu(
title: NSLocalizedString("React…", comment: "chat item menu"), title: NSLocalizedString("React…", comment: "chat item menu"),
@@ -923,7 +953,21 @@ struct ChatView: View {
saveCryptoFile(fileSource) saveCryptoFile(fileSource)
} }
} }
private func downloadFileAction(_ file: CIFile) -> UIAction {
UIAction(
title: NSLocalizedString("Download", comment: "chat item action"),
image: UIImage(systemName: "arrow.down.doc")
) { _ in
Task {
logger.debug("ChatView downloadFileAction, in Task")
if let user = m.currentUser {
await receiveFile(user: user, fileId: file.fileId)
}
}
}
}
private func editAction(_ ci: ChatItem) -> UIAction { private func editAction(_ ci: ChatItem) -> UIAction {
UIAction( UIAction(
title: NSLocalizedString("Edit", comment: "chat item action"), title: NSLocalizedString("Edit", comment: "chat item action"),
@@ -1172,14 +1216,18 @@ struct ChatView: View {
} }
} }
@ViewBuilder func toggleNtfsButton(_ chat: Chat) -> some View { struct ToggleNtfsButton: View {
Button { @ObservedObject var chat: Chat
toggleNotifications(chat, enableNtfs: !chat.chatInfo.ntfsEnabled)
} label: { var body: some View {
if chat.chatInfo.ntfsEnabled { Button {
Label("Mute", systemImage: "speaker.slash") toggleNotifications(chat, enableNtfs: !chat.chatInfo.ntfsEnabled)
} else { } label: {
Label("Unmute", systemImage: "speaker.wave.2") if chat.chatInfo.ntfsEnabled {
Label("Mute", systemImage: "speaker.slash")
} else {
Label("Unmute", systemImage: "speaker.wave.2")
}
} }
} }
} }
@@ -23,6 +23,7 @@ enum ComposeContextItem {
case noContextItem case noContextItem
case quotedItem(chatItem: ChatItem) case quotedItem(chatItem: ChatItem)
case editingItem(chatItem: ChatItem) case editingItem(chatItem: ChatItem)
case forwardingItem(chatItem: ChatItem, fromChatInfo: ChatInfo)
} }
enum VoiceMessageRecordingState { enum VoiceMessageRecordingState {
@@ -72,6 +73,13 @@ struct ComposeState {
} }
} }
init(forwardingItem: ChatItem, fromChatInfo: ChatInfo) {
self.message = ""
self.preview = .noPreview
self.contextItem = .forwardingItem(chatItem: forwardingItem, fromChatInfo: fromChatInfo)
self.voiceMessageRecordingState = .noRecording
}
func copy( func copy(
message: String? = nil, message: String? = nil,
liveMessage: LiveMessage? = nil, liveMessage: LiveMessage? = nil,
@@ -102,12 +110,19 @@ struct ComposeState {
} }
} }
var forwarding: Bool {
switch contextItem {
case .forwardingItem: return true
default: return false
}
}
var sendEnabled: Bool { var sendEnabled: Bool {
switch preview { switch preview {
case let .mediaPreviews(media): return !media.isEmpty case let .mediaPreviews(media): return !media.isEmpty
case .voicePreview: return voiceMessageRecordingState == .finished case .voicePreview: return voiceMessageRecordingState == .finished
case .filePreview: return true case .filePreview: return true
default: return !message.isEmpty || liveMessage != nil default: return !message.isEmpty || forwarding || liveMessage != nil
} }
} }
@@ -153,7 +168,7 @@ struct ComposeState {
} }
var attachmentDisabled: Bool { var attachmentDisabled: Bool {
if editing || liveMessage != nil || inProgress { return true } if editing || forwarding || liveMessage != nil || inProgress { return true }
switch preview { switch preview {
case .noPreview: return false case .noPreview: return false
case .linkPreview: return false case .linkPreview: return false
@@ -667,6 +682,14 @@ struct ComposeView: View {
contextIcon: "pencil", contextIcon: "pencil",
cancelContextItem: { clearState() } cancelContextItem: { clearState() }
) )
case let .forwardingItem(chatItem: forwardedItem, _):
ContextItemView(
chat: chat,
contextItem: forwardedItem,
contextIcon: "arrowshape.turn.up.forward",
cancelContextItem: { composeState = composeState.copy(contextItem: .noContextItem) },
showSender: false
)
} }
} }
@@ -688,6 +711,11 @@ struct ComposeView: View {
} }
if chat.chatInfo.contact?.nextSendGrpInv ?? false { if chat.chatInfo.contact?.nextSendGrpInv ?? false {
await sendMemberContactInvitation() await sendMemberContactInvitation()
} else if case let .forwardingItem(ci, fromChatInfo) = composeState.contextItem {
sent = await forwardItem(ci, fromChatInfo)
if !composeState.message.isEmpty {
sent = await send(checkLinkPreview(), quoted: sent?.id, live: false, ttl: nil)
}
} else if case let .editingItem(ci) = composeState.contextItem { } else if case let .editingItem(ci) = composeState.contextItem {
sent = await updateMessage(ci, live: live) sent = await updateMessage(ci, live: live)
} else if let liveMessage = liveMessage, liveMessage.sentMsg != nil { } else if let liveMessage = liveMessage, liveMessage.sentMsg != nil {
@@ -733,7 +761,15 @@ struct ComposeView: View {
} }
} }
} }
await MainActor.run { clearState(live: live) } await MainActor.run {
let wasForwarding = composeState.forwarding
clearState(live: live)
if wasForwarding,
chatModel.draftChatId == chat.chatInfo.id,
let draft = chatModel.draft {
composeState = draft
}
}
return sent return sent
func sending() async { func sending() async {
@@ -854,6 +890,22 @@ struct ComposeView: View {
return nil return nil
} }
func forwardItem(_ forwardedItem: ChatItem, _ fromChatInfo: ChatInfo) async -> ChatItem? {
if let chatItem = await apiForwardChatItem(
toChatType: chat.chatInfo.chatType,
toChatId: chat.chatInfo.apiId,
fromChatType: fromChatInfo.chatType,
fromChatId: fromChatInfo.apiId,
itemId: forwardedItem.id
) {
await MainActor.run {
chatModel.addChatItem(chat.chatInfo, chatItem)
}
return chatItem
}
return nil
}
func checkLinkPreview() -> MsgContent { func checkLinkPreview() -> MsgContent {
switch (composeState.preview) { switch (composeState.preview) {
case let .linkPreview(linkPreview: linkPreview): case let .linkPreview(linkPreview: linkPreview):
@@ -15,6 +15,7 @@ struct ContextItemView: View {
let contextItem: ChatItem let contextItem: ChatItem
let contextIcon: String let contextIcon: String
let cancelContextItem: () -> Void let cancelContextItem: () -> Void
var showSender: Bool = true
var body: some View { var body: some View {
HStack { HStack {
@@ -23,7 +24,7 @@ struct ContextItemView: View {
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: 16, height: 16) .frame(width: 16, height: 16)
.foregroundColor(.secondary) .foregroundColor(.secondary)
if let sender = contextItem.memberDisplayName { if showSender, let sender = contextItem.memberDisplayName {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text(sender).font(.caption).foregroundColor(.secondary) Text(sender).font(.caption).foregroundColor(.secondary)
msgContentView(lines: 2) msgContentView(lines: 2)
@@ -48,14 +49,26 @@ struct ContextItemView: View {
} }
private func msgContentView(lines: Int) -> some View { private func msgContentView(lines: Int) -> some View {
MsgContentView( contextMsgPreview()
chat: chat, .multilineTextAlignment(isRightToLeft(contextItem.text) ? .trailing : .leading)
text: contextItem.text, .lineLimit(lines)
formattedText: contextItem.formattedText, }
showSecrets: false
) private func contextMsgPreview() -> Text {
.multilineTextAlignment(isRightToLeft(contextItem.text) ? .trailing : .leading) return attachment() + messageText(contextItem.text, contextItem.formattedText, nil, preview: true, showSecrets: false)
.lineLimit(lines)
func attachment() -> Text {
switch contextItem.content.msgContent {
case .file: return image("doc.fill")
case .image: return image("photo")
case .voice: return image("play.fill")
default: return Text("")
}
}
func image(_ s: String) -> Text {
Text(Image(systemName: s)).foregroundColor(Color(uiColor: .tertiaryLabel)) + Text(" ")
}
} }
} }
@@ -16,7 +16,6 @@ struct NativeTextEditor: UIViewRepresentable {
@Binding var disableEditing: Bool @Binding var disableEditing: Bool
@Binding var height: CGFloat @Binding var height: CGFloat
@Binding var focused: Bool @Binding var focused: Bool
let alignment: TextAlignment
let onImagesAdded: ([UploadContent]) -> Void let onImagesAdded: ([UploadContent]) -> Void
private let minHeight: CGFloat = 37 private let minHeight: CGFloat = 37
@@ -30,13 +29,16 @@ struct NativeTextEditor: UIViewRepresentable {
func makeUIView(context: Context) -> UITextView { func makeUIView(context: Context) -> UITextView {
let field = CustomUITextField(height: _height) let field = CustomUITextField(height: _height)
field.text = text field.text = text
field.textAlignment = alignment == .leading ? .left : .right field.textAlignment = alignment(text)
field.autocapitalizationType = .sentences field.autocapitalizationType = .sentences
field.setOnTextChangedListener { newText, images in field.setOnTextChangedListener { newText, images in
if !disableEditing { if !disableEditing {
// Speed up the process of updating layout, reduce jumping content on screen
if !isShortEmoji(newText) { updateHeight(field) }
text = newText text = newText
field.textAlignment = alignment(text)
updateFont(field)
// Speed up the process of updating layout, reduce jumping content on screen
updateHeight(field)
self.height = field.frame.size.height
} else { } else {
field.text = text field.text = text
} }
@@ -53,10 +55,12 @@ struct NativeTextEditor: UIViewRepresentable {
} }
func updateUIView(_ field: UITextView, context: Context) { func updateUIView(_ field: UITextView, context: Context) {
field.text = text if field.markedTextRange == nil && field.text != text {
field.textAlignment = alignment == .leading ? .left : .right field.text = text
updateFont(field) field.textAlignment = alignment(text)
updateHeight(field) updateFont(field)
updateHeight(field)
}
} }
private func updateHeight(_ field: UITextView) { private func updateHeight(_ field: UITextView) {
@@ -73,12 +77,19 @@ struct NativeTextEditor: UIViewRepresentable {
} }
private func updateFont(_ field: UITextView) { private func updateFont(_ field: UITextView) {
field.font = isShortEmoji(field.text) let newFont = isShortEmoji(field.text)
? (field.text.count < 4 ? largeEmojiUIFont : mediumEmojiUIFont) ? (field.text.count < 4 ? largeEmojiUIFont : mediumEmojiUIFont)
: UIFont.preferredFont(forTextStyle: .body) : UIFont.preferredFont(forTextStyle: .body)
if field.font != newFont {
field.font = newFont
}
} }
} }
private func alignment(_ text: String) -> NSTextAlignment {
isRightToLeft(text) ? .right : .left
}
private class CustomUITextField: UITextView, UITextViewDelegate { private class CustomUITextField: UITextView, UITextViewDelegate {
var height: Binding<CGFloat> var height: Binding<CGFloat>
var newHeight: CGFloat = 0 var newHeight: CGFloat = 0
@@ -205,7 +216,6 @@ struct NativeTextEditor_Previews: PreviewProvider{
disableEditing: Binding.constant(false), disableEditing: Binding.constant(false),
height: Binding.constant(100), height: Binding.constant(100),
focused: Binding.constant(false), focused: Binding.constant(false),
alignment: TextAlignment.leading,
onImagesAdded: { _ in } onImagesAdded: { _ in }
) )
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
@@ -54,13 +54,11 @@ struct SendMessageView: View {
.padding(.vertical, 8) .padding(.vertical, 8)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
} else { } else {
let alignment: TextAlignment = isRightToLeft(composeState.message) ? .trailing : .leading
NativeTextEditor( NativeTextEditor(
text: $composeState.message, text: $composeState.message,
disableEditing: $composeState.inProgress, disableEditing: $composeState.inProgress,
height: $teHeight, height: $teHeight,
focused: $keyboardVisible, focused: $keyboardVisible,
alignment: alignment,
onImagesAdded: onMediaAdded onImagesAdded: onMediaAdded
) )
.allowsTightening(false) .allowsTightening(false)
@@ -110,6 +108,7 @@ struct SendMessageView: View {
} else if showVoiceMessageButton } else if showVoiceMessageButton
&& composeState.message.isEmpty && composeState.message.isEmpty
&& !composeState.editing && !composeState.editing
&& !composeState.forwarding
&& composeState.liveMessage == nil && composeState.liveMessage == nil
&& ((composeState.noPreview && vmrs == .noRecording) && ((composeState.noPreview && vmrs == .noRecording)
|| (vmrs == .recording && holdingVMR)) { || (vmrs == .recording && holdingVMR)) {
@@ -225,7 +224,8 @@ struct SendMessageView: View {
@ViewBuilder private func sendButtonContextMenuItems() -> some View { @ViewBuilder private func sendButtonContextMenuItems() -> some View {
if composeState.liveMessage == nil, if composeState.liveMessage == nil,
!composeState.editing { !composeState.editing,
!composeState.forwarding {
if case .noContextItem = composeState.contextItem, if case .noContextItem = composeState.contextItem,
!composeState.voicePreview, !composeState.voicePreview,
let send = sendLiveMessage, let send = sendLiveMessage,
@@ -62,7 +62,7 @@ struct GroupChatInfoView: View {
NavigationView { NavigationView {
let members = chatModel.groupMembers let members = chatModel.groupMembers
.filter { m in let status = m.wrapped.memberStatus; return status != .memLeft && status != .memRemoved } .filter { m in let status = m.wrapped.memberStatus; return status != .memLeft && status != .memRemoved }
.sorted { $0.displayName.lowercased() < $1.displayName.lowercased() } .sorted { $0.wrapped.memberRole > $1.wrapped.memberRole }
List { List {
groupInfoHeader() groupInfoHeader()
@@ -92,7 +92,7 @@ struct ChatListNavLink: View {
.swipeActions(edge: .leading, allowsFullSwipe: true) { .swipeActions(edge: .leading, allowsFullSwipe: true) {
markReadButton() markReadButton()
toggleFavoriteButton() toggleFavoriteButton()
toggleNtfsButton(chat) ToggleNtfsButton(chat: chat)
} }
.swipeActions(edge: .trailing, allowsFullSwipe: true) { .swipeActions(edge: .trailing, allowsFullSwipe: true) {
if !chat.chatItems.isEmpty { if !chat.chatItems.isEmpty {
@@ -181,7 +181,7 @@ struct ChatListNavLink: View {
.swipeActions(edge: .leading, allowsFullSwipe: true) { .swipeActions(edge: .leading, allowsFullSwipe: true) {
markReadButton() markReadButton()
toggleFavoriteButton() toggleFavoriteButton()
toggleNtfsButton(chat) ToggleNtfsButton(chat: chat)
} }
.swipeActions(edge: .trailing, allowsFullSwipe: true) { .swipeActions(edge: .trailing, allowsFullSwipe: true) {
if !chat.chatItems.isEmpty { if !chat.chatItems.isEmpty {
@@ -51,9 +51,10 @@ struct AdvancedNetworkSettings: View {
} }
.disabled(currentNetCfg == NetCfg.proxyDefaults) .disabled(currentNetCfg == NetCfg.proxyDefaults)
timeoutSettingPicker("TCP connection timeout", selection: $netCfg.tcpConnectTimeout, values: [7_500000, 10_000000, 15_000000, 20_000000, 30_000000, 45_000000], label: secondsLabel) timeoutSettingPicker("TCP connection timeout", selection: $netCfg.tcpConnectTimeout, values: [5_000000, 7_500000, 10_000000, 15_000000, 20_000000, 30_000000, 40_000000], label: secondsLabel)
timeoutSettingPicker("Protocol timeout", selection: $netCfg.tcpTimeout, values: [5_000000, 7_000000, 10_000000, 15_000000, 20_000000, 30_000000], label: secondsLabel) timeoutSettingPicker("Protocol timeout", selection: $netCfg.tcpTimeout, values: [5_000000, 7_000000, 10_000000, 15_000000, 20_000000, 30_000000], label: secondsLabel)
timeoutSettingPicker("Protocol timeout per KB", selection: $netCfg.tcpTimeoutPerKb, values: [2_500, 5_000, 10_000, 15_000, 20_000, 30_000], label: secondsLabel) timeoutSettingPicker("Protocol timeout per KB", selection: $netCfg.tcpTimeoutPerKb, values: [2_500, 5_000, 10_000, 15_000, 20_000, 30_000], label: secondsLabel)
intSettingPicker("Receiving concurrency", selection: $netCfg.rcvConcurrency, values: [1, 2, 4, 8, 12, 16, 24], label: "")
timeoutSettingPicker("PING interval", selection: $netCfg.smpPingInterval, values: [120_000000, 300_000000, 600_000000, 1200_000000, 2400_000000, 3600_000000], label: secondsLabel) timeoutSettingPicker("PING interval", selection: $netCfg.smpPingInterval, values: [120_000000, 300_000000, 600_000000, 1200_000000, 2400_000000, 3600_000000], label: secondsLabel)
intSettingPicker("PING count", selection: $netCfg.smpPingCount, values: [1, 2, 3, 5, 8], label: "") intSettingPicker("PING count", selection: $netCfg.smpPingCount, values: [1, 2, 3, 5, 8], label: "")
Toggle("Enable TCP keep-alive", isOn: $enableKeepAlive) Toggle("Enable TCP keep-alive", isOn: $enableKeepAlive)
@@ -739,6 +739,10 @@
<target>Позволи необратимо изтриване на изпратените съобщения. (24 часа)</target> <target>Позволи необратимо изтриване на изпратените съобщения. (24 часа)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Позволи изпращане на файлове и медия.</target> <target>Позволи изпращане на файлове и медия.</target>
@@ -1079,6 +1083,10 @@
<target>Файлът не може да бъде получен</target> <target>Файлът не може да бъде получен</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Промени</target> <target>Промени</target>
@@ -2073,6 +2081,10 @@ This cannot be undone!</source>
<target>Понижи версията и отвори чата</target> <target>Понижи версията и отвори чата</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Неуспешно изтегляне</target> <target>Неуспешно изтегляне</target>
@@ -2183,6 +2195,10 @@ This cannot be undone!</source>
<target>Активирай kод за достъп за самоунищожение</target> <target>Активирай kод за достъп за самоунищожение</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Криптирай</target> <target>Криптирай</target>
@@ -2708,6 +2724,10 @@ This cannot be undone!</source>
<target>Файловете и медията са забранени в тази група.</target> <target>Файловете и медията са забранени в тази група.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Файловете и медията са забранени!</target> <target>Файловете и медията са забранени!</target>
@@ -2773,6 +2793,18 @@ This cannot be undone!</source>
<target>За конзолата</target> <target>За конзолата</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Намерено настолно устройство</target> <target>Намерено настолно устройство</target>
@@ -2883,6 +2915,10 @@ This cannot be undone!</source>
<target>Членовете на групата могат необратимо да изтриват изпратените съобщения. (24 часа)</target> <target>Членовете на групата могат необратимо да изтриват изпратените съобщения. (24 часа)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Членовете на групата могат да изпращат лични съобщения.</target> <target>Членовете на групата могат да изпращат лични съобщения.</target>
@@ -3746,6 +3782,10 @@ This is your link for group %@!</source>
<target>Мрежа и сървъри</target> <target>Мрежа и сървъри</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Мрежови настройки</target> <target>Мрежови настройки</target>
@@ -3856,6 +3896,10 @@ This is your link for group %@!</source>
<target>Няма история</target> <target>Няма история</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Няма разрешение за запис на гласово съобщение</target> <target>Няма разрешение за запис на гласово съобщение</target>
@@ -4070,6 +4114,10 @@ This is your link for group %@!</source>
<target>Или покажи този код</target> <target>Или покажи този код</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>PING бройка</target> <target>PING бройка</target>
@@ -4332,6 +4380,10 @@ Error: %@</source>
<target>Забрани реакциите на съобщенията.</target> <target>Забрани реакциите на съобщенията.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Забрани изпращането на лични съобщения до членовете.</target> <target>Забрани изпращането на лични съобщения до членовете.</target>
@@ -4462,6 +4514,10 @@ Error: %@</source>
<target>Получаващият адрес ще бъде променен към друг сървър. Промяната на адреса ще завърши, след като подателят е онлайн.</target> <target>Получаващият адрес ще бъде променен към друг сървър. Промяната на адреса ще завърши, след като подателят е онлайн.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Получаващият се файл ще бъде спрян.</target> <target>Получаващият се файл ще бъде спрян.</target>
@@ -4477,6 +4533,10 @@ Error: %@</source>
<target>Скорошна история и подобрен [bot за директория за групи](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPd jdLW3%23%2F%3Fv%3D1-2% 26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target> <target>Скорошна история и подобрен [bot за директория за групи](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPd jdLW3%23%2F%3Fv%3D1-2% 26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Получателите виждат актуализации, докато ги въвеждате.</target> <target>Получателите виждат актуализации, докато ги въвеждате.</target>
@@ -4777,11 +4837,19 @@ Error: %@</source>
<target>Запази съобщението при посрещане?</target> <target>Запази съобщението при посрещане?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Запазените WebRTC ICE сървъри ще бъдат премахнати</target> <target>Запазените WebRTC ICE сървъри ще бъдат премахнати</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Запазено съобщение</target> <target>Запазено съобщение</target>
@@ -5205,6 +5273,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleX линкове</target> <target>SimpleX линкове</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6043,6 +6119,10 @@ To connect, please ask your contact to create another connection link and check
<target>Гласовите съобщения са забранени в тази група.</target> <target>Гласовите съобщения са забранени в тази група.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Гласовите съобщения са забранени!</target> <target>Гласовите съобщения са забранени!</target>
@@ -6123,6 +6203,14 @@ To connect, please ask your contact to create another connection link and check
<target>Когато споделяте инкогнито профил с някого, този профил ще се използва за групите, в които той ви кани.</target> <target>Когато споделяте инкогнито профил с някого, този профил ще се използва за групите, в които той ви кани.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>С криптирани файлове и медия.</target> <target>С криптирани файлове и медия.</target>
@@ -6605,6 +6693,10 @@ SimpleX сървърите не могат да видят вашия профи
<target>админ</target> <target>админ</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>съгласуване на криптиране за %@…</target> <target>съгласуване на криптиране за %@…</target>
@@ -6615,6 +6707,10 @@ SimpleX сървърите не могат да видят вашия профи
<target>съгласуване на криптиране…</target> <target>съгласуване на криптиране…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>винаги</target> <target>винаги</target>
@@ -6945,6 +7041,10 @@ SimpleX сървърите не могат да видят вашия профи
<target>събитие се случи</target> <target>събитие се случи</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>групата е изтрита</target> <target>групата е изтрита</target>
@@ -7152,6 +7252,10 @@ SimpleX сървърите не могат да видят вашия профи
<target>собственик</target> <target>собственик</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>peer-to-peer</target> <target>peer-to-peer</target>
@@ -7202,6 +7306,14 @@ SimpleX сървърите не могат да видят вашия профи
<target>ви острани</target> <target>ви острани</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>сек.</target> <target>сек.</target>
@@ -7342,6 +7454,10 @@ SimpleX сървърите не могат да видят вашия профи
<target>да</target> <target>да</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>вие сте поканени в групата</target> <target>вие сте поканени в групата</target>
@@ -720,6 +720,10 @@
<target>Povolit nevratné smazání odeslaných zpráv. (24 hodin)</target> <target>Povolit nevratné smazání odeslaných zpráv. (24 hodin)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Povolit odesílání souborů a médii.</target> <target>Povolit odesílání souborů a médii.</target>
@@ -1043,6 +1047,10 @@
<target>Nelze přijmout soubor</target> <target>Nelze přijmout soubor</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Změnit</target> <target>Změnit</target>
@@ -1999,6 +2007,10 @@ This cannot be undone!</source>
<target>Snížit a otevřít chat</target> <target>Snížit a otevřít chat</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2104,6 +2116,10 @@ This cannot be undone!</source>
<target>Povolit sebedestrukční heslo</target> <target>Povolit sebedestrukční heslo</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Šifrovat</target> <target>Šifrovat</target>
@@ -2611,6 +2627,10 @@ This cannot be undone!</source>
<target>Soubory a média jsou zakázány v této skupině.</target> <target>Soubory a média jsou zakázány v této skupině.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Soubory a média jsou zakázány!</target> <target>Soubory a média jsou zakázány!</target>
@@ -2674,6 +2694,18 @@ This cannot be undone!</source>
<target>Pro konzoli</target> <target>Pro konzoli</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2780,6 +2812,10 @@ This cannot be undone!</source>
<target>Členové skupiny mohou nevratně mazat odeslané zprávy. (24 hodin)</target> <target>Členové skupiny mohou nevratně mazat odeslané zprávy. (24 hodin)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Členové skupiny mohou posílat přímé zprávy.</target> <target>Členové skupiny mohou posílat přímé zprávy.</target>
@@ -3609,6 +3645,10 @@ This is your link for group %@!</source>
<target>Síť a servery</target> <target>Síť a servery</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Nastavení sítě</target> <target>Nastavení sítě</target>
@@ -3718,6 +3758,10 @@ This is your link for group %@!</source>
<target>Žádná historie</target> <target>Žádná historie</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Nemáte oprávnění nahrávat hlasové zprávy</target> <target>Nemáte oprávnění nahrávat hlasové zprávy</target>
@@ -3923,6 +3967,10 @@ This is your link for group %@!</source>
<source>Or show this code</source> <source>Or show this code</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>Počet PING</target> <target>Počet PING</target>
@@ -4173,6 +4221,10 @@ Error: %@</source>
<target>Zakázat reakce na zprávy.</target> <target>Zakázat reakce na zprávy.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Zakázat odesílání přímých zpráv členům.</target> <target>Zakázat odesílání přímých zpráv členům.</target>
@@ -4300,6 +4352,10 @@ Error: %@</source>
<target>Přijímací adresa bude změněna na jiný server. Změna adresy bude dokončena po připojení odesílatele.</target> <target>Přijímací adresa bude změněna na jiný server. Změna adresy bude dokončena po připojení odesílatele.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Příjem souboru bude zastaven.</target> <target>Příjem souboru bude zastaven.</target>
@@ -4314,6 +4370,10 @@ Error: %@</source>
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source> <source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Příjemci uvidí aktualizace během jejich psaní.</target> <target>Příjemci uvidí aktualizace během jejich psaní.</target>
@@ -4607,11 +4667,19 @@ Error: %@</source>
<target>Uložit uvítací zprávu?</target> <target>Uložit uvítací zprávu?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Uložené servery WebRTC ICE budou odstraněny</target> <target>Uložené servery WebRTC ICE budou odstraněny</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<note>message info title</note> <note>message info title</note>
@@ -5026,6 +5094,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>Odkazy na SimpleX</target> <target>Odkazy na SimpleX</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -5828,6 +5904,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Hlasové zprávy jsou v této skupině zakázány.</target> <target>Hlasové zprávy jsou v této skupině zakázány.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Hlasové zprávy jsou zakázány!</target> <target>Hlasové zprávy jsou zakázány!</target>
@@ -5905,6 +5985,14 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Pokud s někým sdílíte inkognito profil, bude tento profil použit pro skupiny, do kterých vás pozve.</target> <target>Pokud s někým sdílíte inkognito profil, bude tento profil použit pro skupiny, do kterých vás pozve.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -6368,6 +6456,10 @@ Servery SimpleX nevidí váš profil.</target>
<target>správce</target> <target>správce</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>povoluji šifrování pro %@…</target> <target>povoluji šifrování pro %@…</target>
@@ -6378,6 +6470,10 @@ Servery SimpleX nevidí váš profil.</target>
<target>povoluji šifrování…</target> <target>povoluji šifrování…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>vždy</target> <target>vždy</target>
@@ -6700,6 +6796,10 @@ Servery SimpleX nevidí váš profil.</target>
<source>event happened</source> <source>event happened</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>skupina smazána</target> <target>skupina smazána</target>
@@ -6906,6 +7006,10 @@ Servery SimpleX nevidí váš profil.</target>
<target>vlastník</target> <target>vlastník</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>peer-to-peer</target> <target>peer-to-peer</target>
@@ -6953,6 +7057,14 @@ Servery SimpleX nevidí váš profil.</target>
<target>odstranil vás</target> <target>odstranil vás</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sek</target> <target>sek</target>
@@ -7086,6 +7198,10 @@ Servery SimpleX nevidí váš profil.</target>
<target>ano</target> <target>ano</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>jste pozváni do skupiny</target> <target>jste pozváni do skupiny</target>
@@ -743,6 +743,10 @@
<target>Unwiederbringliches löschen von gesendeten Nachrichten erlauben. (24 Stunden)</target> <target>Unwiederbringliches löschen von gesendeten Nachrichten erlauben. (24 Stunden)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Das Senden von Dateien und Medien erlauben.</target> <target>Das Senden von Dateien und Medien erlauben.</target>
@@ -1083,6 +1087,10 @@
<target>Datei kann nicht empfangen werden</target> <target>Datei kann nicht empfangen werden</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Ändern</target> <target>Ändern</target>
@@ -2078,6 +2086,10 @@ Das kann nicht rückgängig gemacht werden!</target>
<target>Datenbank herabstufen und den Chat öffnen</target> <target>Datenbank herabstufen und den Chat öffnen</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Herunterladen fehlgeschlagen</target> <target>Herunterladen fehlgeschlagen</target>
@@ -2188,6 +2200,10 @@ Das kann nicht rückgängig gemacht werden!</target>
<target>Selbstzerstörungs-Zugangscode aktivieren</target> <target>Selbstzerstörungs-Zugangscode aktivieren</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Verschlüsseln</target> <target>Verschlüsseln</target>
@@ -2713,6 +2729,10 @@ Das kann nicht rückgängig gemacht werden!</target>
<target>In dieser Gruppe sind Dateien und Medien nicht erlaubt.</target> <target>In dieser Gruppe sind Dateien und Medien nicht erlaubt.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Dateien und Medien sind nicht erlaubt!</target> <target>Dateien und Medien sind nicht erlaubt!</target>
@@ -2778,6 +2798,18 @@ Das kann nicht rückgängig gemacht werden!</target>
<target>Für Konsole</target> <target>Für Konsole</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Gefundener Desktop</target> <target>Gefundener Desktop</target>
@@ -2888,6 +2920,10 @@ Das kann nicht rückgängig gemacht werden!</target>
<target>Gruppenmitglieder können gesendete Nachrichten unwiederbringlich löschen. (24 Stunden)</target> <target>Gruppenmitglieder können gesendete Nachrichten unwiederbringlich löschen. (24 Stunden)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Gruppenmitglieder können Direktnachrichten versenden.</target> <target>Gruppenmitglieder können Direktnachrichten versenden.</target>
@@ -3753,6 +3789,10 @@ Das ist Ihr Link für die Gruppe %@!</target>
<target>Netzwerk &amp; Server</target> <target>Netzwerk &amp; Server</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Netzwerkeinstellungen</target> <target>Netzwerkeinstellungen</target>
@@ -3863,6 +3903,10 @@ Das ist Ihr Link für die Gruppe %@!</target>
<target>Kein Nachrichtenverlauf</target> <target>Kein Nachrichtenverlauf</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Keine Berechtigung für das Aufnehmen von Sprachnachrichten</target> <target>Keine Berechtigung für das Aufnehmen von Sprachnachrichten</target>
@@ -4077,6 +4121,10 @@ Das ist Ihr Link für die Gruppe %@!</target>
<target>Oder diesen QR-Code anzeigen</target> <target>Oder diesen QR-Code anzeigen</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>PING-Zähler</target> <target>PING-Zähler</target>
@@ -4339,6 +4387,10 @@ Fehler: %@</target>
<target>Reaktionen auf Nachrichten nicht erlauben.</target> <target>Reaktionen auf Nachrichten nicht erlauben.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Das Senden von Direktnachrichten an Gruppenmitglieder nicht erlauben.</target> <target>Das Senden von Direktnachrichten an Gruppenmitglieder nicht erlauben.</target>
@@ -4469,6 +4521,10 @@ Fehler: %@</target>
<target>Die Empfängeradresse wird auf einen anderen Server geändert. Der Adresswechsel wird abgeschlossen, wenn der Absender wieder online ist.</target> <target>Die Empfängeradresse wird auf einen anderen Server geändert. Der Adresswechsel wird abgeschlossen, wenn der Absender wieder online ist.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Der Empfang der Datei wird beendet.</target> <target>Der Empfang der Datei wird beendet.</target>
@@ -4484,6 +4540,10 @@ Fehler: %@</target>
<target>Aktueller Nachrichtenverlauf und verbesserter [Gruppenverzeichnis-Bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target> <target>Aktueller Nachrichtenverlauf und verbesserter [Gruppenverzeichnis-Bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Die Empfänger sehen Nachrichtenaktualisierungen, während Sie sie eingeben.</target> <target>Die Empfänger sehen Nachrichtenaktualisierungen, während Sie sie eingeben.</target>
@@ -4784,11 +4844,19 @@ Fehler: %@</target>
<target>Begrüßungsmeldung speichern?</target> <target>Begrüßungsmeldung speichern?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Gespeicherte WebRTC ICE-Server werden entfernt</target> <target>Gespeicherte WebRTC ICE-Server werden entfernt</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Gespeicherte Nachricht</target> <target>Gespeicherte Nachricht</target>
@@ -5212,6 +5280,14 @@ Fehler: %@</target>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleX-Links</target> <target>SimpleX-Links</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6050,6 +6126,10 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
<target>In dieser Gruppe sind Sprachnachrichten nicht erlaubt.</target> <target>In dieser Gruppe sind Sprachnachrichten nicht erlaubt.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Sprachnachrichten sind nicht erlaubt!</target> <target>Sprachnachrichten sind nicht erlaubt!</target>
@@ -6130,6 +6210,14 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
<target>Wenn Sie ein Inkognito-Profil mit Jemandem teilen, wird dieses Profil auch für die Gruppen verwendet, für die Sie von diesem Kontakt eingeladen werden.</target> <target>Wenn Sie ein Inkognito-Profil mit Jemandem teilen, wird dieses Profil auch für die Gruppen verwendet, für die Sie von diesem Kontakt eingeladen werden.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>Mit verschlüsselten Dateien und Medien.</target> <target>Mit verschlüsselten Dateien und Medien.</target>
@@ -6613,6 +6701,10 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
<target>Admin</target> <target>Admin</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>Verschlüsselung von %@ zustimmen…</target> <target>Verschlüsselung von %@ zustimmen…</target>
@@ -6623,6 +6715,10 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
<target>Verschlüsselung zustimmen…</target> <target>Verschlüsselung zustimmen…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>Immer</target> <target>Immer</target>
@@ -6953,6 +7049,10 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
<target>event happened</target> <target>event happened</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>Gruppe gelöscht</target> <target>Gruppe gelöscht</target>
@@ -7160,6 +7260,10 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
<target>Eigentümer</target> <target>Eigentümer</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>Peer-to-Peer</target> <target>Peer-to-Peer</target>
@@ -7210,6 +7314,14 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
<target>hat Sie aus der Gruppe entfernt</target> <target>hat Sie aus der Gruppe entfernt</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sek</target> <target>sek</target>
@@ -7350,6 +7462,10 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
<target>Ja</target> <target>Ja</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>Sie sind zu der Gruppe eingeladen</target> <target>Sie sind zu der Gruppe eingeladen</target>
@@ -743,6 +743,11 @@
<target>Allow to irreversibly delete sent messages. (24 hours)</target> <target>Allow to irreversibly delete sent messages. (24 hours)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<target>Allow to send SimpleX links.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Allow to send files and media.</target> <target>Allow to send files and media.</target>
@@ -1083,6 +1088,11 @@
<target>Cannot receive file</target> <target>Cannot receive file</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<target>Cellular</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Change</target> <target>Change</target>
@@ -2078,6 +2088,11 @@ This cannot be undone!</target>
<target>Downgrade and open chat</target> <target>Downgrade and open chat</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<target>Download</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Download failed</target> <target>Download failed</target>
@@ -2188,6 +2203,11 @@ This cannot be undone!</target>
<target>Enable self-destruct passcode</target> <target>Enable self-destruct passcode</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<target>Enabled for</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Encrypt</target> <target>Encrypt</target>
@@ -2713,6 +2733,11 @@ This cannot be undone!</target>
<target>Files and media are prohibited in this group.</target> <target>Files and media are prohibited in this group.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<target>Files and media not allowed</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Files and media prohibited!</target> <target>Files and media prohibited!</target>
@@ -2778,6 +2803,21 @@ This cannot be undone!</target>
<target>For console</target> <target>For console</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<target>Forward</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Forwarded</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<target>Forwarded from</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Found desktop</target> <target>Found desktop</target>
@@ -2888,6 +2928,11 @@ This cannot be undone!</target>
<target>Group members can irreversibly delete sent messages. (24 hours)</target> <target>Group members can irreversibly delete sent messages. (24 hours)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<target>Group members can send SimpleX links.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Group members can send direct messages.</target> <target>Group members can send direct messages.</target>
@@ -3753,6 +3798,11 @@ This is your link for group %@!</target>
<target>Network &amp; servers</target> <target>Network &amp; servers</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<target>Network connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Network settings</target> <target>Network settings</target>
@@ -3863,6 +3913,11 @@ This is your link for group %@!</target>
<target>No history</target> <target>No history</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<target>No network connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>No permission to record voice message</target> <target>No permission to record voice message</target>
@@ -4077,6 +4132,11 @@ This is your link for group %@!</target>
<target>Or show this code</target> <target>Or show this code</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<target>Other</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>PING count</target> <target>PING count</target>
@@ -4339,6 +4399,11 @@ Error: %@</target>
<target>Prohibit messages reactions.</target> <target>Prohibit messages reactions.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<target>Prohibit sending SimpleX links.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Prohibit sending direct messages to members.</target> <target>Prohibit sending direct messages to members.</target>
@@ -4469,6 +4534,11 @@ Error: %@</target>
<target>Receiving address will be changed to a different server. Address change will complete after sender comes online.</target> <target>Receiving address will be changed to a different server. Address change will complete after sender comes online.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<target>Receiving concurrency</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Receiving file will be stopped.</target> <target>Receiving file will be stopped.</target>
@@ -4484,6 +4554,11 @@ Error: %@</target>
<target>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target> <target>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<target>Recipient(s) can't see who this message is from.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Recipients see updates as you type them.</target> <target>Recipients see updates as you type them.</target>
@@ -4784,11 +4859,21 @@ Error: %@</target>
<target>Save welcome message?</target> <target>Save welcome message?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<target>Saved</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Saved WebRTC ICE servers will be removed</target> <target>Saved WebRTC ICE servers will be removed</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<target>Saved from</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Saved message</target> <target>Saved message</target>
@@ -5212,6 +5297,16 @@ Error: %@</target>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleX links</target> <target>SimpleX links</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<target>SimpleX links are prohibited in this group.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<target>SimpleX links not allowed</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6050,6 +6145,11 @@ To connect, please ask your contact to create another connection link and check
<target>Voice messages are prohibited in this group.</target> <target>Voice messages are prohibited in this group.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<target>Voice messages not allowed</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Voice messages prohibited!</target> <target>Voice messages prohibited!</target>
@@ -6130,6 +6230,16 @@ To connect, please ask your contact to create another connection link and check
<target>When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.</target> <target>When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<target>WiFi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<target>Wired ethernet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>With encrypted files and media.</target> <target>With encrypted files and media.</target>
@@ -6613,6 +6723,11 @@ SimpleX servers cannot see your profile.</target>
<target>admin</target> <target>admin</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<target>admins</target>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>agreeing encryption for %@…</target> <target>agreeing encryption for %@…</target>
@@ -6623,6 +6738,11 @@ SimpleX servers cannot see your profile.</target>
<target>agreeing encryption…</target> <target>agreeing encryption…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<target>all members</target>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>always</target> <target>always</target>
@@ -6953,6 +7073,11 @@ SimpleX servers cannot see your profile.</target>
<target>event happened</target> <target>event happened</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<target>forwarded</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>group deleted</target> <target>group deleted</target>
@@ -7160,6 +7285,11 @@ SimpleX servers cannot see your profile.</target>
<target>owner</target> <target>owner</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<target>owners</target>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>peer-to-peer</target> <target>peer-to-peer</target>
@@ -7210,6 +7340,16 @@ SimpleX servers cannot see your profile.</target>
<target>removed you</target> <target>removed you</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<target>saved</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<target>saved from %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sec</target> <target>sec</target>
@@ -7350,6 +7490,11 @@ SimpleX servers cannot see your profile.</target>
<target>yes</target> <target>yes</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </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 are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>you are invited to group</target> <target>you are invited to group</target>
@@ -743,6 +743,10 @@
<target>Se permite la eliminación irreversible de mensajes. (24 horas)</target> <target>Se permite la eliminación irreversible de mensajes. (24 horas)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Se permite enviar archivos y multimedia.</target> <target>Se permite enviar archivos y multimedia.</target>
@@ -1083,6 +1087,10 @@
<target>No se puede recibir el archivo</target> <target>No se puede recibir el archivo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Cambiar</target> <target>Cambiar</target>
@@ -2078,6 +2086,10 @@ This cannot be undone!</source>
<target>Degradar y abrir Chat</target> <target>Degradar y abrir Chat</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Error en la descarga</target> <target>Error en la descarga</target>
@@ -2188,6 +2200,10 @@ This cannot be undone!</source>
<target>Activar código de autodestrucción</target> <target>Activar código de autodestrucción</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Cifrar</target> <target>Cifrar</target>
@@ -2713,6 +2729,10 @@ This cannot be undone!</source>
<target>No se permiten archivos y multimedia en este grupo.</target> <target>No se permiten archivos y multimedia en este grupo.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>¡Archivos y multimedia no permitidos!</target> <target>¡Archivos y multimedia no permitidos!</target>
@@ -2778,6 +2798,18 @@ This cannot be undone!</source>
<target>Para consola</target> <target>Para consola</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Ordenador encontrado</target> <target>Ordenador encontrado</target>
@@ -2888,6 +2920,10 @@ This cannot be undone!</source>
<target>Los miembros del grupo pueden eliminar mensajes de forma irreversible. (24 horas)</target> <target>Los miembros del grupo pueden eliminar mensajes de forma irreversible. (24 horas)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Los miembros del grupo pueden enviar mensajes directos.</target> <target>Los miembros del grupo pueden enviar mensajes directos.</target>
@@ -3753,6 +3789,10 @@ This is your link for group %@!</source>
<target>Servidores y Redes</target> <target>Servidores y Redes</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Configuración de red</target> <target>Configuración de red</target>
@@ -3863,6 +3903,10 @@ This is your link for group %@!</source>
<target>Sin historial</target> <target>Sin historial</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Sin permiso para grabar mensajes de voz</target> <target>Sin permiso para grabar mensajes de voz</target>
@@ -4077,6 +4121,10 @@ This is your link for group %@!</source>
<target>O mostrar este código</target> <target>O mostrar este código</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>Contador PING</target> <target>Contador PING</target>
@@ -4339,6 +4387,10 @@ Error: %@</target>
<target>No se permiten reacciones a los mensajes.</target> <target>No se permiten reacciones a los mensajes.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>No se permiten mensajes directos entre miembros.</target> <target>No se permiten mensajes directos entre miembros.</target>
@@ -4469,6 +4521,10 @@ Error: %@</target>
<target>La dirección de recepción pasará a otro servidor. El cambio se completará cuando el remitente esté en línea.</target> <target>La dirección de recepción pasará a otro servidor. El cambio se completará cuando el remitente esté en línea.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Se detendrá la recepción del archivo.</target> <target>Se detendrá la recepción del archivo.</target>
@@ -4484,6 +4540,10 @@ Error: %@</target>
<target>Historial reciente y [bot del directorio](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) mejorados.</target> <target>Historial reciente y [bot del directorio](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) mejorados.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Los destinatarios ven actualizarse mientras escribes.</target> <target>Los destinatarios ven actualizarse mientras escribes.</target>
@@ -4784,11 +4844,19 @@ Error: %@</target>
<target>¿Guardar mensaje de bienvenida?</target> <target>¿Guardar mensaje de bienvenida?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Los servidores WebRTC ICE guardados serán eliminados</target> <target>Los servidores WebRTC ICE guardados serán eliminados</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Mensaje guardado</target> <target>Mensaje guardado</target>
@@ -5212,6 +5280,14 @@ Error: %@</target>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>Enlaces SimpleX</target> <target>Enlaces SimpleX</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6051,6 +6127,10 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb
<target>Los mensajes de voz no están permitidos en este grupo.</target> <target>Los mensajes de voz no están permitidos en este grupo.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>¡Mensajes de voz no permitidos!</target> <target>¡Mensajes de voz no permitidos!</target>
@@ -6131,6 +6211,14 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb
<target>Cuando compartes un perfil incógnito con alguien, este perfil también se usará para los grupos a los que te inviten.</target> <target>Cuando compartes un perfil incógnito con alguien, este perfil también se usará para los grupos a los que te inviten.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>Con cifrado de archivos y multimedia.</target> <target>Con cifrado de archivos y multimedia.</target>
@@ -6614,6 +6702,10 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
<target>administrador</target> <target>administrador</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>acordando cifrado para %@…</target> <target>acordando cifrado para %@…</target>
@@ -6624,6 +6716,10 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
<target>acordando cifrado…</target> <target>acordando cifrado…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>siempre</target> <target>siempre</target>
@@ -6954,6 +7050,10 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
<target>evento ocurrido</target> <target>evento ocurrido</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>grupo eliminado</target> <target>grupo eliminado</target>
@@ -7161,6 +7261,10 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
<target>propietario</target> <target>propietario</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>p2p</target> <target>p2p</target>
@@ -7211,6 +7315,14 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
<target>te ha expulsado</target> <target>te ha expulsado</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>seg</target> <target>seg</target>
@@ -7351,6 +7463,10 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
<target>sí</target> <target>sí</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>has sido invitado a un grupo</target> <target>has sido invitado a un grupo</target>
@@ -715,6 +715,10 @@
<target>Salli lähetettyjen viestien peruuttamaton poistaminen. (24 tuntia)</target> <target>Salli lähetettyjen viestien peruuttamaton poistaminen. (24 tuntia)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Salli tiedostojen ja median lähettäminen.</target> <target>Salli tiedostojen ja median lähettäminen.</target>
@@ -1036,6 +1040,10 @@
<target>Tiedostoa ei voi vastaanottaa</target> <target>Tiedostoa ei voi vastaanottaa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Muuta</target> <target>Muuta</target>
@@ -1992,6 +2000,10 @@ This cannot be undone!</source>
<target>Alenna ja avaa keskustelu</target> <target>Alenna ja avaa keskustelu</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2097,6 +2109,10 @@ This cannot be undone!</source>
<target>Ota itsetuhoava pääsykoodi käyttöön</target> <target>Ota itsetuhoava pääsykoodi käyttöön</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Salaa</target> <target>Salaa</target>
@@ -2601,6 +2617,10 @@ This cannot be undone!</source>
<target>Tiedostot ja media ovat tässä ryhmässä kiellettyjä.</target> <target>Tiedostot ja media ovat tässä ryhmässä kiellettyjä.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Tiedostot ja media kielletty!</target> <target>Tiedostot ja media kielletty!</target>
@@ -2664,6 +2684,18 @@ This cannot be undone!</source>
<target>Konsoliin</target> <target>Konsoliin</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2770,6 +2802,10 @@ This cannot be undone!</source>
<target>Ryhmän jäsenet voivat poistaa lähetetyt viestit peruuttamattomasti. (24 tuntia)</target> <target>Ryhmän jäsenet voivat poistaa lähetetyt viestit peruuttamattomasti. (24 tuntia)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Ryhmän jäsenet voivat lähettää suoraviestejä.</target> <target>Ryhmän jäsenet voivat lähettää suoraviestejä.</target>
@@ -3599,6 +3635,10 @@ This is your link for group %@!</source>
<target>Verkko ja palvelimet</target> <target>Verkko ja palvelimet</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Verkkoasetukset</target> <target>Verkkoasetukset</target>
@@ -3707,6 +3747,10 @@ This is your link for group %@!</source>
<target>Ei historiaa</target> <target>Ei historiaa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Ei lupaa ääniviestin tallentamiseen</target> <target>Ei lupaa ääniviestin tallentamiseen</target>
@@ -3911,6 +3955,10 @@ This is your link for group %@!</source>
<source>Or show this code</source> <source>Or show this code</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>PING-määrä</target> <target>PING-määrä</target>
@@ -4161,6 +4209,10 @@ Error: %@</source>
<target>Estä viestireaktiot.</target> <target>Estä viestireaktiot.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Estä suorien viestien lähettäminen jäsenille.</target> <target>Estä suorien viestien lähettäminen jäsenille.</target>
@@ -4288,6 +4340,10 @@ Error: %@</source>
<target>Vastaanotto-osoite vaihdetaan toiseen palvelimeen. Osoitteenmuutos tehdään sen jälkeen, kun lähettäjä tulee verkkoon.</target> <target>Vastaanotto-osoite vaihdetaan toiseen palvelimeen. Osoitteenmuutos tehdään sen jälkeen, kun lähettäjä tulee verkkoon.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Tiedoston vastaanotto pysäytetään.</target> <target>Tiedoston vastaanotto pysäytetään.</target>
@@ -4302,6 +4358,10 @@ Error: %@</source>
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source> <source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Vastaanottajat näkevät päivitykset, kun kirjoitat niitä.</target> <target>Vastaanottajat näkevät päivitykset, kun kirjoitat niitä.</target>
@@ -4595,11 +4655,19 @@ Error: %@</source>
<target>Tallenna tervetuloviesti?</target> <target>Tallenna tervetuloviesti?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Tallennetut WebRTC ICE -palvelimet poistetaan</target> <target>Tallennetut WebRTC ICE -palvelimet poistetaan</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<note>message info title</note> <note>message info title</note>
@@ -5013,6 +5081,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleX-linkit</target> <target>SimpleX-linkit</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -5813,6 +5889,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Ääniviestit ovat kiellettyjä tässä ryhmässä.</target> <target>Ääniviestit ovat kiellettyjä tässä ryhmässä.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Ääniviestit kielletty!</target> <target>Ääniviestit kielletty!</target>
@@ -5890,6 +5970,14 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Kun jaat inkognitoprofiilin jonkun kanssa, tätä profiilia käytetään ryhmissä, joihin tämä sinut kutsuu.</target> <target>Kun jaat inkognitoprofiilin jonkun kanssa, tätä profiilia käytetään ryhmissä, joihin tämä sinut kutsuu.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -6353,6 +6441,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>ylläpitäjä</target> <target>ylläpitäjä</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>salauksesta sovitaan %@:lle…</target> <target>salauksesta sovitaan %@:lle…</target>
@@ -6363,6 +6455,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>hyväksyy salausta…</target> <target>hyväksyy salausta…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>aina</target> <target>aina</target>
@@ -6685,6 +6781,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>tapahtuma tapahtui</target> <target>tapahtuma tapahtui</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>ryhmä poistettu</target> <target>ryhmä poistettu</target>
@@ -6891,6 +6991,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>omistaja</target> <target>omistaja</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>vertais</target> <target>vertais</target>
@@ -6938,6 +7042,14 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>poisti sinut</target> <target>poisti sinut</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sek</target> <target>sek</target>
@@ -7070,6 +7182,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>kyllä</target> <target>kyllä</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>sinut on kutsuttu ryhmään</target> <target>sinut on kutsuttu ryhmään</target>
@@ -743,6 +743,10 @@
<target>Autoriser la suppression irréversible de messages envoyés. (24 heures)</target> <target>Autoriser la suppression irréversible de messages envoyés. (24 heures)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Permet l'envoi de fichiers et de médias.</target> <target>Permet l'envoi de fichiers et de médias.</target>
@@ -1083,6 +1087,10 @@
<target>Impossible de recevoir le fichier</target> <target>Impossible de recevoir le fichier</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Changer</target> <target>Changer</target>
@@ -2078,6 +2086,10 @@ Cette opération ne peut être annulée !</target>
<target>Rétrograder et ouvrir le chat</target> <target>Rétrograder et ouvrir le chat</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Échec du téléchargement</target> <target>Échec du téléchargement</target>
@@ -2188,6 +2200,10 @@ Cette opération ne peut être annulée !</target>
<target>Activer le code d'autodestruction</target> <target>Activer le code d'autodestruction</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Chiffrer</target> <target>Chiffrer</target>
@@ -2713,6 +2729,10 @@ Cette opération ne peut être annulée !</target>
<target>Les fichiers et les médias sont interdits dans ce groupe.</target> <target>Les fichiers et les médias sont interdits dans ce groupe.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Fichiers et médias interdits !</target> <target>Fichiers et médias interdits !</target>
@@ -2778,6 +2798,18 @@ Cette opération ne peut être annulée !</target>
<target>Pour la console</target> <target>Pour la console</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Bureau trouvé</target> <target>Bureau trouvé</target>
@@ -2888,6 +2920,10 @@ Cette opération ne peut être annulée !</target>
<target>Les membres du groupe peuvent supprimer de manière irréversible les messages envoyés. (24 heures)</target> <target>Les membres du groupe peuvent supprimer de manière irréversible les messages envoyés. (24 heures)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Les membres du groupe peuvent envoyer des messages directs.</target> <target>Les membres du groupe peuvent envoyer des messages directs.</target>
@@ -3753,6 +3789,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Réseau et serveurs</target> <target>Réseau et serveurs</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Paramètres réseau</target> <target>Paramètres réseau</target>
@@ -3863,6 +3903,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Aucun historique</target> <target>Aucun historique</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Pas l'autorisation d'enregistrer un message vocal</target> <target>Pas l'autorisation d'enregistrer un message vocal</target>
@@ -4077,6 +4121,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Ou présenter ce code</target> <target>Ou présenter ce code</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>Nombre de PING</target> <target>Nombre de PING</target>
@@ -4339,6 +4387,10 @@ Erreur: %@</target>
<target>Interdire les réactions aux messages.</target> <target>Interdire les réactions aux messages.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Interdire l'envoi de messages directs aux membres.</target> <target>Interdire l'envoi de messages directs aux membres.</target>
@@ -4469,6 +4521,10 @@ Erreur: %@</target>
<target>L'adresse de réception sera changée pour un autre serveur. Le changement d'adresse sera terminé lorsque l'expéditeur sera en ligne.</target> <target>L'adresse de réception sera changée pour un autre serveur. Le changement d'adresse sera terminé lorsque l'expéditeur sera en ligne.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>La réception du fichier sera interrompue.</target> <target>La réception du fichier sera interrompue.</target>
@@ -4484,6 +4540,10 @@ Erreur: %@</target>
<target>Historique récent et amélioration du [bot annuaire](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target> <target>Historique récent et amélioration du [bot annuaire](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Les destinataires voient les mises à jour au fur et à mesure que vous leur écrivez.</target> <target>Les destinataires voient les mises à jour au fur et à mesure que vous leur écrivez.</target>
@@ -4784,11 +4844,19 @@ Erreur: %@</target>
<target>Enregistrer le message d'accueil?</target> <target>Enregistrer le message d'accueil?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Les serveurs WebRTC ICE sauvegardés seront supprimés</target> <target>Les serveurs WebRTC ICE sauvegardés seront supprimés</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Message enregistré</target> <target>Message enregistré</target>
@@ -5212,6 +5280,14 @@ Erreur: %@</target>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>Liens SimpleX</target> <target>Liens SimpleX</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6050,6 +6126,10 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Les messages vocaux sont interdits dans ce groupe.</target> <target>Les messages vocaux sont interdits dans ce groupe.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Messages vocaux interdits !</target> <target>Messages vocaux interdits !</target>
@@ -6130,6 +6210,14 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Lorsque vous partagez un profil incognito avec quelqu'un, ce profil sera utilisé pour les groupes auxquels il vous invite.</target> <target>Lorsque vous partagez un profil incognito avec quelqu'un, ce profil sera utilisé pour les groupes auxquels il vous invite.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>Avec les fichiers et les médias chiffrés.</target> <target>Avec les fichiers et les médias chiffrés.</target>
@@ -6613,6 +6701,10 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
<target>admin</target> <target>admin</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>négociation du chiffrement avec %@…</target> <target>négociation du chiffrement avec %@…</target>
@@ -6623,6 +6715,10 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
<target>négociation du chiffrement…</target> <target>négociation du chiffrement…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>toujours</target> <target>toujours</target>
@@ -6953,6 +7049,10 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
<target>event happened</target> <target>event happened</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>groupe supprimé</target> <target>groupe supprimé</target>
@@ -7160,6 +7260,10 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
<target>propriétaire</target> <target>propriétaire</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>pair-à-pair</target> <target>pair-à-pair</target>
@@ -7210,6 +7314,14 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
<target>vous a retiré</target> <target>vous a retiré</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sec</target> <target>sec</target>
@@ -7350,6 +7462,10 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
<target>oui</target> <target>oui</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>vous êtes invité·e au groupe</target> <target>vous êtes invité·e au groupe</target>
@@ -737,6 +737,10 @@
<target>Elküldött üzenetek visszafordíthatatlan törlésének engedélyezése. (24 óra)</target> <target>Elküldött üzenetek visszafordíthatatlan törlésének engedélyezése. (24 óra)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Fájlok és médiatartalom küldésének engedélyezése.</target> <target>Fájlok és médiatartalom küldésének engedélyezése.</target>
@@ -1072,6 +1076,10 @@
<target>Nem lehet fogadni a fájlt</target> <target>Nem lehet fogadni a fájlt</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Változtatás</target> <target>Változtatás</target>
@@ -2060,6 +2068,10 @@ Ezt nem vonható vissza!</target>
<target>Visszatérés a korábbi verzióra és a csevegés megnyitása</target> <target>Visszatérés a korábbi verzióra és a csevegés megnyitása</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2166,6 +2178,10 @@ Ezt nem vonható vissza!</target>
<target>Önmegsemmisítő jelkód engedélyezése</target> <target>Önmegsemmisítő jelkód engedélyezése</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Titkosít</target> <target>Titkosít</target>
@@ -2684,6 +2700,10 @@ Ezt nem vonható vissza!</target>
<target>A fájlok- és a médiatartalom küldése le van tiltva ebben a csoportban.</target> <target>A fájlok- és a médiatartalom küldése le van tiltva ebben a csoportban.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>A fájlok- és a médiatartalom küldése le van tiltva!</target> <target>A fájlok- és a médiatartalom küldése le van tiltva!</target>
@@ -2747,6 +2767,18 @@ Ezt nem vonható vissza!</target>
<target>Konzolhoz</target> <target>Konzolhoz</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Megtalált számítógép</target> <target>Megtalált számítógép</target>
@@ -2857,6 +2889,10 @@ Ezt nem vonható vissza!</target>
<target>Csoporttagok visszafordíthatatlanul törölhetik az elküldött üzeneteket. (24 óra)</target> <target>Csoporttagok visszafordíthatatlanul törölhetik az elküldött üzeneteket. (24 óra)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Csoporttagok küldhetnek közvetlen üzeneteket.</target> <target>Csoporttagok küldhetnek közvetlen üzeneteket.</target>
@@ -3707,6 +3743,10 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
<target>Hálózat és kiszolgálók</target> <target>Hálózat és kiszolgálók</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Hálózati beállítások</target> <target>Hálózati beállítások</target>
@@ -3817,6 +3857,10 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
<target>Nincsenek előzmények</target> <target>Nincsenek előzmények</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Nincs engedély a hangüzenet rögzítésére</target> <target>Nincs engedély a hangüzenet rögzítésére</target>
@@ -4028,6 +4072,10 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
<target>Vagy mutassa meg ezt a kódot</target> <target>Vagy mutassa meg ezt a kódot</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>PING számláló</target> <target>PING számláló</target>
@@ -4287,6 +4335,10 @@ Hiba: %@</target>
<target>Az üzenetreakciók tiltása.</target> <target>Az üzenetreakciók tiltása.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Közvetlen üzenetek küldésének letiltása tagok részére.</target> <target>Közvetlen üzenetek küldésének letiltása tagok részére.</target>
@@ -4415,6 +4467,10 @@ Hiba: %@</target>
<target>A fogadó cím egy másik kiszolgálóra változik. A címváltoztatás a feladó online állapotba kerülése után fejeződik be.</target> <target>A fogadó cím egy másik kiszolgálóra változik. A címváltoztatás a feladó online állapotba kerülése után fejeződik be.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>A fájl fogadása leállt.</target> <target>A fájl fogadása leállt.</target>
@@ -4430,6 +4486,10 @@ Hiba: %@</target>
<target>Legutóbbi előzmények és továbbfejlesztett [könyvtárbot] (simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2TxW3dfMfxy 3%23%2F%3Fv%3D1-2% 26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gloncbqjek4gloncbqjek.</target> <target>Legutóbbi előzmények és továbbfejlesztett [könyvtárbot] (simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2TxW3dfMfxy 3%23%2F%3Fv%3D1-2% 26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gloncbqjek4gloncbqjek.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>A címzettek a beírás közben látják a frissítéseket.</target> <target>A címzettek a beírás közben látják a frissítéseket.</target>
@@ -4726,11 +4786,19 @@ Hiba: %@</target>
<target>Üdvözlőszöveg mentése?</target> <target>Üdvözlőszöveg mentése?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>A mentett WebRTC ICE kiszolgálók eltávolításra kerülnek</target> <target>A mentett WebRTC ICE kiszolgálók eltávolításra kerülnek</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Mentett üzenet</target> <target>Mentett üzenet</target>
@@ -5152,6 +5220,14 @@ Hiba: %@</target>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleX hivatkozások</target> <target>SimpleX hivatkozások</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -5981,6 +6057,10 @@ A csatlakozáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsola
<target>A hangüzenetek küldése le van tiltva ebben a csoportban.</target> <target>A hangüzenetek küldése le van tiltva ebben a csoportban.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>A hangüzenetek le vannak tilva!</target> <target>A hangüzenetek le vannak tilva!</target>
@@ -6059,6 +6139,14 @@ A csatlakozáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsola
<target>Inkognitóprofil megosztása esetén a rendszer azt a profilt fogja használni azokhoz a csoportokhoz, amelyekbe meghívást kapott.</target> <target>Inkognitóprofil megosztása esetén a rendszer azt a profilt fogja használni azokhoz a csoportokhoz, amelyekbe meghívást kapott.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>Titkosított fájlokkal és médiatartalommal.</target> <target>Titkosított fájlokkal és médiatartalommal.</target>
@@ -6540,6 +6628,10 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
<target>admin</target> <target>admin</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>titkosítás jóváhagyása %@ számára…</target> <target>titkosítás jóváhagyása %@ számára…</target>
@@ -6550,6 +6642,10 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
<target>titkosítás elfogadása…</target> <target>titkosítás elfogadása…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>mindig</target> <target>mindig</target>
@@ -6880,6 +6976,10 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
<target>esemény történt</target> <target>esemény történt</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>a csoport törölve</target> <target>a csoport törölve</target>
@@ -7087,6 +7187,10 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
<target>tulajdonos</target> <target>tulajdonos</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>ponttól-pontig</target> <target>ponttól-pontig</target>
@@ -7136,6 +7240,14 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
<target>eltávolítottak</target> <target>eltávolítottak</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>mp</target> <target>mp</target>
@@ -7275,6 +7387,10 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
<target>igen</target> <target>igen</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>meghívást kapott a csoportba</target> <target>meghívást kapott a csoportba</target>
@@ -743,6 +743,10 @@
<target>Permetti di eliminare irreversibilmente i messaggi inviati. (24 ore)</target> <target>Permetti di eliminare irreversibilmente i messaggi inviati. (24 ore)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Consenti l'invio di file e contenuti multimediali.</target> <target>Consenti l'invio di file e contenuti multimediali.</target>
@@ -1083,6 +1087,10 @@
<target>Impossibile ricevere il file</target> <target>Impossibile ricevere il file</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Cambia</target> <target>Cambia</target>
@@ -2078,6 +2086,10 @@ Non è reversibile!</target>
<target>Esegui downgrade e apri chat</target> <target>Esegui downgrade e apri chat</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Scaricamento fallito</target> <target>Scaricamento fallito</target>
@@ -2188,6 +2200,10 @@ Non è reversibile!</target>
<target>Attiva il codice di autodistruzione</target> <target>Attiva il codice di autodistruzione</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Crittografare</target> <target>Crittografare</target>
@@ -2713,6 +2729,10 @@ Non è reversibile!</target>
<target>File e contenuti multimediali sono vietati in questo gruppo.</target> <target>File e contenuti multimediali sono vietati in questo gruppo.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>File e contenuti multimediali vietati!</target> <target>File e contenuti multimediali vietati!</target>
@@ -2778,6 +2798,18 @@ Non è reversibile!</target>
<target>Per console</target> <target>Per console</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Desktop trovato</target> <target>Desktop trovato</target>
@@ -2888,6 +2920,10 @@ Non è reversibile!</target>
<target>I membri del gruppo possono eliminare irreversibilmente i messaggi inviati. (24 ore)</target> <target>I membri del gruppo possono eliminare irreversibilmente i messaggi inviati. (24 ore)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>I membri del gruppo possono inviare messaggi diretti.</target> <target>I membri del gruppo possono inviare messaggi diretti.</target>
@@ -3753,6 +3789,10 @@ Questo è il tuo link per il gruppo %@!</target>
<target>Rete e server</target> <target>Rete e server</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Impostazioni di rete</target> <target>Impostazioni di rete</target>
@@ -3863,6 +3903,10 @@ Questo è il tuo link per il gruppo %@!</target>
<target>Nessuna cronologia</target> <target>Nessuna cronologia</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Nessuna autorizzazione per registrare messaggi vocali</target> <target>Nessuna autorizzazione per registrare messaggi vocali</target>
@@ -4077,6 +4121,10 @@ Questo è il tuo link per il gruppo %@!</target>
<target>O mostra questo codice</target> <target>O mostra questo codice</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>Conteggio PING</target> <target>Conteggio PING</target>
@@ -4339,6 +4387,10 @@ Errore: %@</target>
<target>Proibisci le reazioni ai messaggi.</target> <target>Proibisci le reazioni ai messaggi.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Proibisci l'invio di messaggi diretti ai membri.</target> <target>Proibisci l'invio di messaggi diretti ai membri.</target>
@@ -4469,6 +4521,10 @@ Errore: %@</target>
<target>L'indirizzo di ricezione verrà cambiato in un server diverso. La modifica dell'indirizzo verrà completata dopo che il mittente sarà in linea.</target> <target>L'indirizzo di ricezione verrà cambiato in un server diverso. La modifica dell'indirizzo verrà completata dopo che il mittente sarà in linea.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>La ricezione del file verrà interrotta.</target> <target>La ricezione del file verrà interrotta.</target>
@@ -4484,6 +4540,10 @@ Errore: %@</target>
<target>Cronologia recente e [bot della directory](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) migliorato.</target> <target>Cronologia recente e [bot della directory](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) migliorato.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>I destinatari vedono gli aggiornamenti mentre li digiti.</target> <target>I destinatari vedono gli aggiornamenti mentre li digiti.</target>
@@ -4784,11 +4844,19 @@ Errore: %@</target>
<target>Salvare il messaggio di benvenuto?</target> <target>Salvare il messaggio di benvenuto?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>I server WebRTC ICE salvati verranno rimossi</target> <target>I server WebRTC ICE salvati verranno rimossi</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Messaggio salvato</target> <target>Messaggio salvato</target>
@@ -5212,6 +5280,14 @@ Errore: %@</target>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>Link di SimpleX</target> <target>Link di SimpleX</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6050,6 +6126,10 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
<target>I messaggi vocali sono vietati in questo gruppo.</target> <target>I messaggi vocali sono vietati in questo gruppo.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Messaggi vocali vietati!</target> <target>Messaggi vocali vietati!</target>
@@ -6130,6 +6210,14 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
<target>Quando condividi un profilo in incognito con qualcuno, questo profilo verrà utilizzato per i gruppi a cui ti invitano.</target> <target>Quando condividi un profilo in incognito con qualcuno, questo profilo verrà utilizzato per i gruppi a cui ti invitano.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>Con file e multimediali criptati.</target> <target>Con file e multimediali criptati.</target>
@@ -6613,6 +6701,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
<target>amministratore</target> <target>amministratore</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>concordando la crittografia per %@…</target> <target>concordando la crittografia per %@…</target>
@@ -6623,6 +6715,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
<target>concordando la crittografia…</target> <target>concordando la crittografia…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>sempre</target> <target>sempre</target>
@@ -6953,6 +7049,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
<target>evento accaduto</target> <target>evento accaduto</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>gruppo eliminato</target> <target>gruppo eliminato</target>
@@ -7160,6 +7260,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
<target>proprietario</target> <target>proprietario</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>peer-to-peer</target> <target>peer-to-peer</target>
@@ -7210,6 +7314,14 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
<target>ti ha rimosso/a</target> <target>ti ha rimosso/a</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sec</target> <target>sec</target>
@@ -7350,6 +7462,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
<target>sì</target> <target>sì</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>sei stato/a invitato/a al gruppo</target> <target>sei stato/a invitato/a al gruppo</target>
@@ -719,6 +719,10 @@
<target>送信済みメッセージの永久削除を許可する。</target> <target>送信済みメッセージの永久削除を許可する。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>ファイルやメディアの送信を許可する。</target> <target>ファイルやメディアの送信を許可する。</target>
@@ -1042,6 +1046,10 @@
<target>ファイル受信ができません</target> <target>ファイル受信ができません</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>変更</target> <target>変更</target>
@@ -1998,6 +2006,10 @@ This cannot be undone!</source>
<target>ダウングレードしてチャットを開く</target> <target>ダウングレードしてチャットを開く</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2103,6 +2115,10 @@ This cannot be undone!</source>
<target>自己破壊パスコードを有効にする</target> <target>自己破壊パスコードを有効にする</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>暗号化する</target> <target>暗号化する</target>
@@ -2608,6 +2624,10 @@ This cannot be undone!</source>
<target>このグループでは、ファイルとメディアは禁止されています。</target> <target>このグループでは、ファイルとメディアは禁止されています。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>ファイルとメディアは禁止されています!</target> <target>ファイルとメディアは禁止されています!</target>
@@ -2671,6 +2691,18 @@ This cannot be undone!</source>
<target>コンソール</target> <target>コンソール</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2777,6 +2809,10 @@ This cannot be undone!</source>
<target>グループのメンバーがメッセージを完全削除することができます。</target> <target>グループのメンバーがメッセージを完全削除することができます。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>グループのメンバーがダイレクトメッセージを送信できます。</target> <target>グループのメンバーがダイレクトメッセージを送信できます。</target>
@@ -3605,6 +3641,10 @@ This is your link for group %@!</source>
<target>ネットワークとサーバ</target> <target>ネットワークとサーバ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>ネットワーク設定</target> <target>ネットワーク設定</target>
@@ -3714,6 +3754,10 @@ This is your link for group %@!</source>
<target>履歴はありません</target> <target>履歴はありません</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>音声メッセージを録音する権限がありません</target> <target>音声メッセージを録音する権限がありません</target>
@@ -3919,6 +3963,10 @@ This is your link for group %@!</source>
<source>Or show this code</source> <source>Or show this code</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>PING回数</target> <target>PING回数</target>
@@ -4169,6 +4217,10 @@ Error: %@</source>
<target>メッセージへのリアクションは禁止されています。</target> <target>メッセージへのリアクションは禁止されています。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>メンバー間のダイレクトメッセージを使用禁止にする。</target> <target>メンバー間のダイレクトメッセージを使用禁止にする。</target>
@@ -4295,6 +4347,10 @@ Error: %@</source>
<target>開発中の機能です!相手のクライアントが4.2でなければ機能しません。アドレス変更が完了すると、会話にメッセージが出ます。連絡相手 (またはグループのメンバー) からメッセージを受信できないかをご確認ください。</target> <target>開発中の機能です!相手のクライアントが4.2でなければ機能しません。アドレス変更が完了すると、会話にメッセージが出ます。連絡相手 (またはグループのメンバー) からメッセージを受信できないかをご確認ください。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>ファイルの受信を停止します。</target> <target>ファイルの受信を停止します。</target>
@@ -4309,6 +4365,10 @@ Error: %@</source>
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source> <source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>受信者には、入力時に更新内容が表示されます。</target> <target>受信者には、入力時に更新内容が表示されます。</target>
@@ -4602,11 +4662,19 @@ Error: %@</source>
<target>ウェルカムメッセージを保存しますか?</target> <target>ウェルカムメッセージを保存しますか?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>保存されたWebRTC ICEサーバは削除されます</target> <target>保存されたWebRTC ICEサーバは削除されます</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<note>message info title</note> <note>message info title</note>
@@ -5013,6 +5081,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleXリンク</target> <target>SimpleXリンク</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -5813,6 +5889,10 @@ To connect, please ask your contact to create another connection link and check
<target>このグループでは音声メッセージが使用禁止です。</target> <target>このグループでは音声メッセージが使用禁止です。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>音声メッセージは使用禁止です!</target> <target>音声メッセージは使用禁止です!</target>
@@ -5890,6 +5970,14 @@ To connect, please ask your contact to create another connection link and check
<target>連絡相手にシークレットモードのプロフィールを共有すると、その連絡相手に招待されたグループでも同じプロフィールが使われます。</target> <target>連絡相手にシークレットモードのプロフィールを共有すると、その連絡相手に招待されたグループでも同じプロフィールが使われます。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -6353,6 +6441,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
<target>管理者</target> <target>管理者</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>%@の暗号化に同意しています…</target> <target>%@の暗号化に同意しています…</target>
@@ -6363,6 +6455,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
<target>暗号化に同意しています…</target> <target>暗号化に同意しています…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>常に</target> <target>常に</target>
@@ -6685,6 +6781,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
<target>イベント発生</target> <target>イベント発生</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>グループ削除済み</target> <target>グループ削除済み</target>
@@ -6891,6 +6991,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
<target>オーナー</target> <target>オーナー</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>P2P</target> <target>P2P</target>
@@ -6938,6 +7042,14 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
<target>あなたを除名しました</target> <target>あなたを除名しました</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>秒</target> <target>秒</target>
@@ -7070,6 +7182,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
<target>はい</target> <target>はい</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>グループ招待が届きました</target> <target>グループ招待が届きました</target>
@@ -743,6 +743,10 @@
<target>Sta toe om verzonden berichten onomkeerbaar te verwijderen. (24 uur)</target> <target>Sta toe om verzonden berichten onomkeerbaar te verwijderen. (24 uur)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Sta toe om bestanden en media te verzenden.</target> <target>Sta toe om bestanden en media te verzenden.</target>
@@ -1083,6 +1087,10 @@
<target>Kan bestand niet ontvangen</target> <target>Kan bestand niet ontvangen</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Veranderen</target> <target>Veranderen</target>
@@ -2078,6 +2086,10 @@ Dit kan niet ongedaan gemaakt worden!</target>
<target>Downgraden en chat openen</target> <target>Downgraden en chat openen</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Download mislukt</target> <target>Download mislukt</target>
@@ -2188,6 +2200,10 @@ Dit kan niet ongedaan gemaakt worden!</target>
<target>Zelfvernietigings wachtwoord inschakelen</target> <target>Zelfvernietigings wachtwoord inschakelen</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Versleutelen</target> <target>Versleutelen</target>
@@ -2713,6 +2729,10 @@ Dit kan niet ongedaan gemaakt worden!</target>
<target>Bestanden en media zijn verboden in deze groep.</target> <target>Bestanden en media zijn verboden in deze groep.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Bestanden en media verboden!</target> <target>Bestanden en media verboden!</target>
@@ -2778,6 +2798,18 @@ Dit kan niet ongedaan gemaakt worden!</target>
<target>Voor console</target> <target>Voor console</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Desktop gevonden</target> <target>Desktop gevonden</target>
@@ -2888,6 +2920,10 @@ Dit kan niet ongedaan gemaakt worden!</target>
<target>Groepsleden kunnen verzonden berichten onherroepelijk verwijderen. (24 uur)</target> <target>Groepsleden kunnen verzonden berichten onherroepelijk verwijderen. (24 uur)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Groepsleden kunnen directe berichten sturen.</target> <target>Groepsleden kunnen directe berichten sturen.</target>
@@ -3753,6 +3789,10 @@ Dit is jouw link voor groep %@!</target>
<target>Netwerk &amp; servers</target> <target>Netwerk &amp; servers</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Netwerk instellingen</target> <target>Netwerk instellingen</target>
@@ -3863,6 +3903,10 @@ Dit is jouw link voor groep %@!</target>
<target>Geen geschiedenis</target> <target>Geen geschiedenis</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Geen toestemming om spraakbericht op te nemen</target> <target>Geen toestemming om spraakbericht op te nemen</target>
@@ -4077,6 +4121,10 @@ Dit is jouw link voor groep %@!</target>
<target>Of laat deze code zien</target> <target>Of laat deze code zien</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>PING count</target> <target>PING count</target>
@@ -4339,6 +4387,10 @@ Fout: %@</target>
<target>Berichten reacties verbieden.</target> <target>Berichten reacties verbieden.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Verbied het sturen van directe berichten naar leden.</target> <target>Verbied het sturen van directe berichten naar leden.</target>
@@ -4469,6 +4521,10 @@ Fout: %@</target>
<target>Het ontvangstadres wordt gewijzigd naar een andere server. Adres wijziging wordt voltooid nadat de afzender online is.</target> <target>Het ontvangstadres wordt gewijzigd naar een andere server. Adres wijziging wordt voltooid nadat de afzender online is.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Het ontvangen van het bestand wordt gestopt.</target> <target>Het ontvangen van het bestand wordt gestopt.</target>
@@ -4484,6 +4540,10 @@ Fout: %@</target>
<target>Recente geschiedenis en verbeterde [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target> <target>Recente geschiedenis en verbeterde [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Ontvangers zien updates terwijl u ze typt.</target> <target>Ontvangers zien updates terwijl u ze typt.</target>
@@ -4784,11 +4844,19 @@ Fout: %@</target>
<target>Welkomst bericht opslaan?</target> <target>Welkomst bericht opslaan?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Opgeslagen WebRTC ICE servers worden verwijderd</target> <target>Opgeslagen WebRTC ICE servers worden verwijderd</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Opgeslagen bericht</target> <target>Opgeslagen bericht</target>
@@ -5212,6 +5280,14 @@ Fout: %@</target>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleX links</target> <target>SimpleX links</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6050,6 +6126,10 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
<target>Spraak berichten zijn verboden in deze groep.</target> <target>Spraak berichten zijn verboden in deze groep.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Spraak berichten verboden!</target> <target>Spraak berichten verboden!</target>
@@ -6130,6 +6210,14 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
<target>Wanneer je een incognito profiel met iemand deelt, wordt dit profiel gebruikt voor de groepen waarvoor ze je uitnodigen.</target> <target>Wanneer je een incognito profiel met iemand deelt, wordt dit profiel gebruikt voor de groepen waarvoor ze je uitnodigen.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>Met versleutelde bestanden en media.</target> <target>Met versleutelde bestanden en media.</target>
@@ -6613,6 +6701,10 @@ SimpleX servers kunnen uw profiel niet zien.</target>
<target>Beheerder</target> <target>Beheerder</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>versleuteling overeenkomen voor %@…</target> <target>versleuteling overeenkomen voor %@…</target>
@@ -6623,6 +6715,10 @@ SimpleX servers kunnen uw profiel niet zien.</target>
<target>versleuteling overeenkomen…</target> <target>versleuteling overeenkomen…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>altijd</target> <target>altijd</target>
@@ -6953,6 +7049,10 @@ SimpleX servers kunnen uw profiel niet zien.</target>
<target>gebeurtenis gebeurd</target> <target>gebeurtenis gebeurd</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>groep verwijderd</target> <target>groep verwijderd</target>
@@ -7160,6 +7260,10 @@ SimpleX servers kunnen uw profiel niet zien.</target>
<target>Eigenaar</target> <target>Eigenaar</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>peer-to-peer</target> <target>peer-to-peer</target>
@@ -7210,6 +7314,14 @@ SimpleX servers kunnen uw profiel niet zien.</target>
<target>heeft je verwijderd</target> <target>heeft je verwijderd</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sec</target> <target>sec</target>
@@ -7350,6 +7462,10 @@ SimpleX servers kunnen uw profiel niet zien.</target>
<target>Ja</target> <target>Ja</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>je bent uitgenodigd voor de groep</target> <target>je bent uitgenodigd voor de groep</target>
@@ -743,6 +743,10 @@
<target>Zezwól na nieodwracalne usunięcie wysłanych wiadomości. (24 godziny)</target> <target>Zezwól na nieodwracalne usunięcie wysłanych wiadomości. (24 godziny)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Pozwól na wysyłanie plików i mediów.</target> <target>Pozwól na wysyłanie plików i mediów.</target>
@@ -1083,6 +1087,10 @@
<target>Nie można odebrać pliku</target> <target>Nie można odebrać pliku</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Zmień</target> <target>Zmień</target>
@@ -2078,6 +2086,10 @@ To nie może być cofnięte!</target>
<target>Obniż wersję i otwórz czat</target> <target>Obniż wersję i otwórz czat</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Pobieranie nie udane</target> <target>Pobieranie nie udane</target>
@@ -2188,6 +2200,10 @@ To nie może być cofnięte!</target>
<target>Włącz pin samodestrukcji</target> <target>Włącz pin samodestrukcji</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Szyfruj</target> <target>Szyfruj</target>
@@ -2713,6 +2729,10 @@ To nie może być cofnięte!</target>
<target>Pliki i media są zabronione w tej grupie.</target> <target>Pliki i media są zabronione w tej grupie.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Pliki i media zabronione!</target> <target>Pliki i media zabronione!</target>
@@ -2778,6 +2798,18 @@ To nie może być cofnięte!</target>
<target>Dla konsoli</target> <target>Dla konsoli</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Znaleziono komputer</target> <target>Znaleziono komputer</target>
@@ -2888,6 +2920,10 @@ To nie może być cofnięte!</target>
<target>Członkowie grupy mogą nieodwracalnie usuwać wysłane wiadomości. (24 godziny)</target> <target>Członkowie grupy mogą nieodwracalnie usuwać wysłane wiadomości. (24 godziny)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Członkowie grupy mogą wysyłać bezpośrednie wiadomości.</target> <target>Członkowie grupy mogą wysyłać bezpośrednie wiadomości.</target>
@@ -3753,6 +3789,10 @@ To jest twój link do grupy %@!</target>
<target>Sieć i serwery</target> <target>Sieć i serwery</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Ustawienia sieci</target> <target>Ustawienia sieci</target>
@@ -3863,6 +3903,10 @@ To jest twój link do grupy %@!</target>
<target>Brak historii</target> <target>Brak historii</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Brak uprawnień do nagrywania wiadomości głosowej</target> <target>Brak uprawnień do nagrywania wiadomości głosowej</target>
@@ -4077,6 +4121,10 @@ To jest twój link do grupy %@!</target>
<target>Lub pokaż ten kod</target> <target>Lub pokaż ten kod</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>Liczba PINGÓW</target> <target>Liczba PINGÓW</target>
@@ -4339,6 +4387,10 @@ Błąd: %@</target>
<target>Zabroń reakcje wiadomości.</target> <target>Zabroń reakcje wiadomości.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Zabroń wysyłania bezpośrednich wiadomości do członków.</target> <target>Zabroń wysyłania bezpośrednich wiadomości do członków.</target>
@@ -4469,6 +4521,10 @@ Błąd: %@</target>
<target>Adres odbiorczy zostanie zmieniony na inny serwer. Zmiana adresu zostanie zakończona gdy nadawca będzie online.</target> <target>Adres odbiorczy zostanie zmieniony na inny serwer. Zmiana adresu zostanie zakończona gdy nadawca będzie online.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Odbieranie pliku zostanie przerwane.</target> <target>Odbieranie pliku zostanie przerwane.</target>
@@ -4484,6 +4540,10 @@ Błąd: %@</target>
<target>Ostania historia i ulepszony [bot adresowy](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target> <target>Ostania historia i ulepszony [bot adresowy](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Odbiorcy widzą aktualizacje podczas ich wpisywania.</target> <target>Odbiorcy widzą aktualizacje podczas ich wpisywania.</target>
@@ -4784,11 +4844,19 @@ Błąd: %@</target>
<target>Zapisać wiadomość powitalną?</target> <target>Zapisać wiadomość powitalną?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Zapisane serwery WebRTC ICE zostaną usunięte</target> <target>Zapisane serwery WebRTC ICE zostaną usunięte</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Zachowano wiadomość</target> <target>Zachowano wiadomość</target>
@@ -5212,6 +5280,14 @@ Błąd: %@</target>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>Linki SimpleX</target> <target>Linki SimpleX</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6050,6 +6126,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
<target>Wiadomości głosowe są zabronione w tej grupie.</target> <target>Wiadomości głosowe są zabronione w tej grupie.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Wiadomości głosowe zabronione!</target> <target>Wiadomości głosowe zabronione!</target>
@@ -6130,6 +6210,14 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
<target>Gdy udostępnisz komuś profil incognito, będzie on używany w grupach, do których Cię zaprosi.</target> <target>Gdy udostępnisz komuś profil incognito, będzie on używany w grupach, do których Cię zaprosi.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>Z zaszyfrowanymi plikami i multimediami.</target> <target>Z zaszyfrowanymi plikami i multimediami.</target>
@@ -6613,6 +6701,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
<target>administrator</target> <target>administrator</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>uzgadnianie szyfrowania dla %@…</target> <target>uzgadnianie szyfrowania dla %@…</target>
@@ -6623,6 +6715,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
<target>uzgadnianie szyfrowania…</target> <target>uzgadnianie szyfrowania…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>zawsze</target> <target>zawsze</target>
@@ -6953,6 +7049,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
<target>nowe wydarzenie</target> <target>nowe wydarzenie</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>grupa usunięta</target> <target>grupa usunięta</target>
@@ -7160,6 +7260,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
<target>właściciel</target> <target>właściciel</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>peer-to-peer</target> <target>peer-to-peer</target>
@@ -7210,6 +7314,14 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
<target>usunął cię</target> <target>usunął cię</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sek</target> <target>sek</target>
@@ -7350,6 +7462,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
<target>tak</target> <target>tak</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>jesteś zaproszony do grupy</target> <target>jesteś zaproszony do grupy</target>
@@ -743,6 +743,10 @@
<target>Разрешить необратимо удалять отправленные сообщения. (24 часа)</target> <target>Разрешить необратимо удалять отправленные сообщения. (24 часа)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Разрешить посылать файлы и медиа.</target> <target>Разрешить посылать файлы и медиа.</target>
@@ -1083,6 +1087,10 @@
<target>Невозможно получить файл</target> <target>Невозможно получить файл</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Поменять</target> <target>Поменять</target>
@@ -2078,6 +2086,10 @@ This cannot be undone!</source>
<target>Откатить версию и открыть чат</target> <target>Откатить версию и открыть чат</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Ошибка загрузки</target> <target>Ошибка загрузки</target>
@@ -2188,6 +2200,10 @@ This cannot be undone!</source>
<target>Включить код самоуничтожения</target> <target>Включить код самоуничтожения</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Зашифровать</target> <target>Зашифровать</target>
@@ -2713,6 +2729,10 @@ This cannot be undone!</source>
<target>Файлы и медиа запрещены в этой группе.</target> <target>Файлы и медиа запрещены в этой группе.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Файлы и медиа запрещены!</target> <target>Файлы и медиа запрещены!</target>
@@ -2778,6 +2798,18 @@ This cannot be undone!</source>
<target>Для консоли</target> <target>Для консоли</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Компьютер найден</target> <target>Компьютер найден</target>
@@ -2888,6 +2920,10 @@ This cannot be undone!</source>
<target>Члены группы могут необратимо удалять отправленные сообщения. (24 часа)</target> <target>Члены группы могут необратимо удалять отправленные сообщения. (24 часа)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Члены группы могут посылать прямые сообщения.</target> <target>Члены группы могут посылать прямые сообщения.</target>
@@ -3753,6 +3789,10 @@ This is your link for group %@!</source>
<target>Сеть &amp; серверы</target> <target>Сеть &amp; серверы</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Настройки сети</target> <target>Настройки сети</target>
@@ -3863,6 +3903,10 @@ This is your link for group %@!</source>
<target>Нет истории</target> <target>Нет истории</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Нет разрешения для записи голосового сообщения</target> <target>Нет разрешения для записи голосового сообщения</target>
@@ -4077,6 +4121,10 @@ This is your link for group %@!</source>
<target>Или покажите этот код</target> <target>Или покажите этот код</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>Количество PING</target> <target>Количество PING</target>
@@ -4339,6 +4387,10 @@ Error: %@</source>
<target>Запретить реакции на сообщения.</target> <target>Запретить реакции на сообщения.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Запретить посылать прямые сообщения членам группы.</target> <target>Запретить посылать прямые сообщения членам группы.</target>
@@ -4469,6 +4521,10 @@ Error: %@</source>
<target>Адрес получения сообщений будет перемещён на другой сервер. Изменение адреса завершится после того как отправитель будет онлайн.</target> <target>Адрес получения сообщений будет перемещён на другой сервер. Изменение адреса завершится после того как отправитель будет онлайн.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Приём файла будет прекращён.</target> <target>Приём файла будет прекращён.</target>
@@ -4484,6 +4540,10 @@ Error: %@</source>
<target>История сообщений и улучшенный [каталог групп](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target> <target>История сообщений и улучшенный [каталог групп](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Получатели видят их в то время как Вы их набираете.</target> <target>Получатели видят их в то время как Вы их набираете.</target>
@@ -4784,11 +4844,19 @@ Error: %@</source>
<target>Сохранить приветственное сообщение?</target> <target>Сохранить приветственное сообщение?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Сохраненные WebRTC ICE серверы будут удалены</target> <target>Сохраненные WebRTC ICE серверы будут удалены</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Сохраненное сообщение</target> <target>Сохраненное сообщение</target>
@@ -5212,6 +5280,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleX ссылки</target> <target>SimpleX ссылки</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6050,6 +6126,10 @@ To connect, please ask your contact to create another connection link and check
<target>Голосовые сообщения запрещены в этой группе.</target> <target>Голосовые сообщения запрещены в этой группе.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Голосовые сообщения запрещены!</target> <target>Голосовые сообщения запрещены!</target>
@@ -6130,6 +6210,14 @@ To connect, please ask your contact to create another connection link and check
<target>Когда Вы соединены с контактом инкогнито, тот же самый инкогнито профиль будет использоваться для групп с этим контактом.</target> <target>Когда Вы соединены с контактом инкогнито, тот же самый инкогнито профиль будет использоваться для групп с этим контактом.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>С зашифрованными файлами и медиа.</target> <target>С зашифрованными файлами и медиа.</target>
@@ -6613,6 +6701,10 @@ SimpleX серверы не могут получить доступ к Ваше
<target>админ</target> <target>админ</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>шифрование согласовывается для %@…</target> <target>шифрование согласовывается для %@…</target>
@@ -6623,6 +6715,10 @@ SimpleX серверы не могут получить доступ к Ваше
<target>шифрование согласовывается…</target> <target>шифрование согласовывается…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>всегда</target> <target>всегда</target>
@@ -6953,6 +7049,10 @@ SimpleX серверы не могут получить доступ к Ваше
<target>событие произошло</target> <target>событие произошло</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>группа удалена</target> <target>группа удалена</target>
@@ -7160,6 +7260,10 @@ SimpleX серверы не могут получить доступ к Ваше
<target>владелец</target> <target>владелец</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>peer-to-peer</target> <target>peer-to-peer</target>
@@ -7210,6 +7314,14 @@ SimpleX серверы не могут получить доступ к Ваше
<target>удалил(а) Вас из группы</target> <target>удалил(а) Вас из группы</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>сек</target> <target>сек</target>
@@ -7350,6 +7462,10 @@ SimpleX серверы не могут получить доступ к Ваше
<target>да</target> <target>да</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>Вы приглашены в группу</target> <target>Вы приглашены в группу</target>
@@ -707,6 +707,10 @@
<target>อนุญาตให้ลบข้อความที่ส่งไปแล้วอย่างถาวร</target> <target>อนุญาตให้ลบข้อความที่ส่งไปแล้วอย่างถาวร</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>อนุญาตให้ส่งไฟล์และสื่อ</target> <target>อนุญาตให้ส่งไฟล์และสื่อ</target>
@@ -1028,6 +1032,10 @@
<target>ไม่สามารถรับไฟล์ได้</target> <target>ไม่สามารถรับไฟล์ได้</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>เปลี่ยน</target> <target>เปลี่ยน</target>
@@ -1979,6 +1987,10 @@ This cannot be undone!</source>
<target>ปรับลดรุ่นและเปิดแชท</target> <target>ปรับลดรุ่นและเปิดแชท</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2084,6 +2096,10 @@ This cannot be undone!</source>
<target>เปิดใช้งานรหัสผ่านแบบทําลายตัวเอง</target> <target>เปิดใช้งานรหัสผ่านแบบทําลายตัวเอง</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Encrypt</target> <target>Encrypt</target>
@@ -2586,6 +2602,10 @@ This cannot be undone!</source>
<target>ไฟล์และสื่อเป็นสิ่งต้องห้ามในกลุ่มนี้</target> <target>ไฟล์และสื่อเป็นสิ่งต้องห้ามในกลุ่มนี้</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>ไฟล์และสื่อต้องห้าม!</target> <target>ไฟล์และสื่อต้องห้าม!</target>
@@ -2649,6 +2669,18 @@ This cannot be undone!</source>
<target>สำหรับคอนโซล</target> <target>สำหรับคอนโซล</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2755,6 +2787,10 @@ This cannot be undone!</source>
<target>สมาชิกกลุ่มสามารถลบข้อความที่ส่งแล้วอย่างถาวร</target> <target>สมาชิกกลุ่มสามารถลบข้อความที่ส่งแล้วอย่างถาวร</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>สมาชิกกลุ่มสามารถส่งข้อความโดยตรงได้</target> <target>สมาชิกกลุ่มสามารถส่งข้อความโดยตรงได้</target>
@@ -3581,6 +3617,10 @@ This is your link for group %@!</source>
<target>เครือข่ายและเซิร์ฟเวอร์</target> <target>เครือข่ายและเซิร์ฟเวอร์</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>การตั้งค่าเครือข่าย</target> <target>การตั้งค่าเครือข่าย</target>
@@ -3688,6 +3728,10 @@ This is your link for group %@!</source>
<target>ไม่มีประวัติ</target> <target>ไม่มีประวัติ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>ไม่อนุญาตให้บันทึกข้อความเสียง</target> <target>ไม่อนุญาตให้บันทึกข้อความเสียง</target>
@@ -3892,6 +3936,10 @@ This is your link for group %@!</source>
<source>Or show this code</source> <source>Or show this code</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>จํานวน PING</target> <target>จํานวน PING</target>
@@ -4142,6 +4190,10 @@ Error: %@</source>
<target>ห้ามแสดงปฏิกิริยาต่อข้อความ</target> <target>ห้ามแสดงปฏิกิริยาต่อข้อความ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>ห้ามส่งข้อความโดยตรงถึงสมาชิก</target> <target>ห้ามส่งข้อความโดยตรงถึงสมาชิก</target>
@@ -4268,6 +4320,10 @@ Error: %@</source>
<target>ที่อยู่ผู้รับจะถูกเปลี่ยนเป็นเซิร์ฟเวอร์อื่น การเปลี่ยนแปลงที่อยู่จะเสร็จสมบูรณ์หลังจากที่ผู้ส่งออนไลน์</target> <target>ที่อยู่ผู้รับจะถูกเปลี่ยนเป็นเซิร์ฟเวอร์อื่น การเปลี่ยนแปลงที่อยู่จะเสร็จสมบูรณ์หลังจากที่ผู้ส่งออนไลน์</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>การรับไฟล์จะหยุดลง</target> <target>การรับไฟล์จะหยุดลง</target>
@@ -4282,6 +4338,10 @@ Error: %@</source>
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source> <source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>ผู้รับจะเห็นการอัปเดตเมื่อคุณพิมพ์</target> <target>ผู้รับจะเห็นการอัปเดตเมื่อคุณพิมพ์</target>
@@ -4574,11 +4634,19 @@ Error: %@</source>
<target>บันทึกข้อความต้อนรับ?</target> <target>บันทึกข้อความต้อนรับ?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>เซิร์ฟเวอร์ WebRTC ICE ที่บันทึกไว้จะถูกลบออก</target> <target>เซิร์ฟเวอร์ WebRTC ICE ที่บันทึกไว้จะถูกลบออก</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<note>message info title</note> <note>message info title</note>
@@ -4989,6 +5057,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>ลิงก์ SimpleX</target> <target>ลิงก์ SimpleX</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -5785,6 +5861,10 @@ To connect, please ask your contact to create another connection link and check
<target>ข้อความเสียงเป็นสิ่งต้องห้ามในกลุ่มนี้</target> <target>ข้อความเสียงเป็นสิ่งต้องห้ามในกลุ่มนี้</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>ห้ามข้อความเสียง!</target> <target>ห้ามข้อความเสียง!</target>
@@ -5862,6 +5942,14 @@ To connect, please ask your contact to create another connection link and check
<target>เมื่อคุณแชร์โปรไฟล์ที่ไม่ระบุตัวตนกับใครสักคน โปรไฟล์นี้จะใช้สำหรับกลุ่มที่พวกเขาเชิญคุณ</target> <target>เมื่อคุณแชร์โปรไฟล์ที่ไม่ระบุตัวตนกับใครสักคน โปรไฟล์นี้จะใช้สำหรับกลุ่มที่พวกเขาเชิญคุณ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -6323,6 +6411,10 @@ SimpleX servers cannot see your profile.</source>
<target>ผู้ดูแลระบบ</target> <target>ผู้ดูแลระบบ</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>ยอมรับ encryption สำหรับ %@…</target> <target>ยอมรับ encryption สำหรับ %@…</target>
@@ -6333,6 +6425,10 @@ SimpleX servers cannot see your profile.</source>
<target>เห็นด้วยกับการ encryption…</target> <target>เห็นด้วยกับการ encryption…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>เสมอ</target> <target>เสมอ</target>
@@ -6653,6 +6749,10 @@ SimpleX servers cannot see your profile.</source>
<source>event happened</source> <source>event happened</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>ลบกลุ่มแล้ว</target> <target>ลบกลุ่มแล้ว</target>
@@ -6859,6 +6959,10 @@ SimpleX servers cannot see your profile.</source>
<target>เจ้าของ</target> <target>เจ้าของ</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>เพื่อนต่อเพื่อน</target> <target>เพื่อนต่อเพื่อน</target>
@@ -6906,6 +7010,14 @@ SimpleX servers cannot see your profile.</source>
<target>ลบคุณออกแล้ว</target> <target>ลบคุณออกแล้ว</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>วินาที</target> <target>วินาที</target>
@@ -7038,6 +7150,10 @@ SimpleX servers cannot see your profile.</source>
<target>ใช่</target> <target>ใช่</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>คุณได้รับเชิญให้เข้าร่วมกลุ่ม</target> <target>คุณได้รับเชิญให้เข้าร่วมกลุ่ม</target>
@@ -743,6 +743,10 @@
<target>Gönderilen mesajların kalıcı olarak silinmesine izin ver. (24 saat içinde)</target> <target>Gönderilen mesajların kalıcı olarak silinmesine izin ver. (24 saat içinde)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Dosya ve medya göndermeye izin ver.</target> <target>Dosya ve medya göndermeye izin ver.</target>
@@ -1083,6 +1087,10 @@
<target>Dosya alınamıyor</target> <target>Dosya alınamıyor</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Değiştir</target> <target>Değiştir</target>
@@ -2078,6 +2086,10 @@ Bu geri alınamaz!</target>
<target>Sürüm düşür ve sohbeti aç</target> <target>Sürüm düşür ve sohbeti aç</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Yükleme başarısız oldu</target> <target>Yükleme başarısız oldu</target>
@@ -2188,6 +2200,10 @@ Bu geri alınamaz!</target>
<target>Kendini imha şifresini etkinleştir</target> <target>Kendini imha şifresini etkinleştir</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Şifreleme</target> <target>Şifreleme</target>
@@ -2713,6 +2729,10 @@ Bu geri alınamaz!</target>
<target>Dosyalar ve medya bu grupta yasaklandı.</target> <target>Dosyalar ve medya bu grupta yasaklandı.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Dosyalar ve medya yasaklandı!</target> <target>Dosyalar ve medya yasaklandı!</target>
@@ -2778,6 +2798,18 @@ Bu geri alınamaz!</target>
<target>Konsol için</target> <target>Konsol için</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Bilgisayar bulundu</target> <target>Bilgisayar bulundu</target>
@@ -2888,6 +2920,10 @@ Bu geri alınamaz!</target>
<target>Grup üyeleri, gönderilen mesajları kalıcı olarak silebilir. (24 saat içinde)</target> <target>Grup üyeleri, gönderilen mesajları kalıcı olarak silebilir. (24 saat içinde)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Grup üyeleri doğrudan mesajlar gönderebilir.</target> <target>Grup üyeleri doğrudan mesajlar gönderebilir.</target>
@@ -3753,6 +3789,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Ağ &amp; sunucular</target> <target>Ağ &amp; sunucular</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Ağ ayarları</target> <target>Ağ ayarları</target>
@@ -3863,6 +3903,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Geçmiş yok</target> <target>Geçmiş yok</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Sesli mesaj kaydetmek için izin yok</target> <target>Sesli mesaj kaydetmek için izin yok</target>
@@ -4077,6 +4121,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Veya bu kodu göster</target> <target>Veya bu kodu göster</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>PING sayısı</target> <target>PING sayısı</target>
@@ -4339,6 +4387,10 @@ Hata: %@</target>
<target>Mesajlarda tepkileri yasakla.</target> <target>Mesajlarda tepkileri yasakla.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Geri dönülmez mesaj silme işlemini yasakla.</target> <target>Geri dönülmez mesaj silme işlemini yasakla.</target>
@@ -4469,6 +4521,10 @@ Hata: %@</target>
<target>Alıcı adresi farklı bir sunucuya değiştirilecektir. Gönderici çevrimiçi olduktan sonra adres değişikliği tamamlanacaktır.</target> <target>Alıcı adresi farklı bir sunucuya değiştirilecektir. Gönderici çevrimiçi olduktan sonra adres değişikliği tamamlanacaktır.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Dosya alımı durdurulacaktır.</target> <target>Dosya alımı durdurulacaktır.</target>
@@ -4484,6 +4540,10 @@ Hata: %@</target>
<target>Yakın geçmiş ve geliştirilmiş [dizin botu](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex. im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target> <target>Yakın geçmiş ve geliştirilmiş [dizin botu](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex. im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Alıcılar yazdığına göre güncellemeleri görecektir.</target> <target>Alıcılar yazdığına göre güncellemeleri görecektir.</target>
@@ -4784,11 +4844,19 @@ Hata: %@</target>
<target>Hoşgeldin mesajı kaydedilsin mi?</target> <target>Hoşgeldin mesajı kaydedilsin mi?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Kaydedilmiş WebRTC ICE sunucuları silinecek</target> <target>Kaydedilmiş WebRTC ICE sunucuları silinecek</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Kaydedilmiş mesaj</target> <target>Kaydedilmiş mesaj</target>
@@ -5212,6 +5280,14 @@ Hata: %@</target>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleX bağlantıları</target> <target>SimpleX bağlantıları</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6050,6 +6126,10 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste
<target>Bu grupta sesli mesajlar yasaktır.</target> <target>Bu grupta sesli mesajlar yasaktır.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Sesli mesajlar yasaktır!</target> <target>Sesli mesajlar yasaktır!</target>
@@ -6130,6 +6210,14 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste
<target>Biriyle gizli bir profil paylaştığınızda, bu profil sizi davet ettikleri gruplar için kullanılacaktır.</target> <target>Biriyle gizli bir profil paylaştığınızda, bu profil sizi davet ettikleri gruplar için kullanılacaktır.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>Şifrelenmiş dosyalar ve medya ile birlikte.</target> <target>Şifrelenmiş dosyalar ve medya ile birlikte.</target>
@@ -6613,6 +6701,10 @@ SimpleX sunucuları profilinizi göremez.</target>
<target>yönetici</target> <target>yönetici</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>%@ için şifreleme kabul ediliyor…</target> <target>%@ için şifreleme kabul ediliyor…</target>
@@ -6623,6 +6715,10 @@ SimpleX sunucuları profilinizi göremez.</target>
<target>şifreleme kabul ediliyor…</target> <target>şifreleme kabul ediliyor…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>her zaman</target> <target>her zaman</target>
@@ -6953,6 +7049,10 @@ SimpleX sunucuları profilinizi göremez.</target>
<target>etkinlik yaşandı</target> <target>etkinlik yaşandı</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>grup silindi</target> <target>grup silindi</target>
@@ -7160,6 +7260,10 @@ SimpleX sunucuları profilinizi göremez.</target>
<target>sahip</target> <target>sahip</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>eşler arası</target> <target>eşler arası</target>
@@ -7210,6 +7314,14 @@ SimpleX sunucuları profilinizi göremez.</target>
<target>sen kaldırıldın</target> <target>sen kaldırıldın</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sn</target> <target>sn</target>
@@ -7350,6 +7462,10 @@ SimpleX sunucuları profilinizi göremez.</target>
<target>evet</target> <target>evet</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>gruba davet edildiniz</target> <target>gruba davet edildiniz</target>
@@ -743,6 +743,10 @@
<target>Дозволяє безповоротно видаляти надіслані повідомлення. (24 години)</target> <target>Дозволяє безповоротно видаляти надіслані повідомлення. (24 години)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Дозволяє надсилати файли та медіа.</target> <target>Дозволяє надсилати файли та медіа.</target>
@@ -1083,6 +1087,10 @@
<target>Не вдається отримати файл</target> <target>Не вдається отримати файл</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Зміна</target> <target>Зміна</target>
@@ -2078,6 +2086,10 @@ This cannot be undone!</source>
<target>Пониження та відкритий чат</target> <target>Пониження та відкритий чат</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<target>Не вдалося завантажити</target> <target>Не вдалося завантажити</target>
@@ -2188,6 +2200,10 @@ This cannot be undone!</source>
<target>Увімкнути пароль самознищення</target> <target>Увімкнути пароль самознищення</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Зашифрувати</target> <target>Зашифрувати</target>
@@ -2713,6 +2729,10 @@ This cannot be undone!</source>
<target>Файли та медіа в цій групі заборонені.</target> <target>Файли та медіа в цій групі заборонені.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Файли та медіа заборонені!</target> <target>Файли та медіа заборонені!</target>
@@ -2778,6 +2798,18 @@ This cannot be undone!</source>
<target>Для консолі</target> <target>Для консолі</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>Знайдено робочий стіл</target> <target>Знайдено робочий стіл</target>
@@ -2888,6 +2920,10 @@ This cannot be undone!</source>
<target>Учасники групи можуть безповоротно видаляти надіслані повідомлення. (24 години)</target> <target>Учасники групи можуть безповоротно видаляти надіслані повідомлення. (24 години)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Учасники групи можуть надсилати прямі повідомлення.</target> <target>Учасники групи можуть надсилати прямі повідомлення.</target>
@@ -3753,6 +3789,10 @@ This is your link for group %@!</source>
<target>Мережа та сервери</target> <target>Мережа та сервери</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Налаштування мережі</target> <target>Налаштування мережі</target>
@@ -3863,6 +3903,10 @@ This is your link for group %@!</source>
<target>Немає історії</target> <target>Немає історії</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Немає дозволу на запис голосового повідомлення</target> <target>Немає дозволу на запис голосового повідомлення</target>
@@ -4077,6 +4121,10 @@ This is your link for group %@!</source>
<target>Або покажіть цей код</target> <target>Або покажіть цей код</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>Кількість PING</target> <target>Кількість PING</target>
@@ -4339,6 +4387,10 @@ Error: %@</source>
<target>Заборонити реакції на повідомлення.</target> <target>Заборонити реакції на повідомлення.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Заборонити надсилати прямі повідомлення учасникам.</target> <target>Заборонити надсилати прямі повідомлення учасникам.</target>
@@ -4469,6 +4521,10 @@ Error: %@</source>
<target>Адреса отримувача буде змінена на інший сервер. Зміна адреси завершиться після того, як відправник з'явиться в мережі.</target> <target>Адреса отримувача буде змінена на інший сервер. Зміна адреси завершиться після того, як відправник з'явиться в мережі.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Отримання файлу буде зупинено.</target> <target>Отримання файлу буде зупинено.</target>
@@ -4484,6 +4540,10 @@ Error: %@</source>
<target>Нещодавня історія та покращення [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target> <target>Нещодавня історія та покращення [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Одержувачі бачать оновлення, коли ви їх вводите.</target> <target>Одержувачі бачать оновлення, коли ви їх вводите.</target>
@@ -4784,11 +4844,19 @@ Error: %@</source>
<target>Зберегти вітальне повідомлення?</target> <target>Зберегти вітальне повідомлення?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Збережені сервери WebRTC ICE буде видалено</target> <target>Збережені сервери WebRTC ICE буде видалено</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>Збережене повідомлення</target> <target>Збережене повідомлення</target>
@@ -5212,6 +5280,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>Посилання SimpleX</target> <target>Посилання SimpleX</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -6050,6 +6126,10 @@ To connect, please ask your contact to create another connection link and check
<target>Голосові повідомлення в цій групі заборонені.</target> <target>Голосові повідомлення в цій групі заборонені.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Голосові повідомлення заборонені!</target> <target>Голосові повідомлення заборонені!</target>
@@ -6130,6 +6210,14 @@ To connect, please ask your contact to create another connection link and check
<target>Коли ви ділитеся з кимось своїм профілем інкогніто, цей профіль буде використовуватися для груп, до яких вас запрошують.</target> <target>Коли ви ділитеся з кимось своїм профілем інкогніто, цей профіль буде використовуватися для груп, до яких вас запрошують.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>З зашифрованими файлами та медіа.</target> <target>З зашифрованими файлами та медіа.</target>
@@ -6613,6 +6701,10 @@ SimpleX servers cannot see your profile.</source>
<target>адмін</target> <target>адмін</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>узгодження шифрування для %@…</target> <target>узгодження шифрування для %@…</target>
@@ -6623,6 +6715,10 @@ SimpleX servers cannot see your profile.</source>
<target>узгодження шифрування…</target> <target>узгодження шифрування…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>завжди</target> <target>завжди</target>
@@ -6953,6 +7049,10 @@ SimpleX servers cannot see your profile.</source>
<target>відбулася подія</target> <target>відбулася подія</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>групу видалено</target> <target>групу видалено</target>
@@ -7160,6 +7260,10 @@ SimpleX servers cannot see your profile.</source>
<target>власник</target> <target>власник</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>одноранговий</target> <target>одноранговий</target>
@@ -7210,6 +7314,14 @@ SimpleX servers cannot see your profile.</source>
<target>прибрали вас</target> <target>прибрали вас</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>сек</target> <target>сек</target>
@@ -7350,6 +7462,10 @@ SimpleX servers cannot see your profile.</source>
<target>так</target> <target>так</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>вас запрошують до групи</target> <target>вас запрошують до групи</target>
@@ -728,6 +728,10 @@
<target>允许不可撤回地删除已发送消息。</target> <target>允许不可撤回地删除已发送消息。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>允许发送文件和媒体。</target> <target>允许发送文件和媒体。</target>
@@ -1063,6 +1067,10 @@
<target>无法接收文件</target> <target>无法接收文件</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>更改</target> <target>更改</target>
@@ -2039,6 +2047,10 @@ This cannot be undone!</source>
<target>降级并打开聊天</target> <target>降级并打开聊天</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve"> <trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source> <source>Download failed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2145,6 +2157,10 @@ This cannot be undone!</source>
<target>启用自毁密码</target> <target>启用自毁密码</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>加密</target> <target>加密</target>
@@ -2658,6 +2674,10 @@ This cannot be undone!</source>
<target>此群组中禁止文件和媒体。</target> <target>此群组中禁止文件和媒体。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>禁止文件和媒体!</target> <target>禁止文件和媒体!</target>
@@ -2721,6 +2741,18 @@ This cannot be undone!</source>
<target>用于控制台</target> <target>用于控制台</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<target>找到了桌面</target> <target>找到了桌面</target>
@@ -2830,6 +2862,10 @@ This cannot be undone!</source>
<target>群组成员可以不可撤回地删除已发送的消息。</target> <target>群组成员可以不可撤回地删除已发送的消息。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>群组成员可以私信。</target> <target>群组成员可以私信。</target>
@@ -3673,6 +3709,10 @@ This is your link for group %@!</source>
<target>网络和服务器</target> <target>网络和服务器</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>网络设置</target> <target>网络设置</target>
@@ -3783,6 +3823,10 @@ This is your link for group %@!</source>
<target>无历史记录</target> <target>无历史记录</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>没有录制语音消息的权限</target> <target>没有录制语音消息的权限</target>
@@ -3993,6 +4037,10 @@ This is your link for group %@!</source>
<target>或者显示此码</target> <target>或者显示此码</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>PING 次数</target> <target>PING 次数</target>
@@ -4248,6 +4296,10 @@ Error: %@</source>
<target>禁止消息回应。</target> <target>禁止消息回应。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>禁止向成员发送私信。</target> <target>禁止向成员发送私信。</target>
@@ -4376,6 +4428,10 @@ Error: %@</source>
<target>接收地址将变更到不同的服务器。地址更改将在发件人上线后完成。</target> <target>接收地址将变更到不同的服务器。地址更改将在发件人上线后完成。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>即将停止接收文件。</target> <target>即将停止接收文件。</target>
@@ -4390,6 +4446,10 @@ Error: %@</source>
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source> <source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>对方会在您键入时看到更新。</target> <target>对方会在您键入时看到更新。</target>
@@ -4686,11 +4746,19 @@ Error: %@</source>
<target>保存欢迎信息?</target> <target>保存欢迎信息?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>已保存的WebRTC ICE服务器将被删除</target> <target>已保存的WebRTC ICE服务器将被删除</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<target>已保存的消息</target> <target>已保存的消息</target>
@@ -5112,6 +5180,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleX 链接</target> <target>SimpleX 链接</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -5939,6 +6015,10 @@ To connect, please ask your contact to create another connection link and check
<target>语音信息在该群组中被禁用。</target> <target>语音信息在该群组中被禁用。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>语音消息禁止发送!</target> <target>语音消息禁止发送!</target>
@@ -6016,6 +6096,14 @@ To connect, please ask your contact to create another connection link and check
<target>当您与某人共享隐身聊天资料时,该资料将用于他们邀请您加入的群组。</target> <target>当您与某人共享隐身聊天资料时,该资料将用于他们邀请您加入的群组。</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<target>加密的文件和媒体。</target> <target>加密的文件和媒体。</target>
@@ -6487,6 +6575,10 @@ SimpleX 服务器无法看到您的资料。</target>
<target>管理员</target> <target>管理员</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>正在协商将加密应用于 %@…</target> <target>正在协商将加密应用于 %@…</target>
@@ -6497,6 +6589,10 @@ SimpleX 服务器无法看到您的资料。</target>
<target>同意加密…</target> <target>同意加密…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>始终</target> <target>始终</target>
@@ -6825,6 +6921,10 @@ SimpleX 服务器无法看到您的资料。</target>
<target>发生的事</target> <target>发生的事</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>群组已删除</target> <target>群组已删除</target>
@@ -7031,6 +7131,10 @@ SimpleX 服务器无法看到您的资料。</target>
<target>群主</target> <target>群主</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>点对点</target> <target>点对点</target>
@@ -7080,6 +7184,14 @@ SimpleX 服务器无法看到您的资料。</target>
<target>已将您移除</target> <target>已将您移除</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>秒</target> <target>秒</target>
@@ -7217,6 +7329,10 @@ SimpleX 服务器无法看到您的资料。</target>
<target>是</target> <target>是</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>您被邀请加入群组</target> <target>您被邀请加入群组</target>
@@ -586,9 +586,6 @@ func receivedMsgNtf(_ res: ChatResponse) async -> (String, NSENotification)? {
cleanupDirectFile(aChatItem) cleanupDirectFile(aChatItem)
} }
return nil return nil
case let .sndFileCompleteXFTP(_, aChatItem, _):
cleanupFile(aChatItem)
return nil
case let .callInvitation(invitation): case let .callInvitation(invitation):
// Do not post it without CallKit support, iOS will stop launching the app without showing CallKit // Do not post it without CallKit support, iOS will stop launching the app without showing CallKit
return ( return (
+30 -26
View File
@@ -29,6 +29,11 @@
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; }; 5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; }; 5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; };
5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; }; 5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; };
5C2217842BD4465500A8B0E7 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C22177F2BD4465500A8B0E7 /* libgmpxx.a */; };
5C2217852BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217802BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a */; };
5C2217862BD4465500A8B0E7 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217812BD4465500A8B0E7 /* libgmp.a */; };
5C2217872BD4465500A8B0E7 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217822BD4465500A8B0E7 /* libffi.a */; };
5C2217882BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217832BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a */; };
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; }; 5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; };
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; }; 5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; };
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; }; 5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; };
@@ -110,11 +115,6 @@
5CC1C99527A6CF7F000D9FF6 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC1C99427A6CF7F000D9FF6 /* ShareSheet.swift */; }; 5CC1C99527A6CF7F000D9FF6 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC1C99427A6CF7F000D9FF6 /* ShareSheet.swift */; };
5CC2C0FC2809BF11000C35E3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FA2809BF11000C35E3 /* Localizable.strings */; }; 5CC2C0FC2809BF11000C35E3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FA2809BF11000C35E3 /* Localizable.strings */; };
5CC2C0FF2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FD2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings */; }; 5CC2C0FF2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FD2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings */; };
5CC83D1A2BCC504B00A0C558 /* libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CC83D152BCC504B00A0C558 /* libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv.a */; };
5CC83D1B2BCC504B00A0C558 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CC83D162BCC504B00A0C558 /* libgmpxx.a */; };
5CC83D1C2BCC504B00A0C558 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CC83D172BCC504B00A0C558 /* libgmp.a */; };
5CC83D1D2BCC504B00A0C558 /* libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv-ghc9.6.4.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CC83D182BCC504B00A0C558 /* libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv-ghc9.6.4.a */; };
5CC83D1E2BCC504B00A0C558 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CC83D192BCC504B00A0C558 /* libffi.a */; };
5CC868F329EB540C0017BBFD /* CIRcvDecryptionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */; }; 5CC868F329EB540C0017BBFD /* CIRcvDecryptionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */; };
5CCB939C297EFCB100399E78 /* NavStackCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */; }; 5CCB939C297EFCB100399E78 /* NavStackCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */; };
5CD67B8F2B0E858A00C510B1 /* hs_init.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CD67B8D2B0E858A00C510B1 /* hs_init.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5CD67B8F2B0E858A00C510B1 /* hs_init.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CD67B8D2B0E858A00C510B1 /* hs_init.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -172,6 +172,7 @@
646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; }; 646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; };
647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; }; 647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; };
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; }; 648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; };
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */; };
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; }; 649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; };
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; }; 649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; }; 64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; };
@@ -278,6 +279,11 @@
5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = "<group>"; }; 5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = "<group>"; };
5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = "<group>"; }; 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = "<group>"; };
5C22177F2BD4465500A8B0E7 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C2217802BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a"; sourceTree = "<group>"; };
5C2217812BD4465500A8B0E7 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C2217822BD4465500A8B0E7 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C2217832BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a"; sourceTree = "<group>"; };
5C245F3C2B501E98001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = "<group>"; }; 5C245F3C2B501E98001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = "<group>"; };
5C245F3D2B501F13001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = "tr.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; }; 5C245F3D2B501F13001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = "tr.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
5C245F3E2B501F13001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 5C245F3E2B501F13001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@@ -402,11 +408,6 @@
5CC1C99427A6CF7F000D9FF6 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = "<group>"; }; 5CC1C99427A6CF7F000D9FF6 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = "<group>"; };
5CC2C0FB2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; }; 5CC2C0FB2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
5CC2C0FE2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "ru.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; }; 5CC2C0FE2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "ru.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
5CC83D152BCC504B00A0C558 /* libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv.a"; sourceTree = "<group>"; };
5CC83D162BCC504B00A0C558 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5CC83D172BCC504B00A0C558 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5CC83D182BCC504B00A0C558 /* libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv-ghc9.6.4.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv-ghc9.6.4.a"; sourceTree = "<group>"; };
5CC83D192BCC504B00A0C558 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIRcvDecryptionError.swift; sourceTree = "<group>"; }; 5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIRcvDecryptionError.swift; sourceTree = "<group>"; };
5CCB939B297EFCB100399E78 /* NavStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavStackCompat.swift; sourceTree = "<group>"; }; 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavStackCompat.swift; sourceTree = "<group>"; };
5CD67B8D2B0E858A00C510B1 /* hs_init.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hs_init.h; sourceTree = "<group>"; }; 5CD67B8D2B0E858A00C510B1 /* hs_init.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hs_init.h; sourceTree = "<group>"; };
@@ -464,6 +465,7 @@
646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationUtils.swift; sourceTree = "<group>"; }; 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationUtils.swift; sourceTree = "<group>"; };
647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberInfoView.swift; sourceTree = "<group>"; }; 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberInfoView.swift; sourceTree = "<group>"; };
648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = "<group>"; }; 648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = "<group>"; };
648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemForwardingView.swift; sourceTree = "<group>"; };
6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; }; 6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = "<group>"; }; 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = "<group>"; };
649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; }; 649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; };
@@ -523,13 +525,13 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
5CC83D1D2BCC504B00A0C558 /* libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv-ghc9.6.4.a in Frameworks */, 5C2217842BD4465500A8B0E7 /* libgmpxx.a in Frameworks */,
5CC83D1B2BCC504B00A0C558 /* libgmpxx.a in Frameworks */, 5C2217872BD4465500A8B0E7 /* libffi.a in Frameworks */,
5CC83D1C2BCC504B00A0C558 /* libgmp.a in Frameworks */, 5C2217862BD4465500A8B0E7 /* libgmp.a in Frameworks */,
5CC83D1A2BCC504B00A0C558 /* libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv.a in Frameworks */, 5C2217882BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a in Frameworks */,
5CC83D1E2BCC504B00A0C558 /* libffi.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
5C2217852BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -585,6 +587,7 @@
5CBE6C11294487F7002D9531 /* VerifyCodeView.swift */, 5CBE6C11294487F7002D9531 /* VerifyCodeView.swift */,
5CBE6C132944CC12002D9531 /* ScanCodeView.swift */, 5CBE6C132944CC12002D9531 /* ScanCodeView.swift */,
64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */, 64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */,
648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */,
); );
path = Chat; path = Chat;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -592,11 +595,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = { 5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
5CC83D192BCC504B00A0C558 /* libffi.a */, 5C2217822BD4465500A8B0E7 /* libffi.a */,
5CC83D172BCC504B00A0C558 /* libgmp.a */, 5C2217812BD4465500A8B0E7 /* libgmp.a */,
5CC83D162BCC504B00A0C558 /* libgmpxx.a */, 5C22177F2BD4465500A8B0E7 /* libgmpxx.a */,
5CC83D182BCC504B00A0C558 /* libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv-ghc9.6.4.a */, 5C2217802BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a */,
5CC83D152BCC504B00A0C558 /* libHSsimplex-chat-5.7.0.0-AhbVfRKDsEZ5w5ND1HSTLv.a */, 5C2217832BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a */,
); );
path = Libraries; path = Libraries;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1161,6 +1164,7 @@
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */, 5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */,
5CBE6C12294487F7002D9531 /* VerifyCodeView.swift in Sources */, 5CBE6C12294487F7002D9531 /* VerifyCodeView.swift in Sources */,
3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */, 3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */,
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */,
64466DC829FC2B3B00E3D48D /* CreateSimpleXAddress.swift in Sources */, 64466DC829FC2B3B00E3D48D /* CreateSimpleXAddress.swift in Sources */,
3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */, 3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */,
5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */, 5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */,
@@ -1540,7 +1544,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 207; CURRENT_PROJECT_VERSION = 208;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
@@ -1589,7 +1593,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 207; CURRENT_PROJECT_VERSION = 208;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
@@ -1675,7 +1679,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 207; CURRENT_PROJECT_VERSION = 208;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s; GCC_OPTIMIZATION_LEVEL = s;
@@ -1712,7 +1716,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 207; CURRENT_PROJECT_VERSION = 208;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO; ENABLE_CODE_COVERAGE = NO;
@@ -1749,7 +1753,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 207; CURRENT_PROJECT_VERSION = 208;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1800,7 +1804,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 207; CURRENT_PROJECT_VERSION = 208;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
+5
View File
@@ -87,6 +87,11 @@ public func chatInitControllerRemovingDatabases() {
public func chatCloseStore() { public func chatCloseStore() {
// Prevent crash when exiting the app with already closed store (for example, after changing a database passpharase)
guard hasChatCtrl() else {
logger.error("chatCloseStore: already closed, chatCtrl is nil")
return
}
let err = fromCString(chat_close_store(getChatCtrl())) let err = fromCString(chat_close_store(getChatCtrl()))
if err != "" { if err != "" {
logger.error("chatCloseStore error: \(err)") logger.error("chatCloseStore error: \(err)")
+9 -2
View File
@@ -50,6 +50,7 @@ public enum ChatCommand {
case apiDeleteChatItem(type: ChatType, id: Int64, itemId: Int64, mode: CIDeleteMode) case apiDeleteChatItem(type: ChatType, id: Int64, itemId: Int64, mode: CIDeleteMode)
case apiDeleteMemberChatItem(groupId: Int64, groupMemberId: Int64, itemId: Int64) case apiDeleteMemberChatItem(groupId: Int64, groupMemberId: Int64, itemId: Int64)
case apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, add: Bool, reaction: MsgReaction) case apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, add: Bool, reaction: MsgReaction)
case apiForwardChatItem(toChatType: ChatType, toChatId: Int64, fromChatType: ChatType, fromChatId: Int64, itemId: Int64)
case apiGetNtfToken case apiGetNtfToken
case apiRegisterToken(token: DeviceToken, notificationMode: NotificationsMode) case apiRegisterToken(token: DeviceToken, notificationMode: NotificationsMode)
case apiVerifyToken(token: DeviceToken, nonce: String, code: String) case apiVerifyToken(token: DeviceToken, nonce: String, code: String)
@@ -195,6 +196,7 @@ public enum ChatCommand {
case let .apiDeleteChatItem(type, id, itemId, mode): return "/_delete item \(ref(type, id)) \(itemId) \(mode.rawValue)" case let .apiDeleteChatItem(type, id, itemId, mode): return "/_delete item \(ref(type, id)) \(itemId) \(mode.rawValue)"
case let .apiDeleteMemberChatItem(groupId, groupMemberId, itemId): return "/_delete member item #\(groupId) \(groupMemberId) \(itemId)" case let .apiDeleteMemberChatItem(groupId, groupMemberId, itemId): return "/_delete member item #\(groupId) \(groupMemberId) \(itemId)"
case let .apiChatItemReaction(type, id, itemId, add, reaction): return "/_reaction \(ref(type, id)) \(itemId) \(onOff(add)) \(encodeJSON(reaction))" case let .apiChatItemReaction(type, id, itemId, add, reaction): return "/_reaction \(ref(type, id)) \(itemId) \(onOff(add)) \(encodeJSON(reaction))"
case let .apiForwardChatItem(toChatType, toChatId, fromChatType, fromChatId, itemId): return "/_forward \(ref(toChatType, toChatId)) \(ref(fromChatType, fromChatId)) \(itemId)"
case .apiGetNtfToken: return "/_ntf get " case .apiGetNtfToken: return "/_ntf get "
case let .apiRegisterToken(token, notificationMode): return "/_ntf register \(token.cmdString) \(notificationMode.rawValue)" case let .apiRegisterToken(token, notificationMode): return "/_ntf register \(token.cmdString) \(notificationMode.rawValue)"
case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)" case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)"
@@ -343,6 +345,7 @@ public enum ChatCommand {
case .apiConnectContactViaAddress: return "apiConnectContactViaAddress" case .apiConnectContactViaAddress: return "apiConnectContactViaAddress"
case .apiDeleteMemberChatItem: return "apiDeleteMemberChatItem" case .apiDeleteMemberChatItem: return "apiDeleteMemberChatItem"
case .apiChatItemReaction: return "apiChatItemReaction" case .apiChatItemReaction: return "apiChatItemReaction"
case .apiForwardChatItem: return "apiForwardChatItem"
case .apiGetNtfToken: return "apiGetNtfToken" case .apiGetNtfToken: return "apiGetNtfToken"
case .apiRegisterToken: return "apiRegisterToken" case .apiRegisterToken: return "apiRegisterToken"
case .apiVerifyToken: return "apiVerifyToken" case .apiVerifyToken: return "apiVerifyToken"
@@ -1254,6 +1257,7 @@ public struct NetCfg: Codable, Equatable {
public var tcpConnectTimeout: Int // microseconds public var tcpConnectTimeout: Int // microseconds
public var tcpTimeout: Int // microseconds public var tcpTimeout: Int // microseconds
public var tcpTimeoutPerKb: Int // microseconds public var tcpTimeoutPerKb: Int // microseconds
public var rcvConcurrency: Int // pool size
public var tcpKeepAlive: KeepAliveOpts? public var tcpKeepAlive: KeepAliveOpts?
public var smpPingInterval: Int // microseconds public var smpPingInterval: Int // microseconds
public var smpPingCount: Int // times public var smpPingCount: Int // times
@@ -1262,9 +1266,10 @@ public struct NetCfg: Codable, Equatable {
public static let defaults: NetCfg = NetCfg( public static let defaults: NetCfg = NetCfg(
socksProxy: nil, socksProxy: nil,
sessionMode: TransportSessionMode.user, sessionMode: TransportSessionMode.user,
tcpConnectTimeout: 20_000_000, tcpConnectTimeout: 10_000_000,
tcpTimeout: 15_000_000, tcpTimeout: 15_000_000,
tcpTimeoutPerKb: 10_000, tcpTimeoutPerKb: 10_000,
rcvConcurrency: 12,
tcpKeepAlive: KeepAliveOpts.defaults, tcpKeepAlive: KeepAliveOpts.defaults,
smpPingInterval: 1200_000_000, smpPingInterval: 1200_000_000,
smpPingCount: 3, smpPingCount: 3,
@@ -1274,9 +1279,10 @@ public struct NetCfg: Codable, Equatable {
public static let proxyDefaults: NetCfg = NetCfg( public static let proxyDefaults: NetCfg = NetCfg(
socksProxy: nil, socksProxy: nil,
sessionMode: TransportSessionMode.user, sessionMode: TransportSessionMode.user,
tcpConnectTimeout: 30_000_000, tcpConnectTimeout: 20_000_000,
tcpTimeout: 20_000_000, tcpTimeout: 20_000_000,
tcpTimeoutPerKb: 15_000, tcpTimeoutPerKb: 15_000,
rcvConcurrency: 8,
tcpKeepAlive: KeepAliveOpts.defaults, tcpKeepAlive: KeepAliveOpts.defaults,
smpPingInterval: 1200_000_000, smpPingInterval: 1200_000_000,
smpPingCount: 3, smpPingCount: 3,
@@ -1718,6 +1724,7 @@ public enum ChatErrorType: Decodable {
case inlineFileProhibited(fileId: Int64) case inlineFileProhibited(fileId: Int64)
case invalidQuote case invalidQuote
case invalidForward case invalidForward
case forwardNoFile
case invalidChatItemUpdate case invalidChatItemUpdate
case invalidChatItemDelete case invalidChatItemDelete
case hasCurrentCall case hasCurrentCall
+5
View File
@@ -29,6 +29,7 @@ let GROUP_DEFAULT_NETWORK_SESSION_MODE = "networkSessionMode"
let GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT = "networkTCPConnectTimeout" let GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT = "networkTCPConnectTimeout"
let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT = "networkTCPTimeout" let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT = "networkTCPTimeout"
let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb" let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb"
let GROUP_DEFAULT_NETWORK_RCV_CONCURRENCY = "networkRcvConcurrency"
let GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL = "networkSMPPingInterval" let GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL = "networkSMPPingInterval"
let GROUP_DEFAULT_NETWORK_SMP_PING_COUNT = "networkSMPPingCount" let GROUP_DEFAULT_NETWORK_SMP_PING_COUNT = "networkSMPPingCount"
let GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE = "networkEnableKeepAlive" let GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE = "networkEnableKeepAlive"
@@ -55,6 +56,7 @@ public func registerGroupDefaults() {
GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT: NetCfg.defaults.tcpConnectTimeout, GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT: NetCfg.defaults.tcpConnectTimeout,
GROUP_DEFAULT_NETWORK_TCP_TIMEOUT: NetCfg.defaults.tcpTimeout, GROUP_DEFAULT_NETWORK_TCP_TIMEOUT: NetCfg.defaults.tcpTimeout,
GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB: NetCfg.defaults.tcpTimeoutPerKb, GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB: NetCfg.defaults.tcpTimeoutPerKb,
GROUP_DEFAULT_NETWORK_RCV_CONCURRENCY: NetCfg.defaults.rcvConcurrency,
GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL: NetCfg.defaults.smpPingInterval, GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL: NetCfg.defaults.smpPingInterval,
GROUP_DEFAULT_NETWORK_SMP_PING_COUNT: NetCfg.defaults.smpPingCount, GROUP_DEFAULT_NETWORK_SMP_PING_COUNT: NetCfg.defaults.smpPingCount,
GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE: NetCfg.defaults.enableKeepAlive, GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE: NetCfg.defaults.enableKeepAlive,
@@ -278,6 +280,7 @@ public func getNetCfg() -> NetCfg {
let tcpConnectTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT) let tcpConnectTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT)
let tcpTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT) let tcpTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT)
let tcpTimeoutPerKb = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB) let tcpTimeoutPerKb = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB)
let rcvConcurrency = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_RCV_CONCURRENCY)
let smpPingInterval = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL) let smpPingInterval = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL)
let smpPingCount = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_SMP_PING_COUNT) let smpPingCount = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_SMP_PING_COUNT)
let enableKeepAlive = groupDefaults.bool(forKey: GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE) let enableKeepAlive = groupDefaults.bool(forKey: GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE)
@@ -297,6 +300,7 @@ public func getNetCfg() -> NetCfg {
tcpConnectTimeout: tcpConnectTimeout, tcpConnectTimeout: tcpConnectTimeout,
tcpTimeout: tcpTimeout, tcpTimeout: tcpTimeout,
tcpTimeoutPerKb: tcpTimeoutPerKb, tcpTimeoutPerKb: tcpTimeoutPerKb,
rcvConcurrency: rcvConcurrency,
tcpKeepAlive: tcpKeepAlive, tcpKeepAlive: tcpKeepAlive,
smpPingInterval: smpPingInterval, smpPingInterval: smpPingInterval,
smpPingCount: smpPingCount, smpPingCount: smpPingCount,
@@ -310,6 +314,7 @@ public func setNetCfg(_ cfg: NetCfg) {
groupDefaults.set(cfg.tcpConnectTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT) groupDefaults.set(cfg.tcpConnectTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT)
groupDefaults.set(cfg.tcpTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT) groupDefaults.set(cfg.tcpTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT)
groupDefaults.set(cfg.tcpTimeoutPerKb, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB) groupDefaults.set(cfg.tcpTimeoutPerKb, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB)
groupDefaults.set(cfg.rcvConcurrency, forKey: GROUP_DEFAULT_NETWORK_RCV_CONCURRENCY)
groupDefaults.set(cfg.smpPingInterval, forKey: GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL) groupDefaults.set(cfg.smpPingInterval, forKey: GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL)
groupDefaults.set(cfg.smpPingCount, forKey: GROUP_DEFAULT_NETWORK_SMP_PING_COUNT) groupDefaults.set(cfg.smpPingCount, forKey: GROUP_DEFAULT_NETWORK_SMP_PING_COUNT)
if let tcpKeepAlive = cfg.tcpKeepAlive { if let tcpKeepAlive = cfg.tcpKeepAlive {
+17 -3
View File
@@ -2784,15 +2784,29 @@ public enum CIDeleted: Decodable {
} }
} }
public enum MsgDirection: Decodable { public enum MsgDirection: String, Decodable {
case rcv case rcv = "rcv"
case snd case snd = "snd"
} }
public enum CIForwardedFrom: Decodable { public enum CIForwardedFrom: Decodable {
case unknown case unknown
case contact(chatName: String, msgDir: MsgDirection, contactId: Int64?, chatItemId: Int64?) case contact(chatName: String, msgDir: MsgDirection, contactId: Int64?, chatItemId: Int64?)
case group(chatName: String, msgDir: MsgDirection, groupId: Int64?, chatItemId: Int64?) case group(chatName: String, msgDir: MsgDirection, groupId: Int64?, chatItemId: Int64?)
var chatName: String {
switch self {
case .unknown: ""
case let .contact(chatName, _, _, _): chatName
case let .group(chatName, _, _, _): chatName
}
}
public func text(_ chatType: ChatType) -> LocalizedStringKey {
chatType == .local
? (chatName == "" ? "saved" : "saved from \(chatName)")
: "forwarded"
}
} }
public enum CIDeleteMode: String, Decodable { public enum CIDeleteMode: String, Decodable {
@@ -89,11 +89,12 @@ class MainActivity: FragmentActivity() {
} }
override fun onBackPressed() { override fun onBackPressed() {
if ( val canFinishActivity = (
onBackPressedDispatcher.hasEnabledCallbacks() // Has something to do in a backstack onBackPressedDispatcher.hasEnabledCallbacks() // Has something to do in a backstack
|| Build.VERSION.SDK_INT >= Build.VERSION_CODES.R // Android 11 or above || Build.VERSION.SDK_INT >= Build.VERSION_CODES.R // Android 11 or above
|| isTaskRoot // there are still other tasks after we reach the main (home) activity || isTaskRoot // there are still other tasks after we reach the main (home) activity
) { ) && SimplexApp.context.chatModel.sharedContent.value !is SharedContent.Forward
if (canFinishActivity) {
// https://medium.com/mobile-app-development-publication/the-risk-of-android-strandhogg-security-issue-and-how-it-can-be-mitigated-80d2ddb4af06 // https://medium.com/mobile-app-development-publication/the-risk-of-android-strandhogg-security-issue-and-how-it-can-be-mitigated-80d2ddb4af06
super.onBackPressed() super.onBackPressed()
} }
@@ -104,9 +105,15 @@ class MainActivity: FragmentActivity() {
AppLock.laFailed.value = true AppLock.laFailed.value = true
} }
if (!onBackPressedDispatcher.hasEnabledCallbacks()) { if (!onBackPressedDispatcher.hasEnabledCallbacks()) {
val sharedContent = chatModel.sharedContent.value
// Drop shared content // Drop shared content
SimplexApp.context.chatModel.sharedContent.value = null chatModel.sharedContent.value = null
finish() if (sharedContent is SharedContent.Forward) {
chatModel.chatId.value = sharedContent.fromChatInfo.id
}
if (canFinishActivity) {
finish()
}
} }
} }
} }
@@ -0,0 +1,235 @@
package chat.simplex.common.views.call
import android.content.Context
import android.media.*
import android.media.AudioManager.OnCommunicationDeviceChangedListener
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.runtime.*
import chat.simplex.common.platform.*
import dev.icerock.moko.resources.ImageResource
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import java.util.concurrent.Executors
interface CallAudioDeviceManagerInterface {
val devices: State<List<AudioDeviceInfo>>
val currentDevice: MutableState<AudioDeviceInfo?>
fun start()
fun stop()
// AudioDeviceInfo.AudioDeviceType
fun selectLastExternalDeviceOrDefault(speaker: Boolean, keepAnyNonEarpiece: Boolean)
// AudioDeviceInfo.AudioDeviceType
fun selectDevice(id: Int)
companion object {
fun new(): CallAudioDeviceManagerInterface =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PostSCallAudioDeviceManager()
} else {
PreSCallAudioDeviceManager()
}
}
}
@RequiresApi(Build.VERSION_CODES.S)
class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
private val am = androidAppContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
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 }}")
super.onAudioDevicesAdded(addedDevices)
val oldDevices = devices.value
devices.value = am.availableCommunicationDevices
Log.d(TAG, "Added audio devices2: ${devices.value.map { it.type }}")
if (devices.value.size - oldDevices.size > 0) {
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, false)
}
}
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>) {
Log.d(TAG, "Removed audio devices: ${removedDevices.map { it.type }}")
super.onAudioDevicesRemoved(removedDevices)
devices.value = am.availableCommunicationDevices
}
}
private val listener: OnCommunicationDeviceChangedListener = OnCommunicationDeviceChangedListener { device ->
devices.value = am.availableCommunicationDevices
currentDevice.value = device
}
override fun start() {
am.registerAudioDeviceCallback(audioCallback, null)
am.addOnCommunicationDeviceChangedListener(Executors.newSingleThreadExecutor(), listener)
}
override fun stop() {
am.unregisterAudioDeviceCallback(audioCallback)
am.removeOnCommunicationDeviceChangedListener(listener)
}
override fun selectLastExternalDeviceOrDefault(speaker: Boolean, keepAnyNonEarpiece: Boolean) {
Log.d(TAG, "selectLastExternalDeviceOrDefault: set audio mode, speaker enabled: $speaker")
am.mode = AudioManager.MODE_IN_COMMUNICATION
val commDevice = am.communicationDevice
if (keepAnyNonEarpiece && commDevice != null && commDevice.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) {
// some external device or speaker selected already, no need to change it
return
}
val preferredSecondaryDevice = if (speaker) AudioDeviceInfo.TYPE_BUILTIN_SPEAKER else AudioDeviceInfo.TYPE_BUILTIN_EARPIECE
val externalDevice = devices.value.lastOrNull { it.type != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER && it.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE }
// External device already selected
if (externalDevice != null && externalDevice.type == am.communicationDevice?.type) {
return
}
if (externalDevice != null) {
am.setCommunicationDevice(externalDevice)
} else if (am.communicationDevice?.type != preferredSecondaryDevice) {
am.availableCommunicationDevices.firstOrNull { it.type == preferredSecondaryDevice }?.let {
am.setCommunicationDevice(it)
}
}
}
override fun selectDevice(id: Int) {
am.mode = AudioManager.MODE_IN_COMMUNICATION
val device = devices.value.lastOrNull { it.id == id }
if (device != null && am.communicationDevice?.id != id ) {
am.setCommunicationDevice(device)
}
}
}
class PreSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
private val am = androidAppContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
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 }}")
super.onAudioDevicesAdded(addedDevices)
val wasSize = devices.value.size
devices.value += addedDevices.filter { it.hasSupportedType() }
val addedCount = devices.value.size - wasSize
//if (addedCount > 0 && chatModel.activeCall.value?.callState == CallState.Connected) {
// Setting params in Connected state makes sure that Bluetooth will NOT be broken on Android < 12
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, false)
//}
}
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>) {
Log.d(TAG, "Removed audio devices: ${removedDevices.map { it.type }}")
super.onAudioDevicesRemoved(removedDevices)
val wasSize = devices.value.size
devices.value = devices.value.filterNot { removedDevices.any { rm -> rm.id == it.id } }
//val removedCount = wasSize - devices.value.size
//if (devices.value.count { it.hasSupportedType() } == 2 && chatModel.activeCall.value?.callState == CallState.Connected) {
// Setting params in Connected state makes sure that Bluetooth will NOT be broken on Android < 12
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, true)
//}
}
}
override fun start() {
am.registerAudioDeviceCallback(audioCallback, null)
}
override fun stop() {
am.unregisterAudioDeviceCallback(audioCallback)
}
override fun selectLastExternalDeviceOrDefault(speaker: Boolean, keepAnyNonEarpiece: Boolean) {
Log.d(TAG, "selectLastExternalDeviceOrDefault: set audio mode, speaker enabled: $speaker")
val preferredSecondaryDevice = if (speaker) AudioDeviceInfo.TYPE_BUILTIN_SPEAKER else AudioDeviceInfo.TYPE_BUILTIN_EARPIECE
val externalDevice = devices.value.lastOrNull { it.hasSupportedType() && it.isSource && it.isSink && it.type != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER && it.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE }
if (externalDevice != null) {
selectDevice(externalDevice.id)
} else {
am.stopBluetoothSco()
am.isWiredHeadsetOn = false
am.isSpeakerphoneOn = preferredSecondaryDevice == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER
am.isBluetoothScoOn = false
val newCurrentDevice = devices.value.firstOrNull { it.type == preferredSecondaryDevice }
adaptToCurrentlyActiveDevice(newCurrentDevice)
}
}
override fun selectDevice(id: Int) {
val device = devices.value.lastOrNull { it.id == id }
val isExternalDevice = device != null && device.type != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER && device.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE
if (isExternalDevice) {
am.isSpeakerphoneOn = false
if (device?.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES) {
am.isWiredHeadsetOn = true
am.stopBluetoothSco()
am.isBluetoothScoOn = false
} else {
am.isWiredHeadsetOn = false
am.startBluetoothSco()
am.isBluetoothScoOn = true
}
adaptToCurrentlyActiveDevice(device)
} else {
am.stopBluetoothSco()
am.isWiredHeadsetOn = false
am.isSpeakerphoneOn = device?.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER
am.isBluetoothScoOn = false
adaptToCurrentlyActiveDevice(device)
}
}
private fun adaptToCurrentlyActiveDevice(newCurrentDevice: AudioDeviceInfo?) {
currentDevice.value = newCurrentDevice
}
private fun AudioDeviceInfo.hasSupportedType(): Boolean = when (type) {
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> true
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> true
AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> true
AudioDeviceInfo.TYPE_BLE_HEADSET -> true
AudioDeviceInfo.TYPE_BLE_SPEAKER -> true
AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> true
else -> false
}
}
val AudioDeviceInfo.icon: ImageResource
get() = when (this.type) {
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> MR.images.ic_volume_down
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> MR.images.ic_volume_up
AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
AudioDeviceInfo.TYPE_BLE_HEADSET,
AudioDeviceInfo.TYPE_BLE_SPEAKER -> MR.images.ic_bluetooth
AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> MR.images.ic_headphones
AudioDeviceInfo.TYPE_USB_HEADSET, AudioDeviceInfo.TYPE_USB_DEVICE -> MR.images.ic_usb
else -> MR.images.ic_brand_awareness_filled
}
val AudioDeviceInfo.name: StringResource?
get() = when (this.type) {
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> MR.strings.audio_device_earpiece
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> MR.strings.audio_device_speaker
AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
AudioDeviceInfo.TYPE_BLE_HEADSET,
AudioDeviceInfo.TYPE_BLE_SPEAKER -> null // Use product name instead
AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> MR.strings.audio_device_wired_headphones
AudioDeviceInfo.TYPE_USB_HEADSET, AudioDeviceInfo.TYPE_USB_DEVICE -> null // Use product name instead
else -> null // Use product name instead
}
@@ -26,8 +26,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import dev.icerock.moko.resources.compose.painterResource import androidx.compose.ui.platform.LocalDensity
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
@@ -39,14 +38,14 @@ import androidx.webkit.WebViewAssetLoader
import androidx.webkit.WebViewClientCompat import androidx.webkit.WebViewClientCompat
import chat.simplex.common.helpers.showAllowPermissionInSettingsAlert import chat.simplex.common.helpers.showAllowPermissionInSettingsAlert
import chat.simplex.common.model.* import chat.simplex.common.model.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.model.ChatModel
import chat.simplex.common.model.Contact
import chat.simplex.common.platform.* import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.* import chat.simplex.common.views.helpers.*
import chat.simplex.res.MR import chat.simplex.res.MR
import com.google.accompanist.permissions.* import com.google.accompanist.permissions.*
import dev.icerock.moko.resources.StringResource import dev.icerock.moko.resources.StringResource
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
@@ -71,7 +70,6 @@ fun activeCallDestroyWebView() = withApi {
actual fun ActiveCallView() { actual fun ActiveCallView() {
val call = remember { chatModel.activeCall }.value val call = remember { chatModel.activeCall }.value
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val audioViaBluetooth = rememberSaveable { mutableStateOf(false) }
val proximityLock = remember { val proximityLock = remember {
val pm = (androidAppContext.getSystemService(Context.POWER_SERVICE) as PowerManager) val pm = (androidAppContext.getSystemService(Context.POWER_SERVICE) as PowerManager)
if (pm.isWakeLockLevelSupported(PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { if (pm.isWakeLockLevelSupported(PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
@@ -87,41 +85,16 @@ actual fun ActiveCallView() {
wasConnected.value = true wasConnected.value = true
} }
} }
val callAudioDeviceManager = remember { CallAudioDeviceManagerInterface.new() }
DisposableEffect(Unit) { DisposableEffect(Unit) {
val am = androidAppContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager callAudioDeviceManager.start()
var btDeviceCount = 0
val audioCallback = object: AudioDeviceCallback() {
override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>) {
Log.d(TAG, "Added audio devices: ${addedDevices.map { it.type }}")
super.onAudioDevicesAdded(addedDevices)
val addedCount = addedDevices.count { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO }
btDeviceCount += addedCount
audioViaBluetooth.value = btDeviceCount > 0
if (addedCount > 0 && chatModel.activeCall.value?.callState == CallState.Connected) {
// Setting params in Connected state makes sure that Bluetooth will NOT be broken on Android < 12
setCallSound(chatModel.activeCall.value?.soundSpeaker ?: return, audioViaBluetooth)
}
}
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>) {
Log.d(TAG, "Removed audio devices: ${removedDevices.map { it.type }}")
super.onAudioDevicesRemoved(removedDevices)
val removedCount = removedDevices.count { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO }
btDeviceCount -= removedCount
audioViaBluetooth.value = btDeviceCount > 0
if (btDeviceCount == 0 && chatModel.activeCall.value?.callState == CallState.Connected) {
// Setting params in Connected state makes sure that Bluetooth will NOT be broken on Android < 12
setCallSound(chatModel.activeCall.value?.soundSpeaker ?: return, audioViaBluetooth)
}
}
}
am.registerAudioDeviceCallback(audioCallback, null)
onDispose { onDispose {
CallSoundsPlayer.stop() CallSoundsPlayer.stop()
if (wasConnected.value) { if (wasConnected.value) {
CallSoundsPlayer.vibrate() CallSoundsPlayer.vibrate()
} }
dropAudioManagerOverrides() dropAudioManagerOverrides()
am.unregisterAudioDeviceCallback(audioCallback) callAudioDeviceManager.stop()
if (proximityLock?.isHeld == true) { if (proximityLock?.isHeld == true) {
proximityLock.release() proximityLock.release()
} }
@@ -147,7 +120,7 @@ actual fun ActiveCallView() {
val callType = CallType(call.localMedia, r.capabilities) val callType = CallType(call.localMedia, r.capabilities)
chatModel.controller.apiSendCallInvitation(callRh, call.contact, callType) chatModel.controller.apiSendCallInvitation(callRh, call.contact, callType)
updateActiveCall(call) { it.copy(callState = CallState.InvitationSent, localCapabilities = r.capabilities) } updateActiveCall(call) { it.copy(callState = CallState.InvitationSent, localCapabilities = r.capabilities) }
setCallSound(call.soundSpeaker, audioViaBluetooth) callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
CallSoundsPlayer.startConnectingCallSound(scope) CallSoundsPlayer.startConnectingCallSound(scope)
activeCallWaitDeliveryReceipt(scope) activeCallWaitDeliveryReceipt(scope)
} }
@@ -168,7 +141,7 @@ actual fun ActiveCallView() {
val callStatus = json.decodeFromString<WebRTCCallStatus>("\"${r.state.connectionState}\"") val callStatus = json.decodeFromString<WebRTCCallStatus>("\"${r.state.connectionState}\"")
if (callStatus == WebRTCCallStatus.Connected) { if (callStatus == WebRTCCallStatus.Connected) {
updateActiveCall(call) { it.copy(callState = CallState.Connected, connectedAt = Clock.System.now()) } updateActiveCall(call) { it.copy(callState = CallState.Connected, connectedAt = Clock.System.now()) }
setCallSound(call.soundSpeaker, audioViaBluetooth) callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
} }
withBGApi { chatModel.controller.apiCallStatus(callRh, call.contact, callStatus) } withBGApi { chatModel.controller.apiCallStatus(callRh, call.contact, callStatus) }
} catch (e: Throwable) { } catch (e: Throwable) {
@@ -177,7 +150,7 @@ actual fun ActiveCallView() {
is WCallResponse.Connected -> { is WCallResponse.Connected -> {
updateActiveCall(call) { it.copy(callState = CallState.Connected, connectionInfo = r.connectionInfo) } updateActiveCall(call) { it.copy(callState = CallState.Connected, connectionInfo = r.connectionInfo) }
scope.launch { scope.launch {
setCallSound(call.soundSpeaker, audioViaBluetooth) callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
} }
} }
is WCallResponse.End -> { is WCallResponse.End -> {
@@ -223,7 +196,7 @@ actual fun ActiveCallView() {
else -> false else -> false
} }
if (call != null && showOverlay) { if (call != null && showOverlay) {
ActiveCallOverlay(call, chatModel, audioViaBluetooth) ActiveCallOverlay(call, chatModel, callAudioDeviceManager)
} }
} }
val context = LocalContext.current val context = LocalContext.current
@@ -249,19 +222,21 @@ actual fun ActiveCallView() {
} }
@Composable @Composable
private fun ActiveCallOverlay(call: Call, chatModel: ChatModel, audioViaBluetooth: MutableState<Boolean>) { private fun ActiveCallOverlay(call: Call, chatModel: ChatModel, callAudioDeviceManager: CallAudioDeviceManagerInterface) {
ActiveCallOverlayLayout( ActiveCallOverlayLayout(
call = call, call = call,
speakerCanBeEnabled = !audioViaBluetooth.value, devices = remember { callAudioDeviceManager.devices }.value,
currentDevice = remember { callAudioDeviceManager.currentDevice },
dismiss = { withBGApi { chatModel.callManager.endCall(call) } }, dismiss = { withBGApi { chatModel.callManager.endCall(call) } },
toggleAudio = { chatModel.callCommand.add(WCallCommand.Media(CallMediaType.Audio, enable = !call.audioEnabled)) }, toggleAudio = { chatModel.callCommand.add(WCallCommand.Media(CallMediaType.Audio, enable = !call.audioEnabled)) },
selectDevice = { callAudioDeviceManager.selectDevice(it.id) },
toggleVideo = { chatModel.callCommand.add(WCallCommand.Media(CallMediaType.Video, enable = !call.videoEnabled)) }, toggleVideo = { chatModel.callCommand.add(WCallCommand.Media(CallMediaType.Video, enable = !call.videoEnabled)) },
toggleSound = { toggleSound = {
var call = chatModel.activeCall.value var call = chatModel.activeCall.value
if (call != null) { if (call != null) {
call = call.copy(soundSpeaker = !call.soundSpeaker) call = call.copy(soundSpeaker = !call.soundSpeaker)
chatModel.activeCall.value = call chatModel.activeCall.value = call
setCallSound(call.soundSpeaker, audioViaBluetooth) callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
} }
}, },
flipCamera = { chatModel.callCommand.add(WCallCommand.Camera(call.localCamera.flipped)) } flipCamera = { chatModel.callCommand.add(WCallCommand.Camera(call.localCamera.flipped)) }
@@ -272,42 +247,18 @@ private fun ActiveCallOverlay(call: Call, chatModel: ChatModel, audioViaBluetoot
fun ActiveCallOverlayDisabled(call: Call) { fun ActiveCallOverlayDisabled(call: Call) {
ActiveCallOverlayLayout( ActiveCallOverlayLayout(
call = call, call = call,
speakerCanBeEnabled = false, devices = emptyList(),
currentDevice = remember { mutableStateOf(null) },
enabled = false, enabled = false,
dismiss = {}, dismiss = {},
toggleAudio = {}, toggleAudio = {},
selectDevice = {},
toggleVideo = {}, toggleVideo = {},
toggleSound = {}, toggleSound = {},
flipCamera = {} flipCamera = {}
) )
} }
private fun setCallSound(speaker: Boolean, audioViaBluetooth: MutableState<Boolean>) {
val am = androidAppContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
Log.d(TAG, "setCallSound: set audio mode, speaker enabled: $speaker")
am.mode = AudioManager.MODE_IN_COMMUNICATION
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val btDevice = am.availableCommunicationDevices.lastOrNull { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO }
val preferredSecondaryDevice = if (speaker) AudioDeviceInfo.TYPE_BUILTIN_SPEAKER else AudioDeviceInfo.TYPE_BUILTIN_EARPIECE
if (btDevice != null) {
am.setCommunicationDevice(btDevice)
} else if (am.communicationDevice?.type != preferredSecondaryDevice) {
am.availableCommunicationDevices.firstOrNull { it.type == preferredSecondaryDevice }?.let {
am.setCommunicationDevice(it)
}
}
} else {
if (audioViaBluetooth.value) {
am.isSpeakerphoneOn = false
am.startBluetoothSco()
} else {
am.stopBluetoothSco()
am.isSpeakerphoneOn = speaker
}
am.isBluetoothScoOn = am.isBluetoothScoAvailableOffCall && audioViaBluetooth.value
}
}
private fun dropAudioManagerOverrides() { private fun dropAudioManagerOverrides() {
val am = androidAppContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager val am = androidAppContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
am.mode = AudioManager.MODE_NORMAL am.mode = AudioManager.MODE_NORMAL
@@ -323,10 +274,12 @@ private fun dropAudioManagerOverrides() {
@Composable @Composable
private fun ActiveCallOverlayLayout( private fun ActiveCallOverlayLayout(
call: Call, call: Call,
speakerCanBeEnabled: Boolean, devices: List<AudioDeviceInfo>,
currentDevice: State<AudioDeviceInfo?>,
enabled: Boolean = true, enabled: Boolean = true,
dismiss: () -> Unit, dismiss: () -> Unit,
toggleAudio: () -> Unit, toggleAudio: () -> Unit,
selectDevice: (AudioDeviceInfo) -> Unit,
toggleVideo: () -> Unit, toggleVideo: () -> Unit,
toggleSound: () -> Unit, toggleSound: () -> Unit,
flipCamera: () -> Unit flipCamera: () -> Unit
@@ -339,6 +292,32 @@ private fun ActiveCallOverlayLayout(
} }
} }
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) { Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
@Composable
fun SelectSoundDevice() {
if (devices.size == 2 &&
devices.all { it.type == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE || it.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER } ||
currentDevice.value == null ||
devices.none { it.id == currentDevice.value?.id }
) {
ToggleSoundButton(call, enabled, toggleSound)
} else {
ExposedDropDownSettingWithIcon(
devices.map { Triple(it, it.icon, if (it.name != null) generalGetString(it.name!!) else it.productName.toString()) },
currentDevice,
fontSize = 18.sp,
iconSize = 40.dp,
listIconSize = 30.dp,
iconColor = Color(0xFFFFFFD8),
minWidth = 300.dp,
onSelected = {
if (it != null) {
selectDevice(it)
}
}
)
}
}
when (media) { when (media) {
CallMediaType.Video -> { CallMediaType.Video -> {
VideoCallInfoView(call) VideoCallInfoView(call)
@@ -347,7 +326,7 @@ private fun ActiveCallOverlayLayout(
} }
Row(Modifier.fillMaxWidth().padding(horizontal = 6.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) { Row(Modifier.fillMaxWidth().padding(horizontal = 6.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
ToggleAudioButton(call, enabled, toggleAudio) ToggleAudioButton(call, enabled, toggleAudio)
Spacer(Modifier.size(40.dp)) SelectSoundDevice()
IconButton(onClick = dismiss, enabled = enabled) { IconButton(onClick = dismiss, enabled = enabled) {
Icon(painterResource(MR.images.ic_call_end_filled), stringResource(MR.strings.icon_descr_hang_up), tint = if (enabled) Color.Red else MaterialTheme.colors.secondary, modifier = Modifier.size(64.dp)) Icon(painterResource(MR.images.ic_call_end_filled), stringResource(MR.strings.icon_descr_hang_up), tint = if (enabled) Color.Red else MaterialTheme.colors.secondary, modifier = Modifier.size(64.dp))
} }
@@ -385,7 +364,7 @@ private fun ActiveCallOverlayLayout(
} }
Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) { Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) {
Box(Modifier.padding(end = 32.dp)) { Box(Modifier.padding(end = 32.dp)) {
ToggleSoundButton(call, speakerCanBeEnabled && enabled, toggleSound) SelectSoundDevice()
} }
} }
} }
@@ -780,9 +759,11 @@ fun PreviewActiveCallOverlayVideo() {
RTCIceCandidate(RTCIceCandidateType.Host, "tcp") RTCIceCandidate(RTCIceCandidateType.Host, "tcp")
) )
), ),
speakerCanBeEnabled = true, devices = emptyList(),
currentDevice = remember { mutableStateOf(null) },
dismiss = {}, dismiss = {},
toggleAudio = {}, toggleAudio = {},
selectDevice = {},
toggleVideo = {}, toggleVideo = {},
toggleSound = {}, toggleSound = {},
flipCamera = {} flipCamera = {}
@@ -807,9 +788,11 @@ fun PreviewActiveCallOverlayAudio() {
RTCIceCandidate(RTCIceCandidateType.Host, "udp") RTCIceCandidate(RTCIceCandidateType.Host, "udp")
) )
), ),
speakerCanBeEnabled = true, devices = emptyList(),
currentDevice = remember { mutableStateOf(null) },
dismiss = {}, dismiss = {},
toggleAudio = {}, toggleAudio = {},
selectDevice = {},
toggleVideo = {}, toggleVideo = {},
toggleSound = {}, toggleSound = {},
flipCamera = {} flipCamera = {}
@@ -111,7 +111,7 @@ object ChatModel {
var draft = mutableStateOf(null as ComposeState?) var draft = mutableStateOf(null as ComposeState?)
var draftChatId = mutableStateOf(null as String?) var draftChatId = mutableStateOf(null as String?)
// working with external intents // working with external intents or internal forwarding of chat items
val sharedContent = mutableStateOf(null as SharedContent?) val sharedContent = mutableStateOf(null as SharedContent?)
val filesToDelete = mutableSetOf<File>() val filesToDelete = mutableSetOf<File>()
@@ -1753,7 +1753,7 @@ data class ChatItem (
val allowAddReaction: Boolean get() = val allowAddReaction: Boolean get() =
meta.itemDeleted == null && !isLiveDummy && (reactions.count { it.userReacted } < 3) meta.itemDeleted == null && !isLiveDummy && (reactions.count { it.userReacted } < 3)
private val isLiveDummy: Boolean get() = meta.itemId == TEMP_LIVE_CHAT_ITEM_ID val isLiveDummy: Boolean get() = meta.itemId == TEMP_LIVE_CHAT_ITEM_ID
val encryptedFile: Boolean? = if (file?.fileSource == null) null else file.fileSource.cryptoArgs != null val encryptedFile: Boolean? = if (file?.fileSource == null) null else file.fileSource.cryptoArgs != null
@@ -2298,8 +2298,26 @@ enum class MsgDirection {
@Serializable @Serializable
sealed class CIForwardedFrom { sealed class CIForwardedFrom {
@Serializable @SerialName("unknown") object Unknown: CIForwardedFrom() @Serializable @SerialName("unknown") object Unknown: CIForwardedFrom()
@Serializable @SerialName("contact") class Contact(val chatName: String, val msgDir: MsgDirection, val contactId: Long? = null, val chatItemId: Long? = null): CIForwardedFrom() @Serializable @SerialName("contact") class Contact(override val chatName: String, val msgDir: MsgDirection, val contactId: Long? = null, val chatItemId: Long? = null): CIForwardedFrom()
@Serializable @SerialName("group") class Group(val chatName: String, val msgDir: MsgDirection, val groupId: Long? = null, val chatItemId: Long? = null): CIForwardedFrom() @Serializable @SerialName("group") class Group(override val chatName: String, val msgDir: MsgDirection, val groupId: Long? = null, val chatItemId: Long? = null): CIForwardedFrom()
open val chatName: String
get() = when (this) {
Unknown -> ""
is Contact -> chatName
is Group -> chatName
}
fun text(chatType: ChatType): String =
if (chatType == ChatType.Local) {
if (chatName.isEmpty()) {
generalGetString(MR.strings.saved_description)
} else {
generalGetString(MR.strings.saved_from_description).format(chatName)
}
} else {
generalGetString(MR.strings.forwarded_description)
}
} }
@Serializable @Serializable
@@ -135,6 +135,7 @@ class AppPreferences {
val networkTCPConnectTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT, NetCfg.defaults.tcpConnectTimeout, NetCfg.proxyDefaults.tcpConnectTimeout) val networkTCPConnectTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT, NetCfg.defaults.tcpConnectTimeout, NetCfg.proxyDefaults.tcpConnectTimeout)
val networkTCPTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_TIMEOUT, NetCfg.defaults.tcpTimeout, NetCfg.proxyDefaults.tcpTimeout) val networkTCPTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_TIMEOUT, NetCfg.defaults.tcpTimeout, NetCfg.proxyDefaults.tcpTimeout)
val networkTCPTimeoutPerKb = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_TIMEOUT_PER_KB, NetCfg.defaults.tcpTimeoutPerKb, NetCfg.proxyDefaults.tcpTimeoutPerKb) val networkTCPTimeoutPerKb = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_TIMEOUT_PER_KB, NetCfg.defaults.tcpTimeoutPerKb, NetCfg.proxyDefaults.tcpTimeoutPerKb)
val networkRcvConcurrency = mkIntPreference(SHARED_PREFS_NETWORK_RCV_CONCURRENCY, NetCfg.defaults.rcvConcurrency)
val networkSMPPingInterval = mkLongPreference(SHARED_PREFS_NETWORK_SMP_PING_INTERVAL, NetCfg.defaults.smpPingInterval) val networkSMPPingInterval = mkLongPreference(SHARED_PREFS_NETWORK_SMP_PING_INTERVAL, NetCfg.defaults.smpPingInterval)
val networkSMPPingCount = mkIntPreference(SHARED_PREFS_NETWORK_SMP_PING_COUNT, NetCfg.defaults.smpPingCount) val networkSMPPingCount = mkIntPreference(SHARED_PREFS_NETWORK_SMP_PING_COUNT, NetCfg.defaults.smpPingCount)
val networkEnableKeepAlive = mkBoolPreference(SHARED_PREFS_NETWORK_ENABLE_KEEP_ALIVE, NetCfg.defaults.enableKeepAlive) val networkEnableKeepAlive = mkBoolPreference(SHARED_PREFS_NETWORK_ENABLE_KEEP_ALIVE, NetCfg.defaults.enableKeepAlive)
@@ -304,6 +305,7 @@ class AppPreferences {
private const val SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT = "NetworkTCPConnectTimeout" private const val SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT = "NetworkTCPConnectTimeout"
private const val SHARED_PREFS_NETWORK_TCP_TIMEOUT = "NetworkTCPTimeout" private const val SHARED_PREFS_NETWORK_TCP_TIMEOUT = "NetworkTCPTimeout"
private const val SHARED_PREFS_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb" private const val SHARED_PREFS_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb"
private const val SHARED_PREFS_NETWORK_RCV_CONCURRENCY = "networkRcvConcurrency"
private const val SHARED_PREFS_NETWORK_SMP_PING_INTERVAL = "NetworkSMPPingInterval" private const val SHARED_PREFS_NETWORK_SMP_PING_INTERVAL = "NetworkSMPPingInterval"
private const val SHARED_PREFS_NETWORK_SMP_PING_COUNT = "NetworkSMPPingCount" private const val SHARED_PREFS_NETWORK_SMP_PING_COUNT = "NetworkSMPPingCount"
private const val SHARED_PREFS_NETWORK_ENABLE_KEEP_ALIVE = "NetworkEnableKeepAlive" private const val SHARED_PREFS_NETWORK_ENABLE_KEEP_ALIVE = "NetworkEnableKeepAlive"
@@ -738,12 +740,16 @@ object ChatController {
suspend fun apiSendMessage(rh: Long?, type: ChatType, id: Long, file: CryptoFile? = null, quotedItemId: Long? = null, mc: MsgContent, live: Boolean = false, ttl: Int? = null): AChatItem? { suspend fun apiSendMessage(rh: Long?, type: ChatType, id: Long, file: CryptoFile? = null, quotedItemId: Long? = null, mc: MsgContent, live: Boolean = false, ttl: Int? = null): AChatItem? {
val cmd = CC.ApiSendMessage(type, id, file, quotedItemId, mc, live, ttl) val cmd = CC.ApiSendMessage(type, id, file, quotedItemId, mc, live, ttl)
return processSendMessageCmd(rh, cmd)
}
private suspend fun processSendMessageCmd(rh: Long?, cmd: CC): AChatItem? {
val r = sendCmd(rh, cmd) val r = sendCmd(rh, cmd)
return when (r) { return when (r) {
is CR.NewChatItem -> r.chatItem is CR.NewChatItem -> r.chatItem
else -> { else -> {
if (!(networkErrorAlert(r))) { if (!(networkErrorAlert(r))) {
apiErrorAlert("apiSendMessage", generalGetString(MR.strings.error_sending_message), r) apiErrorAlert("processSendMessageCmd", generalGetString(MR.strings.error_sending_message), r)
} }
null null
} }
@@ -771,6 +777,13 @@ object ChatController {
} }
} }
suspend fun apiForwardChatItem(rh: Long?, toChatType: ChatType, toChatId: Long, fromChatType: ChatType, fromChatId: Long, itemId: Long): ChatItem? {
val cmd = CC.ApiForwardChatItem(toChatType, toChatId, fromChatType, fromChatId, itemId)
return processSendMessageCmd(rh, cmd)?.chatItem
}
suspend fun apiUpdateChatItem(rh: Long?, type: ChatType, id: Long, itemId: Long, mc: MsgContent, live: Boolean = false): AChatItem? { suspend fun apiUpdateChatItem(rh: Long?, type: ChatType, id: Long, itemId: Long, mc: MsgContent, live: Boolean = false): AChatItem? {
val r = sendCmd(rh, CC.ApiUpdateChatItem(type, id, itemId, mc, live)) val r = sendCmd(rh, CC.ApiUpdateChatItem(type, id, itemId, mc, live))
if (r is CR.ChatItemUpdated) return r.chatItem if (r is CR.ChatItemUpdated) return r.chatItem
@@ -1971,7 +1984,6 @@ object ChatController {
} }
is CR.SndFileCompleteXFTP -> { is CR.SndFileCompleteXFTP -> {
chatItemSimpleUpdate(rhId, r.user, r.chatItem) chatItemSimpleUpdate(rhId, r.user, r.chatItem)
cleanupFile(r.chatItem)
} }
is CR.SndFileError -> { is CR.SndFileError -> {
if (r.chatItem_ != null) { if (r.chatItem_ != null) {
@@ -2295,6 +2307,7 @@ object ChatController {
val tcpConnectTimeout = appPrefs.networkTCPConnectTimeout.get() val tcpConnectTimeout = appPrefs.networkTCPConnectTimeout.get()
val tcpTimeout = appPrefs.networkTCPTimeout.get() val tcpTimeout = appPrefs.networkTCPTimeout.get()
val tcpTimeoutPerKb = appPrefs.networkTCPTimeoutPerKb.get() val tcpTimeoutPerKb = appPrefs.networkTCPTimeoutPerKb.get()
val rcvConcurrency = appPrefs.networkRcvConcurrency.get()
val smpPingInterval = appPrefs.networkSMPPingInterval.get() val smpPingInterval = appPrefs.networkSMPPingInterval.get()
val smpPingCount = appPrefs.networkSMPPingCount.get() val smpPingCount = appPrefs.networkSMPPingCount.get()
val enableKeepAlive = appPrefs.networkEnableKeepAlive.get() val enableKeepAlive = appPrefs.networkEnableKeepAlive.get()
@@ -2314,6 +2327,7 @@ object ChatController {
tcpConnectTimeout = tcpConnectTimeout, tcpConnectTimeout = tcpConnectTimeout,
tcpTimeout = tcpTimeout, tcpTimeout = tcpTimeout,
tcpTimeoutPerKb = tcpTimeoutPerKb, tcpTimeoutPerKb = tcpTimeoutPerKb,
rcvConcurrency = rcvConcurrency,
tcpKeepAlive = tcpKeepAlive, tcpKeepAlive = tcpKeepAlive,
smpPingInterval = smpPingInterval, smpPingInterval = smpPingInterval,
smpPingCount = smpPingCount smpPingCount = smpPingCount
@@ -2331,6 +2345,7 @@ object ChatController {
appPrefs.networkTCPConnectTimeout.set(cfg.tcpConnectTimeout) appPrefs.networkTCPConnectTimeout.set(cfg.tcpConnectTimeout)
appPrefs.networkTCPTimeout.set(cfg.tcpTimeout) appPrefs.networkTCPTimeout.set(cfg.tcpTimeout)
appPrefs.networkTCPTimeoutPerKb.set(cfg.tcpTimeoutPerKb) appPrefs.networkTCPTimeoutPerKb.set(cfg.tcpTimeoutPerKb)
appPrefs.networkRcvConcurrency.set(cfg.rcvConcurrency)
appPrefs.networkSMPPingInterval.set(cfg.smpPingInterval) appPrefs.networkSMPPingInterval.set(cfg.smpPingInterval)
appPrefs.networkSMPPingCount.set(cfg.smpPingCount) appPrefs.networkSMPPingCount.set(cfg.smpPingCount)
if (cfg.tcpKeepAlive != null) { if (cfg.tcpKeepAlive != null) {
@@ -2396,6 +2411,7 @@ sealed class CC {
class ApiDeleteChatItem(val type: ChatType, val id: Long, val itemId: Long, val mode: CIDeleteMode): CC() class ApiDeleteChatItem(val type: ChatType, val id: Long, val itemId: Long, val mode: CIDeleteMode): CC()
class ApiDeleteMemberChatItem(val groupId: Long, val groupMemberId: Long, val itemId: Long): CC() class ApiDeleteMemberChatItem(val groupId: Long, val groupMemberId: Long, val itemId: Long): CC()
class ApiChatItemReaction(val type: ChatType, val id: Long, val itemId: Long, val add: Boolean, val reaction: MsgReaction): CC() class ApiChatItemReaction(val type: ChatType, val id: Long, val itemId: Long, val add: Boolean, val reaction: MsgReaction): CC()
class ApiForwardChatItem(val toChatType: ChatType, val toChatId: Long, val fromChatType: ChatType, val fromChatId: Long, val itemId: Long): CC()
class ApiNewGroup(val userId: Long, val incognito: Boolean, val groupProfile: GroupProfile): CC() class ApiNewGroup(val userId: Long, val incognito: Boolean, val groupProfile: GroupProfile): CC()
class ApiAddMember(val groupId: Long, val contactId: Long, val memberRole: GroupMemberRole): CC() class ApiAddMember(val groupId: Long, val contactId: Long, val memberRole: GroupMemberRole): CC()
class ApiJoinGroup(val groupId: Long): CC() class ApiJoinGroup(val groupId: Long): CC()
@@ -2539,6 +2555,7 @@ sealed class CC {
is ApiDeleteChatItem -> "/_delete item ${chatRef(type, id)} $itemId ${mode.deleteMode}" is ApiDeleteChatItem -> "/_delete item ${chatRef(type, id)} $itemId ${mode.deleteMode}"
is ApiDeleteMemberChatItem -> "/_delete member item #$groupId $groupMemberId $itemId" is ApiDeleteMemberChatItem -> "/_delete member item #$groupId $groupMemberId $itemId"
is ApiChatItemReaction -> "/_reaction ${chatRef(type, id)} $itemId ${onOff(add)} ${json.encodeToString(reaction)}" is ApiChatItemReaction -> "/_reaction ${chatRef(type, id)} $itemId ${onOff(add)} ${json.encodeToString(reaction)}"
is ApiForwardChatItem -> "/_forward ${chatRef(toChatType, toChatId)} ${chatRef(fromChatType, fromChatId)} $itemId"
is ApiNewGroup -> "/_group $userId incognito=${onOff(incognito)} ${json.encodeToString(groupProfile)}" is ApiNewGroup -> "/_group $userId incognito=${onOff(incognito)} ${json.encodeToString(groupProfile)}"
is ApiAddMember -> "/_add #$groupId $contactId ${memberRole.memberRole}" is ApiAddMember -> "/_add #$groupId $contactId ${memberRole.memberRole}"
is ApiJoinGroup -> "/_join #$groupId" is ApiJoinGroup -> "/_join #$groupId"
@@ -2677,6 +2694,7 @@ sealed class CC {
is ApiDeleteChatItem -> "apiDeleteChatItem" is ApiDeleteChatItem -> "apiDeleteChatItem"
is ApiDeleteMemberChatItem -> "apiDeleteMemberChatItem" is ApiDeleteMemberChatItem -> "apiDeleteMemberChatItem"
is ApiChatItemReaction -> "apiChatItemReaction" is ApiChatItemReaction -> "apiChatItemReaction"
is ApiForwardChatItem -> "apiForwardChatItem"
is ApiNewGroup -> "apiNewGroup" is ApiNewGroup -> "apiNewGroup"
is ApiAddMember -> "apiAddMember" is ApiAddMember -> "apiAddMember"
is ApiJoinGroup -> "apiJoinGroup" is ApiJoinGroup -> "apiJoinGroup"
@@ -3021,6 +3039,7 @@ data class NetCfg(
val tcpConnectTimeout: Long, // microseconds val tcpConnectTimeout: Long, // microseconds
val tcpTimeout: Long, // microseconds val tcpTimeout: Long, // microseconds
val tcpTimeoutPerKb: Long, // microseconds val tcpTimeoutPerKb: Long, // microseconds
val rcvConcurrency: Int, // pool size
val tcpKeepAlive: KeepAliveOpts?, val tcpKeepAlive: KeepAliveOpts?,
val smpPingInterval: Long, // microseconds val smpPingInterval: Long, // microseconds
val smpPingCount: Int, val smpPingCount: Int,
@@ -3045,9 +3064,10 @@ data class NetCfg(
hostMode = HostMode.OnionViaSocks, hostMode = HostMode.OnionViaSocks,
requiredHostMode = false, requiredHostMode = false,
sessionMode = TransportSessionMode.User, sessionMode = TransportSessionMode.User,
tcpConnectTimeout = 20_000_000, tcpConnectTimeout = 10_000_000,
tcpTimeout = 15_000_000, tcpTimeout = 15_000_000,
tcpTimeoutPerKb = 10_000, tcpTimeoutPerKb = 10_000,
rcvConcurrency = 12,
tcpKeepAlive = KeepAliveOpts.defaults, tcpKeepAlive = KeepAliveOpts.defaults,
smpPingInterval = 1200_000_000, smpPingInterval = 1200_000_000,
smpPingCount = 3 smpPingCount = 3
@@ -3059,9 +3079,10 @@ data class NetCfg(
hostMode = HostMode.OnionViaSocks, hostMode = HostMode.OnionViaSocks,
requiredHostMode = false, requiredHostMode = false,
sessionMode = TransportSessionMode.User, sessionMode = TransportSessionMode.User,
tcpConnectTimeout = 30_000_000, tcpConnectTimeout = 20_000_000,
tcpTimeout = 20_000_000, tcpTimeout = 20_000_000,
tcpTimeoutPerKb = 15_000, tcpTimeoutPerKb = 15_000,
rcvConcurrency = 8,
tcpKeepAlive = KeepAliveOpts.defaults, tcpKeepAlive = KeepAliveOpts.defaults,
smpPingInterval = 1200_000_000, smpPingInterval = 1200_000_000,
smpPingCount = 3 smpPingCount = 3
@@ -13,9 +13,8 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.*
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource import dev.icerock.moko.resources.compose.stringResource
@@ -29,6 +28,7 @@ import chat.simplex.common.views.chat.item.ItemAction
import chat.simplex.common.views.chat.item.MarkdownText import chat.simplex.common.views.chat.item.MarkdownText
import chat.simplex.common.views.helpers.* import chat.simplex.common.views.helpers.*
import chat.simplex.common.ui.theme.* import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chatlist.*
import chat.simplex.res.MR import chat.simplex.res.MR
import dev.icerock.moko.resources.ImageResource import dev.icerock.moko.resources.ImageResource
@@ -36,10 +36,11 @@ sealed class CIInfoTab {
class Delivery(val memberDeliveryStatuses: List<MemberDeliveryStatus>): CIInfoTab() class Delivery(val memberDeliveryStatuses: List<MemberDeliveryStatus>): CIInfoTab()
object History: CIInfoTab() object History: CIInfoTab()
class Quote(val quotedItem: CIQuote): CIInfoTab() class Quote(val quotedItem: CIQuote): CIInfoTab()
class Forwarded(val forwardedFromChatItem: AChatItem): CIInfoTab()
} }
@Composable @Composable
fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) { fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) {
val sent = ci.chatDir.sent val sent = ci.chatDir.sent
val appColors = CurrentColors.collectAsState().value.appColors val appColors = CurrentColors.collectAsState().value.appColors
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
@@ -151,6 +152,70 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
} }
} }
val local = when (ci.chatDir) {
is CIDirection.LocalSnd -> true
is CIDirection.LocalRcv -> true
else -> false
}
@Composable
fun ForwardedFromSender(forwardedFromItem: AChatItem) {
@Composable
fun ItemText(text: String, fontStyle: FontStyle = FontStyle.Normal, color: Color = MaterialTheme.colors.onBackground) {
Text(
text,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.body1,
fontStyle = fontStyle,
color = color,
)
}
Row(verticalAlignment = Alignment.CenterVertically) {
ChatInfoImage(forwardedFromItem.chatInfo, size = 57.dp)
Column(
modifier = Modifier
.padding(start = 15.dp)
.weight(1F)
) {
if (forwardedFromItem.chatItem.chatDir.sent) {
ItemText(text = stringResource(MR.strings.sender_you_pronoun), fontStyle = FontStyle.Italic)
Spacer(Modifier.height(7.dp))
ItemText(forwardedFromItem.chatInfo.chatViewName, color = MaterialTheme.colors.secondary)
} else if (forwardedFromItem.chatItem.chatDir is CIDirection.GroupRcv) {
ItemText(text = forwardedFromItem.chatItem.chatDir.groupMember.chatViewName)
Spacer(Modifier.height(7.dp))
ItemText(forwardedFromItem.chatInfo.chatViewName, color = MaterialTheme.colors.secondary)
} else {
ItemText(forwardedFromItem.chatInfo.chatViewName, color = MaterialTheme.colors.onBackground)
}
}
}
}
@Composable
fun ForwardedFromView(forwardedFromItem: AChatItem) {
Column {
SectionItemView(
click = {
withBGApi {
openChat(chatRh, forwardedFromItem.chatInfo, chatModel)
ModalManager.end.closeModals()
}
},
padding = PaddingValues(start = 17.dp, end = DEFAULT_PADDING)
) {
ForwardedFromSender(forwardedFromItem)
}
if (!local) {
Divider(Modifier.padding(start = DEFAULT_PADDING_HALF, top = 41.dp, end = DEFAULT_PADDING_HALF, bottom = DEFAULT_PADDING_HALF))
Text(stringResource(MR.strings.recipients_can_not_see_who_message_from), Modifier.padding(horizontal = DEFAULT_PADDING), fontSize = 12.sp, color = MaterialTheme.colors.secondary)
}
}
}
@Composable @Composable
fun Details() { fun Details() {
AppBarTitle(stringResource(if (ci.localNote) MR.strings.saved_message_title else if (sent) MR.strings.sent_message else MR.strings.received_message)) AppBarTitle(stringResource(if (ci.localNote) MR.strings.saved_message_title else if (sent) MR.strings.sent_message else MR.strings.received_message))
@@ -188,7 +253,7 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
// LALAL SCROLLBAR DOESN'T WORK // LALAL SCROLLBAR DOESN'T WORK
ColumnWithScrollBar(Modifier.fillMaxWidth()) { ColumnWithScrollBar(Modifier.fillMaxWidth()) {
Details() Details()
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true)
val versions = ciInfo.itemVersions val versions = ciInfo.itemVersions
if (versions.isNotEmpty()) { if (versions.isNotEmpty()) {
SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) { SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
@@ -213,7 +278,7 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
// LALAL SCROLLBAR DOESN'T WORK // LALAL SCROLLBAR DOESN'T WORK
ColumnWithScrollBar(Modifier.fillMaxWidth()) { ColumnWithScrollBar(Modifier.fillMaxWidth()) {
Details() Details()
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true)
SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) { SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
Text(stringResource(MR.strings.in_reply_to), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING)) Text(stringResource(MR.strings.in_reply_to), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING))
QuotedMsgView(qi) QuotedMsgView(qi)
@@ -222,6 +287,22 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
} }
} }
@Composable
fun ForwardedFromTab(forwardedFromItem: AChatItem) {
// LALAL SCROLLBAR DOESN'T WORK
ColumnWithScrollBar(Modifier.fillMaxWidth()) {
Details()
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true)
SectionView {
Text(stringResource(if (local) MR.strings.saved_from_chat_item_info_title else MR.strings.forwarded_from_chat_item_info_title),
style = MaterialTheme.typography.h2,
modifier = Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING))
ForwardedFromView(forwardedFromItem)
}
SectionBottomSpacer()
}
}
@Composable @Composable
fun MemberDeliveryStatusView(member: GroupMember, status: CIStatus) { fun MemberDeliveryStatusView(member: GroupMember, status: CIStatus) {
SectionItemView( SectionItemView(
@@ -271,7 +352,7 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
// LALAL SCROLLBAR DOESN'T WORK // LALAL SCROLLBAR DOESN'T WORK
ColumnWithScrollBar(Modifier.fillMaxWidth()) { ColumnWithScrollBar(Modifier.fillMaxWidth()) {
Details() Details()
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true)
val mss = membersStatuses(chatModel, memberDeliveryStatuses) val mss = membersStatuses(chatModel, memberDeliveryStatuses)
if (mss.isNotEmpty()) { if (mss.isNotEmpty()) {
SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) { SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
@@ -297,6 +378,7 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
is CIInfoTab.Delivery -> stringResource(MR.strings.delivery) is CIInfoTab.Delivery -> stringResource(MR.strings.delivery)
is CIInfoTab.History -> stringResource(MR.strings.edit_history) is CIInfoTab.History -> stringResource(MR.strings.edit_history)
is CIInfoTab.Quote -> stringResource(MR.strings.in_reply_to) is CIInfoTab.Quote -> stringResource(MR.strings.in_reply_to)
is CIInfoTab.Forwarded -> stringResource(if (local) MR.strings.saved_chat_item_info_tab else MR.strings.forwarded_chat_item_info_tab)
} }
} }
@@ -305,6 +387,7 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
is CIInfoTab.Delivery -> MR.images.ic_double_check is CIInfoTab.Delivery -> MR.images.ic_double_check
is CIInfoTab.History -> MR.images.ic_history is CIInfoTab.History -> MR.images.ic_history
is CIInfoTab.Quote -> MR.images.ic_reply is CIInfoTab.Quote -> MR.images.ic_reply
is CIInfoTab.Forwarded -> MR.images.ic_forward
} }
} }
@@ -316,6 +399,9 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
if (ci.quotedItem != null) { if (ci.quotedItem != null) {
numTabs += 1 numTabs += 1
} }
if (ciInfo.forwardedFromChatItem != null) {
numTabs += 1
}
return numTabs return numTabs
} }
@@ -326,11 +412,6 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
.fillMaxHeight(), .fillMaxHeight(),
verticalArrangement = Arrangement.SpaceBetween verticalArrangement = Arrangement.SpaceBetween
) { ) {
LaunchedEffect(ciInfo) {
if (ciInfo.memberDeliveryStatuses != null) {
selection.value = CIInfoTab.Delivery(ciInfo.memberDeliveryStatuses)
}
}
Column(Modifier.weight(1f)) { Column(Modifier.weight(1f)) {
when (val sel = selection.value) { when (val sel = selection.value) {
is CIInfoTab.Delivery -> { is CIInfoTab.Delivery -> {
@@ -344,6 +425,10 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
is CIInfoTab.Quote -> { is CIInfoTab.Quote -> {
QuoteTab(sel.quotedItem) QuoteTab(sel.quotedItem)
} }
is CIInfoTab.Forwarded -> {
ForwardedFromTab(sel.forwardedFromChatItem)
}
} }
} }
val availableTabs = mutableListOf<CIInfoTab>() val availableTabs = mutableListOf<CIInfoTab>()
@@ -354,6 +439,19 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d
if (ci.quotedItem != null) { if (ci.quotedItem != null) {
availableTabs.add(CIInfoTab.Quote(ci.quotedItem)) availableTabs.add(CIInfoTab.Quote(ci.quotedItem))
} }
if (ciInfo.forwardedFromChatItem != null) {
availableTabs.add(CIInfoTab.Forwarded(ciInfo.forwardedFromChatItem))
}
if (availableTabs.none { it.javaClass == selection.value.javaClass }) {
selection.value = availableTabs.first()
}
LaunchedEffect(ciInfo) {
if (ciInfo.forwardedFromChatItem != null && selection.value is CIInfoTab.Forwarded) {
selection.value = CIInfoTab.Forwarded(ciInfo.forwardedFromChatItem)
} else if (ciInfo.memberDeliveryStatuses != null) {
selection.value = CIInfoTab.Delivery(ciInfo.memberDeliveryStatuses)
}
}
TabRow( TabRow(
selectedTabIndex = availableTabs.indexOfFirst { it::class == selection.value::class }, selectedTabIndex = availableTabs.indexOfFirst { it::class == selection.value::class },
backgroundColor = Color.Transparent, backgroundColor = Color.Transparent,
@@ -52,9 +52,11 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
val user = chatModel.currentUser.value val user = chatModel.currentUser.value
val useLinkPreviews = chatModel.controller.appPrefs.privacyLinkPreviews.get() val useLinkPreviews = chatModel.controller.appPrefs.privacyLinkPreviews.get()
val composeState = rememberSaveable(saver = ComposeState.saver()) { val composeState = rememberSaveable(saver = ComposeState.saver()) {
val draft = chatModel.draft.value
val sharedContent = chatModel.sharedContent.value
mutableStateOf( mutableStateOf(
if (chatModel.draftChatId.value == chatId && chatModel.draft.value != null) { if (chatModel.draftChatId.value == chatId && draft != null && (sharedContent !is SharedContent.Forward || sharedContent.fromChatInfo.id == chatId)) {
chatModel.draft.value ?: ComposeState(useLinkPreviews = useLinkPreviews) draft
} else { } else {
ComposeState(useLinkPreviews = useLinkPreviews) ComposeState(useLinkPreviews = useLinkPreviews)
} }
@@ -408,7 +410,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
clipboard.shareText(itemInfoShareText(chatModel, cItem, ciInfo, chatModel.controller.appPrefs.developerTools.get())) clipboard.shareText(itemInfoShareText(chatModel, cItem, ciInfo, chatModel.controller.appPrefs.developerTools.get()))
} }
}) { close -> }) { close ->
ChatItemInfoView(chatModel, cItem, ciInfo, devTools = chatModel.controller.appPrefs.developerTools.get()) ChatItemInfoView(chatRh, cItem, ciInfo, devTools = chatModel.controller.appPrefs.developerTools.get())
KeyChangeEffect(chatModel.chatId.value) { KeyChangeEffect(chatModel.chatId.value) {
close() close()
} }
@@ -956,7 +958,7 @@ fun BoxWithConstraintsScope.ChatItemsList(
tryOrShowError("${cItem.id}ChatItem", error = { tryOrShowError("${cItem.id}ChatItem", error = {
CIBrokenComposableView(if (cItem.chatDir.sent) Alignment.CenterEnd else Alignment.CenterStart) CIBrokenComposableView(if (cItem.chatDir.sent) Alignment.CenterEnd else Alignment.CenterStart)
}) { }) {
ChatItemView(chat.chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, revealed = revealed, range = range, deleteMessage = deleteMessage, deleteMessages = deleteMessages, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, openDirectChat = openDirectChat, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember, scrollToItem = scrollToItem, setReaction = setReaction, showItemDetails = showItemDetails, developerTools = developerTools) ChatItemView(chat.remoteHostId, chat.chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, revealed = revealed, range = range, deleteMessage = deleteMessage, deleteMessages = deleteMessages, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, openDirectChat = openDirectChat, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember, scrollToItem = scrollToItem, setReaction = setReaction, showItemDetails = showItemDetails, developerTools = developerTools)
} }
} }
@@ -1090,9 +1092,9 @@ private fun ScrollToBottom(chatId: ChatId, listState: LazyListState, chatItems:
.collect { .collect {
try { try {
if (listState.firstVisibleItemIndex == 0 || (listState.firstVisibleItemIndex == 1 && listState.layoutInfo.totalItemsCount == chatItems.size)) { if (listState.firstVisibleItemIndex == 0 || (listState.firstVisibleItemIndex == 1 && listState.layoutInfo.totalItemsCount == chatItems.size)) {
listState.animateScrollToItem(0) if (appPlatform.isAndroid) listState.animateScrollToItem(0) else listState.scrollToItem(0)
} else { } else {
listState.animateScrollBy(scrollDistance) if (appPlatform.isAndroid) listState.animateScrollBy(scrollDistance) else listState.scrollBy(scrollDistance)
} }
} catch (e: CancellationException) { } catch (e: CancellationException) {
/** /**
@@ -46,6 +46,7 @@ sealed class ComposeContextItem {
@Serializable object NoContextItem: ComposeContextItem() @Serializable object NoContextItem: ComposeContextItem()
@Serializable class QuotedItem(val chatItem: ChatItem): ComposeContextItem() @Serializable class QuotedItem(val chatItem: ChatItem): ComposeContextItem()
@Serializable class EditingItem(val chatItem: ChatItem): ComposeContextItem() @Serializable class EditingItem(val chatItem: ChatItem): ComposeContextItem()
@Serializable class ForwardingItem(val chatItem: ChatItem, val fromChatInfo: ChatInfo): ComposeContextItem()
} }
@Serializable @Serializable
@@ -79,13 +80,18 @@ data class ComposeState(
is ComposeContextItem.EditingItem -> true is ComposeContextItem.EditingItem -> true
else -> false else -> false
} }
val forwarding: Boolean
get() = when (contextItem) {
is ComposeContextItem.ForwardingItem -> true
else -> false
}
val sendEnabled: () -> Boolean val sendEnabled: () -> Boolean
get() = { get() = {
val hasContent = when (preview) { val hasContent = when (preview) {
is ComposePreview.MediaPreview -> true is ComposePreview.MediaPreview -> true
is ComposePreview.VoicePreview -> true is ComposePreview.VoicePreview -> true
is ComposePreview.FilePreview -> true is ComposePreview.FilePreview -> true
else -> message.isNotEmpty() || liveMessage != null else -> message.isNotEmpty() || forwarding || liveMessage != null
} }
hasContent && !inProgress hasContent && !inProgress
} }
@@ -109,7 +115,7 @@ data class ComposeState(
val attachmentDisabled: Boolean val attachmentDisabled: Boolean
get() { get() {
if (editing || liveMessage != null || inProgress) return true if (editing || forwarding || liveMessage != null || inProgress) return true
return when (preview) { return when (preview) {
ComposePreview.NoPreview -> false ComposePreview.NoPreview -> false
is ComposePreview.CLinkPreview -> false is ComposePreview.CLinkPreview -> false
@@ -355,6 +361,7 @@ fun ComposeView(
is SharedContent.Media -> shared.uris.map { it.toString() } is SharedContent.Media -> shared.uris.map { it.toString() }
is SharedContent.File -> listOf(shared.uri.toString()) is SharedContent.File -> listOf(shared.uri.toString())
is SharedContent.Text -> emptyList() is SharedContent.Text -> emptyList()
is SharedContent.Forward -> emptyList()
} }
// When sharing a file and pasting it in SimpleX itself, the file shouldn't be deleted before sending or before leaving the chat after sharing // When sharing a file and pasting it in SimpleX itself, the file shouldn't be deleted before sending or before leaving the chat after sharing
chatModel.filesToDelete.removeAll { file -> chatModel.filesToDelete.removeAll { file ->
@@ -401,6 +408,21 @@ fun ComposeView(
composeState.value = composeState.value.copy(inProgress = true) composeState.value = composeState.value.copy(inProgress = true)
} }
suspend fun forwardItem(rhId: Long?, forwardedItem: ChatItem, fromChatInfo: ChatInfo): ChatItem? {
val chatItem = controller.apiForwardChatItem(
rh = rhId,
toChatType = chat.chatInfo.chatType,
toChatId = chat.chatInfo.apiId,
fromChatType = fromChatInfo.chatType,
fromChatId = fromChatInfo.apiId,
itemId = forwardedItem.id
)
if (chatItem != null) {
chatModel.addChatItem(rhId, chat.chatInfo, chatItem)
}
return chatItem
}
fun checkLinkPreview(): MsgContent { fun checkLinkPreview(): MsgContent {
return when (val composePreview = cs.preview) { return when (val composePreview = cs.preview) {
is ComposePreview.CLinkPreview -> { is ComposePreview.CLinkPreview -> {
@@ -460,11 +482,18 @@ fun ComposeView(
if (liveMessage != null) composeState.value = cs.copy(liveMessage = null) if (liveMessage != null) composeState.value = cs.copy(liveMessage = null)
sending() sending()
} }
clearCurrentDraft() if (!cs.forwarding || chatModel.draft.value?.forwarding == true) {
clearCurrentDraft()
}
if (chat.nextSendGrpInv) { if (chat.nextSendGrpInv) {
sendMemberContactInvitation() sendMemberContactInvitation()
sent = null sent = null
} else if (cs.contextItem is ComposeContextItem.ForwardingItem) {
sent = forwardItem(chat.remoteHostId, cs.contextItem.chatItem, cs.contextItem.fromChatInfo)
if (cs.message.isNotEmpty()) {
sent = send(chat, checkLinkPreview(), quoted = sent?.id, live = false, ttl = null)
}
} else if (cs.contextItem is ComposeContextItem.EditingItem) { } else if (cs.contextItem is ComposeContextItem.EditingItem) {
val ei = cs.contextItem.chatItem val ei = cs.contextItem.chatItem
sent = updateMessage(ei, chat, live) sent = updateMessage(ei, chat, live)
@@ -563,7 +592,15 @@ fun ComposeView(
sent = send(chat, MsgContent.MCText(msgText), quotedItemId, null, live, ttl) sent = send(chat, MsgContent.MCText(msgText), quotedItemId, null, live, ttl)
} }
} }
val wasForwarding = cs.forwarding
val forwardingFromChatId = (cs.contextItem as? ComposeContextItem.ForwardingItem)?.fromChatInfo?.id
clearState(live) clearState(live)
val draft = chatModel.draft.value
if (wasForwarding && chatModel.draftChatId.value == chat.chatInfo.id && forwardingFromChatId != chat.chatInfo.id && draft != null) {
composeState.value = draft
} else {
clearCurrentDraft()
}
return sent return sent
} }
@@ -745,6 +782,9 @@ fun ComposeView(
is ComposeContextItem.EditingItem -> ContextItemView(contextItem.chatItem, painterResource(MR.images.ic_edit_filled)) { is ComposeContextItem.EditingItem -> ContextItemView(contextItem.chatItem, painterResource(MR.images.ic_edit_filled)) {
clearState() clearState()
} }
is ComposeContextItem.ForwardingItem -> ContextItemView(contextItem.chatItem, painterResource(MR.images.ic_forward), showSender = false) {
composeState.value = composeState.value.copy(contextItem = ComposeContextItem.NoContextItem)
}
} }
} }
@@ -764,6 +804,10 @@ fun ComposeView(
is SharedContent.Text -> onMessageChange(shared.text) is SharedContent.Text -> onMessageChange(shared.text)
is SharedContent.Media -> composeState.processPickedMedia(shared.uris, shared.text) is SharedContent.Media -> composeState.processPickedMedia(shared.uris, shared.text)
is SharedContent.File -> composeState.processPickedFile(shared.uri, shared.text) is SharedContent.File -> composeState.processPickedFile(shared.uri, shared.text)
is SharedContent.Forward -> composeState.value = composeState.value.copy(
contextItem = ComposeContextItem.ForwardingItem(shared.chatItem, shared.fromChatInfo),
preview = if (composeState.value.preview is ComposePreview.CLinkPreview) composeState.value.preview else ComposePreview.NoPreview
)
null -> {} null -> {}
} }
chatModel.sharedContent.value = null chatModel.sharedContent.value = null
@@ -903,6 +947,17 @@ fun ComposeView(
chatModel.removeLiveDummy() chatModel.removeLiveDummy()
CIFile.cachedRemoteFileRequests.clear() CIFile.cachedRemoteFileRequests.clear()
} }
if (appPlatform.isDesktop) {
// Don't enable this on Android, it breaks it, This method only works on desktop. For Android there is a `KeyChangeEffect(chatModel.chatId.value)`
DisposableEffect(Unit) {
onDispose {
if (chatModel.sharedContent.value is SharedContent.Forward && saveLastDraft && !composeState.value.empty) {
chatModel.draft.value = composeState.value
chatModel.draftChatId.value = chat.id
}
}
}
}
val timedMessageAllowed = remember(chat.chatInfo) { chat.chatInfo.featureEnabled(ChatFeature.TimedMessages) } val timedMessageAllowed = remember(chat.chatInfo) { chat.chatInfo.featureEnabled(ChatFeature.TimedMessages) }
val sendButtonColor = val sendButtonColor =
@@ -4,26 +4,29 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.ui.text.TextStyle import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.runtime.*
import androidx.compose.ui.text.*
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import chat.simplex.common.ui.theme.* import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chat.item.* import chat.simplex.common.views.chat.item.*
import chat.simplex.common.model.* import chat.simplex.common.model.*
import chat.simplex.res.MR import chat.simplex.res.MR
import dev.icerock.moko.resources.ImageResource
import kotlinx.datetime.Clock import kotlinx.datetime.Clock
@Composable @Composable
fun ContextItemView( fun ContextItemView(
contextItem: ChatItem, contextItem: ChatItem,
contextIcon: Painter, contextIcon: Painter,
showSender: Boolean = true,
cancelContextItem: () -> Unit cancelContextItem: () -> Unit
) { ) {
val sent = contextItem.chatDir.sent val sent = contextItem.chatDir.sent
@@ -31,16 +34,47 @@ fun ContextItemView(
val receivedColor = CurrentColors.collectAsState().value.appColors.receivedMessage val receivedColor = CurrentColors.collectAsState().value.appColors.receivedMessage
@Composable @Composable
fun msgContentView(lines: Int) { fun MessageText(attachment: ImageResource?, lines: Int) {
val inlineContent: Pair<AnnotatedString.Builder.() -> Unit, Map<String, InlineTextContent>>? = if (attachment != null) {
remember(contextItem.id) {
val inlineContentBuilder: AnnotatedString.Builder.() -> Unit = {
appendInlineContent(id = "attachmentIcon")
append(" ")
}
val inlineContent = mapOf(
"attachmentIcon" to InlineTextContent(
Placeholder(20.sp, 20.sp, PlaceholderVerticalAlign.TextCenter)
) {
Icon(painterResource(attachment), null, tint = MaterialTheme.colors.secondary)
}
)
inlineContentBuilder to inlineContent
}
} else null
MarkdownText( MarkdownText(
contextItem.text, contextItem.formattedText, contextItem.text, contextItem.formattedText,
sender = null,
toggleSecrets = false, toggleSecrets = false,
maxLines = lines, maxLines = lines,
inlineContent = inlineContent,
linkMode = SimplexLinkMode.DESCRIPTION, linkMode = SimplexLinkMode.DESCRIPTION,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
} }
fun attachment(): ImageResource? =
when (contextItem.content.msgContent) {
is MsgContent.MCFile -> MR.images.ic_draft_filled
is MsgContent.MCImage -> MR.images.ic_image
is MsgContent.MCVoice -> MR.images.ic_play_arrow_filled
else -> null
}
@Composable
fun ContextMsgPreview(lines: Int) {
MessageText(remember(contextItem.id) { attachment() }, lines)
}
Row( Row(
Modifier Modifier
.padding(top = 8.dp) .padding(top = 8.dp)
@@ -64,7 +98,7 @@ fun ContextItemView(
tint = MaterialTheme.colors.secondary, tint = MaterialTheme.colors.secondary,
) )
val sender = contextItem.memberDisplayName val sender = contextItem.memberDisplayName
if (sender != null) { if (showSender && sender != null) {
Column( Column(
horizontalAlignment = Alignment.Start, horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(4.dp), verticalArrangement = Arrangement.spacedBy(4.dp),
@@ -73,10 +107,10 @@ fun ContextItemView(
sender, sender,
style = TextStyle(fontSize = 13.5.sp, color = CurrentColors.value.colors.secondary) style = TextStyle(fontSize = 13.5.sp, color = CurrentColors.value.colors.secondary)
) )
msgContentView(lines = 2) ContextMsgPreview(lines = 2)
} }
} else { } else {
msgContentView(lines = 3) ContextMsgPreview(lines = 3)
} }
} }
IconButton(onClick = cancelContextItem) { IconButton(onClick = cancelContextItem) {
@@ -72,7 +72,7 @@ fun SendMsgView(
} }
} }
val showVoiceButton = !nextSendGrpInv && cs.message.isEmpty() && showVoiceRecordIcon && !composeState.value.editing && val showVoiceButton = !nextSendGrpInv && cs.message.isEmpty() && showVoiceRecordIcon && !composeState.value.editing &&
cs.liveMessage == null && (cs.preview is ComposePreview.NoPreview || recState.value is RecordingState.Started) !composeState.value.forwarding && cs.liveMessage == null && (cs.preview is ComposePreview.NoPreview || recState.value is RecordingState.Started)
val showDeleteTextButton = rememberSaveable { mutableStateOf(false) } val showDeleteTextButton = rememberSaveable { mutableStateOf(false) }
val sendMsgButtonDisabled = !sendMsgEnabled || !cs.sendEnabled() || val sendMsgButtonDisabled = !sendMsgEnabled || !cs.sendEnabled() ||
(!allowedVoiceByPrefs && cs.preview is ComposePreview.VoicePreview) || (!allowedVoiceByPrefs && cs.preview is ComposePreview.VoicePreview) ||
@@ -157,7 +157,7 @@ fun SendMsgView(
fun MenuItems(): List<@Composable () -> Unit> { fun MenuItems(): List<@Composable () -> Unit> {
val menuItems = mutableListOf<@Composable () -> Unit>() val menuItems = mutableListOf<@Composable () -> Unit>()
if (cs.liveMessage == null && !cs.editing && !nextSendGrpInv || sendMsgEnabled) { if (cs.liveMessage == null && !cs.editing && !cs.forwarding && !nextSendGrpInv || sendMsgEnabled) {
if ( if (
cs.preview !is ComposePreview.VoicePreview && cs.preview !is ComposePreview.VoicePreview &&
cs.contextItem is ComposeContextItem.NoContextItem && cs.contextItem is ComposeContextItem.NoContextItem &&
@@ -62,7 +62,7 @@ fun GroupChatInfoView(chatModel: ChatModel, rhId: Long?, chatId: String, groupLi
}, },
members = chatModel.groupMembers members = chatModel.groupMembers
.filter { it.memberStatus != GroupMemberStatus.MemLeft && it.memberStatus != GroupMemberStatus.MemRemoved } .filter { it.memberStatus != GroupMemberStatus.MemLeft && it.memberStatus != GroupMemberStatus.MemRemoved }
.sortedBy { it.displayName.lowercase() }, .sortedByDescending { it.memberRole },
developerTools, developerTools,
groupLink, groupLink,
addMembers = { addMembers = {
@@ -95,8 +95,8 @@ private fun featureInfo(ci: ChatItem, chatInfo: ChatInfo): FeatureInfo? =
when (ci.content) { when (ci.content) {
is CIContent.RcvChatFeature -> ci.content.feature.toFeatureInfo(ci.content.enabled.iconColor, ci.content.param, ci.content.feature.name) is CIContent.RcvChatFeature -> ci.content.feature.toFeatureInfo(ci.content.enabled.iconColor, ci.content.param, ci.content.feature.name)
is CIContent.SndChatFeature -> ci.content.feature.toFeatureInfo(ci.content.enabled.iconColor, ci.content.param, ci.content.feature.name) is CIContent.SndChatFeature -> ci.content.feature.toFeatureInfo(ci.content.enabled.iconColor, ci.content.param, ci.content.feature.name)
is CIContent.RcvGroupFeature -> ci.content.groupFeature.toFeatureInfo(ci.content.preference.enabled(ci.content.memberRole_, (chatInfo as ChatInfo.Group).groupInfo.membership).iconColor, ci.content.param, ci.content.groupFeature.name) is CIContent.RcvGroupFeature -> ci.content.groupFeature.toFeatureInfo(ci.content.preference.enabled(ci.content.memberRole_, (chatInfo as? ChatInfo.Group)?.groupInfo?.membership).iconColor, ci.content.param, ci.content.groupFeature.name)
is CIContent.SndGroupFeature -> ci.content.groupFeature.toFeatureInfo(ci.content.preference.enabled(ci.content.memberRole_, (chatInfo as ChatInfo.Group).groupInfo.membership).iconColor, ci.content.param, ci.content.groupFeature.name) is CIContent.SndGroupFeature -> ci.content.groupFeature.toFeatureInfo(ci.content.preference.enabled(ci.content.memberRole_, (chatInfo as? ChatInfo.Group)?.groupInfo?.membership).iconColor, ci.content.param, ci.content.groupFeature.name)
else -> null else -> null
} }
@@ -12,7 +12,7 @@ import chat.simplex.common.ui.theme.*
@Composable @Composable
fun CIEventView(text: AnnotatedString) { fun CIEventView(text: AnnotatedString) {
Text(text, Modifier.padding(horizontal = 6.dp, vertical = 6.dp), style = MaterialTheme.typography.body1.copy(lineHeight = 22.sp)) Text(text, Modifier.padding(horizontal = 6.dp, vertical = 6.dp), style = MaterialTheme.typography.body1.copy(lineHeight = 22.sp), maxLines = 3)
} }
@Preview/*( @Preview/*(
uiMode = Configuration.UI_MODE_NIGHT_YES, uiMode = Configuration.UI_MODE_NIGHT_YES,
@@ -59,18 +59,11 @@ fun CIFileView(
} }
} }
fun fileSizeValid(): Boolean {
if (file != null) {
return file.fileSize <= getMaxFileSize(file.fileProtocol)
}
return false
}
fun fileAction() { fun fileAction() {
if (file != null) { if (file != null) {
when { when {
file.fileStatus is CIFileStatus.RcvInvitation -> { file.fileStatus is CIFileStatus.RcvInvitation -> {
if (fileSizeValid()) { if (fileSizeValid(file)) {
receiveFile(file.fileId) receiveFile(file.fileId)
} else { } else {
AlertManager.shared.showAlertMsg( AlertManager.shared.showAlertMsg(
@@ -165,7 +158,7 @@ fun CIFileView(
is CIFileStatus.SndCancelled -> fileIcon(innerIcon = painterResource(MR.images.ic_close)) is CIFileStatus.SndCancelled -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
is CIFileStatus.SndError -> fileIcon(innerIcon = painterResource(MR.images.ic_close)) is CIFileStatus.SndError -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
is CIFileStatus.RcvInvitation -> is CIFileStatus.RcvInvitation ->
if (fileSizeValid()) if (fileSizeValid(file))
fileIcon(innerIcon = painterResource(MR.images.ic_arrow_downward), color = MaterialTheme.colors.primary) fileIcon(innerIcon = painterResource(MR.images.ic_arrow_downward), color = MaterialTheme.colors.primary)
else else
fileIcon(innerIcon = painterResource(MR.images.ic_priority_high), color = WarningOrange) fileIcon(innerIcon = painterResource(MR.images.ic_priority_high), color = WarningOrange)
@@ -216,6 +209,8 @@ fun CIFileView(
} }
} }
fun fileSizeValid(file: CIFile): Boolean = file.fileSize <= getMaxFileSize(file.fileProtocol)
@Composable @Composable
fun rememberSaveFileLauncher(ciFile: CIFile?): FileChooserLauncher = fun rememberSaveFileLauncher(ciFile: CIFile?): FileChooserLauncher =
rememberFileChooserLauncher(false, ciFile) { to: URI? -> rememberFileChooserLauncher(false, ciFile) { to: URI? ->
@@ -19,6 +19,7 @@ import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.* import androidx.compose.ui.unit.*
import chat.simplex.common.model.* import chat.simplex.common.model.*
import chat.simplex.common.model.ChatModel.controller
import chat.simplex.common.platform.* import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.* import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chat.* import chat.simplex.common.views.chat.*
@@ -40,6 +41,7 @@ fun chatEventText(eventText: String, ts: String): AnnotatedString =
@Composable @Composable
fun ChatItemView( fun ChatItemView(
rhId: Long?,
cInfo: ChatInfo, cInfo: ChatInfo,
cItem: ChatItem, cItem: ChatItem,
composeState: MutableState<ComposeState>, composeState: MutableState<ComposeState>,
@@ -195,12 +197,16 @@ fun ChatItemView(
} }
val clipboard = LocalClipboardManager.current val clipboard = LocalClipboardManager.current
val cachedRemoteReqs = remember { CIFile.cachedRemoteFileRequests } val cachedRemoteReqs = remember { CIFile.cachedRemoteFileRequests }
val copyAndShareAllowed = when { fun fileForwardingAllowed() = when {
cItem.content.text.isNotEmpty() -> true
cItem.file != null && chatModel.connectedToRemote() && cachedRemoteReqs[cItem.file.fileSource] != false && cItem.file.loaded -> true cItem.file != null && chatModel.connectedToRemote() && cachedRemoteReqs[cItem.file.fileSource] != false && cItem.file.loaded -> true
getLoadedFilePath(cItem.file) != null -> true getLoadedFilePath(cItem.file) != null -> true
else -> false else -> false
} }
val copyAndShareAllowed = when {
cItem.content.text.isNotEmpty() -> true
fileForwardingAllowed() -> true
else -> false
}
if (copyAndShareAllowed) { if (copyAndShareAllowed) {
ItemAction(stringResource(MR.strings.share_verb), painterResource(MR.images.ic_share), onClick = { ItemAction(stringResource(MR.strings.share_verb), painterResource(MR.images.ic_share), onClick = {
@@ -227,8 +233,19 @@ fun ChatItemView(
showMenu.value = false showMenu.value = false
}) })
} }
if ((cItem.content.msgContent is MsgContent.MCImage || cItem.content.msgContent is MsgContent.MCVideo || cItem.content.msgContent is MsgContent.MCFile || cItem.content.msgContent is MsgContent.MCVoice) && (getLoadedFilePath(cItem.file) != null || (chatModel.connectedToRemote() && cachedRemoteReqs[cItem.file?.fileSource] != false && cItem.file?.loaded == true))) { if (cItem.file != null && (getLoadedFilePath(cItem.file) != null || (chatModel.connectedToRemote() && cachedRemoteReqs[cItem.file.fileSource] != false && cItem.file.loaded))) {
SaveContentItemAction(cItem, saveFileLauncher, showMenu) SaveContentItemAction(cItem, saveFileLauncher, showMenu)
} else if (cItem.file != null && cItem.file.fileStatus is CIFileStatus.RcvInvitation && fileSizeValid(cItem.file)) {
ItemAction(stringResource(MR.strings.download_file), painterResource(MR.images.ic_arrow_downward), onClick = {
withBGApi {
Log.d(TAG, "ChatItemView downloadFileAction")
val user = chatModel.currentUser.value
if (user != null) {
controller.receiveFile(rhId, user, cItem.file.fileId)
}
}
showMenu.value = false
})
} }
if (cItem.meta.editable && cItem.content.msgContent !is MsgContent.MCVoice && !live) { if (cItem.meta.editable && cItem.content.msgContent !is MsgContent.MCVoice && !live) {
ItemAction(stringResource(MR.strings.edit_verb), painterResource(MR.images.ic_edit_filled), onClick = { ItemAction(stringResource(MR.strings.edit_verb), painterResource(MR.images.ic_edit_filled), onClick = {
@@ -236,6 +253,16 @@ fun ChatItemView(
showMenu.value = false showMenu.value = false
}) })
} }
if (cItem.meta.itemDeleted == null &&
(cItem.file == null || fileForwardingAllowed()) &&
!cItem.isLiveDummy && !live
) {
ItemAction(stringResource(MR.strings.forward_chat_item), painterResource(MR.images.ic_forward), onClick = {
chatModel.chatId.value = null
chatModel.sharedContent.value = SharedContent.Forward(cItem, cInfo)
showMenu.value = false
})
}
ItemInfoAction(cInfo, cItem, showItemDetails, showMenu) ItemInfoAction(cInfo, cItem, showItemDetails, showMenu)
if (revealed.value) { if (revealed.value) {
HideItemAction(revealed, showMenu) HideItemAction(revealed, showMenu)
@@ -458,11 +485,11 @@ fun ChatItemView(
MsgContentItemDropdownMenu() MsgContentItemDropdownMenu()
} }
is CIContent.RcvGroupFeature -> { is CIContent.RcvGroupFeature -> {
CIChatFeatureView(cInfo, cItem, c.groupFeature, c.preference.enabled(c.memberRole_, (cInfo as ChatInfo.Group).groupInfo.membership).iconColor, revealed = revealed, showMenu = showMenu) CIChatFeatureView(cInfo, cItem, c.groupFeature, c.preference.enabled(c.memberRole_, (cInfo as? ChatInfo.Group)?.groupInfo?.membership).iconColor, revealed = revealed, showMenu = showMenu)
MsgContentItemDropdownMenu() MsgContentItemDropdownMenu()
} }
is CIContent.SndGroupFeature -> { is CIContent.SndGroupFeature -> {
CIChatFeatureView(cInfo, cItem, c.groupFeature, c.preference.enabled(c.memberRole_, (cInfo as ChatInfo.Group).groupInfo.membership).iconColor, revealed = revealed, showMenu = showMenu) CIChatFeatureView(cInfo, cItem, c.groupFeature, c.preference.enabled(c.memberRole_, (cInfo as? ChatInfo.Group)?.groupInfo?.membership).iconColor, revealed = revealed, showMenu = showMenu)
MsgContentItemDropdownMenu() MsgContentItemDropdownMenu()
} }
is CIContent.RcvChatFeatureRejected -> { is CIContent.RcvChatFeatureRejected -> {
@@ -782,6 +809,7 @@ expect fun copyItemToClipboard(cItem: ChatItem, clipboard: ClipboardManager)
fun PreviewChatItemView() { fun PreviewChatItemView() {
SimpleXTheme { SimpleXTheme {
ChatItemView( ChatItemView(
rhId = null,
ChatInfo.Direct.sampleData, ChatInfo.Direct.sampleData,
ChatItem.getSampleData( ChatItem.getSampleData(
1, CIDirection.DirectSnd(), Clock.System.now(), "hello" 1, CIDirection.DirectSnd(), Clock.System.now(), "hello"
@@ -818,6 +846,7 @@ fun PreviewChatItemView() {
fun PreviewChatItemViewDeletedContent() { fun PreviewChatItemViewDeletedContent() {
SimpleXTheme { SimpleXTheme {
ChatItemView( ChatItemView(
rhId = null,
ChatInfo.Direct.sampleData, ChatInfo.Direct.sampleData,
ChatItem.getDeletedContentSampleData(), ChatItem.getDeletedContentSampleData(),
useLinkPreviews = true, useLinkPreviews = true,
@@ -87,14 +87,14 @@ fun FramedItemView(
} }
@Composable @Composable
fun FramedItemHeader(caption: String, italic: Boolean, icon: Painter? = null) { fun FramedItemHeader(caption: String, italic: Boolean, icon: Painter? = null, pad: Boolean = false) {
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
val receivedColor = CurrentColors.collectAsState().value.appColors.receivedMessage val receivedColor = CurrentColors.collectAsState().value.appColors.receivedMessage
Row( Row(
Modifier Modifier
.background(if (sent) sentColor.toQuote() else receivedColor.toQuote()) .background(if (sent) sentColor.toQuote() else receivedColor.toQuote())
.fillMaxWidth() .fillMaxWidth()
.padding(start = 8.dp, top = 6.dp, end = 12.dp, bottom = if (ci.quotedItem == null) 6.dp else 0.dp), .padding(start = 8.dp, top = 6.dp, end = 12.dp, bottom = if (pad || (ci.quotedItem == null && ci.meta.itemForwarded == null)) 6.dp else 0.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp), horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -223,7 +223,7 @@ fun FramedItemView(
if (ci.quotedItem != null) { if (ci.quotedItem != null) {
ciQuoteView(ci.quotedItem) ciQuoteView(ci.quotedItem)
} else if (ci.meta.itemForwarded != null) { } else if (ci.meta.itemForwarded != null) {
FramedItemHeader(stringResource(MR.strings.forwarded_description), true, painterResource(MR.images.ic_forward)) FramedItemHeader(ci.meta.itemForwarded.text(chatInfo.chatType), true, painterResource(MR.images.ic_forward), pad = true)
} }
if (ci.file == null && ci.formattedText == null && !ci.meta.isLive && isShortEmoji(ci.content.text)) { if (ci.file == null && ci.formattedText == null && !ci.meta.isLive && isShortEmoji(ci.content.text)) {
Box(Modifier.padding(vertical = 6.dp, horizontal = 12.dp)) { Box(Modifier.padding(vertical = 6.dp, horizontal = 12.dp)) {
@@ -68,7 +68,7 @@ fun MarkdownText (
senderBold: Boolean = false, senderBold: Boolean = false,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
linkMode: SimplexLinkMode, linkMode: SimplexLinkMode,
inlineContent: Map<String, InlineTextContent>? = null, inlineContent: Pair<AnnotatedString.Builder.() -> Unit, Map<String, InlineTextContent>>? = null,
onLinkLongClick: (link: String) -> Unit = {} onLinkLongClick: (link: String) -> Unit = {}
) { ) {
val textLayoutDirection = remember (text) { val textLayoutDirection = remember (text) {
@@ -119,6 +119,7 @@ fun MarkdownText (
} }
if (formattedText == null) { if (formattedText == null) {
val annotatedText = buildAnnotatedString { val annotatedText = buildAnnotatedString {
inlineContent?.first?.invoke(this)
appendSender(this, sender, senderBold) appendSender(this, sender, senderBold)
if (text is String) append(text) if (text is String) append(text)
else if (text is AnnotatedString) append(text) else if (text is AnnotatedString) append(text)
@@ -127,10 +128,11 @@ fun MarkdownText (
} }
if (meta != null) withStyle(reserveTimestampStyle) { append(reserve) } if (meta != null) withStyle(reserveTimestampStyle) { append(reserve) }
} }
Text(annotatedText, style = style, modifier = modifier, maxLines = maxLines, overflow = overflow, inlineContent = inlineContent ?: mapOf()) Text(annotatedText, style = style, modifier = modifier, maxLines = maxLines, overflow = overflow, inlineContent = inlineContent?.second ?: mapOf())
} else { } else {
var hasAnnotations = false var hasAnnotations = false
val annotatedText = buildAnnotatedString { val annotatedText = buildAnnotatedString {
inlineContent?.first?.invoke(this)
appendSender(this, sender, senderBold) appendSender(this, sender, senderBold)
for ((i, ft) in formattedText.withIndex()) { for ((i, ft) in formattedText.withIndex()) {
if (ft.format == null) append(ft.text) if (ft.format == null) append(ft.text)
@@ -210,7 +212,7 @@ fun MarkdownText (
} }
) )
} else { } else {
Text(annotatedText, style = style, modifier = modifier, maxLines = maxLines, overflow = overflow) Text(annotatedText, style = style, modifier = modifier, maxLines = maxLines, overflow = overflow, inlineContent = inlineContent?.second ?: mapOf())
} }
} }
} }
@@ -90,7 +90,7 @@ fun ChatPreviewView(
Icon(painterResource(MR.images.ic_verified_user), null, Modifier.size(19.dp).padding(end = 3.dp, top = 1.dp), tint = MaterialTheme.colors.secondary) Icon(painterResource(MR.images.ic_verified_user), null, Modifier.size(19.dp).padding(end = 3.dp, top = 1.dp), tint = MaterialTheme.colors.secondary)
} }
fun messageDraft(draft: ComposeState): Pair<AnnotatedString, Map<String, InlineTextContent>> { fun messageDraft(draft: ComposeState): Pair<AnnotatedString.Builder.() -> Unit, Map<String, InlineTextContent>> {
fun attachment(): Pair<ImageResource, String?>? = fun attachment(): Pair<ImageResource, String?>? =
when (draft.preview) { when (draft.preview) {
is ComposePreview.FilePreview -> MR.images.ic_draft_filled to draft.preview.fileName is ComposePreview.FilePreview -> MR.images.ic_draft_filled to draft.preview.fileName
@@ -100,7 +100,7 @@ fun ChatPreviewView(
} }
val attachment = attachment() val attachment = attachment()
val text = buildAnnotatedString { val inlineContentBuilder: AnnotatedString.Builder.() -> Unit = {
appendInlineContent(id = "editIcon") appendInlineContent(id = "editIcon")
append(" ") append(" ")
if (attachment != null) { if (attachment != null) {
@@ -110,7 +110,6 @@ fun ChatPreviewView(
} }
append(" ") append(" ")
} }
append(draft.message)
} }
val inlineContent: Map<String, InlineTextContent> = mapOf( val inlineContent: Map<String, InlineTextContent> = mapOf(
"editIcon" to InlineTextContent( "editIcon" to InlineTextContent(
@@ -124,7 +123,7 @@ fun ChatPreviewView(
Icon(if (attachment?.first != null) painterResource(attachment.first) else painterResource(MR.images.ic_edit_note), null, tint = MaterialTheme.colors.secondary) Icon(if (attachment?.first != null) painterResource(attachment.first) else painterResource(MR.images.ic_edit_note), null, tint = MaterialTheme.colors.secondary)
} }
) )
return text to inlineContent return inlineContentBuilder to inlineContent
} }
@Composable @Composable
@@ -169,7 +168,7 @@ fun ChatPreviewView(
if (ci != null) { if (ci != null) {
if (showChatPreviews || (chatModelDraftChatId == chat.id && chatModelDraft != null)) { if (showChatPreviews || (chatModelDraftChatId == chat.id && chatModelDraft != null)) {
val (text: CharSequence, inlineTextContent) = when { val (text: CharSequence, inlineTextContent) = when {
chatModelDraftChatId == chat.id && chatModelDraft != null -> remember(chatModelDraft) { messageDraft(chatModelDraft) } chatModelDraftChatId == chat.id && chatModelDraft != null -> remember(chatModelDraft) { chatModelDraft.message to messageDraft(chatModelDraft) }
ci.meta.itemDeleted == null -> ci.text to null ci.meta.itemDeleted == null -> ci.text to null
else -> markedDeletedText(ci.meta) to null else -> markedDeletedText(ci.meta) to null
} }
@@ -13,9 +13,8 @@ import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import chat.simplex.common.SettingsViewState import chat.simplex.common.SettingsViewState
import chat.simplex.common.model.*
import chat.simplex.common.views.helpers.* import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.Chat
import chat.simplex.common.model.ChatModel
import chat.simplex.common.platform.* import chat.simplex.common.platform.*
import chat.simplex.res.MR import chat.simplex.res.MR
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -74,7 +73,7 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
val navButton: @Composable RowScope.() -> Unit = { val navButton: @Composable RowScope.() -> Unit = {
when { when {
showSearch -> NavigationButtonBack(hideSearchOnBack) showSearch -> NavigationButtonBack(hideSearchOnBack)
users.size > 1 || chatModel.remoteHosts.isNotEmpty() -> { (users.size > 1 || chatModel.remoteHosts.isNotEmpty()) && remember { chatModel.sharedContent }.value !is SharedContent.Forward -> {
val allRead = users val allRead = users
.filter { u -> !u.user.activeUser && !u.user.hidden } .filter { u -> !u.user.activeUser && !u.user.hidden }
.all { u -> u.unreadCount == 0 } .all { u -> u.unreadCount == 0 }
@@ -82,7 +81,14 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
userPickerState.value = AnimatedViewState.VISIBLE userPickerState.value = AnimatedViewState.VISIBLE
} }
} }
else -> NavigationButtonBack(onButtonClicked = { chatModel.sharedContent.value = null }) else -> NavigationButtonBack(onButtonClicked = {
val sharedContent = chatModel.sharedContent.value
// Drop shared content
chatModel.sharedContent.value = null
if (sharedContent is SharedContent.Forward) {
chatModel.chatId.value = sharedContent.fromChatInfo.id
}
})
} }
} }
if (chatModel.chats.size >= 8) { if (chatModel.chats.size >= 8) {
@@ -118,7 +124,8 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
is SharedContent.Text -> stringResource(MR.strings.share_message) is SharedContent.Text -> stringResource(MR.strings.share_message)
is SharedContent.Media -> stringResource(MR.strings.share_image) is SharedContent.Media -> stringResource(MR.strings.share_image)
is SharedContent.File -> stringResource(MR.strings.share_file) is SharedContent.File -> stringResource(MR.strings.share_file)
else -> stringResource(MR.strings.share_message) is SharedContent.Forward -> stringResource(MR.strings.forward_message)
null -> stringResource(MR.strings.share_message)
}, },
color = MaterialTheme.colors.onBackground, color = MaterialTheme.colors.onBackground,
fontWeight = FontWeight.SemiBold, fontWeight = FontWeight.SemiBold,
@@ -135,12 +142,14 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
@Composable @Composable
private fun ShareList(chatModel: ChatModel, search: String) { private fun ShareList(chatModel: ChatModel, search: String) {
val filter: (Chat) -> Boolean = { chat: Chat ->
chat.chatInfo.chatViewName.lowercase().contains(search.lowercase())
}
val chats by remember(search) { val chats by remember(search) {
derivedStateOf { derivedStateOf {
if (search.isEmpty()) chatModel.chats.toList().filter { it.chatInfo.ready } else chatModel.chats.toList().filter { it.chatInfo.ready }.filter(filter) val sorted = chatModel.chats.toList().sortedByDescending { it.chatInfo is ChatInfo.Local }
if (search.isEmpty()) {
sorted.filter { it.chatInfo.ready }
} else {
sorted.filter { it.chatInfo.ready && it.chatInfo.chatViewName.lowercase().contains(search.lowercase()) }
}
} }
} }
LazyColumnWithScrollBar( LazyColumnWithScrollBar(
@@ -2,6 +2,8 @@
package chat.simplex.common.views.helpers package chat.simplex.common.views.helpers
import androidx.compose.runtime.saveable.Saver import androidx.compose.runtime.saveable.Saver
import chat.simplex.common.model.ChatInfo
import chat.simplex.common.model.ChatItem
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.descriptors.* import kotlinx.serialization.descriptors.*
@@ -13,6 +15,7 @@ sealed class SharedContent {
data class Text(val text: String): SharedContent() data class Text(val text: String): SharedContent()
data class Media(val text: String, val uris: List<URI>): SharedContent() data class Media(val text: String, val uris: List<URI>): SharedContent()
data class File(val text: String, val uri: URI): SharedContent() data class File(val text: String, val uri: URI): SharedContent()
data class Forward(val chatItem: ChatItem, val fromChatInfo: ChatInfo): SharedContent()
} }
enum class AnimatedViewState { enum class AnimatedViewState {
@@ -14,6 +14,7 @@ import androidx.compose.ui.unit.*
import chat.simplex.res.MR import chat.simplex.res.MR
import chat.simplex.common.ui.theme.* import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.usersettings.SettingsActionItemWithContent import chat.simplex.common.views.usersettings.SettingsActionItemWithContent
import dev.icerock.moko.resources.ImageResource
@Composable @Composable
fun <T> ExposedDropDownSetting( fun <T> ExposedDropDownSetting(
@@ -79,6 +80,60 @@ fun <T> ExposedDropDownSetting(
} }
} }
@Composable
fun <T> ExposedDropDownSettingWithIcon(
values: List<Triple<T, ImageResource, String>>,
selection: State<T>,
fontSize: TextUnit = 16.sp,
iconSize: Dp = 40.dp,
listIconSize: Dp = 30.dp,
iconColor: Color = MenuTextColor,
enabled: State<Boolean> = mutableStateOf(true),
minWidth: Dp = 200.dp,
onSelected: (T) -> Unit
) {
val expanded = remember { mutableStateOf(false) }
ExposedDropdownMenuBox(
expanded = expanded.value,
onExpandedChange = {
expanded.value = !expanded.value && enabled.value
}
) {
Row(
Modifier.padding(start = 10.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
) {
val choice = values.first { it.first == selection.value }
Icon(painterResource(choice.second), choice.third, Modifier.size(iconSize), tint = iconColor)
}
DefaultExposedDropdownMenu(
modifier = Modifier.widthIn(min = minWidth),
expanded = expanded,
) {
values.forEach { selectionOption ->
DropdownMenuItem(
onClick = {
onSelected(selectionOption.first)
expanded.value = false
},
contentPadding = PaddingValues(horizontal = DEFAULT_PADDING * 1.5f)
) {
Icon(painterResource(selectionOption.second), selectionOption.third, Modifier.size(listIconSize))
Spacer(Modifier.width(15.dp))
Text(
selectionOption.third,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = MenuTextColor,
fontSize = fontSize,
)
}
}
}
}
}
@Composable @Composable
fun <T> ExposedDropDownSettingRow( fun <T> ExposedDropDownSettingRow(
title: String, title: String,
@@ -34,6 +34,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
val networkTCPConnectTimeout = remember { mutableStateOf(currentCfgVal.tcpConnectTimeout) } val networkTCPConnectTimeout = remember { mutableStateOf(currentCfgVal.tcpConnectTimeout) }
val networkTCPTimeout = remember { mutableStateOf(currentCfgVal.tcpTimeout) } val networkTCPTimeout = remember { mutableStateOf(currentCfgVal.tcpTimeout) }
val networkTCPTimeoutPerKb = remember { mutableStateOf(currentCfgVal.tcpTimeoutPerKb) } val networkTCPTimeoutPerKb = remember { mutableStateOf(currentCfgVal.tcpTimeoutPerKb) }
var networkRcvConcurrency = remember { mutableStateOf(currentCfgVal.rcvConcurrency) }
val networkSMPPingInterval = remember { mutableStateOf(currentCfgVal.smpPingInterval) } val networkSMPPingInterval = remember { mutableStateOf(currentCfgVal.smpPingInterval) }
val networkSMPPingCount = remember { mutableStateOf(currentCfgVal.smpPingCount) } val networkSMPPingCount = remember { mutableStateOf(currentCfgVal.smpPingCount) }
val networkEnableKeepAlive = remember { mutableStateOf(currentCfgVal.enableKeepAlive) } val networkEnableKeepAlive = remember { mutableStateOf(currentCfgVal.enableKeepAlive) }
@@ -68,6 +69,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
tcpConnectTimeout = networkTCPConnectTimeout.value, tcpConnectTimeout = networkTCPConnectTimeout.value,
tcpTimeout = networkTCPTimeout.value, tcpTimeout = networkTCPTimeout.value,
tcpTimeoutPerKb = networkTCPTimeoutPerKb.value, tcpTimeoutPerKb = networkTCPTimeoutPerKb.value,
rcvConcurrency = networkRcvConcurrency.value,
tcpKeepAlive = tcpKeepAlive, tcpKeepAlive = tcpKeepAlive,
smpPingInterval = networkSMPPingInterval.value, smpPingInterval = networkSMPPingInterval.value,
smpPingCount = networkSMPPingCount.value smpPingCount = networkSMPPingCount.value
@@ -78,6 +80,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
networkTCPConnectTimeout.value = cfg.tcpConnectTimeout networkTCPConnectTimeout.value = cfg.tcpConnectTimeout
networkTCPTimeout.value = cfg.tcpTimeout networkTCPTimeout.value = cfg.tcpTimeout
networkTCPTimeoutPerKb.value = cfg.tcpTimeoutPerKb networkTCPTimeoutPerKb.value = cfg.tcpTimeoutPerKb
networkRcvConcurrency.value = cfg.rcvConcurrency
networkSMPPingInterval.value = cfg.smpPingInterval networkSMPPingInterval.value = cfg.smpPingInterval
networkSMPPingCount.value = cfg.smpPingCount networkSMPPingCount.value = cfg.smpPingCount
networkEnableKeepAlive.value = cfg.enableKeepAlive networkEnableKeepAlive.value = cfg.enableKeepAlive
@@ -110,6 +113,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
networkTCPConnectTimeout, networkTCPConnectTimeout,
networkTCPTimeout, networkTCPTimeout,
networkTCPTimeoutPerKb, networkTCPTimeoutPerKb,
networkRcvConcurrency,
networkSMPPingInterval, networkSMPPingInterval,
networkSMPPingCount, networkSMPPingCount,
networkEnableKeepAlive, networkEnableKeepAlive,
@@ -128,6 +132,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
networkTCPConnectTimeout: MutableState<Long>, networkTCPConnectTimeout: MutableState<Long>,
networkTCPTimeout: MutableState<Long>, networkTCPTimeout: MutableState<Long>,
networkTCPTimeoutPerKb: MutableState<Long>, networkTCPTimeoutPerKb: MutableState<Long>,
networkRcvConcurrency: MutableState<Int>,
networkSMPPingInterval: MutableState<Long>, networkSMPPingInterval: MutableState<Long>,
networkSMPPingCount: MutableState<Int>, networkSMPPingCount: MutableState<Int>,
networkEnableKeepAlive: MutableState<Boolean>, networkEnableKeepAlive: MutableState<Boolean>,
@@ -154,7 +159,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
SectionItemView { SectionItemView {
TimeoutSettingRow( TimeoutSettingRow(
stringResource(MR.strings.network_option_tcp_connection_timeout), networkTCPConnectTimeout, stringResource(MR.strings.network_option_tcp_connection_timeout), networkTCPConnectTimeout,
listOf(7_500000, 10_000000, 15_000000, 20_000000, 30_000_000, 45_000_000), secondsLabel listOf(5_000000, 7_500000, 10_000000, 15_000000, 20_000000, 30_000000, 40_000000), secondsLabel
) )
} }
SectionItemView { SectionItemView {
@@ -170,6 +175,12 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
listOf(2_500, 5_000, 10_000, 15_000, 20_000, 30_000), secondsLabel listOf(2_500, 5_000, 10_000, 15_000, 20_000, 30_000), secondsLabel
) )
} }
SectionItemView {
IntSettingRow(
stringResource(MR.strings.network_option_rcv_concurrency), networkRcvConcurrency,
listOf(1, 2, 4, 8, 12, 16, 24), ""
)
}
SectionItemView { SectionItemView {
TimeoutSettingRow( TimeoutSettingRow(
stringResource(MR.strings.network_option_ping_interval), networkSMPPingInterval, stringResource(MR.strings.network_option_ping_interval), networkSMPPingInterval,
@@ -418,6 +429,7 @@ fun PreviewAdvancedNetworkSettingsLayout() {
networkTCPConnectTimeout = remember { mutableStateOf(10_000000) }, networkTCPConnectTimeout = remember { mutableStateOf(10_000000) },
networkTCPTimeout = remember { mutableStateOf(10_000000) }, networkTCPTimeout = remember { mutableStateOf(10_000000) },
networkTCPTimeoutPerKb = remember { mutableStateOf(10_000) }, networkTCPTimeoutPerKb = remember { mutableStateOf(10_000) },
networkRcvConcurrency = remember { mutableStateOf(8) },
networkSMPPingInterval = remember { mutableStateOf(10_000000) }, networkSMPPingInterval = remember { mutableStateOf(10_000000) },
networkSMPPingCount = remember { mutableStateOf(3) }, networkSMPPingCount = remember { mutableStateOf(3) },
networkEnableKeepAlive = remember { mutableStateOf(true) }, networkEnableKeepAlive = remember { mutableStateOf(true) },
@@ -47,6 +47,8 @@
<string name="live">LIVE</string> <string name="live">LIVE</string>
<string name="moderated_description">moderated</string> <string name="moderated_description">moderated</string>
<string name="forwarded_description">forwarded</string> <string name="forwarded_description">forwarded</string>
<string name="saved_description">saved</string>
<string name="saved_from_description">saved from %s</string>
<string name="invalid_chat">invalid chat</string> <string name="invalid_chat">invalid chat</string>
<string name="invalid_data">invalid data</string> <string name="invalid_data">invalid data</string>
<string name="error_showing_message">error showing message</string> <string name="error_showing_message">error showing message</string>
@@ -268,6 +270,11 @@
<string name="edit_history">History</string> <string name="edit_history">History</string>
<string name="no_history">No history</string> <string name="no_history">No history</string>
<string name="in_reply_to">In reply to</string> <string name="in_reply_to">In reply to</string>
<string name="saved_chat_item_info_tab">Saved</string>
<string name="forwarded_chat_item_info_tab">Forwarded</string>
<string name="saved_from_chat_item_info_title">Saved from</string>
<string name="forwarded_from_chat_item_info_title">Forwarded from</string>
<string name="recipients_can_not_see_who_message_from">Recipient(s) can\'t see who this message is from.</string>
<string name="delivery">Delivery</string> <string name="delivery">Delivery</string>
<string name="no_info_on_delivery">No delivery information</string> <string name="no_info_on_delivery">No delivery information</string>
<string name="delete_verb">Delete</string> <string name="delete_verb">Delete</string>
@@ -295,6 +302,8 @@
<string name="revoke_file__title">Revoke file?</string> <string name="revoke_file__title">Revoke file?</string>
<string name="revoke_file__message">File will be deleted from servers.</string> <string name="revoke_file__message">File will be deleted from servers.</string>
<string name="revoke_file__confirm">Revoke</string> <string name="revoke_file__confirm">Revoke</string>
<string name="forward_chat_item">Forward</string>
<string name="download_file">Download</string>
<!-- CIMetaView.kt --> <!-- CIMetaView.kt -->
<string name="icon_descr_edited">edited</string> <string name="icon_descr_edited">edited</string>
@@ -329,6 +338,7 @@
<string name="share_message">Share message…</string> <string name="share_message">Share message…</string>
<string name="share_image">Share media…</string> <string name="share_image">Share media…</string>
<string name="share_file">Share file…</string> <string name="share_file">Share file…</string>
<string name="forward_message">Forward message…</string>
<!-- ComposeView.kt, helpers --> <!-- ComposeView.kt, helpers -->
<string name="attach">Attach</string> <string name="attach">Attach</string>
@@ -826,6 +836,9 @@
<string name="permissions_grant_in_settings">Grant in settings</string> <string name="permissions_grant_in_settings">Grant in settings</string>
<string name="permissions_find_in_settings_and_grant">Find this permission in Android settings and grant it manually.</string> <string name="permissions_find_in_settings_and_grant">Find this permission in Android settings and grant it manually.</string>
<string name="permissions_open_settings">Open settings</string> <string name="permissions_open_settings">Open settings</string>
<string name="audio_device_earpiece">Earpiece</string>
<string name="audio_device_speaker">Speaker</string>
<string name="audio_device_wired_headphones">Headphones</string>
<!-- SimpleXInfo --> <!-- SimpleXInfo -->
<string name="next_generation_of_private_messaging">The next generation of private messaging</string> <string name="next_generation_of_private_messaging">The next generation of private messaging</string>
@@ -1446,6 +1459,7 @@
<string name="network_option_tcp_connection_timeout">TCP connection timeout</string> <string name="network_option_tcp_connection_timeout">TCP connection timeout</string>
<string name="network_option_protocol_timeout">Protocol timeout</string> <string name="network_option_protocol_timeout">Protocol timeout</string>
<string name="network_option_protocol_timeout_per_kb">Protocol timeout per KB</string> <string name="network_option_protocol_timeout_per_kb">Protocol timeout per KB</string>
<string name="network_option_rcv_concurrency">Receiving concurrency</string>
<string name="network_option_ping_interval">PING interval</string> <string name="network_option_ping_interval">PING interval</string>
<string name="network_option_ping_count">PING count</string> <string name="network_option_ping_count">PING count</string>
<string name="network_option_enable_tcp_keep_alive">Enable TCP keep-alive</string> <string name="network_option_enable_tcp_keep_alive">Enable TCP keep-alive</string>
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M451-98v-313L257.5-217.5 217-258l222.5-222L217-702.5l40.5-40.5L451-549.5v-313h28.5L691-651 520-480.5l171 171L479.5-98H451Zm57.5-451.5 102-101.5-102-99.5v201Zm0 339.5 102-99.5-102-101.5v201Z"/></svg>

After

Width:  |  Height:  |  Size: 295 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M653-454.5V-512h142.5v57.5H653Zm32.5 290-117-86 32.5-45 117 86-32.5 45Zm-84.5-500-32.5-45 117-86 32.5 45-117 86ZM125-363v-234h157.5l196-196v626l-196-196H125Z"/></svg>

After

Width:  |  Height:  |  Size: 263 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M327-124.5H182q-22.969 0-40.234-17.266Q124.5-159.031 124.5-182v-298q0-74.09 28-138.795 28-64.705 76-112.705t112.684-76q64.684-28 138.75-28t138.816 28q64.75 28 112.75 76t76 112.705q28 64.705 28 138.795v298q0 22.969-17.266 40.234Q800.969-124.5 778-124.5H633v-290h145V-480q0-124.193-86.937-211.096Q604.125-778 479.884-778t-211.063 86.904Q182-604.193 182-480v65.5h145v290ZM269.5-357H182v175h87.5v-175Zm421 0v175H778v-175h-87.5Zm-421 0H182h87.5Zm421 0H778h-87.5Z"/></svg>

After

Width:  |  Height:  |  Size: 563 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M670-462.5v-163L569.5-525 544-550.5 667.5-674 544-791l25.5-25.5L670-716v-163h16.5l118 121-86 84 86 92.5-118 119H670Zm39.5-74 44-45-44-44v89Zm0-179.5 44-42-44-51.5v93.5Zm81 591Q677-125 558-180.5T338-338Q236-439 180.5-557.75T125-790.692q0-18.808 12.714-31.558Q150.429-835 169.5-835H306q14 0 23.75 9.75t13.75 24.75l26.929 123.641Q372-663.5 369.5-652q-2.5 11.5-10.229 19.226L261-533q26 44 54.688 81.658Q344.375-413.683 379-380q36.5 38 77.25 69.323Q497-279.353 542-255l95.544-98q9.456-10.5 21.357-14.25T682.5-369l117.362 25.438Q815-340 825-327.801q10 12.198 10 27.301v131q0 19.071-12.714 31.786Q809.571-125 790.5-125ZM232-585.5l81-82-23.5-110H183q1.5 41.5 13 88.25t36 103.75Zm364 358q40 19 88.166 31t93.334 14v-107l-102-21.5-79.5 83.5Zm-364-358Zm364 358Z"/></svg>

After

Width:  |  Height:  |  Size: 855 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M480.25-84.5q-31.013 0-50.631-19.559Q410-123.619 410-155q0-21.5 10.75-39.25t30.75-28.197V-334H303q-22.969 0-40.234-17.266Q245.5-368.531 245.5-391.5v-109q-20.5-9-31.25-26.359-10.75-17.358-10.75-39.358 0-31.664 19.535-51.224Q242.569-637 273.916-637t50.965 19.559q19.619 19.56 19.619 51.352 0 22.089-10.75 39.339T303-500.5v109h148.5v-338H373l107-145 107 145h-78v338h148V-496h-41.5v-140.5h141V-496h-42v104.5q0 22.969-17.266 40.234Q679.969-334 657-334H509v111.5q19.95 10.152 30.975 28.733Q551-175.187 551-154.912q0 31.531-19.869 50.971Q511.263-84.5 480.25-84.5Z"/></svg>

After

Width:  |  Height:  |  Size: 662 B

@@ -38,7 +38,7 @@ const processCommand = (function () {
const defaultIceServers = [ const defaultIceServers = [
{ urls: ["stuns:stun.simplex.im:443"] }, { urls: ["stuns:stun.simplex.im:443"] },
{ urls: ["stun:stun.simplex.im:443"] }, { urls: ["stun:stun.simplex.im:443"] },
//{ urls: ["turns:turn.simplex.im:443?transport=udp"], username: "private2", credential: "Hxuq2QxUjnhj96Zq2r4HjqHRj" }, //{urls: ["turns:turn.simplex.im:443?transport=udp"], username: "private2", credential: "Hxuq2QxUjnhj96Zq2r4HjqHRj"},
{ urls: ["turns:turn.simplex.im:443?transport=tcp"], username: "private2", credential: "Hxuq2QxUjnhj96Zq2r4HjqHRj" }, { urls: ["turns:turn.simplex.im:443?transport=tcp"], username: "private2", credential: "Hxuq2QxUjnhj96Zq2r4HjqHRj" },
]; ];
function getCallConfig(encodedInsertableStreams, iceServers, relay) { function getCallConfig(encodedInsertableStreams, iceServers, relay) {
@@ -111,7 +111,17 @@ const processCommand = (function () {
}); });
} }
async function initializeCall(config, mediaType, aesKey) { async function initializeCall(config, mediaType, aesKey) {
const pc = new RTCPeerConnection(config.peerConnectionConfig); var _a;
let pc;
try {
pc = new RTCPeerConnection(config.peerConnectionConfig);
}
catch (e) {
console.log("Error while constructing RTCPeerConnection, will try without 'stuns' specified: " + e);
const withoutStuns = (_a = config.peerConnectionConfig.iceServers) === null || _a === void 0 ? void 0 : _a.filter((elem) => typeof elem.urls === "string" ? !elem.urls.startsWith("stuns:") : !elem.urls.some((url) => url.startsWith("stuns:")));
config.peerConnectionConfig.iceServers = withoutStuns;
pc = new RTCPeerConnection(config.peerConnectionConfig);
}
const remoteStream = new MediaStream(); const remoteStream = new MediaStream();
const localCamera = VideoCamera.User; const localCamera = VideoCamera.User;
const localStream = await getLocalMediaStream(mediaType, localCamera); const localStream = await getLocalMediaStream(mediaType, localCamera);
@@ -376,6 +386,9 @@ const processCommand = (function () {
// setupVideoElement(videos.remote) // setupVideoElement(videos.remote)
videos.local.srcObject = call.localStream; videos.local.srcObject = call.localStream;
videos.remote.srcObject = call.remoteStream; videos.remote.srcObject = call.remoteStream;
// Without doing it manually Firefox shows black screen but video can be played in Picture-in-Picture
videos.local.play();
videos.remote.play();
} }
async function setupEncryptionWorker(call) { async function setupEncryptionWorker(call) {
if (call.aesKey) { if (call.aesKey) {
@@ -448,7 +461,9 @@ const processCommand = (function () {
codecs.splice(selectedCodecIndex, 1); codecs.splice(selectedCodecIndex, 1);
codecs.unshift(selectedCodec); codecs.unshift(selectedCodec);
for (const t of call.connection.getTransceivers()) { for (const t of call.connection.getTransceivers()) {
if (((_a = t.sender.track) === null || _a === void 0 ? void 0 : _a.kind) === "video") { // Firefox doesn't have this function implemented:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1396922
if (((_a = t.sender.track) === null || _a === void 0 ? void 0 : _a.kind) === "video" && t.setCodecPreferences) {
t.setCodecPreferences(codecs); t.setCodecPreferences(codecs);
} }
} }
@@ -471,8 +486,22 @@ const processCommand = (function () {
} }
return; return;
} }
for (const t of call.localStream.getTracks()) if (!call.screenShareEnabled) {
t.stop(); for (const t of call.localStream.getTracks())
t.stop();
}
else {
// Don't stop audio track if switching to screenshare
for (const t of call.localStream.getVideoTracks())
t.stop();
// Replace new track from screenshare with old track from recording device
for (const t of localStream.getAudioTracks()) {
t.stop();
localStream.removeTrack(t);
}
for (const t of call.localStream.getAudioTracks())
localStream.addTrack(t);
}
call.localCamera = camera; call.localCamera = camera;
const audioTracks = localStream.getAudioTracks(); const audioTracks = localStream.getAudioTracks();
const videoTracks = localStream.getVideoTracks(); const videoTracks = localStream.getVideoTracks();
@@ -486,6 +515,7 @@ const processCommand = (function () {
replaceTracks(pc, videoTracks); replaceTracks(pc, videoTracks);
call.localStream = localStream; call.localStream = localStream;
videos.local.srcObject = localStream; videos.local.srcObject = localStream;
videos.local.play();
} }
function replaceTracks(pc, tracks) { function replaceTracks(pc, tracks) {
if (!tracks.length) if (!tracks.length)
@@ -531,7 +561,9 @@ const processCommand = (function () {
//}, //},
//aspectRatio: 1.33, //aspectRatio: 1.33,
}, },
audio: true, audio: false,
// This works with Chrome, Edge, Opera, but not with Firefox and Safari
// systemAudio: "include"
}; };
return navigator.mediaDevices.getDisplayMedia(constraints); return navigator.mediaDevices.getDisplayMedia(constraints);
} }
@@ -10,7 +10,6 @@
<video <video
id="remote-video-stream" id="remote-video-stream"
class="inline" class="inline"
autoplay
playsinline playsinline
poster="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAEUlEQVR42mNk+M+AARiHsiAAcCIKAYwFoQ8AAAAASUVORK5CYII=" poster="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAEUlEQVR42mNk+M+AARiHsiAAcCIKAYwFoQ8AAAAASUVORK5CYII="
onclick="javascript:toggleRemoteVideoFitFill()" onclick="javascript:toggleRemoteVideoFitFill()"
@@ -19,7 +18,6 @@
id="local-video-stream" id="local-video-stream"
class="inline" class="inline"
muted muted
autoplay
playsinline playsinline
poster="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAEUlEQVR42mNk+M+AARiHsiAAcCIKAYwFoQ8AAAAASUVORK5CYII=" poster="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAEUlEQVR42mNk+M+AARiHsiAAcCIKAYwFoQ8AAAAASUVORK5CYII="
></video> ></video>
+4 -4
View File
@@ -26,11 +26,11 @@ android.enableJetifier=true
kotlin.mpp.androidSourceSetLayoutVersion=2 kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.jvm.target=11 kotlin.jvm.target=11
android.version_name=5.7-beta.0 android.version_name=5.7-beta.1
android.version_code=196 android.version_code=197
desktop.version_name=5.7-beta.0 desktop.version_name=5.7-beta.1
desktop.version_code=37 desktop.version_code=38
kotlin.version=1.9.23 kotlin.version=1.9.23
gradle.plugin.version=8.2.0 gradle.plugin.version=8.2.0
@@ -0,0 +1,52 @@
---
layout: layouts/article.html
title: "The dangers of metadata in messengers"
date: 2024-04-16
previewBody: blog_previews/20240416.html
image: images/20240416-metadata.png
imageWide: true
permalink: "/blog/20240416-dangers-of-metadata-in-messengers.html"
---
# The dangers of metadata in messengers
**Published:** Apr 16, 2024
_By [Esra'a al Shafei](https://mastodon.social/@alshafei)_
In many countries around the world, phone numbers are attached to biometrics data and personal IDs. Telecommunications companies are either government owned or are heavily regulated, privately owned monopolies who comply with most government requests for backdoors or user data. The idea that today, we still need to give out our phone numbers as primary identifiers to be able to use the leading messaging apps should be frowned upon and actively challenged. Its necessary to advocate for private alternatives in messaging that do not rely on user IDs of any kind - and yes, its possible.
Messaging is still not where it needs to be. Privacy is confused with security, when both are not synonymous, and there are major gaps in helping users understand the fundamental differences.
<img src="./images/20240416-whatsapp.jpg" class="float-to-right" width="38%">
For example, while WhatsApp messages are [end-to-end encrypted](https://faq.whatsapp.com/820124435853543), lets consider what you give up when you use it, per its own listings in app stores:
- App activity (app interactions, in-app search history, and other user-generated content)
- Location
- Financial information (user payment info and payment history)
- Contacts and their phone numbers
- Groups youre a member of
- When you use the app and how often you use it
- Device and other IDs
- Personal info (email address, user IDs, phone number)
This is called [metadata](https://en.wikipedia.org/wiki/Metadata). It reveals a wealth of information about you and your connections, and in the hands of a centralized monopoly, this can and does get misused in incredibly dangerous ways. Once such metadata is logged, it can create very detailed profiles about who you are, everywhere youve been, and everyone youve ever spoken to. In settling for apps that normalize this while giving you the illusion of privacy in their marketing, we are doing ourselves a disservice by accepting this as the default. Collectively, we arent doing enough to protect ourselves and our social graph from this invasive overreach.
When stored, aggregated and analyzed, this metadata provides ample information that could potentially incriminate someone or be submitted to authorities. When WhatsApp and Facebook Messenger enabled end-to-end encryption for messages, of course it was a welcome and widely celebrated change. But its important to remember that not all end-to-end encryption utilizes the same standards, [some implementations are more secure](https://simplex.chat/blog/20240314-simplex-chat-v5-6-quantum-resistance-signal-double-ratchet-algorithm.html#how-secure-is-end-to-end-encryption-in-different-messengers) than others, so its something that shouldnt necessarily be accepted at face value. More importantly: collecting and storing an obscene amount of metadata should invite global scrutiny, considering this data is often combined with whatever other information companies like Meta harvest about your identity (which is [a lot](https://www.vox.com/recode/23172691/meta-tracking-privacy-hospitals).)
<img src="./images/20240416-metadata.png" class="float-to-right" width="38%">
This is one of the many reasons why we need to resist giving out our phone numbers just to access an app, especially to do something as personal and intimate as private messaging. Even though users can sometimes mask their numbers with a username, their identity on the app is still fundamentally tied to their phone number. App operators have access to this, as well as user contacts. Additionally, with a simple modification to the app's source code, the contacts may also gain access in some cases. This should raise more concerns about privacy, and it makes the need for anonymity difficult to achieve.
Everyone has a different threat model (and if you dont yet, now is a good time to [create one](https://www.privacyguides.org/en/basics/threat-modeling/#creating-your-threat-model)). For many users today, WhatsApp and other apps may be sufficient for their specific needs, especially in connecting with families and friends who are already on the app and unlikely to migrate elsewhere. If that suits your life and needs, and if youre aware and consciously accept the risks, great.
But we also need to acknowledge that the world is becoming increasingly dangerous in the way AI is being used to [supercharge surveillance](https://www.forbes.com/sites/forbestechcouncil/2024/02/02/artificial-intelligence-the-new-eyes-of-surveillance/?sh=cd57bc214f27), and we need to be educated and aware of the risks this is already having on our lives and what it subjects others in your network to when you choose metadata-heavy apps as your primary form of communication. Having alternatives will always be important, even if its not what you default to for everyday messaging. Recognize who in your social circles might require the extra privacy, anonymity and security, so that you can play a role in protecting vulnerable individuals who need it most. The messaging app you choose implicates others as well, not just yourself, and while you personally may not require complete privacy, others might have their lives depend on it.
End-to-end encryption is a solid start, but it's just the beginning of our pursuit for true privacy and security. True privacy means that even when legal demands come knocking, there's no useful metadata to hand over. It's not enough to just protect the content of messages; we need consistent innovation in protecting metadata too.
Changing ingrained habits is tough, but your privacy is always worth the fight. Although giants like WhatsApp and Telegram may dominate global messaging for now, increasing concerns about data harvesting and AI-driven surveillance are fueling demand for alternatives. SimpleX Chat aims to be one of those strong alternatives, hence its radical focus on a decentralized framework with no user identifiers (in other words, nothing that uniquely identifies users on the protocol level to their contacts or to the relays) and extra optionality (self-hosting an [SMP server](https://simplex.chat/docs/server.html) or [XFTP server](https://simplex.chat/docs/xftp-server.html), access via Tor, [chat profiles](https://simplex.chat/docs/guide/chat-profiles.html) with incognito mode, etc.)
As of today, most messaging alternatives, including SimpleX, will have some limitations. But with the limited resources we have, we are committed to daily progress towards creating a truly private messenger that anyone can use while maintaining the features that users have come to know and love in messaging interfaces. We want to be the prime example of a messenger that achieves genuine privacy without compromising it for convenience. We need to be able to reliably move away from small and niche use cases to endorsing and enforcing global standards for privacy and making it accessible for all users regardless of their technical expertise.
Were grateful for the users and [donors](https://github.com/simplex-chat/simplex-chat#help-us-with-donations) who have been following along on this journey thus far and helping with feedback, anything from bug reports to identifying potential risks. Building in the open has always been a necessity for transparency and ongoing [auditability](https://simplex.chat/blog/20221108-simplex-chat-v4.2-security-audit-new-website.html), because we dont want anyone to just take our word for it. [See for yourself](https://github.com/simplex-chat) and engage in the discussions. We fully expect you to hold us accountable to our word.
+8
View File
@@ -1,5 +1,13 @@
# Blog # Blog
Apr 16. 2024 [The dangers of metadata in messengers](./20240416-dangers-of-metadata-in-messengers.md)
_By [Esra'a al Shafei](https://mastodon.social/@alshafei)_
It's important not to be complacent with the current standards of messaging, where metadata aggregation is still normalized in apps falsely and dangerously marketed as "private". This is a post exploring the fundamental differences between privacy and security.
---
Apr 4. 2024 [Why I joined SimpleX Chat](./20240404-why-i-joined-simplex-chat-esraa-al-shafei.md) Apr 4. 2024 [Why I joined SimpleX Chat](./20240404-why-i-joined-simplex-chat-esraa-al-shafei.md)
_By [Esra'a al Shafei](https://mastodon.social/@alshafei)_ _By [Esra'a al Shafei](https://mastodon.social/@alshafei)_
Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

+1 -1
View File
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package source-repository-package
type: git type: git
location: https://github.com/simplex-chat/simplexmq.git location: https://github.com/simplex-chat/simplexmq.git
tag: 5e783396e05ced83b22914c172d2f2e8e14e5be2 tag: 3d40393ae83260245c7122b850fb42cd4243deba
source-repository-package source-repository-package
type: git type: git
+1 -1
View File
@@ -102,7 +102,7 @@ DOCKER_BUILDKIT=1 docker build --output ~/.local/bin .
#### In any OS #### In any OS
1. Install [Haskell GHCup](https://www.haskell.org/ghcup/), GHC 9.6.4 and cabal 3.10.1.0: 1. Install [Haskell GHCup](https://www.haskell.org/ghcup/), GHC 9.6.3 and cabal 3.10.1.0:
```shell ```shell
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
+10 -10
View File
@@ -30,13 +30,13 @@ You will have to add `/opt/homebrew/opt/openssl@1.1/bin` to your PATH in order t
**In simplex-chat repo** **In simplex-chat repo**
- `stable` - stable release of the apps, can be used for updates to the previous stable release (GHC 9.6.4). - `stable` - stable release of the apps, can be used for updates to the previous stable release (GHC 9.6.3).
- `stable-android` - used to build stable Android core library with Nix (GHC 8.10.7) - only for Android armv7a. - `stable-android` - used to build stable Android core library with Nix (GHC 8.10.7) - only for Android armv7a.
- `stable-ios` - used to build stable iOS core library with Nix (GHC 8.10.7) this branch should be the same as `stable-android` except Nix configuration files. Deprecated. - `stable-ios` - used to build stable iOS core library with Nix (GHC 8.10.7) this branch should be the same as `stable-android` except Nix configuration files. Deprecated.
- `master` - branch for beta version releases (GHC 9.6.4). - `master` - branch for beta version releases (GHC 9.6.3).
- `master-ghc8107` - branch for beta version releases (GHC 8.10.7). Deprecated. - `master-ghc8107` - branch for beta version releases (GHC 8.10.7). Deprecated.
@@ -50,7 +50,7 @@ You will have to add `/opt/homebrew/opt/openssl@1.1/bin` to your PATH in order t
**In simplexmq repo** **In simplexmq repo**
- `master` - uses GHC 9.6.4 its commit should be used in `master` branch of simplex-chat repo. - `master` - uses GHC 9.6.3 its commit should be used in `master` branch of simplex-chat repo.
- `master-ghc8107` - its commit should be used in `master-android` (and `master-ios`) branch of simplex-chat repo. Deprecated. - `master-ghc8107` - its commit should be used in `master-android` (and `master-ios`) branch of simplex-chat repo. Deprecated.
@@ -77,28 +77,28 @@ You will have to add `/opt/homebrew/opt/openssl@1.1/bin` to your PATH in order t
7. Independently, `master` branch of simplexmq repo should be merged to `stable` branch on stable releases. 7. Independently, `master` branch of simplexmq repo should be merged to `stable` branch on stable releases.
## Differences between GHC 8.10.7 and GHC 9.6.4 ## Differences between GHC 8.10.7 and GHC 9.6.3
1. The main difference is related to `DuplicateRecordFields` extension. 1. The main difference is related to `DuplicateRecordFields` extension.
It is no longer possible in GHC 9.6.4 to specify type when using selectors, instead OverloadedRecordDot extension and syntax are used that need to be removed in GHC 8.10.7: It is no longer possible in GHC 9.6.3 to specify type when using selectors, instead OverloadedRecordDot extension and syntax are used that need to be removed in GHC 8.10.7:
```haskell ```haskell
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DuplicateRecordFields #-}
-- use this in GHC 9.6.4 when needed -- use this in GHC 9.6.3 when needed
{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedRecordDot #-}
-- GHC 9.6.4 syntax -- GHC 9.6.3 syntax
let x = record.field let x = record.field
-- GHC 8.10.7 syntax absent in GHC 9.6.4 -- GHC 8.10.7 syntax removed in GHC 9.6.3
let x = field (record :: Record) let x = field (record :: Record)
``` ```
It is still possible to specify type when using record update syntax, use this pragma to suppress compiler warning: It is still possible to specify type when using record update syntax, use this pragma to suppress compiler warning:
```haskell ```haskell
-- use this in GHC 9.6.4 when needed -- use this in GHC 9.6.3 when needed
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-} {-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
let r' = (record :: Record) {field = value} let r' = (record :: Record) {field = value}
@@ -107,7 +107,7 @@ let r' = (record :: Record) {field = value}
2. Most monad functions now have to be imported from `Control.Monad`, and not from specific monad modules (e.g. `Control.Monad.Except`). 2. Most monad functions now have to be imported from `Control.Monad`, and not from specific monad modules (e.g. `Control.Monad.Except`).
```haskell ```haskell
-- use this in GHC 9.6.4 when needed -- use this in GHC 9.6.3 when needed
import Control.Monad import Control.Monad
``` ```
@@ -0,0 +1,81 @@
# IP address protection, support for SMP sending proxies
## Problem
IP addresses of senders being visible to recipients' chosen servers, which in case of self-hosting makes it visible to recipients themselves. In case of XFTP files the issue is reversed, with IP addresses of recipients being visible to senders' chosen servers.
## Solution
### SMP
- Agent to support sending proxies
- New network settings configuration "Use SMP proxies"
- Can be set to "always", "never", "for unknown servers"
- Currently configured servers to be considered as "known", including those disabled for new connections
- Initial default is "never" to allow opt-in for testing, to be changed to "for unknown servers" later
- Support in UI
- No alerts about unknown servers are required in UI
- Tor setting to not affect agent decision to use SMP proxy for each given server
``` haskell
data UseSMPProxies
= SMPPAlways
| SMPPNever
| SMPPUnknown
deriving (Eq, Show)
data NetworkConfig = NetworkConfig
{ ...
useSMPProxies :: UseSMPProxies,
...
}
```
### XFTP
Some considerations:
- XFTP proxying is not planned to be implemented initially
- In future it could be done via open socket and with no persistance, and would be required only for FGET command
- Currently XFTP files are automatically set for reception in some cases:
- Images and voice messages
- In background (via "set to receive")
- Agent resumes file reception (download) after app re-start, in case they weren't fully downloaded
- User may change tor setting between and during app sessions, so a file can be "accepted" when app is connected via tor, but resumed when it's no longer
Solution:
- Client would make a decision whether to automatically accept file, or alert user about unknown servers
- Add only_via_tor flag to agent rcv_files + pass through APIs:
- add Bool to `ReceiveFile` (with False meaning user hasn't indicated any intent regarding unknown servers)
- can either be automatically accepted, or require alerting user and asking for confirmation (see below)
- add `onlyViaTor` to `xftpReceiveFile`
- Possible scenarios:
1. XFTP file chunks are fully available on known servers
- Do not show alert, accept automatically (images, voice messages) or without approval (other files)
- `onlyViaTor` is False
2. Some file chunks are on unknown servers, tor is not enabled
- User accepts manually, show alert to user
- User confirms, indicating it's Ok to proceed even though IP would be visible to unknown servers
- `onlyViaTor` is False
- \* Additional user preference to never ask? -> behavior same as now
3. Some file chunks are on unknown servers, tor is enabled
- Do not show alert, accept automatically (images, voice messages) or without approval (other files)
- `onlyViaTor` is True
- On file download:
- `onlyViaTor` equal False is ignored
- If `onlyViaTor` is True, and tor is not enabled, throw new "permanent" error
- Permanent for simplicity as this is an edge case
- File record to be removed from agent
- Could analyze whether it's remaining (not yet downloaded) chunks are on unknown servers, and only abort in this case (and instead proceed if remaining chunks are on known servers)
- This requires changing download to load data for all chunks instead of loading only current chunk
- This is another edge case of edge case, as it seems more likely that sender either used only self-hosted servers, or only preset servers
- So it seems as unnecessary complication, and it should be Ok to abort simply based on only_via_tor flag + tor setting
- Error is RFERR XFTP UNKNOWN_NO_PROXY (new constructor)
- Chat to differentiate RFERR, and make file available for re-download on UNKNOWN_NO_PROXY error, similar to when file is cancelled
- New CIFileStatus - CIFSRcvCancelledNoProxy, to differentiate in UI
- Different icon for retry, alert explaining why file was aborted
### Trusted servers
We also considered an idea of trusted servers, but it proved to have unnecessarily complex UX, and in case of XFTP had issues on file download continuation after restart (e.g. server "trusted" flag changing, automatically accepting with tor enabled). It requires additional consideration and may be better suited to concept of "server providers".
Generated
+21 -74
View File
@@ -175,11 +175,11 @@
"ghc99": { "ghc99": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1701580282, "lastModified": 1697054644,
"narHash": "sha256-drA01r3JrXnkKyzI+owMZGxX0JameMzjK0W5jJE/+V4=", "narHash": "sha256-kKarOuXUaAH3QWv7ASx+gGFMHaHKe0pK5Zu37ky2AL4=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "f5eb0f2982e9cf27515e892c4bdf634bcfb28459", "rev": "f383a242c76f90bcca8a4d7ee001dcb49c172a9a",
"revCount": 62197, "revCount": 62040,
"submodules": true, "submodules": true,
"type": "git", "type": "git",
"url": "https://gitlab.haskell.org/ghc/ghc" "url": "https://gitlab.haskell.org/ghc/ghc"
@@ -225,8 +225,6 @@
"hls-2.2": "hls-2.2", "hls-2.2": "hls-2.2",
"hls-2.3": "hls-2.3", "hls-2.3": "hls-2.3",
"hls-2.4": "hls-2.4", "hls-2.4": "hls-2.4",
"hls-2.5": "hls-2.5",
"hls-2.6": "hls-2.6",
"hpc-coveralls": "hpc-coveralls", "hpc-coveralls": "hpc-coveralls",
"hydra": "hydra", "hydra": "hydra",
"iserv-proxy": "iserv-proxy", "iserv-proxy": "iserv-proxy",
@@ -240,17 +238,16 @@
"nixpkgs-2205": "nixpkgs-2205", "nixpkgs-2205": "nixpkgs-2205",
"nixpkgs-2211": "nixpkgs-2211", "nixpkgs-2211": "nixpkgs-2211",
"nixpkgs-2305": "nixpkgs-2305", "nixpkgs-2305": "nixpkgs-2305",
"nixpkgs-2311": "nixpkgs-2311",
"nixpkgs-unstable": "nixpkgs-unstable", "nixpkgs-unstable": "nixpkgs-unstable",
"old-ghc-nix": "old-ghc-nix", "old-ghc-nix": "old-ghc-nix",
"stackage": "stackage" "stackage": "stackage"
}, },
"locked": { "locked": {
"lastModified": 1705833500, "lastModified": 1701163700,
"narHash": "sha256-rUIr6JNbCedt1g4gVYVvE9t0oFU6FUspCA0DS5cA8Bg=", "narHash": "sha256-sOrewUS3LnzV09nGr7+3R6Q6zsgU4smJc61QsHq+4DE=",
"owner": "input-output-hk", "owner": "input-output-hk",
"repo": "haskell.nix", "repo": "haskell.nix",
"rev": "d0c35e75cbbc6858770af42ac32b0b85495fbd71", "rev": "2808bfe3e62e9eb4ee8974cd623a00e1611f302b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -331,50 +328,16 @@
"hls-2.4": { "hls-2.4": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1699862708, "lastModified": 1696939266,
"narHash": "sha256-YHXSkdz53zd0fYGIYOgLt6HrA0eaRJi9mXVqDgmvrjk=", "narHash": "sha256-VOMf5+kyOeOmfXTHlv4LNFJuDGa7G3pDnOxtzYR40IU=",
"owner": "haskell", "owner": "haskell",
"repo": "haskell-language-server", "repo": "haskell-language-server",
"rev": "54507ef7e85fa8e9d0eb9a669832a3287ffccd57", "rev": "362fdd1293efb4b82410b676ab1273479f6d17ee",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "haskell", "owner": "haskell",
"ref": "2.4.0.1", "ref": "2.4.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.5": {
"flake": false,
"locked": {
"lastModified": 1701080174,
"narHash": "sha256-fyiR9TaHGJIIR0UmcCb73Xv9TJq3ht2ioxQ2mT7kVdc=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "27f8c3d3892e38edaef5bea3870161815c4d014c",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.5.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.6": {
"flake": false,
"locked": {
"lastModified": 1705325287,
"narHash": "sha256-+P87oLdlPyMw8Mgoul7HMWdEvWP/fNlo8jyNtwME8E8=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "6e0b342fa0327e628610f2711f8c3e4eaaa08b1e",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.6.0.0",
"repo": "haskell-language-server", "repo": "haskell-language-server",
"type": "github" "type": "github"
} }
@@ -589,11 +552,11 @@
}, },
"nixpkgs-2305": { "nixpkgs-2305": {
"locked": { "locked": {
"lastModified": 1701362232, "lastModified": 1695416179,
"narHash": "sha256-GVdzxL0lhEadqs3hfRLuj+L1OJFGiL/L7gCcelgBlsw=", "narHash": "sha256-610o1+pwbSu+QuF3GE0NU5xQdTHM3t9wyYhB9l94Cd8=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d2332963662edffacfddfad59ff4f709dde80ffe", "rev": "715d72e967ec1dd5ecc71290ee072bcaf5181ed6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -603,22 +566,6 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-2311": {
"locked": {
"lastModified": 1701386440,
"narHash": "sha256-xI0uQ9E7JbmEy/v8kR9ZQan6389rHug+zOtZeZFiDJk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "293822e55ec1872f715a66d0eda9e592dc14419f",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-23.11-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": { "nixpkgs-lib": {
"locked": { "locked": {
"dir": "lib", "dir": "lib",
@@ -655,17 +602,17 @@
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1694822471, "lastModified": 1695318763,
"narHash": "sha256-6fSDCj++lZVMZlyqOe9SIOL8tYSBz1bI8acwovRwoX8=", "narHash": "sha256-FHVPDRP2AfvsxAdc+AsgFJevMz5VBmnZglFUMlxBkcY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "47585496bcb13fb72e4a90daeea2f434e2501998", "rev": "e12483116b3b51a185a33a272bf351e357ba9a99",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "47585496bcb13fb72e4a90daeea2f434e2501998",
"type": "github" "type": "github"
} }
}, },
@@ -717,11 +664,11 @@
"stackage": { "stackage": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1705709369, "lastModified": 1699834215,
"narHash": "sha256-HWgwM8v0g6ZBkRVCStsPaMUDf26WDOGV0q+AxyGlcBQ=", "narHash": "sha256-g/JKy0BCvJaxPuYDl3QVc4OY8cFEomgG+hW/eEV470M=",
"owner": "input-output-hk", "owner": "input-output-hk",
"repo": "stackage.nix", "repo": "stackage.nix",
"rev": "f7e9bff9f7582d06c4237d183dafaccc33cfa5d4", "rev": "47aacd04abcce6bad57f43cbbbd133538380248e",
"type": "github" "type": "github"
}, },
"original": { "original": {
+123 -134
View File
@@ -29,8 +29,8 @@
}; in }; in
# `appendOverlays` with a singleton is identical to `extend`. # `appendOverlays` with a singleton is identical to `extend`.
let pkgs = haskellNix.legacyPackages.${system}.appendOverlays [android26]; in let pkgs = haskellNix.legacyPackages.${system}.appendOverlays [android26]; in
let drv' = { extra-modules, pkgs', compiler-nix-name, ... }: pkgs'.haskell-nix.project { let drv' = { extra-modules, pkgs', ... }: pkgs'.haskell-nix.project {
inherit compiler-nix-name; compiler-nix-name = "ghc963";
index-state = "2023-12-12T00:00:00Z"; index-state = "2023-12-12T00:00:00Z";
# We need this, to specify we want the cabal project. # We need this, to specify we want the cabal project.
# If the stack.yaml was dropped, this would not be necessary. # If the stack.yaml was dropped, this would not be necessary.
@@ -51,7 +51,7 @@
})] ++ extra-modules; })] ++ extra-modules;
}; in }; in
# by defualt we don't need to pass extra-modules. # by defualt we don't need to pass extra-modules.
let drv = pkgs': drv' { extra-modules = []; inherit pkgs'; compiler-nix-name = "ghc964"; }; in let drv = pkgs': drv' { extra-modules = []; inherit pkgs'; }; in
# This will package up all *.a in $out into a pkg.zip that can # This will package up all *.a in $out into a pkg.zip that can
# be downloaded from hydra. # be downloaded from hydra.
let withHydraLibPkg = pkg: pkg.overrideAttrs (old: { let withHydraLibPkg = pkg: pkg.overrideAttrs (old: {
@@ -140,132 +140,130 @@
# STATIC x86_64-linux # STATIC x86_64-linux
"${pkgs.pkgsCross.musl64.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.musl64).simplex-chat.components.exes.simplex-chat; "${pkgs.pkgsCross.musl64.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.musl64).simplex-chat.components.exes.simplex-chat;
# STATIC i686-linux # STATIC i686-linux
"${pkgs.pkgsCross.musl32.hostPlatform.system}-static:exe:simplex-chat" = (drv' { # "${pkgs.pkgsCross.musl32.hostPlatform.system}-static:exe:simplex-chat" = (drv' {
compiler-nix-name = "ghc810"; # pkgs' = pkgs.pkgsCross.musl32;
pkgs' = pkgs.pkgsCross.musl32; # extra-modules = [{
extra-modules = [{ # # 32 bit patches
# 32 bit patches # packages.basement.patches = [
packages.basement.patches = [ # ./scripts/nix/basement-pr-573.patch
./scripts/nix/basement-pr-573.patch # ];
]; # packages.memory.patches = [
packages.memory.patches = [ # ./scripts/nix/memory-pr-99.patch
./scripts/nix/memory-pr-99.patch # ];
]; # }];
}]; # }).simplex-chat.components.exes.simplex-chat;
}).simplex-chat.components.exes.simplex-chat;
# WINDOWS x86_64-mingwW64 # WINDOWS x86_64-mingwW64
"${pkgs.pkgsCross.mingwW64.hostPlatform.system}:exe:simplex-chat" = (drv' { # "${pkgs.pkgsCross.mingwW64.hostPlatform.system}:exe:simplex-chat" = (drv' {
compiler-nix-name = "ghc964"; # pkgs' = pkgs.pkgsCross.mingwW64;
pkgs' = pkgs.pkgsCross.mingwW64; # extra-modules = [{
extra-modules = [{ # packages.direct-sqlcipher.flags.openssl = true;
packages.direct-sqlcipher.flags.openssl = true; # packages.bitvec.flags.simd = false;
packages.bitvec.flags.simd = false; # packages.direct-sqlcipher.patches = [
packages.direct-sqlcipher.patches = [ # ./scripts/nix/direct-sqlcipher-2.3.27-win.patch
./scripts/nix/direct-sqlcipher-2.3.27-win.patch # ];
]; # packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [ # (pkgs.pkgsCross.mingwW64.openssl) #.override) # { static = true; enableKTLS = false; })
(pkgs.pkgsCross.mingwW64.openssl) #.override) # { static = true; enableKTLS = false; }) # ];
]; # packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [ # (pkgs.pkgsCross.mingwW64.openssl) #.override) # { static = true; enableKTLS = false; })
(pkgs.pkgsCross.mingwW64.openssl) #.override) # { static = true; enableKTLS = false; }) # ];
]; # packages.unix-time.postPatch = ''
packages.unix-time.postPatch = '' # sed -i 's/mingwex//g' unix-time.cabal
sed -i 's/mingwex//g' unix-time.cabal # '';
''; # }];
}]; # }).simplex-chat.components.exes.simplex-chat.override {
}).simplex-chat.components.exes.simplex-chat.override { # postInstall = ''
postInstall = '' # set -x
set -x # ${pkgs.tree}/bin/tree $out
${pkgs.tree}/bin/tree $out # mkdir -p $out/_pkg
mkdir -p $out/_pkg # cp $out/bin/* $out/_pkg
cp $out/bin/* $out/_pkg # ${pkgs.tree}/bin/tree $out/_pkg
${pkgs.tree}/bin/tree $out/_pkg # (cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/${pkgs.pkgsCross.mingwW64.hostPlatform.system}-simplex-chat.zip *)
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/${pkgs.pkgsCross.mingwW64.hostPlatform.system}-simplex-chat.zip *) # rm -fR $out/_pkg
rm -fR $out/_pkg # mkdir -p $out/nix-support
mkdir -p $out/nix-support # echo "file binary-dist \"$(echo $out/*.zip)\"" \
echo "file binary-dist \"$(echo $out/*.zip)\"" \ # > $out/nix-support/hydra-build-products
> $out/nix-support/hydra-build-products # '';
''; # };
}; # "${pkgs.pkgsCross.mingwW64.hostPlatform.system}:lib:simplex-chat" = (drv' rec {
"${pkgs.pkgsCross.mingwW64.hostPlatform.system}:lib:simplex-chat" = (drv' rec { # pkgs' = pkgs.pkgsCross.mingwW64;
compiler-nix-name = "ghc964"; # extra-modules = [{
pkgs' = pkgs.pkgsCross.mingwW64; # packages.direct-sqlcipher.flags.openssl = true;
extra-modules = [{ # # simd will try to read __cpu_model, which we don't expose
packages.direct-sqlcipher.flags.openssl = true; # # from the rts (yet!).
# simd will try to read __cpu_model, which we don't expose # packages.bitvec.flags.simd = false;
# from the rts (yet!). # packages.direct-sqlcipher.patches = [
packages.bitvec.flags.simd = false; # ./scripts/nix/direct-sqlcipher-2.3.27-win.patch
packages.direct-sqlcipher.patches = [ # ];
./scripts/nix/direct-sqlcipher-2.3.27-win.patch # packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
]; # pkgs.pkgsCross.mingwW64.openssl
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [ # ];
pkgs.pkgsCross.mingwW64.openssl # packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
]; # pkgs.pkgsCross.mingwW64.openssl
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [ # ];
pkgs.pkgsCross.mingwW64.openssl # packages.unix-time.postPatch = ''
]; # sed -i 's/mingwex//g' unix-time.cabal
packages.unix-time.postPatch = '' # '';
sed -i 's/mingwex//g' unix-time.cabal # }];
''; # }).simplex-chat.components.library
}]; # .override (p: {
}).simplex-chat.components.library # # enableShared = false;
.override (p: { # setupBuildFlags = p.component.setupBuildFlags ++ map (x: "--ghc-option=${x}") [
# enableShared = false; # "-shared"
setupBuildFlags = p.component.setupBuildFlags ++ map (x: "--ghc-option=${x}") [ # "-threaded"
"-shared" # "-o" "libsimplex.dll"
"-threaded" # # "-optl-lHSrts_thr"
"-o" "libsimplex.dll" # "-optl-lffi"
# "-optl-lHSrts_thr" # # "-optl-static-libgcc"
"-optl-lffi" # # We can't do -optl-static-libstdc++ with gcc. g++ might
# "-optl-static-libgcc" # # but then we are chaning the compiler altogether.
# We can't do -optl-static-libstdc++ with gcc. g++ might # "${./libsimplex.dll.def}"
# but then we are chaning the compiler altogether. # ];
"${./libsimplex.dll.def}" # postInstall = ''
]; # set -x
postInstall = '' # function deps() {
set -x # ${pkgs.binutils}/bin/strings "$1" | grep '.\.dll'|grep -v -E 'Winsock|ADVAPI32|dbghelp|KERNEL32|msvcrt|ntdll|ole32|RPCRT4|SHELL32|USER32|WINMM|WS2_32|kernel32|GDI32'|grep -v "$1"
function deps() { # }
${pkgs.binutils}/bin/strings "$1" | grep '.\.dll'|grep -v -E 'Winsock|ADVAPI32|dbghelp|KERNEL32|msvcrt|ntdll|ole32|RPCRT4|SHELL32|USER32|WINMM|WS2_32|kernel32|GDI32'|grep -v "$1" # ${pkgs.tree}/bin/tree $out
} # mkdir -p $out/_pkg
${pkgs.tree}/bin/tree $out # cp libsimplex.dll $out/_pkg
mkdir -p $out/_pkg # cp libsimplex.dll.a $out/_pkg
cp libsimplex.dll $out/_pkg # mkdir $out/libs
cp libsimplex.dll.a $out/_pkg # find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.openssl} -name "*.dll" -exec cp {} $out/libs \;
mkdir $out/libs # find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.libffi} -name "*.dll" -exec cp {} $out/libs \;
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.openssl} -name "*.dll" -exec cp {} $out/libs \; # find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.gmp} -name "*.dll" -exec cp {} $out/libs \;
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.libffi} -name "*.dll" -exec cp {} $out/libs \; # find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.stdenv.cc.cc} -name "*.dll" -exec cp {} $out/libs \;
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.gmp} -name "*.dll" -exec cp {} $out/libs \; # find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.windows.mcfgthreads} -name "*.dll" -exec cp {} $out/libs \;
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.stdenv.cc.cc} -name "*.dll" -exec cp {} $out/libs \;
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.windows.mcfgthreads} -name "*.dll" -exec cp {} $out/libs \;
pushd $out/_pkg # pushd $out/_pkg
function copyDeps() { # function copyDeps() {
for dep in $(deps "$1"); do # for dep in $(deps "$1"); do
if [ ! -f "$dep" ]; then # if [ ! -f "$dep" ]; then
if [ ! -f ../libs/"$dep" ]; then # if [ ! -f ../libs/"$dep" ]; then
echo "WARN: $1 -> $dep not found!" # echo "WARN: $1 -> $dep not found!"
else # else
cp ../libs/"$dep" . # cp ../libs/"$dep" .
copyDeps "$dep" # copyDeps "$dep"
fi # fi
fi # fi
done # done
} # }
copyDeps libsimplex.dll # copyDeps libsimplex.dll
popd # popd
${pkgs.tree}/bin/tree $out/_pkg # ${pkgs.tree}/bin/tree $out/_pkg
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-${pkgs.pkgsCross.mingwW64.hostPlatform.system}-libsimplex.zip *) # (cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-${pkgs.pkgsCross.mingwW64.hostPlatform.system}-libsimplex.zip *)
rm -fR $out/_pkg # rm -fR $out/_pkg
mkdir -p $out/nix-support # mkdir -p $out/nix-support
echo "file binary-dist \"$(echo $out/*.zip)\"" \ # echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products # > $out/nix-support/hydra-build-products
''; # '';
}); # });
# "${pkgs.pkgsCross.muslpi.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.muslpi).simplex-chat.components.exes.simplex-chat; # "${pkgs.pkgsCross.muslpi.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.muslpi).simplex-chat.components.exes.simplex-chat;
# STATIC aarch64-linux # STATIC aarch64-linux
"${pkgs.pkgsCross.aarch64-multiplatform-musl.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.aarch64-multiplatform-musl).simplex-chat.components.exes.simplex-chat; # "${pkgs.pkgsCross.aarch64-multiplatform-musl.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.aarch64-multiplatform-musl).simplex-chat.components.exes.simplex-chat;
"armv7a-android:lib:support" = (drv' { extra-modules = []; pkgs' = android32Pkgs; compiler-nix-name = "ghc8107"; } ).android-support.components.library.override (p: {
"armv7a-android:lib:support" = (drv android32Pkgs).android-support.components.library.override (p: {
smallAddressSpace = true; smallAddressSpace = true;
# we won't want -dyamic (see aarch64-android:lib:simplex-chat) # we won't want -dyamic (see aarch64-android:lib:simplex-chat)
enableShared = false; enableShared = false;
@@ -328,7 +326,6 @@
''; '';
}); });
"armv7a-android:lib:simplex-chat" = (drv' { "armv7a-android:lib:simplex-chat" = (drv' {
compiler-nix-name = "ghc8107";
pkgs' = android32Pkgs; pkgs' = android32Pkgs;
extra-modules = [{ extra-modules = [{
packages.text.flags.simdutf = false; packages.text.flags.simdutf = false;
@@ -344,7 +341,7 @@
]; ];
# 32 bit patches # 32 bit patches
packages.basement.patches = [ packages.basement.patches = [
# ./scripts/nix/basement-pr-573.patch ./scripts/nix/basement-pr-573.patch
]; ];
packages.memory.patches = [ packages.memory.patches = [
./scripts/nix/memory-pr-99.patch ./scripts/nix/memory-pr-99.patch
@@ -367,7 +364,6 @@
"-threaded" "-threaded"
# "-debug" # "-debug"
"-optl-lffi" "-optl-lffi"
"-optl-lHSrts_thr"
] ]
# This is fairly idiotic. LLD will strip out foreign exported # This is fairly idiotic. LLD will strip out foreign exported
# symbols (a GHC bug? Codegen bug?). So we need to pass `-u <sym>` # symbols (a GHC bug? Codegen bug?). So we need to pass `-u <sym>`
@@ -392,8 +388,6 @@
"chat_valid_name" "chat_valid_name"
"chat_json_length" "chat_json_length"
"chat_write_file" "chat_write_file"
# We also need to keep the rts init method around.
"hs_init_with_rtsopts"
]; ];
postInstall = '' postInstall = ''
set -x set -x
@@ -440,7 +434,6 @@
''; '';
}); });
"aarch64-android:lib:simplex-chat" = (drv' { "aarch64-android:lib:simplex-chat" = (drv' {
compiler-nix-name = "ghc964";
pkgs' = androidPkgs; pkgs' = androidPkgs;
extra-modules = [{ extra-modules = [{
packages.text.flags.simdutf = false; packages.text.flags.simdutf = false;
@@ -549,7 +542,6 @@
"aarch64-darwin" = { "aarch64-darwin" = {
# aarch64-darwin iOS build (to be patched with mac2ios) # aarch64-darwin iOS build (to be patched with mac2ios)
"aarch64-darwin-ios:lib:simplex-chat" = (drv' { "aarch64-darwin-ios:lib:simplex-chat" = (drv' {
compiler-nix-name = "ghc964";
pkgs' = pkgs; pkgs' = pkgs;
extra-modules = [{ extra-modules = [{
packages.simplex-chat.flags.swift = true; packages.simplex-chat.flags.swift = true;
@@ -566,7 +558,6 @@
); );
# aarch64-darwin build with tagged JSON format (for Mac & Flutter) # aarch64-darwin build with tagged JSON format (for Mac & Flutter)
"aarch64-darwin:lib:simplex-chat" = (drv' { "aarch64-darwin:lib:simplex-chat" = (drv' {
compiler-nix-name = "ghc964";
pkgs' = pkgs; pkgs' = pkgs;
extra-modules = [{ extra-modules = [{
packages.direct-sqlcipher.flags.commoncrypto = true; packages.direct-sqlcipher.flags.commoncrypto = true;
@@ -582,7 +573,6 @@
"x86_64-darwin" = { "x86_64-darwin" = {
# x86_64-darwin iOS simulator build (to be patched with mac2ios) # x86_64-darwin iOS simulator build (to be patched with mac2ios)
"x86_64-darwin-ios:lib:simplex-chat" = (drv' { "x86_64-darwin-ios:lib:simplex-chat" = (drv' {
compiler-nix-name = "ghc964";
pkgs' = pkgs; pkgs' = pkgs;
extra-modules = [{ extra-modules = [{
packages.simplex-chat.flags.swift = true; packages.simplex-chat.flags.swift = true;
@@ -598,7 +588,6 @@
); );
# x86_64-darwin build with tagged JSON format (for Mac & Flutter iOS simulator) # x86_64-darwin build with tagged JSON format (for Mac & Flutter iOS simulator)
"x86_64-darwin:lib:simplex-chat" = (drv' { "x86_64-darwin:lib:simplex-chat" = (drv' {
compiler-nix-name = "ghc964";
pkgs' = pkgs; pkgs' = pkgs;
extra-modules = [{ extra-modules = [{
packages.direct-sqlcipher.flags.commoncrypto = true; packages.direct-sqlcipher.flags.commoncrypto = true;
+1 -1
View File
@@ -1,5 +1,5 @@
name: simplex-chat name: simplex-chat
version: 5.7.0.0 version: 5.7.0.1
#synopsis: #synopsis:
#description: #description:
homepage: https://github.com/simplex-chat/simplex-chat#readme homepage: https://github.com/simplex-chat/simplex-chat#readme
+33 -4
View File
@@ -321,7 +321,17 @@ const processCommand = (function () {
} }
async function initializeCall(config: CallConfig, mediaType: CallMediaType, aesKey?: string): Promise<Call> { async function initializeCall(config: CallConfig, mediaType: CallMediaType, aesKey?: string): Promise<Call> {
const pc = new RTCPeerConnection(config.peerConnectionConfig) let pc: RTCPeerConnection
try {
pc = new RTCPeerConnection(config.peerConnectionConfig)
} catch (e) {
console.log("Error while constructing RTCPeerConnection, will try without 'stuns' specified: " + e)
const withoutStuns = config.peerConnectionConfig.iceServers?.filter((elem) =>
typeof elem.urls === "string" ? !elem.urls.startsWith("stuns:") : !elem.urls.some((url) => url.startsWith("stuns:"))
)
config.peerConnectionConfig.iceServers = withoutStuns
pc = new RTCPeerConnection(config.peerConnectionConfig)
}
const remoteStream = new MediaStream() const remoteStream = new MediaStream()
const localCamera = VideoCamera.User const localCamera = VideoCamera.User
const localStream = await getLocalMediaStream(mediaType, localCamera) const localStream = await getLocalMediaStream(mediaType, localCamera)
@@ -577,6 +587,9 @@ const processCommand = (function () {
// setupVideoElement(videos.remote) // setupVideoElement(videos.remote)
videos.local.srcObject = call.localStream videos.local.srcObject = call.localStream
videos.remote.srcObject = call.remoteStream videos.remote.srcObject = call.remoteStream
// Without doing it manually Firefox shows black screen but video can be played in Picture-in-Picture
videos.local.play()
videos.remote.play()
} }
async function setupEncryptionWorker(call: Call) { async function setupEncryptionWorker(call: Call) {
@@ -652,7 +665,9 @@ const processCommand = (function () {
codecs.splice(selectedCodecIndex, 1) codecs.splice(selectedCodecIndex, 1)
codecs.unshift(selectedCodec) codecs.unshift(selectedCodec)
for (const t of call.connection.getTransceivers()) { for (const t of call.connection.getTransceivers()) {
if (t.sender.track?.kind === "video") { // Firefox doesn't have this function implemented:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1396922
if (t.sender.track?.kind === "video" && t.setCodecPreferences) {
t.setCodecPreferences(codecs) t.setCodecPreferences(codecs)
} }
} }
@@ -674,7 +689,18 @@ const processCommand = (function () {
} }
return return
} }
for (const t of call.localStream.getTracks()) t.stop() if (!call.screenShareEnabled) {
for (const t of call.localStream.getTracks()) t.stop()
} else {
// Don't stop audio track if switching to screenshare
for (const t of call.localStream.getVideoTracks()) t.stop()
// Replace new track from screenshare with old track from recording device
for (const t of localStream.getAudioTracks()) {
t.stop()
localStream.removeTrack(t)
}
for (const t of call.localStream.getAudioTracks()) localStream.addTrack(t)
}
call.localCamera = camera call.localCamera = camera
const audioTracks = localStream.getAudioTracks() const audioTracks = localStream.getAudioTracks()
@@ -690,6 +716,7 @@ const processCommand = (function () {
replaceTracks(pc, videoTracks) replaceTracks(pc, videoTracks)
call.localStream = localStream call.localStream = localStream
videos.local.srcObject = localStream videos.local.srcObject = localStream
videos.local.play()
} }
function replaceTracks(pc: RTCPeerConnection, tracks: MediaStreamTrack[]) { function replaceTracks(pc: RTCPeerConnection, tracks: MediaStreamTrack[]) {
@@ -739,7 +766,9 @@ const processCommand = (function () {
//}, //},
//aspectRatio: 1.33, //aspectRatio: 1.33,
}, },
audio: true, audio: false,
// This works with Chrome, Edge, Opera, but not with Firefox and Safari
// systemAudio: "include"
} }
return navigator.mediaDevices.getDisplayMedia(constraints) return navigator.mediaDevices.getDisplayMedia(constraints)
} }
@@ -10,7 +10,6 @@
<video <video
id="remote-video-stream" id="remote-video-stream"
class="inline" class="inline"
autoplay
playsinline playsinline
poster="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAEUlEQVR42mNk+M+AARiHsiAAcCIKAYwFoQ8AAAAASUVORK5CYII=" poster="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAEUlEQVR42mNk+M+AARiHsiAAcCIKAYwFoQ8AAAAASUVORK5CYII="
onclick="javascript:toggleRemoteVideoFitFill()" onclick="javascript:toggleRemoteVideoFitFill()"
@@ -19,7 +18,6 @@
id="local-video-stream" id="local-video-stream"
class="inline" class="inline"
muted muted
autoplay
playsinline playsinline
poster="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAEUlEQVR42mNk+M+AARiHsiAAcCIKAYwFoQ8AAAAASUVORK5CYII=" poster="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAEUlEQVR42mNk+M+AARiHsiAAcCIKAYwFoQ8AAAAASUVORK5CYII="
></video> ></video>
+1 -1
View File
@@ -8,7 +8,7 @@ function readlink() {
OS=linux OS=linux
ARCH=${1:-`uname -a | rev | cut -d' ' -f2 | rev`} ARCH=${1:-`uname -a | rev | cut -d' ' -f2 | rev`}
GHC_VERSION=9.6.4 GHC_VERSION=9.6.3
if [ "$ARCH" == "aarch64" ]; then if [ "$ARCH" == "aarch64" ]; then
COMPOSE_ARCH=arm64 COMPOSE_ARCH=arm64
+1 -1
View File
@@ -5,7 +5,7 @@ set -e
OS=mac OS=mac
ARCH="${1:-`uname -a | rev | cut -d' ' -f1 | rev`}" ARCH="${1:-`uname -a | rev | cut -d' ' -f1 | rev`}"
COMPOSE_ARCH=$ARCH COMPOSE_ARCH=$ARCH
GHC_VERSION=9.6.4 GHC_VERSION=9.6.3
if [ "$ARCH" == "arm64" ]; then if [ "$ARCH" == "arm64" ]; then
ARCH=aarch64 ARCH=aarch64
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"https://github.com/simplex-chat/simplexmq.git"."5e783396e05ced83b22914c172d2f2e8e14e5be2" = "1bxbhy5vddczspan0xzcwk2jvkial6n84m0s5wznqbg03i4y7j1y"; "https://github.com/simplex-chat/simplexmq.git"."3d40393ae83260245c7122b850fb42cd4243deba" = "0hkfz5k8kn1lqq0ms0b266pzsk48pq1gkfm7wgw6w5mr1pw149ay";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
+1 -1
View File
@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
name: simplex-chat name: simplex-chat
version: 5.7.0.0 version: 5.7.0.1
category: Web, System, Services, Cryptography category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat author: simplex.chat
+30 -27
View File
@@ -895,7 +895,7 @@ processChatCommand' vr = \case
cci <- getDirectChatItem db user fromChatId itemId cci <- getDirectChatItem db user fromChatId itemId
pure (ct, cci) pure (ct, cci)
(mc, mDir) <- forwardMC ci (mc, mDir) <- forwardMC ci
file <- forwardCryptoFile ci `catchChatError` (\e -> toView (CRChatError (Just user) e) $> Nothing) file <- forwardCryptoFile ci
let ciff = forwardCIFF ci $ Just (CIFFContact (forwardName ct) mDir (Just fromChatId) (Just itemId)) let ciff = forwardCIFF ci $ Just (CIFFContact (forwardName ct) mDir (Just fromChatId) (Just itemId))
pure (ComposedMessage file Nothing mc, ciff) pure (ComposedMessage file Nothing mc, ciff)
where where
@@ -909,7 +909,7 @@ processChatCommand' vr = \case
cci <- getGroupChatItem db user fromChatId itemId cci <- getGroupChatItem db user fromChatId itemId
pure (gInfo, cci) pure (gInfo, cci)
(mc, mDir) <- forwardMC ci (mc, mDir) <- forwardMC ci
file <- forwardCryptoFile ci `catchChatError` (\e -> toView (CRChatError (Just user) e) $> Nothing) file <- forwardCryptoFile ci
let ciff = forwardCIFF ci $ Just (CIFFGroup (forwardName gInfo) mDir (Just fromChatId) (Just itemId)) let ciff = forwardCIFF ci $ Just (CIFFGroup (forwardName gInfo) mDir (Just fromChatId) (Just itemId))
pure (ComposedMessage file Nothing mc, ciff) pure (ComposedMessage file Nothing mc, ciff)
where where
@@ -918,7 +918,7 @@ processChatCommand' vr = \case
CTLocal -> do CTLocal -> do
(CChatItem _ ci) <- withStore $ \db -> getLocalChatItem db user fromChatId itemId (CChatItem _ ci) <- withStore $ \db -> getLocalChatItem db user fromChatId itemId
(mc, _) <- forwardMC ci (mc, _) <- forwardMC ci
file <- forwardCryptoFile ci `catchChatError` (\e -> toView (CRChatError (Just user) e) $> Nothing) file <- forwardCryptoFile ci
let ciff = forwardCIFF ci Nothing let ciff = forwardCIFF ci Nothing
pure (ComposedMessage file Nothing mc, ciff) pure (ComposedMessage file Nothing mc, ciff)
CTContactRequest -> throwChatError $ CECommandError "not supported" CTContactRequest -> throwChatError $ CECommandError "not supported"
@@ -930,31 +930,34 @@ processChatCommand' vr = \case
forwardMC ChatItem {content = CIRcvMsgContent fmc} = pure (fmc, MDRcv) forwardMC ChatItem {content = CIRcvMsgContent fmc} = pure (fmc, MDRcv)
forwardMC _ = throwChatError CEInvalidForward forwardMC _ = throwChatError CEInvalidForward
forwardCIFF :: ChatItem c d -> Maybe CIForwardedFrom -> Maybe CIForwardedFrom forwardCIFF :: ChatItem c d -> Maybe CIForwardedFrom -> Maybe CIForwardedFrom
forwardCIFF ChatItem {meta = CIMeta {itemForwarded = Just ciff}} _ = Just ciff forwardCIFF ChatItem {meta = CIMeta {itemForwarded}} ciff = case itemForwarded of
forwardCIFF _ ciff = ciff Nothing -> ciff
Just CIFFUnknown -> ciff
Just prevCIFF -> Just prevCIFF
forwardCryptoFile :: ChatItem c d -> CM (Maybe CryptoFile) forwardCryptoFile :: ChatItem c d -> CM (Maybe CryptoFile)
forwardCryptoFile ChatItem {file = Just CIFile {fileName, fileStatus, fileSource = Just fromCF@CryptoFile {filePath, cryptoArgs = fromArgs}}} forwardCryptoFile ChatItem {file = Nothing} = pure Nothing
| ciFileLoaded fileStatus = forwardCryptoFile ChatItem {file = Just ciFile} = case ciFile of
chatReadVar filesFolder >>= \case CIFile {fileName, fileStatus, fileSource = Just fromCF@CryptoFile {filePath}}
Nothing -> | ciFileLoaded fileStatus ->
ifM (doesFileExist filePath) (pure $ Just fromCF) (pure Nothing) chatReadVar filesFolder >>= \case
Just filesFolder -> do Nothing ->
let fsFromPath = filesFolder </> filePath ifM (doesFileExist filePath) (pure $ Just fromCF) (throwChatError CEForwardNoFile)
ifM Just filesFolder -> do
(doesFileExist fsFromPath) let fsFromPath = filesFolder </> filePath
( do ifM
fsNewPath <- liftIO $ filesFolder `uniqueCombine` fileName (doesFileExist fsFromPath)
liftIO $ B.writeFile fsNewPath "" -- create empty file ( do
encrypt <- chatReadVar encryptLocalFiles fsNewPath <- liftIO $ filesFolder `uniqueCombine` fileName
cfArgs <- if encrypt then Just <$> (atomically . CF.randomArgs =<< asks random) else pure Nothing liftIO $ B.writeFile fsNewPath "" -- create empty file
let toCF = CryptoFile fsNewPath cfArgs encrypt <- chatReadVar encryptLocalFiles
-- to keep forwarded file in case original is deleted cfArgs <- if encrypt then Just <$> (atomically . CF.randomArgs =<< asks random) else pure Nothing
liftIOEither $ runExceptT $ withExceptT (ChatError . CEInternalError . show) $ copyCryptoFile (fromCF {filePath = fsFromPath} :: CryptoFile) toCF let toCF = CryptoFile fsNewPath cfArgs
pure $ Just (toCF {filePath = takeFileName fsNewPath} :: CryptoFile) -- to keep forwarded file in case original is deleted
) liftIOEither $ runExceptT $ withExceptT (ChatError . CEInternalError . show) $ copyCryptoFile (fromCF {filePath = fsFromPath} :: CryptoFile) toCF
(pure Nothing) pure $ Just (toCF {filePath = takeFileName fsNewPath} :: CryptoFile)
| otherwise = pure Nothing )
forwardCryptoFile _ = pure Nothing (throwChatError CEForwardNoFile)
_ -> throwChatError CEForwardNoFile
copyCryptoFile :: CryptoFile -> CryptoFile -> ExceptT CF.FTCryptoError IO () copyCryptoFile :: CryptoFile -> CryptoFile -> ExceptT CF.FTCryptoError IO ()
copyCryptoFile fromCF@CryptoFile {filePath = fsFromPath, cryptoArgs = fromArgs} toCF@CryptoFile {cryptoArgs = toArgs} = do copyCryptoFile fromCF@CryptoFile {filePath = fsFromPath, cryptoArgs = fromArgs} toCF@CryptoFile {cryptoArgs = toArgs} = do
fromSizeFull <- getFileSize fsFromPath fromSizeFull <- getFileSize fsFromPath
+1
View File
@@ -1121,6 +1121,7 @@ data ChatErrorType
| CEInlineFileProhibited {fileId :: FileTransferId} | CEInlineFileProhibited {fileId :: FileTransferId}
| CEInvalidQuote | CEInvalidQuote
| CEInvalidForward | CEInvalidForward
| CEForwardNoFile
| CEInvalidChatItemUpdate | CEInvalidChatItemUpdate
| CEInvalidChatItemDelete | CEInvalidChatItemDelete
| CEHasCurrentCall | CEHasCurrentCall
+1
View File
@@ -1968,6 +1968,7 @@ viewChatError logLevel testView = \case
CEInlineFileProhibited _ -> ["A small file sent without acceptance - you can enable receiving such files with -f option."] CEInlineFileProhibited _ -> ["A small file sent without acceptance - you can enable receiving such files with -f option."]
CEInvalidQuote -> ["cannot reply to this message"] CEInvalidQuote -> ["cannot reply to this message"]
CEInvalidForward -> ["cannot forward this message"] CEInvalidForward -> ["cannot forward this message"]
CEForwardNoFile -> ["cannot forward this message, file not found"]
CEInvalidChatItemUpdate -> ["cannot update this item"] CEInvalidChatItemUpdate -> ["cannot update this item"]
CEInvalidChatItemDelete -> ["cannot delete this item"] CEInvalidChatItemDelete -> ["cannot delete this item"]
CEHasCurrentCall -> ["call already in progress"] CEHasCurrentCall -> ["call already in progress"]
+29
View File
@@ -24,6 +24,7 @@ chatForwardTests = do
it "from notes to notes" testForwardNotesToNotes -- TODO forward between different folders when supported it "from notes to notes" testForwardNotesToNotes -- TODO forward between different folders when supported
describe "interactions with forwarded messages" $ do describe "interactions with forwarded messages" $ do
it "preserve original forward info" testForwardPreserveInfo it "preserve original forward info" testForwardPreserveInfo
it "received forwarded message is saved with new forward info" testForwardRcvMsgNewInfo
it "quoted message is not included" testForwardQuotedMsg it "quoted message is not included" testForwardQuotedMsg
it "editing is prohibited" testForwardEditProhibited it "editing is prohibited" testForwardEditProhibited
it "delete for other" testForwardDeleteForOther it "delete for other" testForwardDeleteForOther
@@ -276,6 +277,34 @@ testForwardPreserveInfo =
dan <# "#team alice> -> forwarded" dan <# "#team alice> -> forwarded"
dan <## " hey" dan <## " hey"
testForwardRcvMsgNewInfo :: HasCallStack => FilePath -> IO ()
testForwardRcvMsgNewInfo =
testChat4 aliceProfile bobProfile cathProfile danProfile $
\alice bob cath dan -> do
connectUsers bob dan
createCCNoteFolder alice
connectUsers alice bob
connectUsers alice cath
dan #> "@bob hey"
bob <# "dan> hey"
bob `send` "@alice <- @dan hey"
bob <# "@alice <- @dan"
bob <## " hey"
alice <# "bob> -> forwarded"
alice <## " hey"
alice `send` "* <- @bob hey"
alice <# "* <- @bob"
alice <## " hey"
alice `send` "@cath <- * hey"
alice <# "@cath <- @bob"
alice <## " hey"
cath <# "alice> -> forwarded"
cath <## " hey"
testForwardQuotedMsg :: HasCallStack => FilePath -> IO () testForwardQuotedMsg :: HasCallStack => FilePath -> IO ()
testForwardQuotedMsg = testForwardQuotedMsg =
testChat3 aliceProfile bobProfile cathProfile $ testChat3 aliceProfile bobProfile cathProfile $
@@ -0,0 +1,5 @@
<em>By Esra'a al Shafei</em>
<p>It's important not to be complacent with the current standards of messaging,
where metadata aggregation is still normalized in apps falsely and dangerously marketed as "private".
This is a post exploring the fundamental differences between privacy and security.</p>