diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 262c4a4b48..7dae94dfcd 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -74,6 +74,7 @@ final class ChatModel: ObservableObject { @Published var chatToTop: String? @Published var groupMembers: [GMember] = [] @Published var groupMembersIndexes: Dictionary = [:] // groupMemberId to index in groupMembers list + @Published var membersLoaded = false // items in the terminal view @Published var showingTerminal = false @Published var terminalItems: [TerminalItem] = [] @@ -195,6 +196,18 @@ final class ChatModel: ObservableObject { return nil } + func loadGroupMembers(_ groupInfo: GroupInfo, updateView: @escaping () -> Void = {}) async { + let groupMembers = await apiListMembers(groupInfo.groupId) + await MainActor.run { + if chatId == groupInfo.id { + self.groupMembers = groupMembers.map { GMember.init($0) } + self.populateGroupMembersIndexes() + self.membersLoaded = true + updateView() + } + } + } + private func getChatIndex(_ id: String) -> Int? { chats.firstIndex(where: { $0.id == id }) } @@ -390,8 +403,8 @@ final class ChatModel: ObservableObject { } func removeChatItem(_ cInfo: ChatInfo, _ cItem: ChatItem) { - if cItem.isRcvNew { - decreaseUnreadCounter(cInfo) + if cItem.isRcvNew, let chatIndex = getChatIndex(cInfo.id) { + decreaseUnreadCounter(chatIndex) } // update previews if let chat = getChat(cInfo.id) { @@ -536,13 +549,18 @@ final class ChatModel: ObservableObject { } } - func markChatItemRead(_ cInfo: ChatInfo, _ cItem: ChatItem) { - if chatId == cInfo.id, let i = getChatItemIndex(cItem) { - if reversedChatItems[i].isRcvNew { - // update current chat - markChatItemRead_(i) - // update preview - decreaseUnreadCounter(cInfo) + func markChatItemRead(_ cInfo: ChatInfo, _ cItem: ChatItem) async { + if chatId == cInfo.id, + let itemIndex = getChatItemIndex(cItem), + let chatIndex = getChatIndex(cInfo.id), + reversedChatItems[itemIndex].isRcvNew { + await MainActor.run { + withTransaction(Transaction()) { + // update current chat + markChatItemRead_(itemIndex) + // update preview + decreaseUnreadCounter(chatIndex) + } } } } @@ -558,11 +576,9 @@ final class ChatModel: ObservableObject { } } - func decreaseUnreadCounter(_ cInfo: ChatInfo) { - if let i = getChatIndex(cInfo.id) { - chats[i].chatStats.unreadCount = chats[i].chatStats.unreadCount - 1 - decreaseUnreadCounter(user: currentUser!) - } + func decreaseUnreadCounter(_ chatIndex: Int) { + chats[chatIndex].chatStats.unreadCount = chats[chatIndex].chatStats.unreadCount - 1 + decreaseUnreadCounter(user: currentUser!) } func increaseUnreadCounter(user: any UserLike) { diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 8c90c4b1ac..dd0610e48c 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -1091,23 +1091,55 @@ func deleteRemoteCtrl(_ rcId: Int64) async throws { try await sendCommandOkResp(.deleteRemoteCtrl(remoteCtrlId: rcId)) } -func networkErrorAlert(_ r: ChatResponse) -> Alert? { +struct ErrorAlert { + var title: LocalizedStringKey + var message: LocalizedStringKey +} + +func getNetworkErrorAlert(_ r: ChatResponse) -> ErrorAlert? { switch r { case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TIMEOUT))): - return mkAlert( - title: "Connection timeout", - message: "Please check your network connection with \(serverHostname(addr)) and try again." - ) + return ErrorAlert(title: "Connection timeout", message: "Please check your network connection with \(serverHostname(addr)) and try again.") case let .chatCmdError(_, .errorAgent(.BROKER(addr, .NETWORK))): - return mkAlert( - title: "Connection error", - message: "Please check your network connection with \(serverHostname(addr)) and try again." - ) + return ErrorAlert(title: "Connection error", message: "Please check your network connection with \(serverHostname(addr)) and try again.") + case let .chatCmdError(_, .errorAgent(.BROKER(addr, .HOST))): + return ErrorAlert(title: "Connection error", message: "Server address is incompatible with network settings: \(serverHostname(addr)).") + case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TRANSPORT(.version)))): + return ErrorAlert(title: "Connection error", message: "Server version is incompatible with your app: \(serverHostname(addr)).") + case let .chatCmdError(_, .errorAgent(.SMP(.PROXY(proxyErr)))): + return proxyErrorAlert(proxyErr) + case let .chatCmdError(_, .errorAgent(.PROXY(_, _, .protocolError(.PROXY(proxyErr))))): + return proxyErrorAlert(proxyErr) default: return nil } } +private func proxyErrorAlert(_ proxyErr: ProxyError) -> ErrorAlert? { + switch proxyErr { + case .BROKER(brokerErr: .TIMEOUT): + return ErrorAlert(title: "Private routing error", message: "Please try later.") + case .BROKER(brokerErr: .NETWORK): + return ErrorAlert(title: "Private routing error", message: "Please try later.") + case .NO_SESSION: + return ErrorAlert(title: "Private routing error", message: "Please try later.") + case .BROKER(brokerErr: .HOST): + return ErrorAlert(title: "Private routing error", message: "Server address is incompatible with network settings.") + case .BROKER(brokerErr: .TRANSPORT(.version)): + return ErrorAlert(title: "Private routing error", message: "Server version is incompatible with network settings.") + default: + return nil + } +} + +func networkErrorAlert(_ r: ChatResponse) -> Alert? { + if let alert = getNetworkErrorAlert(r) { + return mkAlert(title: alert.title, message: alert.message) + } else { + return nil + } +} + func acceptContactRequest(incognito: Bool, contactRequest: UserContactRequest) async { if let contact = await apiAcceptContactRequest(incognito: incognito, contactReqId: contactRequest.apiId) { let chat = Chat(chatInfo: ChatInfo.direct(contact: contact), chatItems: []) @@ -1207,7 +1239,7 @@ func apiMarkChatItemRead(_ cInfo: ChatInfo, _ cItem: ChatItem) async { do { logger.debug("apiMarkChatItemRead: \(cItem.id)") try await apiChatRead(type: cInfo.chatType, id: cInfo.apiId, itemRange: (cItem.id, cItem.id)) - await MainActor.run { ChatModel.shared.markChatItemRead(cInfo, cItem) } + await ChatModel.shared.markChatItemRead(cInfo, cItem) } catch { logger.error("apiMarkChatItemRead apiChatRead error: \(responseError(error))") } diff --git a/apps/ios/Shared/Theme/Theme.swift b/apps/ios/Shared/Theme/Theme.swift index 3f7013bad7..d4dcc8097f 100644 --- a/apps/ios/Shared/Theme/Theme.swift +++ b/apps/ios/Shared/Theme/Theme.swift @@ -102,8 +102,7 @@ extension ThemeWallpaper { public func importFromString() -> ThemeWallpaper { if preset == nil, let image { // Need to save image from string and to save its path - if let data = Data(base64Encoded: dropImagePrefix(image)), - let parsed = UIImage(data: data), + if let parsed = UIImage(base64Encoded: image), let filename = saveWallpaperFile(image: parsed) { var copy = self copy.image = nil diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift index 0f7ea9a716..3e6ef4abff 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift @@ -15,8 +15,7 @@ struct CILinkView: View { var body: some View { VStack(alignment: .center, spacing: 6) { - if let data = Data(base64Encoded: dropImagePrefix(linkPreview.image)), - let uiImage = UIImage(data: data) { + if let uiImage = UIImage(base64Encoded: linkPreview.image) { Image(uiImage: uiImage) .resizable() .scaledToFit() diff --git a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift index 5d6327139a..595d9bf2fc 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift @@ -188,8 +188,7 @@ struct FramedItemView: View { let v = ZStack(alignment: .topTrailing) { switch (qi.content) { case let .image(_, image): - if let data = Data(base64Encoded: dropImagePrefix(image)), - let uiImage = UIImage(data: data) { + if let uiImage = UIImage(base64Encoded: image) { ciQuotedMsgView(qi) .padding(.trailing, 70).frame(minWidth: msgWidth, alignment: .leading) Image(uiImage: uiImage) @@ -201,8 +200,7 @@ struct FramedItemView: View { ciQuotedMsgView(qi) } case let .video(_, image, _): - if let data = Data(base64Encoded: dropImagePrefix(image)), - let uiImage = UIImage(data: data) { + if let uiImage = UIImage(base64Encoded: image) { ciQuotedMsgView(qi) .padding(.trailing, 70).frame(minWidth: msgWidth, alignment: .leading) Image(uiImage: uiImage) diff --git a/apps/ios/Shared/Views/Chat/ChatItemView.swift b/apps/ios/Shared/Views/Chat/ChatItemView.swift index 4cb97112ca..d06e67e2e6 100644 --- a/apps/ios/Shared/Views/Chat/ChatItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItemView.swift @@ -68,9 +68,7 @@ struct ChatItemView: View { default: nil } } - .map { dropImagePrefix($0) } - .flatMap { Data(base64Encoded: $0) } - .flatMap { UIImage(data: $0) } + .flatMap { UIImage(base64Encoded: $0) } let adjustedMaxWidth = { if let preview, preview.size.width <= preview.size.height { maxWidth * 0.75 diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 7e302d67d1..f8723fdba8 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -37,7 +37,6 @@ struct ChatView: View { @State private var searchText: String = "" @FocusState private var searchFocussed // opening GroupMemberInfoView on member icon - @State private var membersLoaded = false @State private var selectedMember: GMember? = nil // opening GroupLinkView on link button (incognito) @State private var showGroupLinkSheet: Bool = false @@ -122,7 +121,7 @@ struct ChatView: View { chatModel.reversedChatItems = [] chatModel.groupMembers = [] chatModel.groupMembersIndexes.removeAll() - membersLoaded = false + chatModel.membersLoaded = false } } } @@ -164,7 +163,7 @@ struct ChatView: View { } } else if case let .group(groupInfo) = cInfo { Button { - Task { await loadGroupMembers(groupInfo) { showChatInfoSheet = true } } + Task { await chatModel.loadGroupMembers(groupInfo) { showChatInfoSheet = true } } } label: { ChatInfoToolbar(chat: chat) .tint(theme.colors.primary) @@ -250,19 +249,7 @@ struct ChatView: View { } } } - - private func loadGroupMembers(_ groupInfo: GroupInfo, updateView: @escaping () -> Void = {}) async { - let groupMembers = await apiListMembers(groupInfo.groupId) - await MainActor.run { - if chatModel.chatId == groupInfo.id { - chatModel.groupMembers = groupMembers.map { GMember.init($0) } - chatModel.populateGroupMembersIndexes() - membersLoaded = true - updateView() - } - } - } - + private func initChatView() { let cInfo = chat.chatInfo // This check prevents the call to apiContactInfo after the app is suspended, and the database is closed. @@ -477,9 +464,7 @@ struct ChatView: View { .foregroundColor(theme.colors.primary) } .onTapGesture { - if let latestUnreadItem = filtered(chatModel.reversedChatItems).last(where: { $0.isRcvNew }) { - scrollModel.scrollToItem(id: latestUnreadItem.id) - } + scrollModel.scrollToBottom() } } else if !counts.isNearBottom { circleButton { @@ -534,7 +519,7 @@ struct ChatView: View { private func addMembersButton() -> some View { Button { if case let .group(gInfo) = chat.chatInfo { - Task { await loadGroupMembers(gInfo) { showAddMembersSheet = true } } + Task { await chatModel.loadGroupMembers(gInfo) { showAddMembersSheet = true } } } } label: { Image(systemName: "person.crop.circle.badge.plus") @@ -604,11 +589,9 @@ struct ChatView: View { chat: chat, chatItem: ci, maxWidth: maxWidth, - itemWidth: maxWidth, composeState: $composeState, selectedMember: $selectedMember, - revealedChatItem: $revealedChatItem, - chatView: self + revealedChatItem: $revealedChatItem ) } @@ -616,13 +599,11 @@ struct ChatView: View { @EnvironmentObject var m: ChatModel @EnvironmentObject var theme: AppTheme @ObservedObject var chat: Chat - var chatItem: ChatItem - var maxWidth: CGFloat - @State var itemWidth: CGFloat + let chatItem: ChatItem + let maxWidth: CGFloat @Binding var composeState: ComposeState @Binding var selectedMember: GMember? @Binding var revealedChatItem: ChatItem? - var chatView: ChatView @State private var deletingItem: ChatItem? = nil @State private var showDeleteMessage = false @@ -700,11 +681,11 @@ struct ChatView: View { HStack(alignment: .top, spacing: 8) { ProfileImage(imageStr: member.memberProfile.image, size: memberImageSize, backgroundColor: theme.colors.background) .onTapGesture { - if chatView.membersLoaded { + if m.membersLoaded { selectedMember = m.getGroupMember(member.groupMemberId) } else { Task { - await chatView.loadGroupMembers(groupInfo) { + await m.loadGroupMembers(groupInfo) { selectedMember = m.getGroupMember(member.groupMemberId) } } @@ -1099,7 +1080,7 @@ struct ChatView: View { chatItemInfo = ciInfo } if case let .group(gInfo) = chat.chatInfo { - await chatView.loadGroupMembers(gInfo) + await m.loadGroupMembers(gInfo) } } catch let error { logger.error("apiGetChatItemInfo error: \(responseError(error))") diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeImageView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeImageView.swift index 52655f1c6a..d9f63f6d33 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeImageView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeImageView.swift @@ -18,10 +18,7 @@ struct ComposeImageView: View { var body: some View { HStack(alignment: .center, spacing: 8) { let imgs: [UIImage] = images.compactMap { image in - if let data = Data(base64Encoded: dropImagePrefix(image)) { - return UIImage(data: data) - } - return nil + UIImage(base64Encoded: image) } if imgs.count == 0 { ProgressView() diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift index 4137370e3f..7df0a3037a 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift @@ -69,8 +69,7 @@ struct ComposeLinkView: View { private func linkPreviewView(_ linkPreview: LinkPreview) -> some View { HStack(alignment: .center, spacing: 8) { - if let data = Data(base64Encoded: dropImagePrefix(linkPreview.image)), - let uiImage = UIImage(data: data) { + if let uiImage = UIImage(base64Encoded: linkPreview.image) { Image(uiImage: uiImage) .resizable() .aspectRatio(contentMode: .fit) diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index 819b337a73..c1b709fea5 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -849,6 +849,7 @@ struct ComposeView: View { func sendVideo(_ imageData: (String, UploadContent?), text: String = "", quoted: Int64? = nil, live: Bool = false, ttl: Int?) async -> ChatItem? { let (image, data) = imageData if case let .video(_, url, duration) = data, let savedFile = moveTempFileFromURL(url) { + ChatModel.shared.filesToDelete.remove(url) return await send(.video(text: text, image: image, duration: duration), quoted: quoted, file: savedFile, live: live, ttl: ttl) } return nil diff --git a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift index c8a6efd282..c0cc42bd8e 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift @@ -564,18 +564,11 @@ func joinGroup(_ groupId: Int64, _ onComplete: @escaping () async -> Void) { } } -struct ErrorAlert { - var title: LocalizedStringKey - var message: LocalizedStringKey -} - func getErrorAlert(_ error: Error, _ title: LocalizedStringKey) -> ErrorAlert { - switch error as? ChatResponse { - case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TIMEOUT))): - return ErrorAlert(title: "Connection timeout", message: "Please check your network connection with \(serverHostname(addr)) and try again.") - case let .chatCmdError(_, .errorAgent(.BROKER(addr, .NETWORK))): - return ErrorAlert(title: "Connection error", message: "Please check your network connection with \(serverHostname(addr)) and try again.") - default: + if let r = error as? ChatResponse, + let alert = getNetworkErrorAlert(r) { + return alert + } else { return ErrorAlert(title: title, message: "Error: \(responseError(error))") } } diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 886b7465f3..16f87f0c13 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -266,23 +266,19 @@ struct ChatListView: View { } struct SubsStatusIndicator: View { - @State private var subs: SMPServerSubs = SMPServerSubs.newSMPServerSubs - @State private var sess: ServerSessions = ServerSessions.newServerSessions + @State private var serversSummary: PresentedServersSummary? @State private var timer: Timer? = nil @State private var timerCounter = 0 @State private var showServersSummary = false @AppStorage(DEFAULT_SHOW_SUBSCRIPTION_PERCENTAGE) private var showSubscriptionPercentage = false - // Constants for the intervals - let initialInterval: TimeInterval = 1.0 - let regularInterval: TimeInterval = 3.0 - let initialPhaseDuration: TimeInterval = 10.0 // Duration for initial phase in seconds - var body: some View { Button { showServersSummary = true } label: { + let subs = serversSummary?.allUsersSMP.smpTotals.subs ?? SMPServerSubs.newSMPServerSubs + let sess = serversSummary?.allUsersSMP.smpTotals.sessions ?? ServerSessions.newServerSessions HStack(spacing: 4) { SubscriptionStatusIndicatorView(subs: subs, sess: sess) if showSubscriptionPercentage { @@ -291,34 +287,24 @@ struct SubsStatusIndicator: View { } } .onAppear { - startInitialTimer() + startTimer() } .onDisappear { stopTimer() } .sheet(isPresented: $showServersSummary) { - ServersSummaryView() + ServersSummaryView(serversSummary: $serversSummary) } } - private func startInitialTimer() { - timer = Timer.scheduledTimer(withTimeInterval: initialInterval, repeats: true) { _ in - getServersSummary() - timerCounter += 1 - // Switch to the regular timer after the initial phase - if timerCounter * Int(initialInterval) >= Int(initialPhaseDuration) { - switchToRegularTimer() + private func startTimer() { + timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in + if AppChatState.shared.value == .active { + getServersSummary() } } } - func switchToRegularTimer() { - timer?.invalidate() - timer = Timer.scheduledTimer(withTimeInterval: regularInterval, repeats: true) { _ in - getServersSummary() - } - } - func stopTimer() { timer?.invalidate() timer = nil @@ -326,8 +312,7 @@ struct SubsStatusIndicator: View { private func getServersSummary() { do { - let summ = try getAgentServersSummary() - (subs, sess) = (summ.allUsersSMP.smpTotals.subs, summ.allUsersSMP.smpTotals.sessions) + serversSummary = try getAgentServersSummary() } catch let error { logger.error("getAgentServersSummary error: \(responseError(error))") } diff --git a/apps/ios/Shared/Views/ChatList/ServersSummaryView.swift b/apps/ios/Shared/Views/ChatList/ServersSummaryView.swift index 1fb889f863..3021a7ceb2 100644 --- a/apps/ios/Shared/Views/ChatList/ServersSummaryView.swift +++ b/apps/ios/Shared/Views/ChatList/ServersSummaryView.swift @@ -11,12 +11,12 @@ import SimpleXChat struct ServersSummaryView: View { @EnvironmentObject var m: ChatModel - @State private var serversSummary: PresentedServersSummary? = nil + @EnvironmentObject var theme: AppTheme + @Binding var serversSummary: PresentedServersSummary? @State private var selectedUserCategory: PresentedUserCategory = .allUsers @State private var selectedServerType: PresentedServerType = .smp @State private var selectedSMPServer: String? = nil @State private var selectedXFTPServer: String? = nil - @State private var timer: Timer? = nil @State private var alert: SomeAlert? @AppStorage(DEFAULT_SHOW_SUBSCRIPTION_PERCENTAGE) private var showSubscriptionPercentage = false @@ -47,26 +47,10 @@ struct ServersSummaryView: View { if m.users.filter({ u in u.user.activeUser || !u.user.hidden }).count == 1 { selectedUserCategory = .currentUser } - getServersSummary() - startTimer() - } - .onDisappear { - stopTimer() } .alert(item: $alert) { $0.alert } } - private func startTimer() { - timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in - getServersSummary() - } - } - - func stopTimer() { - timer?.invalidate() - timer = nil - } - private func shareButton() -> some View { Button { if let serversSummary = serversSummary { @@ -183,6 +167,8 @@ struct ServersSummaryView: View { } } else { Text("No info, try to reload") + .foregroundColor(theme.colors.secondary) + .background(theme.colors.background) } } @@ -369,7 +355,6 @@ struct ServersSummaryView: View { Task { do { try await resetAgentServersStats() - getServersSummary() } catch let error { alert = SomeAlert( alert: mkAlert( @@ -389,14 +374,6 @@ struct ServersSummaryView: View { Text("Reset all statistics") } } - - private func getServersSummary() { - do { - serversSummary = try getAgentServersSummary() - } catch let error { - logger.error("getAgentServersSummary error: \(responseError(error))") - } - } } struct SubscriptionStatusIndicatorView: View { @@ -734,5 +711,7 @@ struct DetailedXFTPStatsView: View { } #Preview { - ServersSummaryView() + ServersSummaryView( + serversSummary: Binding.constant(nil) + ) } diff --git a/apps/ios/Shared/Views/Helpers/ProfileImage.swift b/apps/ios/Shared/Views/Helpers/ProfileImage.swift index 0a0aab6253..e7145711af 100644 --- a/apps/ios/Shared/Views/Helpers/ProfileImage.swift +++ b/apps/ios/Shared/Views/Helpers/ProfileImage.swift @@ -21,9 +21,7 @@ struct ProfileImage: View { @AppStorage(DEFAULT_PROFILE_IMAGE_CORNER_RADIUS) private var radius = defaultProfileImageCorner var body: some View { - if let image = imageStr, - let data = Data(base64Encoded: dropImagePrefix(image)), - let uiImage = UIImage(data: data) { + if let uiImage = UIImage(base64Encoded: imageStr) { clipProfileImage(Image(uiImage: uiImage), size: size, radius: radius) } else { let c = color.asAnotherColorFromSecondaryVariant(theme) diff --git a/apps/ios/Shared/Views/UserSettings/ProtocolServerView.swift b/apps/ios/Shared/Views/UserSettings/ProtocolServerView.swift index f4e5459613..6433168810 100644 --- a/apps/ios/Shared/Views/UserSettings/ProtocolServerView.swift +++ b/apps/ios/Shared/Views/UserSettings/ProtocolServerView.swift @@ -15,7 +15,6 @@ struct ProtocolServerView: View { let serverProtocol: ServerProtocol @Binding var server: ServerCfg @State var serverToEdit: ServerCfg - @State var serverEnabled: Bool @State private var showTestFailure = false @State private var testing = false @State private var testFailure: ProtocolTestFailure? @@ -113,10 +112,10 @@ struct ProtocolServerView: View { Spacer() showTestStatus(server: serverToEdit) } - Toggle("Use for new connections", isOn: $serverEnabled) - .onChange(of: serverEnabled) { enabled in - serverToEdit.enabled = enabled ? .enabled : .disabled - } + let useForNewDisabled = serverToEdit.tested != true && !serverToEdit.preset + Toggle("Use for new connections", isOn: $serverToEdit.enabled) + .disabled(useForNewDisabled) + .foregroundColor(useForNewDisabled ? theme.colors.secondary : theme.colors.onBackground) } } } @@ -185,8 +184,7 @@ struct ProtocolServerView_Previews: PreviewProvider { ProtocolServerView( serverProtocol: .smp, server: Binding.constant(ServerCfg.sampleData.custom), - serverToEdit: ServerCfg.sampleData.custom, - serverEnabled: true + serverToEdit: ServerCfg.sampleData.custom ) } } diff --git a/apps/ios/Shared/Views/UserSettings/ProtocolServersView.swift b/apps/ios/Shared/Views/UserSettings/ProtocolServersView.swift index 857bab69fb..ea1953e4ac 100644 --- a/apps/ios/Shared/Views/UserSettings/ProtocolServersView.swift +++ b/apps/ios/Shared/Views/UserSettings/ProtocolServersView.swift @@ -18,8 +18,9 @@ struct ProtocolServersView: View { @Environment(\.editMode) private var editMode let serverProtocol: ServerProtocol @State private var currServers: [ServerCfg] = [] - @State private var presetServers: [String] = [] - @State private var servers: [ServerCfg] = [] + @State private var presetServers: [ServerCfg] = [] + @State private var configuredServers: [ServerCfg] = [] + @State private var otherServers: [ServerCfg] = [] @State private var selectedServer: String? = nil @State private var showAddServer = false @State private var showScanProtoServer = false @@ -53,31 +54,53 @@ struct ProtocolServersView: View { private func protocolServersView() -> some View { List { - Section { - ForEach($servers) { srv in - protocolServerView(srv) + if !configuredServers.isEmpty { + Section { + ForEach($configuredServers) { srv in + protocolServerView(srv) + } + .onMove { indexSet, offset in + configuredServers.move(fromOffsets: indexSet, toOffset: offset) + } + .onDelete { indexSet in + configuredServers.remove(atOffsets: indexSet) + } + } header: { + Text("Configured \(proto) servers") + .foregroundColor(theme.colors.secondary) + } footer: { + Text("The servers for new connections of your current chat profile **\(m.currentUser?.displayName ?? "")**.") + .foregroundColor(theme.colors.secondary) + .lineLimit(10) } - .onMove { indexSet, offset in - servers.move(fromOffsets: indexSet, toOffset: offset) + } + + if !otherServers.isEmpty { + Section { + ForEach($otherServers) { srv in + protocolServerView(srv) + } + .onMove { indexSet, offset in + otherServers.move(fromOffsets: indexSet, toOffset: offset) + } + .onDelete { indexSet in + otherServers.remove(atOffsets: indexSet) + } + } header: { + Text("Other \(proto) servers") + .foregroundColor(theme.colors.secondary) } - .onDelete { indexSet in - servers.remove(atOffsets: indexSet) - } - Button("Add server…") { - showAddServer = true - } - } header: { - Text("\(proto) servers") - .foregroundColor(theme.colors.secondary) - } footer: { - Text("The servers for new connections of your current chat profile **\(m.currentUser?.displayName ?? "")**.") - .foregroundColor(theme.colors.secondary) - .lineLimit(10) } Section { - Button("Reset") { servers = currServers } - .disabled(servers == currServers || testing) + Button("Add server") { + showAddServer = true + } + } + + Section { + Button("Reset") { partitionServers(currServers) } + .disabled(Set(allServers) == Set(currServers) || testing) Button("Test servers", action: testServers) .disabled(testing || allServersDisabled) Button("Save servers", action: saveServers) @@ -86,17 +109,17 @@ struct ProtocolServersView: View { } } .toolbar { EditButton() } - .confirmationDialog("Add server…", isPresented: $showAddServer, titleVisibility: .hidden) { + .confirmationDialog("Add server", isPresented: $showAddServer, titleVisibility: .hidden) { Button("Enter server manually") { - servers.append(ServerCfg.empty) - selectedServer = servers.last?.id + otherServers.append(ServerCfg.empty) + selectedServer = allServers.last?.id } Button("Scan server QR code") { showScanProtoServer = true } Button("Add preset servers", action: addAllPresets) .disabled(hasAllPresets()) } .sheet(isPresented: $showScanProtoServer) { - ScanProtocolServer(servers: $servers) + ScanProtocolServer(servers: $otherServers) .modifier(ThemedBackground(grouped: true)) } .modifier(BackButton(disabled: Binding.constant(false)) { @@ -133,27 +156,39 @@ struct ProtocolServersView: View { } .onAppear { // this condition is needed to prevent re-setting the servers when exiting single server view - if !justOpened { return } - do { - let r = try getUserProtoServers(serverProtocol) - currServers = r.protoServers - presetServers = r.presetServers - servers = currServers - } catch let error { - alert = .error( - title: "Error loading \(proto) servers", - error: "Error: \(responseError(error))" - ) + if justOpened { + do { + let r = try getUserProtoServers(serverProtocol) + currServers = r.protoServers + presetServers = r.presetServers + partitionServers(currServers) + } catch let error { + alert = .error( + title: "Error loading \(proto) servers", + error: "Error: \(responseError(error))" + ) + } + justOpened = false + } else { + partitionServers(allServers) } - justOpened = false } } + private func partitionServers(_ servers: [ServerCfg]) { + configuredServers = servers.filter { $0.preset || $0.enabled } + otherServers = servers.filter { !($0.preset || $0.enabled) } + } + + private var allServers: [ServerCfg] { + configuredServers + otherServers + } + private var saveDisabled: Bool { - servers.isEmpty || - servers == currServers || + allServers.isEmpty || + Set(allServers) == Set(currServers) || testing || - !servers.allSatisfy { srv in + !allServers.allSatisfy { srv in if let address = parseServerAddress(srv.server) { return uniqueAddress(srv, address) } @@ -163,7 +198,7 @@ struct ProtocolServersView: View { } private var allServersDisabled: Bool { - servers.allSatisfy { $0.enabled != .enabled } + allServers.allSatisfy { !$0.enabled } } private func protocolServerView(_ server: Binding) -> some View { @@ -172,8 +207,7 @@ struct ProtocolServersView: View { ProtocolServerView( serverProtocol: serverProtocol, server: server, - serverToEdit: srv, - serverEnabled: srv.enabled == .enabled + serverToEdit: srv ) .navigationBarTitle(srv.preset ? "Preset server" : "Your server") .modifier(ThemedBackground(grouped: true)) @@ -187,7 +221,7 @@ struct ProtocolServersView: View { invalidServer() } else if !uniqueAddress(srv, address) { Image(systemName: "exclamationmark.circle").foregroundColor(.red) - } else if srv.enabled != .enabled { + } else if !srv.enabled { Image(systemName: "slash.circle").foregroundColor(theme.colors.secondary) } else { showTestStatus(server: srv) @@ -200,7 +234,7 @@ struct ProtocolServersView: View { .padding(.trailing, 4) let v = Text(address?.hostnames.first ?? srv.server).lineLimit(1) - if srv.enabled == .enabled { + if srv.enabled { v } else { v.foregroundColor(theme.colors.secondary) @@ -227,7 +261,7 @@ struct ProtocolServersView: View { } private func uniqueAddress(_ s: ServerCfg, _ address: ServerAddress) -> Bool { - servers.allSatisfy { srv in + allServers.allSatisfy { srv in address.hostnames.allSatisfy { host in srv.id == s.id || !srv.server.contains(host) } @@ -241,13 +275,13 @@ struct ProtocolServersView: View { private func addAllPresets() { for srv in presetServers { if !hasPreset(srv) { - servers.append(ServerCfg(server: srv, preset: true, tested: nil, enabled: .enabled)) + configuredServers.append(srv) } } } - private func hasPreset(_ srv: String) -> Bool { - servers.contains(where: { $0.server == srv }) + private func hasPreset(_ srv: ServerCfg) -> Bool { + allServers.contains(where: { $0.server == srv.server }) } private func testServers() { @@ -265,19 +299,31 @@ struct ProtocolServersView: View { } private func resetTestStatus() { - for i in 0.. [String: ProtocolTestFailure] { var fs: [String: ProtocolTestFailure] = [:] - for i in 0..Add servers by scanning QR codes. No comment provided by engineer. - - Add server… + + Add server No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff index 7ac1db1557..f3a70390da 100644 --- a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff +++ b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff @@ -615,9 +615,9 @@ Добави сървъри чрез сканиране на QR кодове. No comment provided by engineer. - - Add server… - Добави сървър… + + Add server + Добави сървър No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff b/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff index f599f9c300..b92196b78b 100644 --- a/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff +++ b/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff @@ -386,8 +386,8 @@ Add servers by scanning QR codes. No comment provided by engineer. - - Add server… + + Add server No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff index 392b9cf70d..46a890f5ba 100644 --- a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff +++ b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff @@ -596,9 +596,9 @@ Přidejte servery skenováním QR kódů. No comment provided by engineer. - - Add server… - Přidat server… + + Add server + Přidat server No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff index cc2773d5e4..656cc6c70e 100644 --- a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff +++ b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff @@ -615,9 +615,9 @@ Fügen Sie Server durch Scannen der QR Codes hinzu. No comment provided by engineer. - - Add server… - Füge Server hinzu… + + Add server + Füge Server hinzu No comment provided by engineer. @@ -1152,7 +1152,7 @@ Cellular - Zellulär + Mobilfunknetz No comment provided by engineer. @@ -1837,6 +1837,7 @@ Das ist Ihr eigener Einmal-Link! Debug delivery + Debugging-Zustellung No comment provided by engineer. @@ -3922,6 +3923,7 @@ Das ist Ihr Link für die Gruppe %@! Message queue info + Nachrichten-Warteschlangen-Information No comment provided by engineer. @@ -4817,7 +4819,7 @@ Fehler: %@ Protect your IP address from the messaging relays chosen by your contacts. Enable in *Network & servers* settings. - Schützen Sie Ihre IP-Adresse vor den Nachrichten-Relais , die Ihre Kontakte ausgewählt haben. + Schützen Sie Ihre IP-Adresse vor den Nachrichten-Relais, die Ihre Kontakte ausgewählt haben. Aktivieren Sie es in den *Netzwerk & Server* Einstellungen. No comment provided by engineer. @@ -8103,6 +8105,9 @@ SimpleX-Server können Ihr Profil nicht einsehen. server queue info: %1$@ last received msg: %2$@ + Server-Warteschlangen-Information: %1$@ + +Zuletzt empfangene Nachricht: %2$@ queue info diff --git a/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff b/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff index 18051ae350..b8432a33b6 100644 --- a/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff +++ b/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff @@ -336,8 +336,8 @@ Available in v5.1 Add servers by scanning QR codes. No comment provided by engineer. - - Add server… + + Add server No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff index 08e1255199..29f3f30d89 100644 --- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff +++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff @@ -618,9 +618,9 @@ Add servers by scanning QR codes. No comment provided by engineer. - - Add server… - Add server… + + Add server + Add server No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff index 3e37e6c6d5..a4cc2d2e68 100644 --- a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff +++ b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff @@ -615,9 +615,9 @@ Añadir servidores mediante el escaneo de códigos QR. No comment provided by engineer. - - Add server… - Añadir servidor… + + Add server + Añadir servidor No comment provided by engineer. @@ -1507,7 +1507,7 @@ This is your own one-time link! Connection error (AUTH) - Error conexión (Autenticación) + Error de conexión (Autenticación) No comment provided by engineer. @@ -1522,7 +1522,7 @@ This is your own one-time link! Connection timeout - Tiempo de conexión expirado + Tiempo de conexión agotado No comment provided by engineer. @@ -1837,6 +1837,7 @@ This is your own one-time link! Debug delivery + Informe debug No comment provided by engineer. @@ -3333,7 +3334,7 @@ Error: %2$@ If you can't meet in person, show QR code in a video call, or share the link. - Si no puedes reunirte en persona, muestra el código QR por videollamada, o comparte el enlace. + Si no puedes reunirte en persona, muestra el código QR por videollamada o comparte el enlace. No comment provided by engineer. @@ -3922,6 +3923,7 @@ This is your link for group %@! Message queue info + Información cola de mensajes No comment provided by engineer. @@ -4323,7 +4325,7 @@ This is your link for group %@! One-time invitation link - Enlace único de invitación de un uso + Enlace de invitación de un solo uso No comment provided by engineer. @@ -4467,7 +4469,7 @@ This is your link for group %@! Or scan QR code - O escanear código QR + O escanea el código QR No comment provided by engineer. @@ -4477,7 +4479,7 @@ This is your link for group %@! Or show this code - O mostrar este código + O muestra este código QR No comment provided by engineer. @@ -4547,7 +4549,7 @@ This is your link for group %@! Paste the link you received - Pegar el enlace recibido + Pega el enlace recibido No comment provided by engineer. @@ -4561,7 +4563,7 @@ This is your link for group %@! Periodically - Periódico + Periódicamente No comment provided by engineer. @@ -4828,12 +4830,12 @@ Actívalo en ajustes de *Servidores y Redes*. Protocol timeout - Tiempo de espera del protocolo + Timeout protocolo No comment provided by engineer. Protocol timeout per KB - Límite de espera del protocolo por KB + Timeout protocolo por KB No comment provided by engineer. @@ -4876,32 +4878,32 @@ Actívalo en ajustes de *Servidores y Redes*. Read more - Saber más + Conoce más No comment provided by engineer. Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). - Saber más en el [Manual del Usuario](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). + Conoce más en el [Manual del Usuario](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). - Saber más en [Guía de Usuario](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + Conoce más en la [Guía del Usuario](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). No comment provided by engineer. Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). - Saber más en el [Manual del Usuario](https://simplex.chat/docs/guide/readme.html#connect-to-friends). + Conoce más en el [Manual del Usuario](https://simplex.chat/docs/guide/readme.html#connect-to-friends). No comment provided by engineer. Read more in our GitHub repository. - Saber más en nuestro repositorio GitHub. + Conoce más en nuestro repositorio GitHub. No comment provided by engineer. Read more in our [GitHub repository](https://github.com/simplex-chat/simplex-chat#readme). - Saber más en nuestro [repositorio GitHub](https://github.com/simplex-chat/simplex-chat#readme). + Conoce más en nuestro [repositorio GitHub](https://github.com/simplex-chat/simplex-chat#readme). No comment provided by engineer. @@ -5755,7 +5757,7 @@ Actívalo en ajustes de *Servidores y Redes*. Share this 1-time invite link - Compartir este enlace de un uso + Comparte este enlace de un solo uso No comment provided by engineer. @@ -6037,7 +6039,7 @@ Actívalo en ajustes de *Servidores y Redes*. TCP connection timeout - Tiempo de espera de la conexión TCP agotado + Timeout de la conexión TCP No comment provided by engineer. @@ -6087,7 +6089,7 @@ Actívalo en ajustes de *Servidores y Redes*. Tap to paste link - Pulsa para pegar enlace + Pulsa para pegar el enlacePulsa para pegar enlace No comment provided by engineer. @@ -6355,7 +6357,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. To protect your IP address, private routing uses your SMP servers to deliver messages. - Para proteger tu dirección IP, el enrutamiento privado usa tus servidores SMP para enviar mensajes. + Para proteger tu dirección IP, el enrutamiento privado usa tu lista de servidores SMP para enviar mensajes. No comment provided by engineer. @@ -6516,9 +6518,8 @@ Se te pedirá que completes la autenticación antes de activar esta función. Unless your contact deleted the connection or this link was already used, it might be a bug - please report it. To connect, please ask your contact to create another connection link and check that you have a stable network connection. - A menos que tu contacto haya eliminado la conexión o -que este enlace ya se haya usado, podría ser un error. Por favor, notifícalo. -Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueba que tienes buena conexión de red. + A menos que tu contacto haya eliminado la conexión o el enlace haya sido usado, podría ser un error. Por favor, notifícalo. +Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión de red. No comment provided by engineer. @@ -6670,12 +6671,12 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb Use private routing with unknown servers when IP address is not protected. - Usar enrutamiento privado con servidores desconocidos cuando la dirección IP no está protegida. + Usar enrutamiento privado con servidores desconocidos cuando tu dirección IP no está protegida. No comment provided by engineer. Use private routing with unknown servers. - Usar enrutamiento privado con servidores desconocidos. + Usar enrutamiento privado con servidores de retransmisión desconocidos. No comment provided by engineer. @@ -7218,7 +7219,7 @@ Repeat connection request? You will be required to authenticate when you start or resume the app after 30 seconds in background. - Se te pedirá identificarte cuándo inicies o continues usando la aplicación tras 30 segundos en segundo plano. + Se te pedirá autenticarte cuando inicies la aplicación o sigas usándola tras 30 segundos en segundo plano. No comment provided by engineer. @@ -7351,8 +7352,8 @@ Puedes cancelarla y eliminar el contacto (e intentarlo más tarde con un enlace Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. - Tu perfil se almacena en tu dispositivo y sólo se comparte con tus contactos. -Los servidores de SimpleX no pueden ver tu perfil. + Tu perfil es almacenado en tu dispositivo y solamente se comparte con tus contactos. +Los servidores SimpleX no pueden ver tu perfil. No comment provided by engineer. @@ -8104,6 +8105,9 @@ Los servidores de SimpleX no pueden ver tu perfil. server queue info: %1$@ last received msg: %2$@ + información cola del servidor: %1$@ + +último mensaje recibido: %2$@ queue info @@ -8148,7 +8152,7 @@ last received msg: %2$@ unknown relays - servidor de retransmisión desconocido + con servidores desconocidos No comment provided by engineer. @@ -8158,7 +8162,7 @@ last received msg: %2$@ unprotected - desprotegido + con IP desprotegida No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff index 71e0f0796a..e132584d0e 100644 --- a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff +++ b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff @@ -591,9 +591,9 @@ Lisää palvelimia skannaamalla QR-koodeja. No comment provided by engineer. - - Add server… - Lisää palvelin… + + Add server + Lisää palvelin No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff index 4f618f26b0..5416324e89 100644 --- a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff +++ b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff @@ -615,9 +615,9 @@ Ajoutez des serveurs en scannant des codes QR. No comment provided by engineer. - - Add server… - Ajouter un serveur… + + Add server + Ajouter un serveur No comment provided by engineer. @@ -1837,6 +1837,7 @@ Il s'agit de votre propre lien unique ! Debug delivery + Livraison de débogage No comment provided by engineer. @@ -3922,6 +3923,7 @@ Voici votre lien pour le groupe %@ ! Message queue info + Informations sur la file d'attente des messages No comment provided by engineer. @@ -8103,6 +8105,9 @@ Les serveurs SimpleX ne peuvent pas voir votre profil. server queue info: %1$@ last received msg: %2$@ + info sur la file d'attente du serveur : %1$@ + +dernier message reçu : %2$@ queue info diff --git a/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff b/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff index 45cfe0c468..ee628c7935 100644 --- a/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff +++ b/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff @@ -403,9 +403,9 @@ Available in v5.1 הוספת שרתים על ידי סריקת קוד QR. No comment provided by engineer. - - Add server… - הוסף שרת… + + Add server + הוסף שרת No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/hi.xcloc/Localized Contents/hi.xliff b/apps/ios/SimpleX Localizations/hi.xcloc/Localized Contents/hi.xliff index 31746eccd9..a4ed3b39d8 100644 --- a/apps/ios/SimpleX Localizations/hi.xcloc/Localized Contents/hi.xliff +++ b/apps/ios/SimpleX Localizations/hi.xcloc/Localized Contents/hi.xliff @@ -300,8 +300,8 @@ Add servers by scanning QR codes. No comment provided by engineer. - - Add server… + + Add server No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/hr.xcloc/Localized Contents/hr.xliff b/apps/ios/SimpleX Localizations/hr.xcloc/Localized Contents/hr.xliff index abf15ee42d..50f5536e5e 100644 --- a/apps/ios/SimpleX Localizations/hr.xcloc/Localized Contents/hr.xliff +++ b/apps/ios/SimpleX Localizations/hr.xcloc/Localized Contents/hr.xliff @@ -367,8 +367,8 @@ Add servers by scanning QR codes. No comment provided by engineer. - - Add server… + + Add server No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff b/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff index ecc0610115..0264f5ffc4 100644 --- a/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff +++ b/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff @@ -497,7 +497,7 @@ <p>Hi!</p> <p><a href="%@">Connect to me via SimpleX Chat</a></p> <p>Üdvözlöm!</p> -<p><a href="%@">Csatlakozzon hozzám a SimpleX Chaten</a></p> +<p><a href=„%@”>Csatlakozzon hozzám a SimpleX Chaten</a></p> email text @@ -544,17 +544,17 @@ About SimpleX - A SimpleX névjegye + A SimpleX-ről No comment provided by engineer. About SimpleX Chat - A SimpleX Chat névjegye + A SimpleX Chat-ről No comment provided by engineer. About SimpleX address - A SimpleX azonosítóról + A SimpleX címről No comment provided by engineer. @@ -592,7 +592,7 @@ Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts. - Azonosító hozzáadása a profilhoz, hogy az ismerősei megoszthassák másokkal. A profilfrissítés elküldésre kerül az ismerősei számára. + Cím hozzáadása a profilhoz, hogy az ismerősei megoszthassák másokkal. A profilfrissítés elküldésre kerül az ismerősei számára. No comment provided by engineer. @@ -615,9 +615,9 @@ Kiszolgáló hozzáadása QR-kód beolvasásával. No comment provided by engineer. - - Add server… - Kiszolgáló hozzáadása… + + Add server + Kiszolgáló hozzáadása No comment provided by engineer. @@ -766,7 +766,7 @@ Allow sending direct messages to members. - Közvetlen üzenetek küldésének engedélyezése a tagok számára. + A közvetlen üzenetek küldése a tagok között engedélyezve van. No comment provided by engineer. @@ -999,7 +999,7 @@ Bad desktop address - Hibás számítógép azonosító + Hibás számítógép cím No comment provided by engineer. @@ -1033,7 +1033,7 @@ Block for all - Mindenki számára letiltva + Letiltás mindenki számára No comment provided by engineer. @@ -1108,7 +1108,7 @@ Camera not available - A fényképező nem elérhető + A kamera nem elérhető No comment provided by engineer. @@ -1428,7 +1428,7 @@ Connect to yourself? This is your own SimpleX address! Kapcsolódás saját magához? -Ez a SimpleX azonosítója! +Ez az ön SimpleX címe! No comment provided by engineer. @@ -1440,7 +1440,7 @@ Ez az egyszer használatos hivatkozása! Connect via contact address - Kapcsolódás a kapcsolattartási azonosítón keresztül + Kapcsolódás a kapcsolattartási címen keresztül No comment provided by engineer. @@ -1613,7 +1613,7 @@ Ez az egyszer használatos hivatkozása! Create SimpleX address - SimpleX azonosító létrehozása + SimpleX cím létrehozása No comment provided by engineer. @@ -1623,7 +1623,7 @@ Ez az egyszer használatos hivatkozása! Create an address to let people connect with you. - Azonosító létrehozása, hogy az emberek kapcsolatba léphessenek önnel. + Cím létrehozása, hogy az emberek kapcsolatba léphessenek önnel. No comment provided by engineer. @@ -1837,6 +1837,7 @@ Ez az egyszer használatos hivatkozása! Debug delivery + Kézbesítési hibák felderítése No comment provided by engineer. @@ -1866,12 +1867,12 @@ Ez az egyszer használatos hivatkozása! Delete address - Azonosító törlése + Cím törlése No comment provided by engineer. Delete address? - Azonosító törlése? + Cím törlése? No comment provided by engineer. @@ -2081,7 +2082,7 @@ Ez a művelet nem vonható vissza! Desktop address - Számítógép azonosítója + Számítógép címe No comment provided by engineer. @@ -2239,7 +2240,7 @@ Ez a művelet nem vonható vissza! Don't create address - Ne hozzon létre azonosítót + Ne hozzon létre címet No comment provided by engineer. @@ -2331,7 +2332,7 @@ Ez a művelet nem vonható vissza! Enable TCP keep-alive - TCP életben tartásának engedélyezése + TCP életben tartása No comment provided by engineer. @@ -2521,7 +2522,7 @@ Ez a művelet nem vonható vissza! Error aborting address change - Hiba az azonosító megváltoztatásának megszakításakor + Hiba a cím megváltoztatásának megszakításakor No comment provided by engineer. @@ -2541,7 +2542,7 @@ Ez a művelet nem vonható vissza! Error changing address - Hiba az azonosító megváltoztatásakor + Hiba a cím megváltoztatásakor No comment provided by engineer. @@ -2556,7 +2557,7 @@ Ez a művelet nem vonható vissza! Error creating address - Hiba az azonosító létrehozásakor + Hiba a cím létrehozásakor No comment provided by engineer. @@ -2712,7 +2713,7 @@ Ez a művelet nem vonható vissza! Error saving group profile - Hiba a csoport profil mentésekor + Hiba a csoportprofil mentésekor No comment provided by engineer. @@ -3223,7 +3224,7 @@ Hiba: %2$@ Group profile - Csoport profil + Csoportprofil No comment provided by engineer. @@ -3826,12 +3827,12 @@ Ez az ön hivatkozása a(z) %@ csoporthoz! Make sure %@ server addresses are in correct format, line separated and are not duplicated (%@). - Győződjön meg arról, hogy a %@ kiszolgálócímek megfelelő formátumúak, sorszeparáltak és nem duplikáltak (%@). + Győződjön meg arról, hogy a %@ kiszolgálócímek megfelelő formátumúak, sorszeparáltak és nincsenek duplikálva (%@). No comment provided by engineer. Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated. - Győződjön meg arról, hogy a WebRTC ICE-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nem duplikáltak. + Győződjön meg arról, hogy a WebRTC ICE-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nincsenek duplikálva. No comment provided by engineer. @@ -3875,12 +3876,12 @@ Ez az ön hivatkozása a(z) %@ csoporthoz! Member role will be changed to "%@". All group members will be notified. - A tag szerepköre meg fog változni erre: "%@". A csoport minden tagja értesítést kap róla. + A tag szerepköre meg fog változni erre: „%@”. A csoport minden tagja értesítést kap róla. No comment provided by engineer. Member role will be changed to "%@". The member will receive a new invitation. - A tag szerepköre meg fog változni erre: "%@". A tag új meghívást fog kapni. + A tag szerepköre meg fog változni erre: „%@”. A tag új meghívást fog kapni. No comment provided by engineer. @@ -3922,6 +3923,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz! Message queue info + Üzenet-várakoztatási információ No comment provided by engineer. @@ -4293,7 +4295,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz! - disable members ("observer" role) Most már az adminok is: - törölhetik a tagok üzeneteit. -- letilthatnak tagokat ("megfigyelő" szerepkör) +- letilthatnak tagokat („megfigyelő” szerepkör) No comment provided by engineer. @@ -4527,12 +4529,12 @@ Ez az ön hivatkozása a(z) %@ csoporthoz! Past member %@ - Korábbi csoport tag %@ + Már nem tag - %@ past/unknown group member Paste desktop address - Számítógép azonosítójának beillesztése + Számítógép címének beillesztése No comment provided by engineer. @@ -4786,7 +4788,7 @@ Hiba: %@ Prohibit sending direct messages to members. - A közvetlen üzenetek küldése le van tiltva a tagok között. + A közvetlen üzenetek küldése a tagok között le van tiltva. No comment provided by engineer. @@ -4806,7 +4808,7 @@ Hiba: %@ Protect IP address - Az IP-cím védelme + IP-cím védelem No comment provided by engineer. @@ -5037,12 +5039,12 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.< Relay server is only used if necessary. Another party can observe your IP address. - Az átjátszó kiszolgáló csak szükség esetén kerül használatra. Egy másik fél megfigyelheti az IP-címét. + Az átjátszó kiszolgáló csak szükség esetén kerül használatra. Egy másik fél megfigyelheti az IP-címet. No comment provided by engineer. Relay server protects your IP address, but it can observe the duration of the call. - Az átjátszó kiszolgáló megvédi IP-címét, de megfigyelheti a hívás időtartamát. + Az átjátszó kiszolgáló megvédi az IP-címet, de megfigyelheti a hívás időtartamát. No comment provided by engineer. @@ -5192,7 +5194,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.< Revert - Visszaállít + Visszaállítás No comment provided by engineer. @@ -5226,7 +5228,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.< SMP servers - Üzenetküldő (SMP) kiszolgálók + SMP kiszolgálók No comment provided by engineer. @@ -5261,7 +5263,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.< Save and update group profile - Mentés és a csoport profil frissítése + Mentés és csoportprofil frissítése No comment provided by engineer. @@ -5276,7 +5278,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.< Save group profile - Csoport profil elmentése + Csoportprofil elmentése No comment provided by engineer. @@ -5740,12 +5742,12 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.< Share address - Azonosító megosztása + Cím megosztása No comment provided by engineer. Share address with contacts? - Megosztja az azonosítót az ismerőseivel? + Megosztja a címet az ismerőseivel? No comment provided by engineer. @@ -5809,7 +5811,7 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.< SimpleX Address - SimpleX azonosító + SimpleX cím No comment provided by engineer. @@ -5839,12 +5841,12 @@ Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.< SimpleX address - SimpleX azonosító + SimpleX cím No comment provided by engineer. SimpleX contact address - SimpleX kapcsolattartási azonosító + SimpleX kapcsolattartási cím simplex link type @@ -6302,7 +6304,7 @@ Ez valamilyen hiba, vagy sérült kapcsolat esetén fordulhat elő. This is your own SimpleX address! - Ez a SimpleX azonosítója! + Ez az ön SimpleX címe! No comment provided by engineer. @@ -6355,7 +6357,7 @@ Ez valamilyen hiba, vagy sérült kapcsolat esetén fordulhat elő. To protect your IP address, private routing uses your SMP servers to deliver messages. - Az IP-címe védelme érdekében a privát útválasztás az SMP-kiszolgálókat használja az üzenetek kézbesítéséhez. + Az IP-cím védelmének érdekében a privát útválasztás az SMP kiszolgálókat használja az üzenetek kézbesítéséhez. No comment provided by engineer. @@ -6974,7 +6976,7 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol You accepted connection - Kapcsolódás elfogadva + Kapcsolat létrehozása No comment provided by engineer. @@ -7095,12 +7097,12 @@ Csatlakozási kérés megismétlése? You can share this address with your contacts to let them connect with **%@**. - Megoszthatja ezt az azonosítót az ismerőseivel, hogy kapcsolatba léphessenek önnel a **%@** nevű profilján keresztül. + Megoszthatja ezt a címet az ismerőseivel, hogy kapcsolatba léphessenek önnel a(z) **%@** nevű profilján keresztül. No comment provided by engineer. You can share your address as a link or QR code - anybody can connect to you. - Megoszthatja azonosítóját hivatkozásként vagy QR-kódként – így bárki kapcsolódhat önhöz. + Megoszthatja a címét egy hivatkozásként vagy QR-kódként – így bárki kapcsolódhat önhöz. No comment provided by engineer. @@ -7140,7 +7142,7 @@ Csatlakozási kérés megismétlése? You have already requested connection via this address! - Már kért egy kapcsolódási kérelmet ezen az azonosítón keresztül! + Már kért egy kapcsolódási kérelmet ezen a címen keresztül! No comment provided by engineer. @@ -7237,7 +7239,7 @@ Kapcsolódási kérés megismétlése? You won't lose your contacts if you later delete your address. - Nem veszíti el az ismerőseit, ha később törli az azonosítóját. + Nem veszíti el az ismerőseit, ha később törli a címét. No comment provided by engineer. @@ -7267,7 +7269,7 @@ Kapcsolódási kérés megismétlése? Your SimpleX address - SimpleX azonosítója + Az ön SimpleX címe No comment provided by engineer. @@ -7446,7 +7448,7 @@ A SimpleX kiszolgálók nem látjhatják profilját. and %lld other events - és %lld további esemény + és további %lld esemény No comment provided by engineer. @@ -7480,7 +7482,7 @@ A SimpleX kiszolgálók nem látjhatják profilját. blocked %@ - %@ letiltva + letiltotta őt: %@ rcv group event chat item @@ -7530,12 +7532,12 @@ A SimpleX kiszolgálók nem látjhatják profilját. changing address for %@… - cím módosítása %@ számára… + cím megváltoztatása nála: %@… chat item text changing address… - azonosító megváltoztatása… + cím megváltoztatása… chat item text @@ -7694,7 +7696,7 @@ A SimpleX kiszolgálók nem látjhatják profilját. duplicate message - duplikálódott üzenet + duplikált üzenet integrity error chat item @@ -7797,7 +7799,7 @@ A SimpleX kiszolgálók nem látjhatják profilját. group profile updated - csoport profil frissítve + csoportprofil frissítve snd group event chat item @@ -7976,7 +7978,7 @@ A SimpleX kiszolgálók nem látjhatják profilját. off - ki + kikapcsolva enabled status group pref value time to disappear @@ -8051,7 +8053,7 @@ A SimpleX kiszolgálók nem látjhatják profilját. removed contact address - törölt kapcsolattartási azonosító + törölt kapcsolattartási cím profile update event chat item @@ -8103,16 +8105,19 @@ A SimpleX kiszolgálók nem látjhatják profilját. server queue info: %1$@ last received msg: %2$@ + kiszolgáló üzenet-várakotatási információ: %1$@ + +utoljára fogadott üzenet: %2$@ queue info set new contact address - új kapcsolattartási azonosító beállítása + új kapcsolattartási cím beállítása profile update event chat item set new profile picture - új profilkép beállítása + új profilképet állított be profile update event chat item @@ -8182,7 +8187,7 @@ last received msg: %2$@ via contact address link - kapcsolattartási azonosító-hivatkozáson keresztül + kapcsolattartási cím-hivatkozáson keresztül chat list item description @@ -8257,12 +8262,12 @@ last received msg: %2$@ you changed address - azonosítója megváltoztatva + cím megváltoztatva chat item text you changed address for %@ - %@ azonosítója megváltoztatva + cím megváltoztatva nála: %@ chat item text diff --git a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff index 8d311a803c..024950730f 100644 --- a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff +++ b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff @@ -615,9 +615,9 @@ Aggiungi server scansionando codici QR. No comment provided by engineer. - - Add server… - Aggiungi server… + + Add server + Aggiungi server No comment provided by engineer. @@ -1837,6 +1837,7 @@ Questo è il tuo link una tantum! Debug delivery + Debug della consegna No comment provided by engineer. @@ -3922,6 +3923,7 @@ Questo è il tuo link per il gruppo %@! Message queue info + Info coda messaggi No comment provided by engineer. @@ -4702,7 +4704,7 @@ Errore: %@ Private message routing - Instradamento privato messaggi + Instradamento privato dei messaggi No comment provided by engineer. @@ -8103,6 +8105,9 @@ I server di SimpleX non possono vedere il tuo profilo. server queue info: %1$@ last received msg: %2$@ + info coda server: %1$@ + +ultimo msg ricevuto: %2$@ queue info diff --git a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff index 43f0f8f6cd..589973d1c0 100644 --- a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff +++ b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff @@ -608,9 +608,9 @@ QRコードでサーバを追加する。 No comment provided by engineer. - - Add server… - サーバを追加… + + Add server + サーバを追加 No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/ko.xcloc/Localized Contents/ko.xliff b/apps/ios/SimpleX Localizations/ko.xcloc/Localized Contents/ko.xliff index cc7b5522e6..511536427d 100644 --- a/apps/ios/SimpleX Localizations/ko.xcloc/Localized Contents/ko.xliff +++ b/apps/ios/SimpleX Localizations/ko.xcloc/Localized Contents/ko.xliff @@ -5,9 +5,11 @@ - + + + No comment provided by engineer. @@ -300,8 +302,8 @@ Add servers by scanning QR codes. No comment provided by engineer. - - Add server… + + Add server No comment provided by engineer. @@ -484,53 +486,62 @@ Can't delete user profile! No comment provided by engineer. - + Can't invite contact! + 주소를 초대할 수 없습니다. No comment provided by engineer. Can't invite contacts! No comment provided by engineer. - + Cancel + 취소 No comment provided by engineer. - + Cannot access keychain to save database password + 데이터베이스 암호를 저장하는 키체인에 접근 할 수 없습니다 No comment provided by engineer. - + Cannot receive file + 파일을 받을 수 없습니다 No comment provided by engineer. - + Change + 변경 No comment provided by engineer. Change database passphrase? No comment provided by engineer. - + Change member role? + 멤버 역할을 변경하시겠습니까? No comment provided by engineer. - + Change receiving address + 수신 주소 변경 No comment provided by engineer. Change receiving address? - 修改接收地址? + 수신 주소를 변경하시겠습니까? No comment provided by engineer. - + Change role + 역할 변경 No comment provided by engineer. - + Chat archive + 채팅 기록 보관함 No comment provided by engineer. @@ -545,8 +556,9 @@ Chat database deleted No comment provided by engineer. - + Chat database imported + 채팅 데이터베이스를 가져옴 No comment provided by engineer. @@ -2397,24 +2409,29 @@ We will be adding server redundancy to prevent lost messages. Send live message No comment provided by engineer. - + Send notifications + 알림 전송 No comment provided by engineer. - + Send notifications: + 알림 전송: No comment provided by engineer. - + Send questions and ideas + 질문이나 아이디어 보내기 No comment provided by engineer. - + Send them from gallery or custom keyboards. + 갤러리 또는 사용자 정의 키보드에서 그들을 보내십시오. No comment provided by engineer. - + Sender cancelled file transfer. + 상대방이 파일 전송을 취소했습니다. No comment provided by engineer. @@ -3755,6 +3772,26 @@ SimpleX servers cannot see your profile. \~strike~ No comment provided by engineer. + + Change passcode + 패스코드 변경 + authentication reason + + + Cellular + 셀룰러 + No comment provided by engineer. + + + Send messages directly when your or destination server does not support private routing. + 이 서버 또는 도착 서버가 비밀 라우팅을 지원하지 않을 때 직통 메시지 보내기. + No comment provided by engineer. + + + Send up to 100 last messages to new members. + 새로운 멤버에게 최대 100개의 마지막 메시지 보내기. + No comment provided by engineer. + @@ -3778,8 +3815,9 @@ SimpleX servers cannot see your profile. SimpleX needs microphone access for audio and video calls, and to record voice messages. Privacy - Microphone Usage Description - + SimpleX needs access to Photo Library for saving captured and received media + SimpleX는 캡처 및 수신 된 미디어를 저장하기 위해 사진 라이브러리에 접근이 필요합니다 Privacy - Photo Library Additions Usage Description @@ -3793,8 +3831,9 @@ SimpleX servers cannot see your profile. SimpleX NSE Bundle display name - + SimpleX NSE + SimpleX NSE Bundle name diff --git a/apps/ios/SimpleX Localizations/lt.xcloc/Localized Contents/lt.xliff b/apps/ios/SimpleX Localizations/lt.xcloc/Localized Contents/lt.xliff index feb1e177f1..6df24149e9 100644 --- a/apps/ios/SimpleX Localizations/lt.xcloc/Localized Contents/lt.xliff +++ b/apps/ios/SimpleX Localizations/lt.xcloc/Localized Contents/lt.xliff @@ -329,9 +329,9 @@ Pridėti serverius skenuojant QR kodus. No comment provided by engineer. - - Add server… - Pridėti serverį… + + Add server + Pridėti serverį No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/ml.xcloc/Localized Contents/ml.xliff b/apps/ios/SimpleX Localizations/ml.xcloc/Localized Contents/ml.xliff index f4a1a815ea..1726f2ea77 100644 --- a/apps/ios/SimpleX Localizations/ml.xcloc/Localized Contents/ml.xliff +++ b/apps/ios/SimpleX Localizations/ml.xcloc/Localized Contents/ml.xliff @@ -367,8 +367,8 @@ Add servers by scanning QR codes. No comment provided by engineer. - - Add server… + + Add server No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff index fdfd49c3d3..44fda15333 100644 --- a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff +++ b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff @@ -615,9 +615,9 @@ Servers toevoegen door QR-codes te scannen. No comment provided by engineer. - - Add server… - Server toevoegen… + + Add server + Server toevoegen No comment provided by engineer. @@ -1837,6 +1837,7 @@ Dit is uw eigen eenmalige link! Debug delivery + Foutopsporing bezorging No comment provided by engineer. @@ -3922,6 +3923,7 @@ Dit is jouw link voor groep %@! Message queue info + Informatie over berichtenwachtrij No comment provided by engineer. @@ -8103,6 +8105,9 @@ SimpleX servers kunnen uw profiel niet zien. server queue info: %1$@ last received msg: %2$@ + informatie over serverwachtrij: %1$@ + +laatst ontvangen bericht: %2$@ queue info diff --git a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff index 9da2b6bd82..dd4aecf428 100644 --- a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff +++ b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff @@ -615,9 +615,9 @@ Dodaj serwery, skanując kody QR. No comment provided by engineer. - - Add server… - Dodaj serwer… + + Add server + Dodaj serwer No comment provided by engineer. @@ -1837,6 +1837,7 @@ To jest twój jednorazowy link! Debug delivery + Dostarczenie debugowania No comment provided by engineer. @@ -3922,6 +3923,7 @@ To jest twój link do grupy %@! Message queue info + Informacje kolejki wiadomości No comment provided by engineer. @@ -8103,6 +8105,9 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu. server queue info: %1$@ last received msg: %2$@ + Informacje kolejki serwera: %1$@ + +ostatnia otrzymana wiadomość: %2$@ queue info diff --git a/apps/ios/SimpleX Localizations/pt-BR.xcloc/Localized Contents/pt-BR.xliff b/apps/ios/SimpleX Localizations/pt-BR.xcloc/Localized Contents/pt-BR.xliff index b4fa69449f..0abab468fd 100644 --- a/apps/ios/SimpleX Localizations/pt-BR.xcloc/Localized Contents/pt-BR.xliff +++ b/apps/ios/SimpleX Localizations/pt-BR.xcloc/Localized Contents/pt-BR.xliff @@ -374,9 +374,9 @@ Adicione servidores escaneando o QR code. No comment provided by engineer. - - Add server… - Adicionar servidor… + + Add server + Adicionar servidor No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/pt.xcloc/Localized Contents/pt.xliff b/apps/ios/SimpleX Localizations/pt.xcloc/Localized Contents/pt.xliff index c9c9707c39..a9bf86e778 100644 --- a/apps/ios/SimpleX Localizations/pt.xcloc/Localized Contents/pt.xliff +++ b/apps/ios/SimpleX Localizations/pt.xcloc/Localized Contents/pt.xliff @@ -5,9 +5,11 @@ - + + + No comment provided by engineer. @@ -50,16 +52,19 @@ Available in v5.1 #secreto# No comment provided by engineer. - + %@ + %@ No comment provided by engineer. - + %@ %@ + %@ %@ No comment provided by engineer. - + %@ / %@ + %@ / %@ No comment provided by engineer. @@ -117,12 +122,14 @@ Available in v5.1 %d mensagem(s) ignorada(s) integrity error chat item - + %lld + %lld No comment provided by engineer. - + %lld %@ + %lld %@ No comment provided by engineer. @@ -155,24 +162,29 @@ Available in v5.1 %lld segundos No comment provided by engineer. - + %lldd + %lldd No comment provided by engineer. - + %lldh + %lldh No comment provided by engineer. - + %lldk + %lldk No comment provided by engineer. - + %lldm + %lldm No comment provided by engineer. - + %lldmth + %lldmth No comment provided by engineer. @@ -193,8 +205,9 @@ Available in v5.1 %u mensagens ignoradas. No comment provided by engineer. - + ( + ( No comment provided by engineer. @@ -359,8 +372,8 @@ Available in v5.1 Add servers by scanning QR codes. No comment provided by engineer. - - Add server… + + Add server No comment provided by engineer. @@ -4540,6 +4553,31 @@ SimpleX servers cannot see your profile. Confirmar envio No comment provided by engineer. + + %@ downloaded + %@ baixado + No comment provided by engineer. + + + # %@ + # %@ + copied message info title, # <title> + + + %@: + %@: + copied message info + + + %@ (current) + %@(atual) + No comment provided by engineer. + + + %@ (current): + %@ (atual): + copied message info + diff --git a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff index db7f5bfb9e..f4ad23262c 100644 --- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff +++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff @@ -615,9 +615,9 @@ Добавить серверы через QR код. No comment provided by engineer. - - Add server… - Добавить сервер… + + Add server + Добавить сервер No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff index a71061d578..7e3298ed58 100644 --- a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff +++ b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff @@ -583,9 +583,9 @@ เพิ่มเซิร์ฟเวอร์โดยการสแกนรหัสคิวอาร์โค้ด No comment provided by engineer. - - Add server… - เพิ่มเซิร์ฟเวอร์… + + Add server + เพิ่มเซิร์ฟเวอร์ No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff index 66f24d5bb7..15ea09d060 100644 --- a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff +++ b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff @@ -615,9 +615,9 @@ Karekod taratarak sunucuları ekleyin. No comment provided by engineer. - - Add server… - Sunucu ekle… + + Add server + Sunucu ekle No comment provided by engineer. @@ -1837,6 +1837,7 @@ Bu senin kendi tek kullanımlık bağlantın! Debug delivery + Hata ayıklama teslimatı No comment provided by engineer. @@ -3922,6 +3923,7 @@ Bu senin grup için bağlantın %@! Message queue info + Mesaj kuyruğu bilgisi No comment provided by engineer. @@ -8103,6 +8105,9 @@ SimpleX sunucuları profilinizi göremez. server queue info: %1$@ last received msg: %2$@ + sunucu kuyruk bilgisi: %1$@ + +son alınan msj: %2$@ queue info diff --git a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff index bf0b5718f7..aa069d444b 100644 --- a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff +++ b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff @@ -615,9 +615,9 @@ Додайте сервери, відсканувавши QR-код. No comment provided by engineer. - - Add server… - Додати сервер… + + Add server + Додати сервер No comment provided by engineer. @@ -1837,6 +1837,7 @@ This is your own one-time link! Debug delivery + Доставка налагодження No comment provided by engineer. @@ -3922,6 +3923,7 @@ This is your link for group %@! Message queue info + Інформація про чергу повідомлень No comment provided by engineer. @@ -8103,6 +8105,9 @@ SimpleX servers cannot see your profile. server queue info: %1$@ last received msg: %2$@ + інформація про чергу на сервері: %1$@ + +останнє отримане повідомлення: %2$@ queue info diff --git a/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff b/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff index 5d1852b0b4..3823d6e6a9 100644 --- a/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff +++ b/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff @@ -603,9 +603,9 @@ 扫描二维码来添加服务器。 No comment provided by engineer. - - Add server… - 添加服务器… + + Add server + 添加服务器 No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff b/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff index 03a108d112..8bc5a3b25d 100644 --- a/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff +++ b/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff @@ -358,9 +358,9 @@ 使用二維碼掃描以新增伺服器。 No comment provided by engineer. - - Add server… - 新增伺服器… + + Add server + 新增伺服器 No comment provided by engineer. diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 9bd72ff5a9..dba8db792a 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -100,7 +100,6 @@ 5CB924D727A8563F00ACCCDD /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB924D627A8563F00ACCCDD /* SettingsView.swift */; }; 5CB924E127A867BA00ACCCDD /* UserProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB924E027A867BA00ACCCDD /* UserProfile.swift */; }; 5CB9250D27A9432000ACCCDD /* ChatListNavLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB9250C27A9432000ACCCDD /* ChatListNavLink.swift */; }; - 5CBD285A295711D700EC2CF4 /* ImageUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBD2859295711D700EC2CF4 /* ImageUtils.swift */; }; 5CBD285C29575B8E00EC2CF4 /* WhatsNewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBD285B29575B8E00EC2CF4 /* WhatsNewView.swift */; }; 5CBE6C12294487F7002D9531 /* VerifyCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBE6C11294487F7002D9531 /* VerifyCodeView.swift */; }; 5CBE6C142944CC12002D9531 /* ScanCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBE6C132944CC12002D9531 /* ScanCodeView.swift */; }; @@ -195,6 +194,8 @@ 8C9BC2652C240D5200875A27 /* ThemeModeEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C9BC2642C240D5100875A27 /* ThemeModeEditor.swift */; }; 8CC4ED902BD7B8530078AEE8 /* CallAudioDeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */; }; 8CC956EE2BC0041000412A11 /* NetworkObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC956ED2BC0041000412A11 /* NetworkObserver.swift */; }; + CE38A29A2C3FCA54005ED185 /* ImageUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBD2859295711D700EC2CF4 /* ImageUtils.swift */; }; + CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = CE38A29B2C3FCD72005ED185 /* SwiftyGif */; }; CE984D4B2C36C5D500E3AEFF /* ChatItemClipShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE984D4A2C36C5D500E3AEFF /* ChatItemClipShape.swift */; }; CEEA861D2C2ABCB50084E1EA /* ReverseList.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEA861C2C2ABCB50084E1EA /* ReverseList.swift */; }; D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; }; @@ -560,6 +561,7 @@ E50581022C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN-ghc9.6.3.a in Frameworks */, E50581062C3DDD9D009C3F71 /* Yams in Frameworks */, E50581042C3DDD7F009C3F71 /* libHSsimplex-chat-6.0.0.0-IhofDzGnTMcDdW5i3Fb7xN.a in Frameworks */, + CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -658,7 +660,6 @@ 5CF937212B25034A00E1D781 /* NSESubscriber.swift */, 5CB346E82869E8BA001FD2EF /* PushEnvironment.swift */, 5C93293E2928E0FD0090FFF9 /* AudioRecPlay.swift */, - 5CBD2859295711D700EC2CF4 /* ImageUtils.swift */, 8CC956ED2BC0041000412A11 /* NetworkObserver.swift */, ); path = Model; @@ -858,6 +859,7 @@ 5C9FD96A27A56D4D0075386C /* JSON.swift */, 5CDCAD7D2818941F00503DA2 /* API.swift */, 5CDCAD80281A7E2700503DA2 /* Notifications.swift */, + 5CBD2859295711D700EC2CF4 /* ImageUtils.swift */, 64DAE1502809D9F5000DA960 /* FileUtils.swift */, 5C9D81182AA7A4F1001D49FD /* CryptoFile.swift */, 5C00168028C4FE760094D739 /* KeyChain.swift */, @@ -1068,6 +1070,7 @@ name = SimpleXChat; packageProductDependencies = ( E50581052C3DDD9D009C3F71 /* Yams */, + CE38A29B2C3FCD72005ED185 /* SwiftyGif */, ); productName = SimpleXChat; productReference = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; @@ -1205,7 +1208,6 @@ 6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */, 5C93293129239BED0090FFF9 /* ProtocolServerView.swift in Sources */, 5C9CC7AD28C55D7800BEF955 /* DatabaseEncryptionView.swift in Sources */, - 5CBD285A295711D700EC2CF4 /* ImageUtils.swift in Sources */, 8C74C3EC2C1B92A900039E77 /* Theme.swift in Sources */, 6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */, 5CE4407927ADB701007B033A /* EmojiItemView.swift in Sources */, @@ -1376,6 +1378,7 @@ 5CE2BA90284533A300EC33A6 /* JSON.swift in Sources */, 5CE2BA8B284533A300EC33A6 /* ChatTypes.swift in Sources */, 5CE2BA8F284533A300EC33A6 /* APITypes.swift in Sources */, + CE38A29A2C3FCA54005ED185 /* ImageUtils.swift in Sources */, 5C9D811A2AA8727A001D49FD /* CryptoFile.swift in Sources */, 5CE2BA8C284533A300EC33A6 /* AppGroup.swift in Sources */, 8C74C3E52C1B900600039E77 /* ThemeTypes.swift in Sources */, @@ -2023,6 +2026,11 @@ package = 8C73C1162C21E17B00892670 /* XCRemoteSwiftPackageReference "Yams" */; productName = Yams; }; + CE38A29B2C3FCD72005ED185 /* SwiftyGif */ = { + isa = XCSwiftPackageProductDependency; + package = D77B92DA2952372200A5A1CC /* XCRemoteSwiftPackageReference "SwiftyGif" */; + productName = SwiftyGif; + }; D7197A1729AE89660055C05A /* WebRTC */ = { isa = XCSwiftPackageProductDependency; package = D7197A1629AE89660055C05A /* XCRemoteSwiftPackageReference "WebRTC" */; diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index 2d3663b9f8..d5cd9c8f3b 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -1122,20 +1122,20 @@ public struct ProtoServersConfig: Codable { public struct UserProtoServers: Decodable { public var serverProtocol: ServerProtocol public var protoServers: [ServerCfg] - public var presetServers: [String] + public var presetServers: [ServerCfg] } -public struct ServerCfg: Identifiable, Equatable, Codable { +public struct ServerCfg: Identifiable, Equatable, Codable, Hashable { public var server: String public var preset: Bool public var tested: Bool? - public var enabled: ServerEnabled + public var enabled: Bool var createdAt = Date() // public var sendEnabled: Bool // can we potentially want to prevent sending on the servers we use to receive? // Even if we don't see the use case, it's probably better to allow it in the model // In any case, "trusted/known" servers are out of scope of this change - public init(server: String, preset: Bool, tested: Bool?, enabled: ServerEnabled) { + public init(server: String, preset: Bool, tested: Bool?, enabled: Bool) { self.server = server self.preset = preset self.tested = tested @@ -1148,7 +1148,7 @@ public struct ServerCfg: Identifiable, Equatable, Codable { public var id: String { "\(server) \(createdAt)" } - public static var empty = ServerCfg(server: "", preset: false, tested: nil, enabled: .enabled) + public static var empty = ServerCfg(server: "", preset: false, tested: nil, enabled: false) public var isEmpty: Bool { server.trimmingCharacters(in: .whitespaces) == "" @@ -1165,19 +1165,19 @@ public struct ServerCfg: Identifiable, Equatable, Codable { server: "smp://abcd@smp8.simplex.im", preset: true, tested: true, - enabled: .enabled + enabled: true ), custom: ServerCfg( server: "smp://abcd@smp9.simplex.im", preset: false, tested: false, - enabled: .disabled + enabled: false ), untested: ServerCfg( server: "smp://abcd@smp10.simplex.im", preset: false, tested: nil, - enabled: .enabled + enabled: true ) ) @@ -1189,12 +1189,6 @@ public struct ServerCfg: Identifiable, Equatable, Codable { } } -public enum ServerEnabled: String, Codable { - case disabled - case enabled - case known -} - public enum ProtocolTestStep: String, Decodable, Equatable { case connect case disconnect @@ -1906,6 +1900,7 @@ public enum AgentErrorType: Decodable, Hashable { case SMP(smpErr: ProtocolErrorType) case NTF(ntfErr: ProtocolErrorType) case XFTP(xftpErr: XFTPErrorType) + case PROXY(proxyServer: String, relayServer: String, proxyErr: ProxyClientError) case RCP(rcpErr: RCErrorType) case BROKER(brokerAddress: String, brokerErr: BrokerErrorType) case AGENT(agentErr: SMPAgentError) @@ -1943,13 +1938,23 @@ public enum ProtocolErrorType: Decodable, Hashable { case BLOCK case SESSION case CMD(cmdErr: ProtocolCommandError) + indirect case PROXY(proxyErr: ProxyError) case AUTH + case CRYPTO case QUOTA case NO_MSG case LARGE_MSG + case EXPIRED case INTERNAL } +public enum ProxyError: Decodable, Hashable { + case PROTOCOL(protocolErr: ProtocolErrorType) + case BROKER(brokerErr: BrokerErrorType) + case BASIC_AUTH + case NO_SESSION +} + public enum XFTPErrorType: Decodable, Hashable { case BLOCK case SESSION @@ -1967,6 +1972,12 @@ public enum XFTPErrorType: Decodable, Hashable { case INTERNAL } +public enum ProxyClientError: Decodable, Hashable { + case protocolError(protocolErr: ProtocolErrorType) + case unexpectedResponse(responseStr: String) + case responseError(responseErr: ProtocolErrorType) +} + public enum RCErrorType: Decodable, Hashable { case `internal`(internalErr: String) case identity @@ -1996,6 +2007,7 @@ public enum ProtocolCommandError: Decodable, Hashable { public enum ProtocolTransportError: Decodable, Hashable { case badBlock + case version case largeMsg case badSession case noServerAuth diff --git a/apps/ios/Shared/Model/ImageUtils.swift b/apps/ios/SimpleXChat/ImageUtils.swift similarity index 88% rename from apps/ios/Shared/Model/ImageUtils.swift rename to apps/ios/SimpleXChat/ImageUtils.swift index 073621caa4..fd6d951f48 100644 --- a/apps/ios/Shared/Model/ImageUtils.swift +++ b/apps/ios/SimpleXChat/ImageUtils.swift @@ -7,18 +7,18 @@ // import Foundation -import SimpleXChat import SwiftUI import AVKit +import SwiftyGif -func getLoadedFileSource(_ file: CIFile?) -> CryptoFile? { +public func getLoadedFileSource(_ file: CIFile?) -> CryptoFile? { if let file = file, file.loaded { return file.fileSource } return nil } -func getLoadedImage(_ file: CIFile?) -> UIImage? { +public func getLoadedImage(_ file: CIFile?) -> UIImage? { if let fileSource = getLoadedFileSource(file) { let filePath = getAppFilePath(fileSource.filePath) do { @@ -37,7 +37,7 @@ func getLoadedImage(_ file: CIFile?) -> UIImage? { return nil } -func getFileData(_ path: URL, _ cfArgs: CryptoFileArgs?) throws -> Data { +public func getFileData(_ path: URL, _ cfArgs: CryptoFileArgs?) throws -> Data { if let cfArgs = cfArgs { return try readCryptoFile(path: path.path, cryptoArgs: cfArgs) } else { @@ -45,7 +45,7 @@ func getFileData(_ path: URL, _ cfArgs: CryptoFileArgs?) throws -> Data { } } -func getLoadedVideo(_ file: CIFile?) -> URL? { +public func getLoadedVideo(_ file: CIFile?) -> URL? { if let fileSource = getLoadedFileSource(file) { let filePath = getAppFilePath(fileSource.filePath) if FileManager.default.fileExists(atPath: filePath.path) { @@ -55,13 +55,13 @@ func getLoadedVideo(_ file: CIFile?) -> URL? { return nil } -func saveAnimImage(_ image: UIImage) -> CryptoFile? { +public func saveAnimImage(_ image: UIImage) -> CryptoFile? { let fileName = generateNewFileName("IMG", "gif") guard let imageData = image.imageData else { return nil } return saveFile(imageData, fileName, encrypted: privacyEncryptLocalFilesGroupDefault.get()) } -func saveImage(_ uiImage: UIImage) -> CryptoFile? { +public func saveImage(_ uiImage: UIImage) -> CryptoFile? { let hasAlpha = imageHasAlpha(uiImage) let ext = hasAlpha ? "png" : "jpg" if let imageDataResized = resizeImageToDataSize(uiImage, maxDataSize: MAX_IMAGE_SIZE, hasAlpha: hasAlpha) { @@ -71,7 +71,7 @@ func saveImage(_ uiImage: UIImage) -> CryptoFile? { return nil } -func cropToSquare(_ image: UIImage) -> UIImage { +public func cropToSquare(_ image: UIImage) -> UIImage { let size = image.size let side = min(size.width, size.height) let newSize = CGSize(width: side, height: side) @@ -84,7 +84,7 @@ func cropToSquare(_ image: UIImage) -> UIImage { return resizeImage(image, newBounds: CGRect(origin: .zero, size: newSize), drawIn: CGRect(origin: origin, size: size), hasAlpha: imageHasAlpha(image)) } -func resizeImageToDataSize(_ image: UIImage, maxDataSize: Int64, hasAlpha: Bool) -> Data? { +public func resizeImageToDataSize(_ image: UIImage, maxDataSize: Int64, hasAlpha: Bool) -> Data? { var img = image var data = hasAlpha ? img.pngData() : img.jpegData(compressionQuality: 0.85) var dataSize = data?.count ?? 0 @@ -99,7 +99,7 @@ func resizeImageToDataSize(_ image: UIImage, maxDataSize: Int64, hasAlpha: Bool) return data } -func resizeImageToStrSize(_ image: UIImage, maxDataSize: Int64) -> String? { +public func resizeImageToStrSize(_ image: UIImage, maxDataSize: Int64) -> String? { var img = image let hasAlpha = imageHasAlpha(image) var str = compressImageStr(img, hasAlpha: hasAlpha) @@ -115,7 +115,7 @@ func resizeImageToStrSize(_ image: UIImage, maxDataSize: Int64) -> String? { return str } -func compressImageStr(_ image: UIImage, _ compressionQuality: CGFloat = 0.85, hasAlpha: Bool) -> String? { +public func compressImageStr(_ image: UIImage, _ compressionQuality: CGFloat = 0.85, hasAlpha: Bool) -> String? { let ext = hasAlpha ? "png" : "jpg" if let data = hasAlpha ? image.pngData() : image.jpegData(compressionQuality: compressionQuality) { return "data:image/\(ext);base64,\(data.base64EncodedString())" @@ -138,7 +138,7 @@ private func resizeImage(_ image: UIImage, newBounds: CGRect, drawIn: CGRect, ha } } -func imageHasAlpha(_ img: UIImage) -> Bool { +public func imageHasAlpha(_ img: UIImage) -> Bool { if let cgImage = img.cgImage { let colorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue) @@ -158,7 +158,7 @@ func imageHasAlpha(_ img: UIImage) -> Bool { return false } -func saveFileFromURL(_ url: URL) -> CryptoFile? { +public func saveFileFromURL(_ url: URL) -> CryptoFile? { let encrypted = privacyEncryptLocalFilesGroupDefault.get() let savedFile: CryptoFile? if url.startAccessingSecurityScopedResource() { @@ -184,7 +184,7 @@ func saveFileFromURL(_ url: URL) -> CryptoFile? { return savedFile } -func moveTempFileFromURL(_ url: URL) -> CryptoFile? { +public func moveTempFileFromURL(_ url: URL) -> CryptoFile? { do { let encrypted = privacyEncryptLocalFilesGroupDefault.get() let fileName = uniqueCombine(url.lastPathComponent) @@ -197,7 +197,6 @@ func moveTempFileFromURL(_ url: URL) -> CryptoFile? { try FileManager.default.moveItem(at: url, to: getAppFilePath(fileName)) savedFile = CryptoFile.plain(fileName) } - ChatModel.shared.filesToDelete.remove(url) return savedFile } catch { logger.error("ImageUtils.moveTempFileFromURL error: \(error.localizedDescription)") @@ -205,7 +204,7 @@ func moveTempFileFromURL(_ url: URL) -> CryptoFile? { } } -func saveWallpaperFile(url: URL) -> String? { +public func saveWallpaperFile(url: URL) -> String? { let destFile = URL(fileURLWithPath: generateNewFileName(getWallpaperDirectory().path + "/" + "wallpaper", "jpg", fullPath: true)) do { try FileManager.default.copyItem(atPath: url.path, toPath: destFile.path) @@ -216,7 +215,7 @@ func saveWallpaperFile(url: URL) -> String? { } } -func saveWallpaperFile(image: UIImage) -> String? { +public func saveWallpaperFile(image: UIImage) -> String? { let hasAlpha = imageHasAlpha(image) let destFile = URL(fileURLWithPath: generateNewFileName(getWallpaperDirectory().path + "/" + "wallpaper", hasAlpha ? "png" : "jpg", fullPath: true)) let dataResized = resizeImageToDataSize(image, maxDataSize: 5_000_000, hasAlpha: hasAlpha) @@ -229,7 +228,7 @@ func saveWallpaperFile(image: UIImage) -> String? { } } -func removeWallpaperFile(fileName: String? = nil) { +public func removeWallpaperFile(fileName: String? = nil) { do { try FileManager.default.contentsOfDirectory(atPath: getWallpaperDirectory().path).forEach { if URL(fileURLWithPath: $0).lastPathComponent == fileName { try FileManager.default.removeItem(atPath: $0) } @@ -242,7 +241,7 @@ func removeWallpaperFile(fileName: String? = nil) { } } -func generateNewFileName(_ prefix: String, _ ext: String, fullPath: Bool = false) -> String { +public func generateNewFileName(_ prefix: String, _ ext: String, fullPath: Bool = false) -> String { uniqueCombine("\(prefix)_\(getTimestamp()).\(ext)", fullPath: fullPath) } @@ -274,7 +273,7 @@ private func getTimestamp() -> String { return df.string(from: Date()) } -func dropImagePrefix(_ s: String) -> String { +public func dropImagePrefix(_ s: String) -> String { dropPrefix(dropPrefix(s, "data:image/png;base64,"), "data:image/jpg;base64,") } @@ -283,7 +282,7 @@ private func dropPrefix(_ s: String, _ prefix: String) -> String { } extension AVAsset { - func generatePreview() -> (UIImage, Int)? { + public func generatePreview() -> (UIImage, Int)? { let generator = AVAssetImageGenerator(asset: self) generator.appliesPreferredTrackTransform = true var actualTime = CMTimeMake(value: 0, timescale: 0) @@ -295,7 +294,7 @@ extension AVAsset { } extension UIImage { - func replaceColor(_ from: UIColor, _ to: UIColor) -> UIImage { + public func replaceColor(_ from: UIColor, _ to: UIColor) -> UIImage { if let cgImage = cgImage { let colorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue) @@ -340,4 +339,12 @@ extension UIImage { } return self } + + public convenience init?(base64Encoded: String?) { + if let base64Encoded, let data = Data(base64Encoded: dropImagePrefix(base64Encoded)) { + self.init(data: data) + } else { + return nil + } + } } diff --git a/apps/ios/bg.lproj/Localizable.strings b/apps/ios/bg.lproj/Localizable.strings index 5fe8fe909c..9748a26730 100644 --- a/apps/ios/bg.lproj/Localizable.strings +++ b/apps/ios/bg.lproj/Localizable.strings @@ -337,9 +337,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "по-горе, след това избери:"; -/* No comment provided by engineer. */ -"Accent color" = "Основен цвят"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Приеми"; @@ -369,7 +366,7 @@ "Add profile" = "Добави профил"; /* No comment provided by engineer. */ -"Add server…" = "Добави сървър…"; +"Add server" = "Добави сървър"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Добави сървъри чрез сканиране на QR кодове."; @@ -647,7 +644,7 @@ /* rcv group event chat item */ "blocked %@" = "блокиран %@"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "блокиран от админ"; /* No comment provided by engineer. */ @@ -831,9 +828,6 @@ /* No comment provided by engineer. */ "colored" = "цветен"; -/* No comment provided by engineer. */ -"Colors" = "Цветове"; - /* server test step */ "Compare file" = "Сравни файл"; @@ -1011,7 +1005,7 @@ /* No comment provided by engineer. */ "Continue" = "Продължи"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Копирай"; /* No comment provided by engineer. */ @@ -1779,7 +1773,8 @@ /* No comment provided by engineer. */ "Error: " = "Грешка: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Грешка: %@"; /* No comment provided by engineer. */ @@ -3791,9 +3786,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "Текстът, който поставихте, не е SimpleX линк за връзка."; -/* No comment provided by engineer. */ -"Theme" = "Тема"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Тези настройки са за текущия ви профил **%@**."; diff --git a/apps/ios/cs.lproj/Localizable.strings b/apps/ios/cs.lproj/Localizable.strings index bbe46b225f..95c79efd8b 100644 --- a/apps/ios/cs.lproj/Localizable.strings +++ b/apps/ios/cs.lproj/Localizable.strings @@ -289,9 +289,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "výše, pak vyberte:"; -/* No comment provided by engineer. */ -"Accent color" = "Zbarvení"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Přijmout"; @@ -318,7 +315,7 @@ "Add profile" = "Přidat profil"; /* No comment provided by engineer. */ -"Add server…" = "Přidat server…"; +"Add server" = "Přidat server"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Přidejte servery skenováním QR kódů."; @@ -678,9 +675,6 @@ /* No comment provided by engineer. */ "colored" = "barevné"; -/* No comment provided by engineer. */ -"Colors" = "Barvy"; - /* server test step */ "Compare file" = "Porovnat soubor"; @@ -813,7 +807,7 @@ /* No comment provided by engineer. */ "Continue" = "Pokračovat"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Kopírovat"; /* No comment provided by engineer. */ @@ -1461,7 +1455,8 @@ /* No comment provided by engineer. */ "Error: " = "Chyba: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Chyba: %@"; /* No comment provided by engineer. */ @@ -3095,9 +3090,6 @@ /* No comment provided by engineer. */ "The servers for new connections of your current chat profile **%@**." = "Servery pro nová připojení vašeho aktuálního chat profilu **%@**."; -/* No comment provided by engineer. */ -"Theme" = "Téma"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Toto nastavení je pro váš aktuální profil **%@**."; diff --git a/apps/ios/de.lproj/Localizable.strings b/apps/ios/de.lproj/Localizable.strings index 01a760721f..7464e096c4 100644 --- a/apps/ios/de.lproj/Localizable.strings +++ b/apps/ios/de.lproj/Localizable.strings @@ -337,9 +337,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "Danach die gewünschte Aktion auswählen:"; -/* No comment provided by engineer. */ -"Accent color" = "Akzentfarbe"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Annehmen"; @@ -369,7 +366,7 @@ "Add profile" = "Profil hinzufügen"; /* No comment provided by engineer. */ -"Add server…" = "Füge Server hinzu…"; +"Add server" = "Füge Server hinzu"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Fügen Sie Server durch Scannen der QR Codes hinzu."; @@ -653,7 +650,7 @@ /* rcv group event chat item */ "blocked %@" = "%@ wurde blockiert"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "wurde vom Administrator blockiert"; /* No comment provided by engineer. */ @@ -726,7 +723,7 @@ "Capacity exceeded - recipient did not receive previously sent messages." = "Kapazität überschritten - der Empfänger hat die zuvor gesendeten Nachrichten nicht empfangen."; /* No comment provided by engineer. */ -"Cellular" = "Zellulär"; +"Cellular" = "Mobilfunknetz"; /* No comment provided by engineer. */ "Change" = "Ändern"; @@ -840,9 +837,6 @@ /* No comment provided by engineer. */ "colored" = "farbig"; -/* No comment provided by engineer. */ -"Colors" = "Farben"; - /* server test step */ "Compare file" = "Datei vergleichen"; @@ -1023,7 +1017,7 @@ /* No comment provided by engineer. */ "Continue" = "Weiter"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Kopieren"; /* No comment provided by engineer. */ @@ -1167,6 +1161,9 @@ /* time unit */ "days" = "Tage"; +/* No comment provided by engineer. */ +"Debug delivery" = "Debugging-Zustellung"; + /* No comment provided by engineer. */ "Decentralized" = "Dezentral"; @@ -1800,7 +1797,8 @@ /* No comment provided by engineer. */ "Error: " = "Fehler: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Fehler: %@"; /* No comment provided by engineer. */ @@ -2496,6 +2494,9 @@ /* No comment provided by engineer. */ "Message draft" = "Nachrichtenentwurf"; +/* No comment provided by engineer. */ +"Message queue info" = "Nachrichten-Warteschlangen-Information"; + /* chat feature */ "Message reactions" = "Reaktionen auf Nachrichten"; @@ -3060,7 +3061,7 @@ "Protect your chat profiles with a password!" = "Ihre Chat-Profile mit einem Passwort schützen!"; /* No comment provided by engineer. */ -"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Schützen Sie Ihre IP-Adresse vor den Nachrichten-Relais , die Ihre Kontakte ausgewählt haben.\nAktivieren Sie es in den *Netzwerk & Server* Einstellungen."; +"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Schützen Sie Ihre IP-Adresse vor den Nachrichten-Relais, die Ihre Kontakte ausgewählt haben.\nAktivieren Sie es in den *Netzwerk & Server* Einstellungen."; /* No comment provided by engineer. */ "Protocol timeout" = "Protokollzeitüberschreitung"; @@ -3518,6 +3519,9 @@ /* srv error text. */ "Server address is incompatible with network settings." = "Die Server-Adresse ist nicht mit den Netzwerk-Einstellungen kompatibel."; +/* queue info */ +"server queue info: %@\n\nlast received msg: %@" = "Server-Warteschlangen-Information: %1$@\n\nZuletzt empfangene Nachricht: %2$@"; + /* server test error */ "Server requires authorization to create queues, check password" = "Um Warteschlangen zu erzeugen benötigt der Server eine Authentifizierung. Bitte überprüfen Sie das Passwort"; @@ -3872,9 +3876,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "Der von Ihnen eingefügte Text ist kein SimpleX-Link."; -/* No comment provided by engineer. */ -"Theme" = "Design"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Diese Einstellungen betreffen Ihr aktuelles Profil **%@**."; diff --git a/apps/ios/es.lproj/Localizable.strings b/apps/ios/es.lproj/Localizable.strings index 01924b1903..54316b092f 100644 --- a/apps/ios/es.lproj/Localizable.strings +++ b/apps/ios/es.lproj/Localizable.strings @@ -337,9 +337,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "y después elige:"; -/* No comment provided by engineer. */ -"Accent color" = "Color"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Aceptar"; @@ -369,7 +366,7 @@ "Add profile" = "Añadir perfil"; /* No comment provided by engineer. */ -"Add server…" = "Añadir servidor…"; +"Add server" = "Añadir servidor"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Añadir servidores mediante el escaneo de códigos QR."; @@ -653,7 +650,7 @@ /* rcv group event chat item */ "blocked %@" = "ha bloqueado a %@"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "bloqueado por administrador"; /* No comment provided by engineer. */ @@ -840,9 +837,6 @@ /* No comment provided by engineer. */ "colored" = "coloreado"; -/* No comment provided by engineer. */ -"Colors" = "Colores"; - /* server test step */ "Compare file" = "Comparar archivo"; @@ -967,7 +961,7 @@ "Connection error" = "Error conexión"; /* No comment provided by engineer. */ -"Connection error (AUTH)" = "Error conexión (Autenticación)"; +"Connection error (AUTH)" = "Error de conexión (Autenticación)"; /* chat list item title (it should not be shown */ "connection established" = "conexión establecida"; @@ -979,7 +973,7 @@ "Connection terminated" = "Conexión finalizada"; /* No comment provided by engineer. */ -"Connection timeout" = "Tiempo de conexión expirado"; +"Connection timeout" = "Tiempo de conexión agotado"; /* connection information */ "connection:%@" = "conexión: % @"; @@ -1023,7 +1017,7 @@ /* No comment provided by engineer. */ "Continue" = "Continuar"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Copiar"; /* No comment provided by engineer. */ @@ -1167,6 +1161,9 @@ /* time unit */ "days" = "días"; +/* No comment provided by engineer. */ +"Debug delivery" = "Informe debug"; + /* No comment provided by engineer. */ "Decentralized" = "Descentralizada"; @@ -1800,7 +1797,8 @@ /* No comment provided by engineer. */ "Error: " = "Error: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Error: %@"; /* No comment provided by engineer. */ @@ -2101,7 +2099,7 @@ "ICE servers (one per line)" = "Servidores ICE (uno por línea)"; /* No comment provided by engineer. */ -"If you can't meet in person, show QR code in a video call, or share the link." = "Si no puedes reunirte en persona, muestra el código QR por videollamada, o comparte el enlace."; +"If you can't meet in person, show QR code in a video call, or share the link." = "Si no puedes reunirte en persona, muestra el código QR por videollamada o comparte el enlace."; /* No comment provided by engineer. */ "If you enter this passcode when opening the app, all app data will be irreversibly removed!" = "¡Si introduces este código al abrir la aplicación, todos los datos de la misma se eliminarán de forma irreversible!"; @@ -2496,6 +2494,9 @@ /* No comment provided by engineer. */ "Message draft" = "Borrador de mensaje"; +/* No comment provided by engineer. */ +"Message queue info" = "Información cola de mensajes"; + /* chat feature */ "Message reactions" = "Reacciones a mensajes"; @@ -2766,7 +2767,7 @@ "on" = "Activado"; /* No comment provided by engineer. */ -"One-time invitation link" = "Enlace único de invitación de un uso"; +"One-time invitation link" = "Enlace de invitación de un solo uso"; /* No comment provided by engineer. */ "Onion hosts will be required for connection. Requires enabling VPN." = "Se requieren hosts .onion para la conexión. Requiere activación de la VPN."; @@ -2850,13 +2851,13 @@ "Or paste archive link" = "O pegar enlace del archivo"; /* No comment provided by engineer. */ -"Or scan QR code" = "O escanear código QR"; +"Or scan QR code" = "O escanea el código QR"; /* No comment provided by engineer. */ "Or securely share this file link" = "O comparte de forma segura este enlace al archivo"; /* No comment provided by engineer. */ -"Or show this code" = "O mostrar este código"; +"Or show this code" = "O muestra este código QR"; /* No comment provided by engineer. */ "Other" = "Otro"; @@ -2898,7 +2899,7 @@ "Paste link to connect!" = "Pegar enlace para conectar!"; /* No comment provided by engineer. */ -"Paste the link you received" = "Pegar el enlace recibido"; +"Paste the link you received" = "Pega el enlace recibido"; /* No comment provided by engineer. */ "peer-to-peer" = "p2p"; @@ -2907,7 +2908,7 @@ "People can connect to you only via the links you share." = "Las personas pueden conectarse contigo solo mediante los enlaces que compartes."; /* No comment provided by engineer. */ -"Periodically" = "Periódico"; +"Periodically" = "Periódicamente"; /* message decrypt error item */ "Permanent decryption error" = "Error permanente descifrado"; @@ -3063,10 +3064,10 @@ "Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Protege tu dirección IP de los servidores de retransmisión elegidos por tus contactos.\nActívalo en ajustes de *Servidores y Redes*."; /* No comment provided by engineer. */ -"Protocol timeout" = "Tiempo de espera del protocolo"; +"Protocol timeout" = "Timeout protocolo"; /* No comment provided by engineer. */ -"Protocol timeout per KB" = "Límite de espera del protocolo por KB"; +"Protocol timeout per KB" = "Timeout protocolo por KB"; /* No comment provided by engineer. */ "Push notifications" = "Notificaciones automáticas"; @@ -3090,22 +3091,22 @@ "Read" = "Leer"; /* No comment provided by engineer. */ -"Read more" = "Saber más"; +"Read more" = "Conoce más"; /* No comment provided by engineer. */ -"Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address)." = "Saber más en el [Manual del Usuario](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address)."; +"Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address)." = "Conoce más en el [Manual del Usuario](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address)."; /* No comment provided by engineer. */ -"Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode)." = "Saber más en [Guía de Usuario](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode)."; +"Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode)." = "Conoce más en la [Guía del Usuario](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode)."; /* No comment provided by engineer. */ -"Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends)." = "Saber más en el [Manual del Usuario](https://simplex.chat/docs/guide/readme.html#connect-to-friends)."; +"Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends)." = "Conoce más en el [Manual del Usuario](https://simplex.chat/docs/guide/readme.html#connect-to-friends)."; /* No comment provided by engineer. */ -"Read more in our [GitHub repository](https://github.com/simplex-chat/simplex-chat#readme)." = "Saber más en nuestro [repositorio GitHub](https://github.com/simplex-chat/simplex-chat#readme)."; +"Read more in our [GitHub repository](https://github.com/simplex-chat/simplex-chat#readme)." = "Conoce más en nuestro [repositorio GitHub](https://github.com/simplex-chat/simplex-chat#readme)."; /* No comment provided by engineer. */ -"Read more in our GitHub repository." = "Saber más en nuestro repositorio GitHub."; +"Read more in our GitHub repository." = "Conoce más en nuestro repositorio GitHub."; /* No comment provided by engineer. */ "Receipts are disabled" = "Las confirmaciones están desactivadas"; @@ -3518,6 +3519,9 @@ /* srv error text. */ "Server address is incompatible with network settings." = "La dirección del servidor es incompatible con la configuración de la red."; +/* queue info */ +"server queue info: %@\n\nlast received msg: %@" = "información cola del servidor: %1$@\n\núltimo mensaje recibido: %2$@"; + /* server test error */ "Server requires authorization to create queues, check password" = "El servidor requiere autorización para crear colas, comprueba la contraseña"; @@ -3591,7 +3595,7 @@ "Share link" = "Compartir enlace"; /* No comment provided by engineer. */ -"Share this 1-time invite link" = "Compartir este enlace de un uso"; +"Share this 1-time invite link" = "Comparte este enlace de un solo uso"; /* No comment provided by engineer. */ "Share with contacts" = "Compartir con contactos"; @@ -3771,7 +3775,7 @@ "Tap to join incognito" = "Pulsa para unirte en modo incógnito"; /* No comment provided by engineer. */ -"Tap to paste link" = "Pulsa para pegar enlace"; +"Tap to paste link" = "Pulsa para pegar el enlacePulsa para pegar enlace"; /* No comment provided by engineer. */ "Tap to scan" = "Pulsa para escanear"; @@ -3780,7 +3784,7 @@ "Tap to start a new chat" = "Pulsa para iniciar chat nuevo"; /* No comment provided by engineer. */ -"TCP connection timeout" = "Tiempo de espera de la conexión TCP agotado"; +"TCP connection timeout" = "Timeout de la conexión TCP"; /* No comment provided by engineer. */ "TCP_KEEPCNT" = "TCP_KEEPCNT"; @@ -3872,9 +3876,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "El texto pegado no es un enlace SimpleX."; -/* No comment provided by engineer. */ -"Theme" = "Tema"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Esta configuración afecta a tu perfil actual **%@**."; @@ -3942,7 +3943,7 @@ "To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Para proteger tu información, activa el Bloqueo SimpleX.\nSe te pedirá que completes la autenticación antes de activar esta función."; /* No comment provided by engineer. */ -"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Para proteger tu dirección IP, el enrutamiento privado usa tus servidores SMP para enviar mensajes."; +"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Para proteger tu dirección IP, el enrutamiento privado usa tu lista de servidores SMP para enviar mensajes."; /* No comment provided by engineer. */ "To record voice message please grant permission to use Microphone." = "Para grabar el mensaje de voz concede permiso para usar el micrófono."; @@ -4029,7 +4030,7 @@ "Unknown error" = "Error desconocido"; /* No comment provided by engineer. */ -"unknown relays" = "servidor de retransmisión desconocido"; +"unknown relays" = "con servidores desconocidos"; /* No comment provided by engineer. */ "Unknown servers!" = "¡Servidores desconocidos!"; @@ -4041,7 +4042,7 @@ "Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." = "A menos que utilices la interfaz de llamadas de iOS, activa el modo No molestar para evitar interrupciones."; /* No comment provided by engineer. */ -"Unless your contact deleted the connection or this link was already used, it might be a bug - please report it.\nTo connect, please ask your contact to create another connection link and check that you have a stable network connection." = "A menos que tu contacto haya eliminado la conexión o\nque este enlace ya se haya usado, podría ser un error. Por favor, notifícalo.\nPara conectarte, pide a tu contacto que cree otro enlace de conexión y comprueba que tienes buena conexión de red."; +"Unless your contact deleted the connection or this link was already used, it might be a bug - please report it.\nTo connect, please ask your contact to create another connection link and check that you have a stable network connection." = "A menos que tu contacto haya eliminado la conexión o el enlace haya sido usado, podría ser un error. Por favor, notifícalo.\nPara conectarte pide a tu contacto que cree otro enlace y comprueba la conexión de red."; /* No comment provided by engineer. */ "Unlink" = "Desenlazar"; @@ -4059,7 +4060,7 @@ "Unmute" = "Activar audio"; /* No comment provided by engineer. */ -"unprotected" = "desprotegido"; +"unprotected" = "con IP desprotegida"; /* No comment provided by engineer. */ "Unread" = "No leído"; @@ -4131,10 +4132,10 @@ "Use only local notifications?" = "¿Usar sólo notificaciones locales?"; /* No comment provided by engineer. */ -"Use private routing with unknown servers when IP address is not protected." = "Usar enrutamiento privado con servidores desconocidos cuando la dirección IP no está protegida."; +"Use private routing with unknown servers when IP address is not protected." = "Usar enrutamiento privado con servidores desconocidos cuando tu dirección IP no está protegida."; /* No comment provided by engineer. */ -"Use private routing with unknown servers." = "Usar enrutamiento privado con servidores desconocidos."; +"Use private routing with unknown servers." = "Usar enrutamiento privado con servidores de retransmisión desconocidos."; /* No comment provided by engineer. */ "Use server" = "Usar servidor"; @@ -4524,7 +4525,7 @@ "You will be connected when your contact's device is online, please wait or check later!" = "Te conectarás cuando el dispositivo del contacto esté en línea, por favor espera o compruébalo más tarde."; /* No comment provided by engineer. */ -"You will be required to authenticate when you start or resume the app after 30 seconds in background." = "Se te pedirá identificarte cuándo inicies o continues usando la aplicación tras 30 segundos en segundo plano."; +"You will be required to authenticate when you start or resume the app after 30 seconds in background." = "Se te pedirá autenticarte cuando inicies la aplicación o sigas usándola tras 30 segundos en segundo plano."; /* No comment provided by engineer. */ "You will connect to all group members." = "Te conectarás con todos los miembros del grupo."; @@ -4596,7 +4597,7 @@ "Your profile **%@** will be shared." = "Tu perfil **%@** será compartido."; /* No comment provided by engineer. */ -"Your profile is stored on your device and shared only with your contacts.\nSimpleX servers cannot see your profile." = "Tu perfil se almacena en tu dispositivo y sólo se comparte con tus contactos.\nLos servidores de SimpleX no pueden ver tu perfil."; +"Your profile is stored on your device and shared only with your contacts.\nSimpleX servers cannot see your profile." = "Tu perfil es almacenado en tu dispositivo y solamente se comparte con tus contactos.\nLos servidores SimpleX no pueden ver tu perfil."; /* No comment provided by engineer. */ "Your profile, contacts and delivered messages are stored on your device." = "Tu perfil, contactos y mensajes se almacenan en tu dispositivo."; diff --git a/apps/ios/fi.lproj/Localizable.strings b/apps/ios/fi.lproj/Localizable.strings index 12d17aac36..1405f14694 100644 --- a/apps/ios/fi.lproj/Localizable.strings +++ b/apps/ios/fi.lproj/Localizable.strings @@ -280,9 +280,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "edellä, valitse sitten:"; -/* No comment provided by engineer. */ -"Accent color" = "Korostusväri"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Hyväksy"; @@ -309,7 +306,7 @@ "Add profile" = "Lisää profiili"; /* No comment provided by engineer. */ -"Add server…" = "Lisää palvelin…"; +"Add server" = "Lisää palvelin"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Lisää palvelimia skannaamalla QR-koodeja."; @@ -663,9 +660,6 @@ /* No comment provided by engineer. */ "colored" = "värillinen"; -/* No comment provided by engineer. */ -"Colors" = "Värit"; - /* server test step */ "Compare file" = "Vertaa tiedostoa"; @@ -795,7 +789,7 @@ /* No comment provided by engineer. */ "Continue" = "Jatka"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Kopioi"; /* No comment provided by engineer. */ @@ -1434,7 +1428,8 @@ /* No comment provided by engineer. */ "Error: " = "Virhe: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Virhe: %@"; /* No comment provided by engineer. */ @@ -3056,9 +3051,6 @@ /* No comment provided by engineer. */ "The servers for new connections of your current chat profile **%@**." = "Palvelimet nykyisen keskusteluprofiilisi uusille yhteyksille **%@**."; -/* No comment provided by engineer. */ -"Theme" = "Teema"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Nämä asetukset koskevat nykyistä profiiliasi **%@**."; diff --git a/apps/ios/fr.lproj/Localizable.strings b/apps/ios/fr.lproj/Localizable.strings index 91b8d7c866..aa9bfef3e5 100644 --- a/apps/ios/fr.lproj/Localizable.strings +++ b/apps/ios/fr.lproj/Localizable.strings @@ -337,9 +337,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "ci-dessus, puis choisissez :"; -/* No comment provided by engineer. */ -"Accent color" = "Couleur principale"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Accepter"; @@ -369,7 +366,7 @@ "Add profile" = "Ajouter un profil"; /* No comment provided by engineer. */ -"Add server…" = "Ajouter un serveur…"; +"Add server" = "Ajouter un serveur"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Ajoutez des serveurs en scannant des codes QR."; @@ -653,7 +650,7 @@ /* rcv group event chat item */ "blocked %@" = "%@ bloqué"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "bloqué par l'administrateur"; /* No comment provided by engineer. */ @@ -840,9 +837,6 @@ /* No comment provided by engineer. */ "colored" = "coloré"; -/* No comment provided by engineer. */ -"Colors" = "Couleurs"; - /* server test step */ "Compare file" = "Comparer le fichier"; @@ -1023,7 +1017,7 @@ /* No comment provided by engineer. */ "Continue" = "Continuer"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Copier"; /* No comment provided by engineer. */ @@ -1167,6 +1161,9 @@ /* time unit */ "days" = "jours"; +/* No comment provided by engineer. */ +"Debug delivery" = "Livraison de débogage"; + /* No comment provided by engineer. */ "Decentralized" = "Décentralisé"; @@ -1800,7 +1797,8 @@ /* No comment provided by engineer. */ "Error: " = "Erreur : "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Erreur : %@"; /* No comment provided by engineer. */ @@ -2496,6 +2494,9 @@ /* No comment provided by engineer. */ "Message draft" = "Brouillon de message"; +/* No comment provided by engineer. */ +"Message queue info" = "Informations sur la file d'attente des messages"; + /* chat feature */ "Message reactions" = "Réactions aux messages"; @@ -3518,6 +3519,9 @@ /* srv error text. */ "Server address is incompatible with network settings." = "L'adresse du serveur est incompatible avec les paramètres du réseau."; +/* queue info */ +"server queue info: %@\n\nlast received msg: %@" = "info sur la file d'attente du serveur : %1$@\n\ndernier message reçu : %2$@"; + /* server test error */ "Server requires authorization to create queues, check password" = "Le serveur requiert une autorisation pour créer des files d'attente, vérifiez le mot de passe"; @@ -3872,9 +3876,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "Le texte collé n'est pas un lien SimpleX."; -/* No comment provided by engineer. */ -"Theme" = "Thème"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Ces paramètres s'appliquent à votre profil actuel **%@**."; diff --git a/apps/ios/hu.lproj/Localizable.strings b/apps/ios/hu.lproj/Localizable.strings index 9d04ebd4fb..44b3447ef8 100644 --- a/apps/ios/hu.lproj/Localizable.strings +++ b/apps/ios/hu.lproj/Localizable.strings @@ -266,7 +266,7 @@ "`a + b`" = "a + b"; /* email text */ -"

Hi!

\n

Connect to me via SimpleX Chat

" = "

Üdvözlöm!

\n

Csatlakozzon hozzám a SimpleX Chaten

"; +"

Hi!

\n

Connect to me via SimpleX Chat

" = "

Üdvözlöm!

\n

Csatlakozzon hozzám a SimpleX Chaten

"; /* No comment provided by engineer. */ "~strike~" = "\\~áthúzott~"; @@ -326,20 +326,17 @@ "Abort changing address?" = "Címváltoztatás megszakítása??"; /* No comment provided by engineer. */ -"About SimpleX" = "A SimpleX névjegye"; +"About SimpleX" = "A SimpleX-ről"; /* No comment provided by engineer. */ -"About SimpleX address" = "A SimpleX azonosítóról"; +"About SimpleX address" = "A SimpleX címről"; /* No comment provided by engineer. */ -"About SimpleX Chat" = "A SimpleX Chat névjegye"; +"About SimpleX Chat" = "A SimpleX Chat-ről"; /* No comment provided by engineer. */ "above, then choose:" = "gombra fent, majd válassza ki:"; -/* No comment provided by engineer. */ -"Accent color" = "Kiemelő szín"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Elfogadás"; @@ -357,7 +354,7 @@ "accepted call" = "elfogadott hívás"; /* No comment provided by engineer. */ -"Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." = "Azonosító hozzáadása a profilhoz, hogy az ismerősei megoszthassák másokkal. A profilfrissítés elküldésre kerül az ismerősei számára."; +"Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." = "Cím hozzáadása a profilhoz, hogy az ismerősei megoszthassák másokkal. A profilfrissítés elküldésre kerül az ismerősei számára."; /* No comment provided by engineer. */ "Add contact" = "Ismerős hozzáadása"; @@ -369,7 +366,7 @@ "Add profile" = "Profil hozzáadása"; /* No comment provided by engineer. */ -"Add server…" = "Kiszolgáló hozzáadása…"; +"Add server" = "Kiszolgáló hozzáadása"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Kiszolgáló hozzáadása QR-kód beolvasásával."; @@ -462,7 +459,7 @@ "Allow message reactions." = "Üzenetreakciók engedélyezése."; /* No comment provided by engineer. */ -"Allow sending direct messages to members." = "Közvetlen üzenetek küldésének engedélyezése a tagok számára."; +"Allow sending direct messages to members." = "A közvetlen üzenetek küldése a tagok között engedélyezve van."; /* No comment provided by engineer. */ "Allow sending disappearing messages." = "Az eltűnő üzenetek küldése engedélyezve van."; @@ -522,7 +519,7 @@ "An empty chat profile with the provided name is created, and the app opens as usual." = "Egy üres csevegési profil jön létre a megadott névvel, és az alkalmazás a szokásos módon megnyílik."; /* No comment provided by engineer. */ -"and %lld other events" = "és %lld további esemény"; +"and %lld other events" = "és további %lld esemény"; /* No comment provided by engineer. */ "Answer call" = "Hívás fogadása"; @@ -609,7 +606,7 @@ "Back" = "Vissza"; /* No comment provided by engineer. */ -"Bad desktop address" = "Hibás számítógép azonosító"; +"Bad desktop address" = "Hibás számítógép cím"; /* integrity error chat item */ "bad message hash" = "téves üzenet hash"; @@ -633,7 +630,7 @@ "Block" = "Blokkolás"; /* No comment provided by engineer. */ -"Block for all" = "Mindenki számára letiltva"; +"Block for all" = "Letiltás mindenki számára"; /* No comment provided by engineer. */ "Block group members" = "Csoporttagok blokkolása"; @@ -651,9 +648,9 @@ "blocked" = "blokkolva"; /* rcv group event chat item */ -"blocked %@" = "%@ letiltva"; +"blocked %@" = "letiltotta őt: %@"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "letiltva az admin által"; /* No comment provided by engineer. */ @@ -699,7 +696,7 @@ "Calls" = "Hívások"; /* No comment provided by engineer. */ -"Camera not available" = "A fényképező nem elérhető"; +"Camera not available" = "A kamera nem elérhető"; /* No comment provided by engineer. */ "Can't invite contact!" = "Ismerősök meghívása le van tiltva!"; @@ -769,10 +766,10 @@ "changed your role to %@" = "megváltoztatta a szerepkörét erre: %@"; /* chat item text */ -"changing address for %@…" = "cím módosítása %@ számára…"; +"changing address for %@…" = "cím megváltoztatása nála: %@…"; /* chat item text */ -"changing address…" = "azonosító megváltoztatása…"; +"changing address…" = "cím megváltoztatása…"; /* No comment provided by engineer. */ "Chat archive" = "Csevegési archívum"; @@ -840,9 +837,6 @@ /* No comment provided by engineer. */ "colored" = "színes"; -/* No comment provided by engineer. */ -"Colors" = "Színek"; - /* server test step */ "Compare file" = "Fájl összehasonlítás"; @@ -904,10 +898,10 @@ "Connect to yourself?\nThis is your own one-time link!" = "Kapcsolódás saját magához?\nEz az egyszer használatos hivatkozása!"; /* No comment provided by engineer. */ -"Connect to yourself?\nThis is your own SimpleX address!" = "Kapcsolódás saját magához?\nEz a SimpleX azonosítója!"; +"Connect to yourself?\nThis is your own SimpleX address!" = "Kapcsolódás saját magához?\nEz az ön SimpleX címe!"; /* No comment provided by engineer. */ -"Connect via contact address" = "Kapcsolódás a kapcsolattartási azonosítón keresztül"; +"Connect via contact address" = "Kapcsolódás a kapcsolattartási címen keresztül"; /* No comment provided by engineer. */ "Connect via link" = "Kapcsolódás egy hivatkozáson keresztül"; @@ -1023,7 +1017,7 @@ /* No comment provided by engineer. */ "Continue" = "Folytatás"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Másolás"; /* No comment provided by engineer. */ @@ -1039,7 +1033,7 @@ "Create a group using a random profile." = "Csoport létrehozása véletlenszerűen létrehozott profillal."; /* No comment provided by engineer. */ -"Create an address to let people connect with you." = "Azonosító létrehozása, hogy az emberek kapcsolatba léphessenek önnel."; +"Create an address to let people connect with you." = "Cím létrehozása, hogy az emberek kapcsolatba léphessenek önnel."; /* server test step */ "Create file" = "Fájl létrehozása"; @@ -1066,7 +1060,7 @@ "Create secret group" = "Titkos csoport létrehozása"; /* No comment provided by engineer. */ -"Create SimpleX address" = "SimpleX azonosító létrehozása"; +"Create SimpleX address" = "SimpleX cím létrehozása"; /* No comment provided by engineer. */ "Create your profile" = "Saját profil létrehozása"; @@ -1167,6 +1161,9 @@ /* time unit */ "days" = "nap"; +/* No comment provided by engineer. */ +"Debug delivery" = "Kézbesítési hibák felderítése"; + /* No comment provided by engineer. */ "Decentralized" = "Decentralizált"; @@ -1189,10 +1186,10 @@ "Delete %lld messages?" = "Töröl %lld üzenetet?"; /* No comment provided by engineer. */ -"Delete address" = "Azonosító törlése"; +"Delete address" = "Cím törlése"; /* No comment provided by engineer. */ -"Delete address?" = "Azonosító törlése?"; +"Delete address?" = "Cím törlése?"; /* No comment provided by engineer. */ "Delete after" = "Törlés ennyi idő után"; @@ -1324,7 +1321,7 @@ "Description" = "Leírás"; /* No comment provided by engineer. */ -"Desktop address" = "Számítógép azonosítója"; +"Desktop address" = "Számítógép címe"; /* No comment provided by engineer. */ "Desktop app version %@ is not compatible with this app." = "Az asztali kliens verziója %@ nem kompatibilis ezzel az alkalmazással."; @@ -1423,7 +1420,7 @@ "Do NOT use SimpleX for emergency calls." = "NE használja a SimpleX-et segélyhívásokhoz."; /* No comment provided by engineer. */ -"Don't create address" = "Ne hozzon létre azonosítót"; +"Don't create address" = "Ne hozzon létre címet"; /* No comment provided by engineer. */ "Don't enable" = "Ne engedélyezze"; @@ -1453,7 +1450,7 @@ "Duplicate display name!" = "Duplikált megjelenítési név!"; /* integrity error chat item */ -"duplicate message" = "duplikálódott üzenet"; +"duplicate message" = "duplikált üzenet"; /* No comment provided by engineer. */ "Duration" = "Időtartam"; @@ -1507,7 +1504,7 @@ "Enable SimpleX Lock" = "SimpleX zárolás engedélyezése"; /* No comment provided by engineer. */ -"Enable TCP keep-alive" = "TCP életben tartásának engedélyezése"; +"Enable TCP keep-alive" = "TCP életben tartása"; /* enabled status */ "enabled" = "engedélyezve"; @@ -1633,7 +1630,7 @@ "Error" = "Hiba"; /* No comment provided by engineer. */ -"Error aborting address change" = "Hiba az azonosító megváltoztatásának megszakításakor"; +"Error aborting address change" = "Hiba a cím megváltoztatásának megszakításakor"; /* No comment provided by engineer. */ "Error accepting contact request" = "Hiba történt a kapcsolatfelvételi kérelem elfogadásakor"; @@ -1645,7 +1642,7 @@ "Error adding member(s)" = "Hiba a tag(-ok) hozzáadásakor"; /* No comment provided by engineer. */ -"Error changing address" = "Hiba az azonosító megváltoztatásakor"; +"Error changing address" = "Hiba a cím megváltoztatásakor"; /* No comment provided by engineer. */ "Error changing role" = "Hiba a szerepkör megváltoztatásakor"; @@ -1654,7 +1651,7 @@ "Error changing setting" = "Hiba a beállítás megváltoztatásakor"; /* No comment provided by engineer. */ -"Error creating address" = "Hiba az azonosító létrehozásakor"; +"Error creating address" = "Hiba a cím létrehozásakor"; /* No comment provided by engineer. */ "Error creating group" = "Hiba a csoport létrehozásakor"; @@ -1735,7 +1732,7 @@ "Error saving %@ servers" = "Hiba történt a %@ kiszolgálók mentése közben"; /* No comment provided by engineer. */ -"Error saving group profile" = "Hiba a csoport profil mentésekor"; +"Error saving group profile" = "Hiba a csoportprofil mentésekor"; /* No comment provided by engineer. */ "Error saving ICE servers" = "Hiba az ICE kiszolgálók mentésekor"; @@ -1800,7 +1797,8 @@ /* No comment provided by engineer. */ "Error: " = "Hiba: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Hiba: %@"; /* No comment provided by engineer. */ @@ -2029,13 +2027,13 @@ "Group preferences" = "Csoport beállítások"; /* No comment provided by engineer. */ -"Group profile" = "Csoport profil"; +"Group profile" = "Csoportprofil"; /* No comment provided by engineer. */ "Group profile is stored on members' devices, not on the servers." = "A csoport profilja a tagok eszközein tárolódik, nem a kiszolgálókon."; /* snd group event chat item */ -"group profile updated" = "csoport profil frissítve"; +"group profile updated" = "csoportprofil frissítve"; /* No comment provided by engineer. */ "Group welcome message" = "Csoport üdvözlő üzenete"; @@ -2437,10 +2435,10 @@ "Make profile private!" = "Tegye priváttá a profilját!"; /* No comment provided by engineer. */ -"Make sure %@ server addresses are in correct format, line separated and are not duplicated (%@)." = "Győződjön meg arról, hogy a %@ kiszolgálócímek megfelelő formátumúak, sorszeparáltak és nem duplikáltak (%@)."; +"Make sure %@ server addresses are in correct format, line separated and are not duplicated (%@)." = "Győződjön meg arról, hogy a %@ kiszolgálócímek megfelelő formátumúak, sorszeparáltak és nincsenek duplikálva (%@)."; /* No comment provided by engineer. */ -"Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated." = "Győződjön meg arról, hogy a WebRTC ICE-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nem duplikáltak."; +"Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated." = "Győződjön meg arról, hogy a WebRTC ICE-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nincsenek duplikálva."; /* No comment provided by engineer. */ "Many people asked: *if SimpleX has no user identifiers, how can it deliver messages?*" = "Sokan kérdezték: *ha a SimpleX-nek nincsenek felhasználói azonosítói, akkor hogyan tud üzeneteket kézbesíteni?*"; @@ -2476,10 +2474,10 @@ "member connected" = "kapcsolódott"; /* No comment provided by engineer. */ -"Member role will be changed to \"%@\". All group members will be notified." = "A tag szerepköre meg fog változni erre: \"%@\". A csoport minden tagja értesítést kap róla."; +"Member role will be changed to \"%@\". All group members will be notified." = "A tag szerepköre meg fog változni erre: „%@”. A csoport minden tagja értesítést kap róla."; /* No comment provided by engineer. */ -"Member role will be changed to \"%@\". The member will receive a new invitation." = "A tag szerepköre meg fog változni erre: \"%@\". A tag új meghívást fog kapni."; +"Member role will be changed to \"%@\". The member will receive a new invitation." = "A tag szerepköre meg fog változni erre: „%@”. A tag új meghívást fog kapni."; /* No comment provided by engineer. */ "Member will be removed from group - this cannot be undone!" = "A tag eltávolítása a csoportból - ez a művelet nem vonható vissza!"; @@ -2496,6 +2494,9 @@ /* No comment provided by engineer. */ "Message draft" = "Üzenetvázlat"; +/* No comment provided by engineer. */ +"Message queue info" = "Üzenet-várakoztatási információ"; + /* chat feature */ "Message reactions" = "Üzenetreakciók"; @@ -2731,7 +2732,7 @@ "Notifications are disabled!" = "Az értesítések le vannak tiltva!"; /* No comment provided by engineer. */ -"Now admins can:\n- delete members' messages.\n- disable members (\"observer\" role)" = "Most már az adminok is:\n- törölhetik a tagok üzeneteit.\n- letilthatnak tagokat (\"megfigyelő\" szerepkör)"; +"Now admins can:\n- delete members' messages.\n- disable members (\"observer\" role)" = "Most már az adminok is:\n- törölhetik a tagok üzeneteit.\n- letilthatnak tagokat („megfigyelő” szerepkör)"; /* member role */ "observer" = "megfigyelő"; @@ -2739,7 +2740,7 @@ /* enabled status group pref value time to disappear */ -"off" = "ki"; +"off" = "kikapcsolva"; /* No comment provided by engineer. */ "Off" = "Ki"; @@ -2886,10 +2887,10 @@ "Password to show" = "Jelszó megjelenítése"; /* past/unknown group member */ -"Past member %@" = "Korábbi csoport tag %@"; +"Past member %@" = "Már nem tag - %@"; /* No comment provided by engineer. */ -"Paste desktop address" = "Számítógép azonosítójának beillesztése"; +"Paste desktop address" = "Számítógép címének beillesztése"; /* No comment provided by engineer. */ "Paste image" = "Kép beillesztése"; @@ -3036,7 +3037,7 @@ "Prohibit messages reactions." = "Az üzenetreakciók tiltása."; /* No comment provided by engineer. */ -"Prohibit sending direct messages to members." = "A közvetlen üzenetek küldése le van tiltva a tagok között."; +"Prohibit sending direct messages to members." = "A közvetlen üzenetek küldése a tagok között le van tiltva."; /* No comment provided by engineer. */ "Prohibit sending disappearing messages." = "Az eltűnő üzenetek küldése le van tiltva."; @@ -3054,7 +3055,7 @@ "Protect app screen" = "Alkalmazás képernyőjének védelme"; /* No comment provided by engineer. */ -"Protect IP address" = "Az IP-cím védelme"; +"Protect IP address" = "IP-cím védelem"; /* No comment provided by engineer. */ "Protect your chat profiles with a password!" = "Csevegési profiljok védelme jelszóval!"; @@ -3174,10 +3175,10 @@ "rejected call" = "elutasított hívás"; /* No comment provided by engineer. */ -"Relay server is only used if necessary. Another party can observe your IP address." = "Az átjátszó kiszolgáló csak szükség esetén kerül használatra. Egy másik fél megfigyelheti az IP-címét."; +"Relay server is only used if necessary. Another party can observe your IP address." = "Az átjátszó kiszolgáló csak szükség esetén kerül használatra. Egy másik fél megfigyelheti az IP-címet."; /* No comment provided by engineer. */ -"Relay server protects your IP address, but it can observe the duration of the call." = "Az átjátszó kiszolgáló megvédi IP-címét, de megfigyelheti a hívás időtartamát."; +"Relay server protects your IP address, but it can observe the duration of the call." = "Az átjátszó kiszolgáló megvédi az IP-címet, de megfigyelheti a hívás időtartamát."; /* No comment provided by engineer. */ "Remove" = "Eltávolítás"; @@ -3198,7 +3199,7 @@ "removed %@" = "%@ eltávolítva"; /* profile update event chat item */ -"removed contact address" = "törölt kapcsolattartási azonosító"; +"removed contact address" = "törölt kapcsolattartási cím"; /* profile update event chat item */ "removed profile picture" = "törölt profilkép"; @@ -3270,7 +3271,7 @@ "Reveal" = "Felfedés"; /* No comment provided by engineer. */ -"Revert" = "Visszaállít"; +"Revert" = "Visszaállítás"; /* No comment provided by engineer. */ "Revoke" = "Visszavonás"; @@ -3306,7 +3307,7 @@ "Save and notify group members" = "Mentés és a csoporttagok értesítése"; /* No comment provided by engineer. */ -"Save and update group profile" = "Mentés és a csoport profil frissítése"; +"Save and update group profile" = "Mentés és csoportprofil frissítése"; /* No comment provided by engineer. */ "Save archive" = "Archívum mentése"; @@ -3315,7 +3316,7 @@ "Save auto-accept settings" = "Automatikus elfogadási beállítások mentése"; /* No comment provided by engineer. */ -"Save group profile" = "Csoport profil elmentése"; +"Save group profile" = "Csoportprofil elmentése"; /* No comment provided by engineer. */ "Save passphrase and open chat" = "Jelmondat elmentése és csevegés megnyitása"; @@ -3518,6 +3519,9 @@ /* srv error text. */ "Server address is incompatible with network settings." = "A kiszolgáló címe nem kompatibilis a hálózati beállításokkal."; +/* queue info */ +"server queue info: %@\n\nlast received msg: %@" = "kiszolgáló üzenet-várakotatási információ: %1$@\n\nutoljára fogadott üzenet: %2$@"; + /* server test error */ "Server requires authorization to create queues, check password" = "A kiszolgálónak engedélyre van szüksége a várólisták létrehozásához, ellenőrizze jelszavát"; @@ -3549,10 +3553,10 @@ "Set it instead of system authentication." = "Rendszerhitelesítés helyetti beállítás."; /* profile update event chat item */ -"set new contact address" = "új kapcsolattartási azonosító beállítása"; +"set new contact address" = "új kapcsolattartási cím beállítása"; /* profile update event chat item */ -"set new profile picture" = "új profilkép beállítása"; +"set new profile picture" = "új profilképet állított be"; /* No comment provided by engineer. */ "Set passcode" = "Jelkód beállítása"; @@ -3582,10 +3586,10 @@ "Share 1-time link" = "Egyszer használatos hivatkozás megosztása"; /* No comment provided by engineer. */ -"Share address" = "Azonosító megosztása"; +"Share address" = "Cím megosztása"; /* No comment provided by engineer. */ -"Share address with contacts?" = "Megosztja az azonosítót az ismerőseivel?"; +"Share address with contacts?" = "Megosztja a címet az ismerőseivel?"; /* No comment provided by engineer. */ "Share link" = "Hivatkozás megosztása"; @@ -3621,16 +3625,16 @@ "Show:" = "Megjelenítés:"; /* No comment provided by engineer. */ -"SimpleX address" = "SimpleX azonosító"; +"SimpleX address" = "SimpleX cím"; /* No comment provided by engineer. */ -"SimpleX Address" = "SimpleX azonosító"; +"SimpleX Address" = "SimpleX cím"; /* No comment provided by engineer. */ "SimpleX Chat security was audited by Trail of Bits." = "A SimpleX Chat biztonsága a Trail of Bits által lett auditálva."; /* simplex link type */ -"SimpleX contact address" = "SimpleX kapcsolattartási azonosító"; +"SimpleX contact address" = "SimpleX kapcsolattartási cím"; /* notification */ "SimpleX encrypted message or connection event" = "SimpleX titkosított üzenet vagy kapcsolati esemény"; @@ -3675,7 +3679,7 @@ "Small groups (max 20)" = "Kis csoportok (max. 20 tag)"; /* No comment provided by engineer. */ -"SMP servers" = "Üzenetküldő (SMP) kiszolgálók"; +"SMP servers" = "SMP kiszolgálók"; /* No comment provided by engineer. */ "Some non-fatal errors occurred during import - you may see Chat console for more details." = "Néhány nem végzetes hiba történt az importálás során – további részletekért a csevegési konzolban olvashat."; @@ -3872,9 +3876,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "A beillesztett szöveg nem egy SimpleX hivatkozás."; -/* No comment provided by engineer. */ -"Theme" = "Téma"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Ezek a beállítások a jelenlegi **%@** profiljára vonatkoznak."; @@ -3915,7 +3916,7 @@ "This is your own one-time link!" = "Ez az egyszer használatos hivatkozása!"; /* No comment provided by engineer. */ -"This is your own SimpleX address!" = "Ez a SimpleX azonosítója!"; +"This is your own SimpleX address!" = "Ez az ön SimpleX címe!"; /* No comment provided by engineer. */ "This setting applies to messages in your current chat profile **%@**." = "Ez a beállítás a jelenlegi **%@** profiljában lévő üzenetekre érvényes."; @@ -3942,7 +3943,7 @@ "To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Az adatavédelem érdekében kapcsolja be a SimpleX zárolás funkciót.\nA funkció engedélyezése előtt a rendszer felszólítja a hitelesítés befejezésére."; /* No comment provided by engineer. */ -"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Az IP-címe védelme érdekében a privát útválasztás az SMP-kiszolgálókat használja az üzenetek kézbesítéséhez."; +"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Az IP-cím védelmének érdekében a privát útválasztás az SMP kiszolgálókat használja az üzenetek kézbesítéséhez."; /* No comment provided by engineer. */ "To record voice message please grant permission to use Microphone." = "Hangüzenet rögzítéséhez adjon engedélyt a mikrofon használathoz."; @@ -4185,7 +4186,7 @@ "Via browser" = "Böngészőn keresztül"; /* chat list item description */ -"via contact address link" = "kapcsolattartási azonosító-hivatkozáson keresztül"; +"via contact address link" = "kapcsolattartási cím-hivatkozáson keresztül"; /* chat list item description */ "via group link" = "csoport hivatkozáson keresztül"; @@ -4347,7 +4348,7 @@ "You **must not** use the same database on two devices." = "**Nem szabad** ugyanazt az adatbázist használni egyszerre két eszközön."; /* No comment provided by engineer. */ -"You accepted connection" = "Kapcsolódás elfogadva"; +"You accepted connection" = "Kapcsolat létrehozása"; /* No comment provided by engineer. */ "You allow" = "Engedélyezte"; @@ -4425,10 +4426,10 @@ "You can share a link or a QR code - anybody will be able to join the group. You won't lose members of the group if you later delete it." = "Megoszthat egy hivatkozást vagy QR-kódot - így bárki csatlakozhat a csoporthoz. Ha a csoport később törlésre kerül, akkor nem fogja elveszíteni annak tagjait."; /* No comment provided by engineer. */ -"You can share this address with your contacts to let them connect with **%@**." = "Megoszthatja ezt az azonosítót az ismerőseivel, hogy kapcsolatba léphessenek önnel a **%@** nevű profilján keresztül."; +"You can share this address with your contacts to let them connect with **%@**." = "Megoszthatja ezt a címet az ismerőseivel, hogy kapcsolatba léphessenek önnel a(z) **%@** nevű profilján keresztül."; /* No comment provided by engineer. */ -"You can share your address as a link or QR code - anybody can connect to you." = "Megoszthatja azonosítóját hivatkozásként vagy QR-kódként – így bárki kapcsolódhat önhöz."; +"You can share your address as a link or QR code - anybody can connect to you." = "Megoszthatja a címét egy hivatkozásként vagy QR-kódként – így bárki kapcsolódhat önhöz."; /* No comment provided by engineer. */ "You can start chat via app Settings / Database or by restarting the app" = "A csevegést az alkalmazás Beállítások / Adatbázis menü segítségével vagy az alkalmazás újraindításával indíthatja el"; @@ -4446,10 +4447,10 @@ "You can't send messages!" = "Nem lehet üzeneteket küldeni!"; /* chat item text */ -"you changed address" = "azonosítója megváltoztatva"; +"you changed address" = "cím megváltoztatva"; /* chat item text */ -"you changed address for %@" = "%@ azonosítója megváltoztatva"; +"you changed address for %@" = "cím megváltoztatva nála: %@"; /* snd group event chat item */ "you changed role for yourself to %@" = "saját szerepkör megváltoztatva erre: %@"; @@ -4464,7 +4465,7 @@ "You could not be verified; please try again." = "Nem lehetett ellenőrizni; próbálja meg újra."; /* No comment provided by engineer. */ -"You have already requested connection via this address!" = "Már kért egy kapcsolódási kérelmet ezen az azonosítón keresztül!"; +"You have already requested connection via this address!" = "Már kért egy kapcsolódási kérelmet ezen a címen keresztül!"; /* No comment provided by engineer. */ "You have already requested connection!\nRepeat connection request?" = "Már kért egy kapcsolódási kérelmet!\nKapcsolódási kérés megismétlése?"; @@ -4536,7 +4537,7 @@ "You will stop receiving messages from this group. Chat history will be preserved." = "Ettől a csoporttól nem fog értesítéseket kapni. A csevegési előzmények megmaradnak."; /* No comment provided by engineer. */ -"You won't lose your contacts if you later delete your address." = "Nem veszíti el az ismerőseit, ha később törli az azonosítóját."; +"You won't lose your contacts if you later delete your address." = "Nem veszíti el az ismerőseit, ha később törli a címét."; /* No comment provided by engineer. */ "you: " = "ön: "; @@ -4614,7 +4615,7 @@ "Your settings" = "Beállítások"; /* No comment provided by engineer. */ -"Your SimpleX address" = "SimpleX azonosítója"; +"Your SimpleX address" = "Az ön SimpleX címe"; /* No comment provided by engineer. */ "Your SMP servers" = "SMP kiszolgálók"; diff --git a/apps/ios/it.lproj/Localizable.strings b/apps/ios/it.lproj/Localizable.strings index 7039ebc4d0..addb026ab7 100644 --- a/apps/ios/it.lproj/Localizable.strings +++ b/apps/ios/it.lproj/Localizable.strings @@ -337,9 +337,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "sopra, quindi scegli:"; -/* No comment provided by engineer. */ -"Accent color" = "Colore principale"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Accetta"; @@ -369,7 +366,7 @@ "Add profile" = "Aggiungi profilo"; /* No comment provided by engineer. */ -"Add server…" = "Aggiungi server…"; +"Add server" = "Aggiungi server"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Aggiungi server scansionando codici QR."; @@ -653,7 +650,7 @@ /* rcv group event chat item */ "blocked %@" = "ha bloccato %@"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "bloccato dall'amministratore"; /* No comment provided by engineer. */ @@ -840,9 +837,6 @@ /* No comment provided by engineer. */ "colored" = "colorato"; -/* No comment provided by engineer. */ -"Colors" = "Colori"; - /* server test step */ "Compare file" = "Confronta file"; @@ -1023,7 +1017,7 @@ /* No comment provided by engineer. */ "Continue" = "Continua"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Copia"; /* No comment provided by engineer. */ @@ -1167,6 +1161,9 @@ /* time unit */ "days" = "giorni"; +/* No comment provided by engineer. */ +"Debug delivery" = "Debug della consegna"; + /* No comment provided by engineer. */ "Decentralized" = "Decentralizzato"; @@ -1800,7 +1797,8 @@ /* No comment provided by engineer. */ "Error: " = "Errore: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Errore: %@"; /* No comment provided by engineer. */ @@ -2496,6 +2494,9 @@ /* No comment provided by engineer. */ "Message draft" = "Bozza dei messaggi"; +/* No comment provided by engineer. */ +"Message queue info" = "Info coda messaggi"; + /* chat feature */ "Message reactions" = "Reazioni ai messaggi"; @@ -2991,7 +2992,7 @@ "Private filenames" = "Nomi di file privati"; /* No comment provided by engineer. */ -"Private message routing" = "Instradamento privato messaggi"; +"Private message routing" = "Instradamento privato dei messaggi"; /* No comment provided by engineer. */ "Private message routing 🚀" = "Instradamento privato dei messaggi 🚀"; @@ -3518,6 +3519,9 @@ /* srv error text. */ "Server address is incompatible with network settings." = "L'indirizzo del server non è compatibile con le impostazioni di rete."; +/* queue info */ +"server queue info: %@\n\nlast received msg: %@" = "info coda server: %1$@\n\nultimo msg ricevuto: %2$@"; + /* server test error */ "Server requires authorization to create queues, check password" = "Il server richiede l'autorizzazione di creare code, controlla la password"; @@ -3872,9 +3876,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "Il testo che hai incollato non è un link SimpleX."; -/* No comment provided by engineer. */ -"Theme" = "Tema"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Queste impostazioni sono per il tuo profilo attuale **%@**."; diff --git a/apps/ios/ja.lproj/Localizable.strings b/apps/ios/ja.lproj/Localizable.strings index bfb6ef4a3a..d66f5bee3d 100644 --- a/apps/ios/ja.lproj/Localizable.strings +++ b/apps/ios/ja.lproj/Localizable.strings @@ -331,9 +331,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "上で選んでください:"; -/* No comment provided by engineer. */ -"Accent color" = "アクセントカラー"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "承諾"; @@ -360,7 +357,7 @@ "Add profile" = "プロフィールを追加"; /* No comment provided by engineer. */ -"Add server…" = "サーバを追加…"; +"Add server" = "サーバを追加"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "QRコードでサーバを追加する。"; @@ -735,9 +732,6 @@ /* No comment provided by engineer. */ "colored" = "色付き"; -/* No comment provided by engineer. */ -"Colors" = "色"; - /* server test step */ "Compare file" = "ファイルを比較"; @@ -867,7 +861,7 @@ /* No comment provided by engineer. */ "Continue" = "続ける"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "コピー"; /* No comment provided by engineer. */ @@ -1509,7 +1503,8 @@ /* No comment provided by engineer. */ "Error: " = "エラー : "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "エラー : %@"; /* No comment provided by engineer. */ @@ -3113,9 +3108,6 @@ /* No comment provided by engineer. */ "The servers for new connections of your current chat profile **%@**." = "現在のチャットプロフィールの新しい接続のサーバ **%@**。"; -/* No comment provided by engineer. */ -"Theme" = "テーマ"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "これらの設定は現在のプロファイル **%@** 用です。"; diff --git a/apps/ios/nl.lproj/Localizable.strings b/apps/ios/nl.lproj/Localizable.strings index 119cbc6378..c361c2c64e 100644 --- a/apps/ios/nl.lproj/Localizable.strings +++ b/apps/ios/nl.lproj/Localizable.strings @@ -337,9 +337,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "hier boven, kies dan:"; -/* No comment provided by engineer. */ -"Accent color" = "Accent kleur"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Accepteer"; @@ -369,7 +366,7 @@ "Add profile" = "Profiel toevoegen"; /* No comment provided by engineer. */ -"Add server…" = "Server toevoegen…"; +"Add server" = "Server toevoegen"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Servers toevoegen door QR-codes te scannen."; @@ -653,7 +650,7 @@ /* rcv group event chat item */ "blocked %@" = "geblokkeerd %@"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "geblokkeerd door beheerder"; /* No comment provided by engineer. */ @@ -840,9 +837,6 @@ /* No comment provided by engineer. */ "colored" = "gekleurd"; -/* No comment provided by engineer. */ -"Colors" = "Kleuren"; - /* server test step */ "Compare file" = "Bestand vergelijken"; @@ -1023,7 +1017,7 @@ /* No comment provided by engineer. */ "Continue" = "Doorgaan"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Kopiëren"; /* No comment provided by engineer. */ @@ -1167,6 +1161,9 @@ /* time unit */ "days" = "dagen"; +/* No comment provided by engineer. */ +"Debug delivery" = "Foutopsporing bezorging"; + /* No comment provided by engineer. */ "Decentralized" = "Gedecentraliseerd"; @@ -1800,7 +1797,8 @@ /* No comment provided by engineer. */ "Error: " = "Fout: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Fout: %@"; /* No comment provided by engineer. */ @@ -2496,6 +2494,9 @@ /* No comment provided by engineer. */ "Message draft" = "Concept bericht"; +/* No comment provided by engineer. */ +"Message queue info" = "Informatie over berichtenwachtrij"; + /* chat feature */ "Message reactions" = "Reacties op berichten"; @@ -3518,6 +3519,9 @@ /* srv error text. */ "Server address is incompatible with network settings." = "Serveradres is niet compatibel met netwerkinstellingen."; +/* queue info */ +"server queue info: %@\n\nlast received msg: %@" = "informatie over serverwachtrij: %1$@\n\nlaatst ontvangen bericht: %2$@"; + /* server test error */ "Server requires authorization to create queues, check password" = "Server vereist autorisatie om wachtrijen te maken, controleer wachtwoord"; @@ -3872,9 +3876,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "De tekst die u hebt geplakt is geen SimpleX link."; -/* No comment provided by engineer. */ -"Theme" = "Thema"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Deze instellingen zijn voor uw huidige profiel **%@**."; diff --git a/apps/ios/pl.lproj/Localizable.strings b/apps/ios/pl.lproj/Localizable.strings index 3189c74cf2..5860ed1868 100644 --- a/apps/ios/pl.lproj/Localizable.strings +++ b/apps/ios/pl.lproj/Localizable.strings @@ -337,9 +337,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "powyżej, a następnie wybierz:"; -/* No comment provided by engineer. */ -"Accent color" = "Kolor akcentu"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Akceptuj"; @@ -369,7 +366,7 @@ "Add profile" = "Dodaj profil"; /* No comment provided by engineer. */ -"Add server…" = "Dodaj serwer…"; +"Add server" = "Dodaj serwer"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Dodaj serwery, skanując kody QR."; @@ -653,7 +650,7 @@ /* rcv group event chat item */ "blocked %@" = "zablokowany %@"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "zablokowany przez admina"; /* No comment provided by engineer. */ @@ -840,9 +837,6 @@ /* No comment provided by engineer. */ "colored" = "kolorowy"; -/* No comment provided by engineer. */ -"Colors" = "Kolory"; - /* server test step */ "Compare file" = "Porównaj plik"; @@ -1023,7 +1017,7 @@ /* No comment provided by engineer. */ "Continue" = "Kontynuuj"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Kopiuj"; /* No comment provided by engineer. */ @@ -1167,6 +1161,9 @@ /* time unit */ "days" = "dni"; +/* No comment provided by engineer. */ +"Debug delivery" = "Dostarczenie debugowania"; + /* No comment provided by engineer. */ "Decentralized" = "Zdecentralizowane"; @@ -1800,7 +1797,8 @@ /* No comment provided by engineer. */ "Error: " = "Błąd: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Błąd: %@"; /* No comment provided by engineer. */ @@ -2496,6 +2494,9 @@ /* No comment provided by engineer. */ "Message draft" = "Wersja robocza wiadomości"; +/* No comment provided by engineer. */ +"Message queue info" = "Informacje kolejki wiadomości"; + /* chat feature */ "Message reactions" = "Reakcje wiadomości"; @@ -3518,6 +3519,9 @@ /* srv error text. */ "Server address is incompatible with network settings." = "Adres serwera jest niekompatybilny z ustawieniami sieciowymi."; +/* queue info */ +"server queue info: %@\n\nlast received msg: %@" = "Informacje kolejki serwera: %1$@\n\nostatnia otrzymana wiadomość: %2$@"; + /* server test error */ "Server requires authorization to create queues, check password" = "Serwer wymaga autoryzacji do tworzenia kolejek, sprawdź hasło"; @@ -3872,9 +3876,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "Tekst, który wkleiłeś nie jest linkiem SimpleX."; -/* No comment provided by engineer. */ -"Theme" = "Motyw"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Te ustawienia dotyczą Twojego bieżącego profilu **%@**."; diff --git a/apps/ios/ru.lproj/Localizable.strings b/apps/ios/ru.lproj/Localizable.strings index c0ad6e23cf..450a6147b7 100644 --- a/apps/ios/ru.lproj/Localizable.strings +++ b/apps/ios/ru.lproj/Localizable.strings @@ -337,9 +337,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "наверху, затем выберите:"; -/* No comment provided by engineer. */ -"Accent color" = "Основной цвет"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Принять"; @@ -369,7 +366,7 @@ "Add profile" = "Добавить профиль"; /* No comment provided by engineer. */ -"Add server…" = "Добавить сервер…"; +"Add server" = "Добавить сервер"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Добавить серверы через QR код."; @@ -653,7 +650,7 @@ /* rcv group event chat item */ "blocked %@" = "%@ заблокирован"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "заблокировано администратором"; /* No comment provided by engineer. */ @@ -840,9 +837,6 @@ /* No comment provided by engineer. */ "colored" = "цвет"; -/* No comment provided by engineer. */ -"Colors" = "Цвета"; - /* server test step */ "Compare file" = "Сравнение файла"; @@ -1023,7 +1017,7 @@ /* No comment provided by engineer. */ "Continue" = "Продолжить"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Скопировать"; /* No comment provided by engineer. */ @@ -1800,7 +1794,8 @@ /* No comment provided by engineer. */ "Error: " = "Ошибка: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Ошибка: %@"; /* No comment provided by engineer. */ @@ -3872,9 +3867,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "Вставленный текст не является SimpleX-ссылкой."; -/* No comment provided by engineer. */ -"Theme" = "Тема"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Установки для Вашего активного профиля **%@**."; diff --git a/apps/ios/th.lproj/Localizable.strings b/apps/ios/th.lproj/Localizable.strings index fa31dccf96..5ce2e40e14 100644 --- a/apps/ios/th.lproj/Localizable.strings +++ b/apps/ios/th.lproj/Localizable.strings @@ -259,9 +259,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "ด้านบน จากนั้นเลือก:"; -/* No comment provided by engineer. */ -"Accent color" = "สีเน้น"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "รับ"; @@ -285,7 +282,7 @@ "Add profile" = "เพิ่มโปรไฟล์"; /* No comment provided by engineer. */ -"Add server…" = "เพิ่มเซิร์ฟเวอร์…"; +"Add server" = "เพิ่มเซิร์ฟเวอร์"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "เพิ่มเซิร์ฟเวอร์โดยการสแกนรหัสคิวอาร์โค้ด"; @@ -639,9 +636,6 @@ /* No comment provided by engineer. */ "colored" = "มีสี"; -/* No comment provided by engineer. */ -"Colors" = "สี"; - /* server test step */ "Compare file" = "เปรียบเทียบไฟล์"; @@ -765,7 +759,7 @@ /* No comment provided by engineer. */ "Continue" = "ดำเนินการต่อ"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "คัดลอก"; /* No comment provided by engineer. */ @@ -1386,7 +1380,8 @@ /* No comment provided by engineer. */ "Error: " = "ผิดพลาด: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "ข้อผิดพลาด: % @"; /* No comment provided by engineer. */ @@ -2975,9 +2970,6 @@ /* No comment provided by engineer. */ "The servers for new connections of your current chat profile **%@**." = "เซิร์ฟเวอร์สำหรับการเชื่อมต่อใหม่ของโปรไฟล์การแชทปัจจุบันของคุณ **%@**"; -/* No comment provided by engineer. */ -"Theme" = "ธีม"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "การตั้งค่าเหล่านี้ใช้สำหรับโปรไฟล์ปัจจุบันของคุณ **%@**"; diff --git a/apps/ios/tr.lproj/Localizable.strings b/apps/ios/tr.lproj/Localizable.strings index 696d5a3f21..65496a82bf 100644 --- a/apps/ios/tr.lproj/Localizable.strings +++ b/apps/ios/tr.lproj/Localizable.strings @@ -337,9 +337,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "yukarı çıkın, ardından seçin:"; -/* No comment provided by engineer. */ -"Accent color" = "Vurgu rengi"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Kabul et"; @@ -369,7 +366,7 @@ "Add profile" = "Profil ekle"; /* No comment provided by engineer. */ -"Add server…" = "Sunucu ekle…"; +"Add server" = "Sunucu ekle"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Karekod taratarak sunucuları ekleyin."; @@ -653,7 +650,7 @@ /* rcv group event chat item */ "blocked %@" = "engellendi %@"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "yönetici tarafından engellendi"; /* No comment provided by engineer. */ @@ -840,9 +837,6 @@ /* No comment provided by engineer. */ "colored" = "renklendirilmiş"; -/* No comment provided by engineer. */ -"Colors" = "Renkler"; - /* server test step */ "Compare file" = "Dosya karşılaştır"; @@ -1023,7 +1017,7 @@ /* No comment provided by engineer. */ "Continue" = "Devam et"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Kopyala"; /* No comment provided by engineer. */ @@ -1167,6 +1161,9 @@ /* time unit */ "days" = "gün"; +/* No comment provided by engineer. */ +"Debug delivery" = "Hata ayıklama teslimatı"; + /* No comment provided by engineer. */ "Decentralized" = "Merkezi Olmayan"; @@ -1800,7 +1797,8 @@ /* No comment provided by engineer. */ "Error: " = "Hata: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Hata: %@"; /* No comment provided by engineer. */ @@ -2496,6 +2494,9 @@ /* No comment provided by engineer. */ "Message draft" = "Mesaj taslağı"; +/* No comment provided by engineer. */ +"Message queue info" = "Mesaj kuyruğu bilgisi"; + /* chat feature */ "Message reactions" = "Mesaj tepkileri"; @@ -3518,6 +3519,9 @@ /* srv error text. */ "Server address is incompatible with network settings." = "Sunucu adresi ağ ayarlarıyla uyumlu değil."; +/* queue info */ +"server queue info: %@\n\nlast received msg: %@" = "sunucu kuyruk bilgisi: %1$@\n\nson alınan msj: %2$@"; + /* server test error */ "Server requires authorization to create queues, check password" = "Sunucunun sıra oluşturması için yetki gereklidir, şifreyi kontrol edin"; @@ -3872,9 +3876,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "Yapıştırdığın metin bir SimpleX bağlantısı değildir."; -/* No comment provided by engineer. */ -"Theme" = "Tema"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Bu ayarlar mevcut profiliniz **%@** içindir."; diff --git a/apps/ios/uk.lproj/Localizable.strings b/apps/ios/uk.lproj/Localizable.strings index 7cb4270d5b..69aac64ab5 100644 --- a/apps/ios/uk.lproj/Localizable.strings +++ b/apps/ios/uk.lproj/Localizable.strings @@ -337,9 +337,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "вище, а потім обирайте:"; -/* No comment provided by engineer. */ -"Accent color" = "Акцентний колір"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "Прийняти"; @@ -369,7 +366,7 @@ "Add profile" = "Додати профіль"; /* No comment provided by engineer. */ -"Add server…" = "Додати сервер…"; +"Add server" = "Додати сервер"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "Додайте сервери, відсканувавши QR-код."; @@ -653,7 +650,7 @@ /* rcv group event chat item */ "blocked %@" = "заблоковано %@"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "заблоковано адміністратором"; /* No comment provided by engineer. */ @@ -840,9 +837,6 @@ /* No comment provided by engineer. */ "colored" = "кольоровий"; -/* No comment provided by engineer. */ -"Colors" = "Кольори"; - /* server test step */ "Compare file" = "Порівняти файл"; @@ -1023,7 +1017,7 @@ /* No comment provided by engineer. */ "Continue" = "Продовжуйте"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "Копіювати"; /* No comment provided by engineer. */ @@ -1167,6 +1161,9 @@ /* time unit */ "days" = "днів"; +/* No comment provided by engineer. */ +"Debug delivery" = "Доставка налагодження"; + /* No comment provided by engineer. */ "Decentralized" = "Децентралізований"; @@ -1800,7 +1797,8 @@ /* No comment provided by engineer. */ "Error: " = "Помилка: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "Помилка: %@"; /* No comment provided by engineer. */ @@ -2496,6 +2494,9 @@ /* No comment provided by engineer. */ "Message draft" = "Чернетка повідомлення"; +/* No comment provided by engineer. */ +"Message queue info" = "Інформація про чергу повідомлень"; + /* chat feature */ "Message reactions" = "Реакції на повідомлення"; @@ -3518,6 +3519,9 @@ /* srv error text. */ "Server address is incompatible with network settings." = "Адреса сервера несумісна з налаштуваннями мережі."; +/* queue info */ +"server queue info: %@\n\nlast received msg: %@" = "інформація про чергу на сервері: %1$@\n\nостаннє отримане повідомлення: %2$@"; + /* server test error */ "Server requires authorization to create queues, check password" = "Сервер вимагає авторизації для створення черг, перевірте пароль"; @@ -3872,9 +3876,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "Текст, який ви вставили, не є посиланням SimpleX."; -/* No comment provided by engineer. */ -"Theme" = "Тема"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "Ці налаштування стосуються вашого поточного профілю **%@**."; diff --git a/apps/ios/zh-Hans.lproj/Localizable.strings b/apps/ios/zh-Hans.lproj/Localizable.strings index 74d9970b93..94588646c8 100644 --- a/apps/ios/zh-Hans.lproj/Localizable.strings +++ b/apps/ios/zh-Hans.lproj/Localizable.strings @@ -301,9 +301,6 @@ /* No comment provided by engineer. */ "above, then choose:" = "上面,然后选择:"; -/* No comment provided by engineer. */ -"Accent color" = "色调"; - /* accept contact request via notification accept incoming call via notification */ "Accept" = "接受"; @@ -333,7 +330,7 @@ "Add profile" = "添加个人资料"; /* No comment provided by engineer. */ -"Add server…" = "添加服务器…"; +"Add server" = "添加服务器"; /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "扫描二维码来添加服务器。"; @@ -605,7 +602,7 @@ /* rcv group event chat item */ "blocked %@" = "已封禁 %@"; -/* marked deleted chat item preview text */ +/* blocked chat item */ "blocked by admin" = "由管理员封禁"; /* No comment provided by engineer. */ @@ -786,9 +783,6 @@ /* No comment provided by engineer. */ "colored" = "彩色"; -/* No comment provided by engineer. */ -"Colors" = "颜色"; - /* server test step */ "Compare file" = "对比文件"; @@ -951,7 +945,7 @@ /* No comment provided by engineer. */ "Continue" = "继续"; -/* chat item action */ +/* No comment provided by engineer. */ "Copy" = "复制"; /* No comment provided by engineer. */ @@ -1689,7 +1683,8 @@ /* No comment provided by engineer. */ "Error: " = "错误: "; -/* snd error text */ +/* file error text + snd error text */ "Error: %@" = "错误: %@"; /* No comment provided by engineer. */ @@ -3644,9 +3639,6 @@ /* No comment provided by engineer. */ "The text you pasted is not a SimpleX link." = "您粘贴的文本不是 SimpleX 链接。"; -/* No comment provided by engineer. */ -"Theme" = "主题"; - /* No comment provided by engineer. */ "These settings are for your current profile **%@**." = "这些设置适用于您当前的配置文件 **%@**。"; diff --git a/apps/multiplatform/common/build.gradle.kts b/apps/multiplatform/common/build.gradle.kts index ac131c9748..7e97ea3414 100644 --- a/apps/multiplatform/common/build.gradle.kts +++ b/apps/multiplatform/common/build.gradle.kts @@ -105,6 +105,7 @@ kotlin { implementation("uk.co.caprica:vlcj:4.8.2") implementation("com.github.NanoHttpd.nanohttpd:nanohttpd:efb2ebf85a") implementation("com.github.NanoHttpd.nanohttpd:nanohttpd-websocket:efb2ebf85a") + implementation("com.squareup.okhttp3:okhttp:4.12.0") } } val desktopTest by getting diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/AppCommon.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/AppCommon.android.kt index 547db51bad..d739a033f9 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/AppCommon.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/AppCommon.android.kt @@ -6,8 +6,6 @@ import android.net.LocalServerSocket import android.util.Log import androidx.activity.ComponentActivity import androidx.fragment.app.FragmentActivity -import chat.simplex.common.* -import chat.simplex.common.platform.* import java.io.* import java.lang.ref.WeakReference import java.util.* @@ -24,6 +22,8 @@ var isAppOnForeground: Boolean = false @Suppress("ConstantLocale") val defaultLocale: Locale = Locale.getDefault() +actual fun isAppVisibleAndFocused(): Boolean = isAppOnForeground + @SuppressLint("StaticFieldLeak") lateinit var androidAppContext: Context var mainActivity: WeakReference = WeakReference(null) diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Files.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Files.android.kt index ea092453ee..bfe961a512 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Files.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Files.android.kt @@ -29,6 +29,8 @@ actual val remoteHostsDir: File = File(tmpDir.absolutePath + File.separator + "r actual fun desktopOpenDatabaseDir() {} +actual fun desktopOpenDir(dir: File) {} + @Composable actual fun rememberFileChooserLauncher(getContent: Boolean, rememberedValue: Any?, onResult: (URI?) -> Unit): FileChooserLauncher { val launcher = rememberLauncherForActivityResult( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt index bd35594ac0..59f5307a19 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt @@ -80,6 +80,7 @@ fun MainScreen() { laUnavailableInstructionAlert() } } + platform.desktopShowAppUpdateNotice() LaunchedEffect(chatModel.clearOverlays.value) { if (chatModel.clearOverlays.value) { ModalManager.closeAllModalsEverywhere() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt index 87e317200d..6e187df317 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt @@ -28,6 +28,7 @@ import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.* +import java.io.Closeable import java.io.File import java.net.URI import java.time.format.DateTimeFormatter @@ -65,6 +66,7 @@ object ChatModel { val deletedChats = mutableStateOf>>(emptyList()) val chatItemStatuses = mutableMapOf() val groupMembers = mutableStateListOf() + val groupMembersIndexes = mutableStateMapOf() val terminalItems = mutableStateOf>(listOf()) val userAddress = mutableStateOf(null) @@ -121,6 +123,9 @@ object ChatModel { val clipboardHasText = mutableStateOf(false) val networkInfo = mutableStateOf(UserNetworkInfo(networkType = UserNetworkType.OTHER, online = true)) + val updatingProgress = mutableStateOf(null as Float?) + var updatingRequest: Closeable? = null + val updatingChatsMutex: Mutex = Mutex() val changingActiveUserMutex: Mutex = Mutex() @@ -170,7 +175,23 @@ object ChatModel { fun getChat(id: String): Chat? = chats.toList().firstOrNull { it.id == id } fun getContactChat(contactId: Long): Chat? = chats.toList().firstOrNull { it.chatInfo is ChatInfo.Direct && it.chatInfo.apiId == contactId } fun getGroupChat(groupId: Long): Chat? = chats.toList().firstOrNull { it.chatInfo is ChatInfo.Group && it.chatInfo.apiId == groupId } - fun getGroupMember(groupMemberId: Long): GroupMember? = groupMembers.firstOrNull { it.groupMemberId == groupMemberId } + + fun populateGroupMembersIndexes() { + groupMembersIndexes.clear() + groupMembers.forEachIndexed { i, member -> + groupMembersIndexes[member.groupMemberId] = i + } + } + + fun getGroupMember(groupMemberId: Long): GroupMember? { + val memberIndex = groupMembersIndexes[groupMemberId] + return if (memberIndex != null) { + groupMembers[memberIndex] + } else { + null + } + } + private fun getChatIndex(rhId: Long?, id: String): Int = chats.toList().indexOfFirst { it.id == id && it.remoteHostId == rhId } fun addChat(chat: Chat) = chats.add(index = 0, chat) @@ -620,12 +641,13 @@ object ChatModel { } // update current chat return if (chatId.value == groupInfo.id) { - val memberIndex = groupMembers.indexOfFirst { it.groupMemberId == member.groupMemberId } - if (memberIndex >= 0) { + val memberIndex = groupMembersIndexes[member.groupMemberId] + if (memberIndex != null) { groupMembers[memberIndex] = member false } else { groupMembers.add(member) + groupMembersIndexes[member.groupMemberId] = groupMembers.size - 1 true } } else { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index be6295f2b0..22592e0013 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -160,6 +160,9 @@ class AppPreferences { val showHiddenProfilesNotice = mkBoolPreference(SHARED_PREFS_SHOW_HIDDEN_PROFILES_NOTICE, true) val showMuteProfileAlert = mkBoolPreference(SHARED_PREFS_SHOW_MUTE_PROFILE_ALERT, true) val appLanguage = mkStrPreference(SHARED_PREFS_APP_LANGUAGE, null) + val appUpdateChannel = mkEnumPreference(SHARED_PREFS_APP_UPDATE_CHANNEL, AppUpdatesChannel.DISABLED) { AppUpdatesChannel.entries.firstOrNull { it.name == this } } + val appSkippedUpdate = mkStrPreference(SHARED_PREFS_APP_SKIPPED_UPDATE, "") + val appUpdateNoticeShown = mkBoolPreference(SHARED_PREFS_APP_UPDATE_NOTICE_SHOWN, false) val onboardingStage = mkEnumPreference(SHARED_PREFS_ONBOARDING_STAGE, OnboardingStage.OnboardingComplete) { OnboardingStage.values().firstOrNull { it.name == this } } val migrationToStage = mkStrPreference(SHARED_PREFS_MIGRATION_TO_STAGE, null) @@ -334,6 +337,9 @@ class AppPreferences { private const val SHARED_PREFS_CHAT_ARCHIVE_NAME = "ChatArchiveName" private const val SHARED_PREFS_CHAT_ARCHIVE_TIME = "ChatArchiveTime" private const val SHARED_PREFS_APP_LANGUAGE = "AppLanguage" + private const val SHARED_PREFS_APP_UPDATE_CHANNEL = "AppUpdateChannel" + private const val SHARED_PREFS_APP_SKIPPED_UPDATE = "AppSkippedUpdate" + private const val SHARED_PREFS_APP_UPDATE_NOTICE_SHOWN = "AppUpdateNoticeShown" private const val SHARED_PREFS_ONBOARDING_STAGE = "OnboardingStage" const val SHARED_PREFS_MIGRATION_TO_STAGE = "MigrationToStage" const val SHARED_PREFS_MIGRATION_FROM_STAGE = "MigrationFromStage" @@ -1831,6 +1837,80 @@ object ChatController { ) true } + r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorAgent + && r.chatError.agentError is AgentErrorType.BROKER + && r.chatError.agentError.brokerErr is BrokerErrorType.HOST -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.connection_error), + String.format(generalGetString(MR.strings.network_error_broker_host_desc), serverHostname(r.chatError.agentError.brokerAddress)) + ) + true + } + r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorAgent + && r.chatError.agentError is AgentErrorType.BROKER + && r.chatError.agentError.brokerErr is BrokerErrorType.TRANSPORT + && r.chatError.agentError.brokerErr.transportErr is SMPTransportError.Version -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.connection_error), + String.format(generalGetString(MR.strings.network_error_broker_version_desc), serverHostname(r.chatError.agentError.brokerAddress)) + ) + true + } + r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorAgent + && r.chatError.agentError is AgentErrorType.SMP + && r.chatError.agentError.smpErr is SMPErrorType.PROXY -> + proxyErrorAlert(r.chatError.agentError.smpErr.proxyErr) + r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorAgent + && r.chatError.agentError is AgentErrorType.PROXY + && r.chatError.agentError.proxyErr is ProxyClientError.ProxyProtocolError + && r.chatError.agentError.proxyErr.protocolErr is SMPErrorType.PROXY -> + proxyErrorAlert(r.chatError.agentError.proxyErr.protocolErr.proxyErr) + else -> false + } + } + + private fun proxyErrorAlert(pe: ProxyError): Boolean { + return when { + pe is ProxyError.BROKER + && pe.brokerErr is BrokerErrorType.TIMEOUT -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.private_routing_error), + generalGetString(MR.strings.please_try_later) + ) + true + } + pe is ProxyError.BROKER + && pe.brokerErr is BrokerErrorType.NETWORK -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.private_routing_error), + generalGetString(MR.strings.please_try_later) + ) + true + } + pe is ProxyError.NO_SESSION -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.private_routing_error), + generalGetString(MR.strings.please_try_later) + ) + true + } + pe is ProxyError.BROKER + && pe.brokerErr is BrokerErrorType.HOST -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.private_routing_error), + generalGetString(MR.strings.srv_error_host) + ) + true + } + pe is ProxyError.BROKER + && pe.brokerErr is BrokerErrorType.TRANSPORT + && pe.brokerErr.transportErr is SMPTransportError.Version -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.private_routing_error), + generalGetString(MR.strings.srv_error_version) + ) + true + } else -> false } } @@ -3086,7 +3166,7 @@ data class ProtoServersConfig( data class UserProtocolServers( val serverProtocol: ServerProtocol, val protoServers: List, - val presetServers: List, + val presetServers: List, ) @Serializable @@ -3095,7 +3175,7 @@ data class ServerCfg( val server: String, val preset: Boolean, val tested: Boolean? = null, - val enabled: ServerEnabled + val enabled: Boolean ) { @Transient private val createdAt: Date = Date() @@ -3109,7 +3189,7 @@ data class ServerCfg( get() = server.isBlank() companion object { - val empty = ServerCfg(remoteHostId = null, server = "", preset = false, tested = null, enabled = ServerEnabled.Enabled) + val empty = ServerCfg(remoteHostId = null, server = "", preset = false, tested = null, enabled = false) class SampleData( val preset: ServerCfg, @@ -3123,33 +3203,26 @@ data class ServerCfg( server = "smp://abcd@smp8.simplex.im", preset = true, tested = true, - enabled = ServerEnabled.Enabled + enabled = true ), custom = ServerCfg( remoteHostId = null, server = "smp://abcd@smp9.simplex.im", preset = false, tested = false, - enabled = ServerEnabled.Disabled + enabled = false ), untested = ServerCfg( remoteHostId = null, server = "smp://abcd@smp10.simplex.im", preset = false, tested = null, - enabled = ServerEnabled.Enabled + enabled = true ) ) } } -@Serializable -enum class ServerEnabled { - @SerialName("disabled") Disabled, - @SerialName("enabled") Enabled, - @SerialName("known") Known; -} - @Serializable enum class ProtocolTestStep { @SerialName("connect") Connect, @@ -5535,6 +5608,7 @@ sealed class AgentErrorType { is SMP -> "SMP ${smpErr.string}" // is NTF -> "NTF ${ntfErr.string}" is XFTP -> "XFTP ${xftpErr.string}" + is PROXY -> "PROXY $proxyServer $relayServer ${proxyErr.string}" is RCP -> "RCP ${rcpErr.string}" is BROKER -> "BROKER ${brokerErr.string}" is AGENT -> "AGENT ${agentErr.string}" @@ -5547,6 +5621,7 @@ sealed class AgentErrorType { @Serializable @SerialName("SMP") class SMP(val smpErr: SMPErrorType): AgentErrorType() // @Serializable @SerialName("NTF") class NTF(val ntfErr: SMPErrorType): AgentErrorType() @Serializable @SerialName("XFTP") class XFTP(val xftpErr: XFTPErrorType): AgentErrorType() + @Serializable @SerialName("PROXY") class PROXY(val proxyServer: String, val relayServer: String, val proxyErr: ProxyClientError): AgentErrorType() @Serializable @SerialName("RCP") class RCP(val rcpErr: RCErrorType): AgentErrorType() @Serializable @SerialName("BROKER") class BROKER(val brokerAddress: String, val brokerErr: BrokerErrorType): AgentErrorType() @Serializable @SerialName("AGENT") class AGENT(val agentErr: SMPAgentError): AgentErrorType() @@ -5611,22 +5686,42 @@ sealed class SMPErrorType { is BLOCK -> "BLOCK" is SESSION -> "SESSION" is CMD -> "CMD ${cmdErr.string}" + is PROXY -> "PROXY ${proxyErr.string}" is AUTH -> "AUTH" + is CRYPTO -> "CRYPTO" is QUOTA -> "QUOTA" is NO_MSG -> "NO_MSG" is LARGE_MSG -> "LARGE_MSG" + is EXPIRED -> "EXPIRED" is INTERNAL -> "INTERNAL" } @Serializable @SerialName("BLOCK") class BLOCK: SMPErrorType() @Serializable @SerialName("SESSION") class SESSION: SMPErrorType() @Serializable @SerialName("CMD") class CMD(val cmdErr: ProtocolCommandError): SMPErrorType() + @Serializable @SerialName("PROXY") class PROXY(val proxyErr: ProxyError): SMPErrorType() @Serializable @SerialName("AUTH") class AUTH: SMPErrorType() + @Serializable @SerialName("CRYPTO") class CRYPTO: SMPErrorType() @Serializable @SerialName("QUOTA") class QUOTA: SMPErrorType() @Serializable @SerialName("NO_MSG") class NO_MSG: SMPErrorType() @Serializable @SerialName("LARGE_MSG") class LARGE_MSG: SMPErrorType() + @Serializable @SerialName("EXPIRED") class EXPIRED: SMPErrorType() @Serializable @SerialName("INTERNAL") class INTERNAL: SMPErrorType() } +@Serializable +sealed class ProxyError { + val string: String get() = when (this) { + is PROTOCOL -> "PROTOCOL ${protocolErr.string}" + is BROKER -> "BROKER ${brokerErr.string}" + is BASIC_AUTH -> "BASIC_AUTH" + is NO_SESSION -> "NO_SESSION" + } + @Serializable @SerialName("PROTOCOL") class PROTOCOL(val protocolErr: SMPErrorType): ProxyError() + @Serializable @SerialName("BROKER") class BROKER(val brokerErr: BrokerErrorType): ProxyError() + @Serializable @SerialName("BASIC_AUTH") class BASIC_AUTH: ProxyError() + @Serializable @SerialName("NO_SESSION") class NO_SESSION: ProxyError() +} + @Serializable sealed class ProtocolCommandError { val string: String get() = when (this) { @@ -5649,12 +5744,14 @@ sealed class ProtocolCommandError { sealed class SMPTransportError { val string: String get() = when (this) { is BadBlock -> "badBlock" + is Version -> "version" is LargeMsg -> "largeMsg" is BadSession -> "badSession" is NoServerAuth -> "noServerAuth" is Handshake -> "handshake ${handshakeErr.string}" } @Serializable @SerialName("badBlock") class BadBlock: SMPTransportError() + @Serializable @SerialName("version") class Version: SMPTransportError() @Serializable @SerialName("largeMsg") class LargeMsg: SMPTransportError() @Serializable @SerialName("badSession") class BadSession: SMPTransportError() @Serializable @SerialName("noServerAuth") class NoServerAuth: SMPTransportError() @@ -5727,6 +5824,18 @@ sealed class XFTPErrorType { @Serializable @SerialName("INTERNAL") object INTERNAL: XFTPErrorType() } +@Serializable +sealed class ProxyClientError { + val string: String get() = when (this) { + is ProxyProtocolError -> "ProxyProtocolError $protocolErr" + is ProxyUnexpectedResponse -> "ProxyUnexpectedResponse $responseStr" + is ProxyResponseError -> "ProxyResponseError $responseErr" + } + @Serializable @SerialName("protocolError") class ProxyProtocolError(val protocolErr: SMPErrorType): ProxyClientError() + @Serializable @SerialName("unexpectedResponse") class ProxyUnexpectedResponse(val responseStr: String): ProxyClientError() + @Serializable @SerialName("responseError") class ProxyResponseError(val responseErr: SMPErrorType): ProxyClientError() +} + @Serializable sealed class RCErrorType { val string: String get() = when (this) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/AppCommon.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/AppCommon.kt index 10cb17df1d..60a65eaac6 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/AppCommon.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/AppCommon.kt @@ -3,7 +3,8 @@ package chat.simplex.common.platform import chat.simplex.common.BuildConfigCommon import chat.simplex.common.model.* import chat.simplex.common.ui.theme.DefaultTheme -import java.io.File +import chat.simplex.common.views.helpers.generalGetString +import chat.simplex.res.MR import java.util.* enum class AppPlatform { @@ -20,6 +21,8 @@ expect val appPlatform: AppPlatform expect val deviceName: String +expect fun isAppVisibleAndFocused(): Boolean + val appVersionInfo: Pair = if (appPlatform == AppPlatform.ANDROID) BuildConfigCommon.ANDROID_VERSION_NAME to BuildConfigCommon.ANDROID_VERSION_CODE else @@ -55,3 +58,16 @@ fun runMigrations() { } } } + +enum class AppUpdatesChannel { + DISABLED, + STABLE, + BETA; + + val text: String + get() = when (this) { + DISABLED -> generalGetString(MR.strings.app_check_for_updates_disabled) + STABLE -> generalGetString(MR.strings.app_check_for_updates_stable) + BETA -> generalGetString(MR.strings.app_check_for_updates_beta) + } +} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Files.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Files.kt index 250afe03c4..9110987190 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Files.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Files.kt @@ -34,6 +34,8 @@ expect val remoteHostsDir: File expect fun desktopOpenDatabaseDir() +expect fun desktopOpenDir(dir: File) + fun createURIFromPath(absolutePath: String): URI = URI.create(URLEncoder.encode(absolutePath, "UTF-8")) fun URI.toFile(): File = File(URLDecoder.decode(rawPath, "UTF-8").removePrefix("file:")) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt index f61c5bc83e..7020a42c1e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt @@ -29,6 +29,7 @@ interface PlatformInterface { @Composable fun desktopScrollBarComponents(): Triple, Modifier, MutableState> = remember { Triple(Animatable(0f), Modifier, mutableStateOf(Job())) } @Composable fun desktopScrollBar(state: LazyListState, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) {} @Composable fun desktopScrollBar(state: ScrollState, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) {} + @Composable fun desktopShowAppUpdateNotice() {} } /** * Multiplatform project has separate directories per platform + common directory that contains directories per platform + common for all of them. diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index b1107d058b..9d2afefa03 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -159,6 +159,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId: AudioPlayer.stop() chatModel.chatId.value = null chatModel.groupMembers.clear() + chatModel.groupMembersIndexes.clear() }, info = { if (ModalManager.end.hasModalsOpen()) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt index 89751dd140..f181126b33 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt @@ -128,30 +128,6 @@ fun CIFileView( } } - @Composable - fun progressIndicator() { - CircularProgressIndicator( - Modifier.size(32.dp), - color = if (isInDarkTheme()) FileDark else FileLight, - strokeWidth = 3.dp - ) - } - - @Composable - fun progressCircle(progress: Long, total: Long) { - val angle = 360f * (progress.toDouble() / total.toDouble()).toFloat() - val strokeWidth = with(LocalDensity.current) { 3.dp.toPx() } - val strokeColor = if (isInDarkTheme()) FileDark else FileLight - Surface( - Modifier.drawRingModifier(angle, strokeColor, strokeWidth), - color = Color.Transparent, - shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)), - contentColor = LocalContentColor.current - ) { - Box(Modifier.size(32.dp)) - } - } - @Composable fun fileIndicator() { Box( @@ -164,14 +140,14 @@ fun CIFileView( when (file.fileStatus) { is CIFileStatus.SndStored -> when (file.fileProtocol) { - FileProtocol.XFTP -> progressIndicator() + FileProtocol.XFTP -> CIFileViewScope.progressIndicator() FileProtocol.SMP -> fileIcon() FileProtocol.LOCAL -> fileIcon() } is CIFileStatus.SndTransfer -> when (file.fileProtocol) { - FileProtocol.XFTP -> progressCircle(file.fileStatus.sndProgress, file.fileStatus.sndTotal) - FileProtocol.SMP -> progressIndicator() + FileProtocol.XFTP -> CIFileViewScope.progressCircle(file.fileStatus.sndProgress, file.fileStatus.sndTotal) + FileProtocol.SMP -> CIFileViewScope.progressIndicator() FileProtocol.LOCAL -> {} } is CIFileStatus.SndComplete -> fileIcon(innerIcon = painterResource(MR.images.ic_check_filled)) @@ -186,9 +162,9 @@ fun CIFileView( is CIFileStatus.RcvAccepted -> fileIcon(innerIcon = painterResource(MR.images.ic_more_horiz)) is CIFileStatus.RcvTransfer -> if (file.fileProtocol == FileProtocol.XFTP && file.fileStatus.rcvProgress < file.fileStatus.rcvTotal) { - progressCircle(file.fileStatus.rcvProgress, file.fileStatus.rcvTotal) + CIFileViewScope.progressCircle(file.fileStatus.rcvProgress, file.fileStatus.rcvTotal) } else { - progressIndicator() + CIFileViewScope.progressIndicator() } is CIFileStatus.RcvAborted -> fileIcon(innerIcon = painterResource(MR.images.ic_sync_problem), color = MaterialTheme.colors.primary) @@ -265,6 +241,32 @@ fun rememberSaveFileLauncher(ciFile: CIFile?): FileChooserLauncher = } } +object CIFileViewScope { + @Composable + fun progressIndicator() { + CircularProgressIndicator( + Modifier.size(32.dp), + color = if (isInDarkTheme()) FileDark else FileLight, + strokeWidth = 3.dp + ) + } + + @Composable + fun progressCircle(progress: Long, total: Long) { + val angle = 360f * (progress.toDouble() / total.toDouble()).toFloat() + val strokeWidth = with(LocalDensity.current) { 3.dp.toPx() } + val strokeColor = if (isInDarkTheme()) FileDark else FileLight + Surface( + Modifier.drawRingModifier(angle, strokeColor, strokeWidth), + color = Color.Transparent, + shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)), + contentColor = LocalContentColor.current + ) { + Box(Modifier.size(32.dp)) + } + } +} + /* class ChatItemProvider: PreviewParameterProvider { private val sentFile = ChatItem( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt index f7e9855b86..aa30e757ec 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt @@ -261,7 +261,9 @@ suspend fun setGroupMembers(rhId: Long?, groupInfo: GroupInfo, chatModel: ChatMo } } chatModel.groupMembers.clear() + chatModel.groupMembersIndexes.clear() chatModel.groupMembers.addAll(newMembers) + chatModel.populateGroupMembersIndexes() } @Composable diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt index 332c1d070e..7bf72384b8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt @@ -1,8 +1,10 @@ package chat.simplex.common.views.chatlist -import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.* +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsHoveredAsState import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.BoxScope.* import androidx.compose.foundation.lazy.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape @@ -14,7 +16,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.focus.* import androidx.compose.ui.graphics.* -import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.platform.* import androidx.compose.ui.text.TextRange @@ -33,6 +34,7 @@ import chat.simplex.common.views.onboarding.shouldShowWhatsNew import chat.simplex.common.views.usersettings.SettingsView import chat.simplex.common.platform.* import chat.simplex.common.views.call.Call +import chat.simplex.common.views.chat.item.CIFileViewScope import chat.simplex.common.views.newchat.* import chat.simplex.res.MR import kotlinx.coroutines.* @@ -40,7 +42,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.serialization.json.Json import java.net.URI -import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds @Composable @@ -77,8 +78,29 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } val scope = rememberCoroutineScope() val (userPickerState, scaffoldState ) = settingsState - Scaffold(topBar = { Box(Modifier.padding(end = endPadding)) { ChatListTopBar(stopped) } }, - bottomBar = { Box(Modifier.padding(end = endPadding)) { ChatListBottomToolbar(scaffoldState.drawerState, userPickerState) } }, + Scaffold( + topBar = { + if (!oneHandUI.state.value) { + Box(Modifier.padding(end = endPadding)) { + ChatListToolbar( + scaffoldState.drawerState, + userPickerState, + stopped + ) + } + } + }, + bottomBar = { + if (oneHandUI.state.value) { + Box(Modifier.padding(end = endPadding)) { + ChatListToolbar( + scaffoldState.drawerState, + userPickerState, + stopped + ) + } + } + }, scaffoldState = scaffoldState, drawerContent = { tryOrShowError("Settings", error = { ErrorSettingsView() }) { @@ -156,7 +178,12 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf } if (appPlatform.isAndroid) { tryOrShowError("UserPicker", error = {}) { - UserPicker(chatModel, userPickerState) { + + UserPicker( + chatModel = chatModel, + userPickerState = userPickerState, + containerModifier = Modifier.padding(bottom = AppBarHeight), + contentAlignment = if (oneHandUI.state.value) Alignment.BottomStart else Alignment.TopStart) { scope.launch { if (scaffoldState.drawerState.isOpen) scaffoldState.drawerState.close() else scaffoldState.drawerState.open() } userPickerState.value = AnimatedViewState.GONE } @@ -202,11 +229,27 @@ private fun ConnectButton(text: String, onClick: () -> Unit) { } @Composable -private fun ChatListTopBar(stopped: Boolean) { +private fun ChatListToolbar(drawerState: DrawerState, userPickerState: MutableStateFlow, stopped: Boolean) { val serversSummary: MutableState = remember { mutableStateOf(null) } - val barButtons = arrayListOf<@Composable RowScope.() -> Unit>() - if (stopped) { + val updatingProgress = remember { chatModel.updatingProgress }.value + if (updatingProgress != null) { + barButtons.add { + val interactionSource = remember { MutableInteractionSource() } + val hovered = interactionSource.collectIsHoveredAsState().value + IconButton(onClick = { + chatModel.updatingRequest?.close() + }, Modifier.hoverable(interactionSource)) { + if (hovered) { + Icon(painterResource(MR.images.ic_close), null, tint = WarningOrange) + } else if (updatingProgress == -1f) { + CIFileViewScope.progressIndicator() + } else { + CIFileViewScope.progressCircle((updatingProgress * 100).toLong(), 100) + } + } + } + } else if (stopped) { barButtons.add { IconButton(onClick = { AlertManager.shared.showAlertMsg( @@ -222,10 +265,26 @@ private fun ChatListTopBar(stopped: Boolean) { } } } - + val scope = rememberCoroutineScope() val clipboard = LocalClipboardManager.current - DefaultTopAppBar( + navigationButton = { + if (chatModel.users.isEmpty() && !chatModel.desktopNoUserNoRemote) { + NavigationButtonMenu { scope.launch { if (drawerState.isOpen) drawerState.close() else drawerState.open() } } + } else { + val users by remember { derivedStateOf { chatModel.users.filter { u -> u.user.activeUser || !u.user.hidden } } } + val allRead = users + .filter { u -> !u.user.activeUser && !u.user.hidden } + .all { u -> u.unreadCount == 0 } + UserProfileButton(chatModel.currentUser.value?.profile?.image, allRead) { + if (users.size == 1 && chatModel.remoteHosts.isEmpty()) { + scope.launch { drawerState.open() } + } else { + userPickerState.value = AnimatedViewState.VISIBLE + } + } + } + }, title = { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(DEFAULT_SPACE_AFTER_ICON)) { Text( @@ -261,133 +320,36 @@ private fun ChatListTopBar(stopped: Boolean) { onSearchValueChanged = {}, buttons = barButtons ) - Divider(Modifier.padding(top = AppBarHeight)) -} - -@Composable -fun SettingsButton(drawerState: DrawerState, userPickerState: MutableStateFlow) { - val scope = rememberCoroutineScope() - if (chatModel.users.isEmpty() && !chatModel.desktopNoUserNoRemote) { - NavigationButtonMenu { scope.launch { if (drawerState.isOpen) drawerState.close() else drawerState.open() } } - } else { - val users by remember { derivedStateOf { chatModel.users.filter { u -> u.user.activeUser || !u.user.hidden } } } - val allRead = users - .filter { u -> !u.user.activeUser && !u.user.hidden } - .all { u -> u.unreadCount == 0 } - - UserProfileButton(chatModel.currentUser.value?.profile?.image, allRead) { - if (users.size == 1 && chatModel.remoteHosts.isEmpty()) { - scope.launch { drawerState.open() } - } else { - userPickerState.value = AnimatedViewState.VISIBLE - } - } - } -} - -@Composable -fun toolbarIcon(icon: Painter) { - Icon( - icon, - contentDescription = null, - Modifier.size(24.dp * fontSizeSqrtMultiplier), - tint = MaterialTheme.colors.secondary - ) -} - -@Composable -fun ChatListToolbarButton(icon: @Composable () -> Unit, title: String, onClick: () -> Unit) { - Surface( - Modifier - .size(56.dp * fontSizeSqrtMultiplier), - shape = RoundedCornerShape(10.dp), - color = Color.Transparent, - ) { - Column( - Modifier - .clickable { onClick () }, - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - icon() - Text( - title, - style = MaterialTheme.typography.subtitle2.copy(fontWeight = FontWeight.Normal, fontSize = 12.sp * fontSizeSqrtMultiplier), - color = MaterialTheme.colors.secondary - ) - } - } -} - -@Composable -private fun ChatListBottomToolbar(drawerState: DrawerState, userPickerState: MutableStateFlow) { - Box( - Modifier - .fillMaxWidth() - .height(BottomAppBarHeight) - .background(MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f)) - ) { - Divider() - Row( - Modifier - .fillMaxHeight() - .fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly, - verticalAlignment = Alignment.CenterVertically, - ) { - SettingsButton(drawerState, userPickerState) - - ChatListToolbarButton( - icon = { toolbarIcon(painterResource(MR.images.ic_chat_bubble_filled)) }, - title = generalGetString(MR.strings.your_chats), - onClick = { } - ) - } - } + Divider(Modifier.padding(top = AppBarHeight * fontSizeSqrtMultiplier)) } @Composable fun SubscriptionStatusIndicator(serversSummary: MutableState, click: (() -> Unit)) { var subs by remember { mutableStateOf(SMPServerSubs.newSMPServerSubs) } var sess by remember { mutableStateOf(ServerSessions.newServerSessions) } - var timer: Job? by remember { mutableStateOf(null) } - - val fetchInterval: Duration = 1.seconds - val scope = rememberCoroutineScope() - fun setServersSummary() { - withBGApi { - serversSummary.value = chatModel.controller.getAgentServersSummary(chatModel.remoteHostId()) + suspend fun setServersSummary() { + serversSummary.value = chatModel.controller.getAgentServersSummary(chatModel.remoteHostId()) - serversSummary.value?.let { - subs = it.allUsersSMP.smpTotals.subs - sess = it.allUsersSMP.smpTotals.sessions - } + serversSummary.value?.let { + subs = it.allUsersSMP.smpTotals.subs + sess = it.allUsersSMP.smpTotals.sessions } } LaunchedEffect(Unit) { setServersSummary() - timer = timer ?: scope.launch { - while (true) { - delay(fetchInterval.inWholeMilliseconds) - setServersSummary() + scope.launch { + while (isActive) { + delay(1.seconds) + if ((appPlatform.isDesktop || chatModel.chatId.value == null) && !ModalManager.start.hasModalsOpen() && !ModalManager.fullscreen.hasModalsOpen() && isAppVisibleAndFocused()) { + setServersSummary() + } } } } - fun stopTimer() { - timer?.cancel() - timer = null - } - - DisposableEffect(Unit) { - onDispose { - stopTimer() - } - } - SimpleButtonFrame(click = click) { SubscriptionStatusIndicatorView(subs = subs, sess = sess) } @@ -395,38 +357,32 @@ fun SubscriptionStatusIndicator(serversSummary: MutableState Unit) { - ChatListToolbarButton( - icon = { + Row(verticalAlignment = Alignment.CenterVertically) { + IconButton(onClick = onButtonClicked) { Box { ProfileImage( image = image, - size = 24.dp * fontSizeSqrtMultiplier, - color = MaterialTheme.colors.secondaryVariant.mixWith( - MaterialTheme.colors.onBackground, - 0.97f - ) + size = 37.dp * fontSizeSqrtMultiplier, + color = MaterialTheme.colors.secondaryVariant.mixWith(MaterialTheme.colors.onBackground, 0.97f) ) if (!allRead) { unreadBadge() } } - }, - onClick = onButtonClicked, - title = generalGetString(MR.strings.toolbar_settings), - - ) - - if (appPlatform.isDesktop) { - val h by remember { chatModel.currentRemoteHost } - if (h != null) { - Spacer(Modifier.width(12.dp)) - HostDisconnectButton { - stopRemoteHostAndReloadHosts(h!!, true) + } + if (appPlatform.isDesktop) { + val h by remember { chatModel.currentRemoteHost } + if (h != null) { + Spacer(Modifier.width(12.dp)) + HostDisconnectButton { + stopRemoteHostAndReloadHosts(h!!, true) + } } } } } + @Composable private fun BoxScope.unreadBadge(text: String? = "") { Text( @@ -507,7 +463,7 @@ private fun ChatListSearchBar(listState: LazyListState, searchText: MutableState } else { val padding = if (appPlatform.isDesktop) 0.dp else 7.dp if (chatModel.chats.size > 0) { - ToggleFilterEnabledButton() + ToggleFilterEnabledButton() } Spacer(Modifier.width(padding)) } @@ -668,18 +624,17 @@ private fun filteredChats( } else { val s = if (searchShowingSimplexLink.value) "" else searchText.trim().lowercase() if (s.isEmpty() && !showUnreadAndFavorites) - chats.filter { chat -> !chat.chatInfo.chatDeleted } + chats else { chats.filter { chat -> when (val cInfo = chat.chatInfo) { - is ChatInfo.Direct -> !chat.chatInfo.chatDeleted && ( - if (s.isEmpty()) { - chat.id == chatModel.chatId.value || filtered(chat) - } else { - (viewNameContains(cInfo, s) || - cInfo.contact.profile.displayName.lowercase().contains(s) || - cInfo.contact.fullName.lowercase().contains(s)) - }) + is ChatInfo.Direct -> if (s.isEmpty()) { + chat.id == chatModel.chatId.value || filtered(chat) + } else { + (viewNameContains(cInfo, s) || + cInfo.contact.profile.displayName.lowercase().contains(s) || + cInfo.contact.fullName.lowercase().contains(s)) + } is ChatInfo.Group -> if (s.isEmpty()) { chat.id == chatModel.chatId.value || filtered(chat) || cInfo.groupInfo.membership.memberStatus == GroupMemberStatus.MemInvited } else { @@ -697,8 +652,8 @@ private fun filteredChats( private fun filtered(chat: Chat): Boolean = (chat.chatInfo.chatSettings?.favorite ?: false) || - chat.chatStats.unreadChat || - (chat.chatInfo.ntfsEnabled && chat.chatStats.unreadCount > 0) + chat.chatStats.unreadChat || + (chat.chatInfo.ntfsEnabled && chat.chatStats.unreadCount > 0) private fun viewNameContains(cInfo: ChatInfo, s: String): Boolean = cInfo.chatViewName.lowercase().contains(s.lowercase()) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt index 66405afb27..101ba7a3a2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt @@ -39,11 +39,13 @@ import kotlin.math.roundToInt fun UserPicker( chatModel: ChatModel, userPickerState: MutableStateFlow, + containerModifier: Modifier = Modifier, + contentAlignment: Alignment = Alignment.TopStart, showSettings: Boolean = true, showCancel: Boolean = false, cancelClicked: () -> Unit = {}, useFromDesktopClicked: () -> Unit = {}, - settingsClicked: () -> Unit = {}, + settingsClicked: () -> Unit = {} ) { val scope = rememberCoroutineScope() var newChat by remember { mutableStateOf(userPickerState.value) } @@ -149,18 +151,17 @@ fun UserPicker( .graphicsLayer { alpha = animatedFloat.value translationY = (animatedFloat.value - 1) * xOffset - } + }, + contentAlignment = contentAlignment ) { Column( - Modifier - .align(Alignment.BottomStart) - .padding(bottom = BottomAppBarHeight) + containerModifier .widthIn(min = 260.dp) .width(IntrinsicSize.Min) .height(IntrinsicSize.Min) .shadow(8.dp, RoundedCornerShape(corner = CornerSize(25.dp)), clip = true) .background(MaterialTheme.colors.surface, RoundedCornerShape(corner = CornerSize(25.dp))) - .clip(RoundedCornerShape(corner = CornerSize(25.dp))) + .clip(RoundedCornerShape(corner = CornerSize(25.dp))), ) { val currentRemoteHost = remember { chatModel.currentRemoteHost }.value Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt index 98f3921059..6bfcf2809f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt @@ -69,16 +69,19 @@ class AlertManager { fun showAlertDialogButtonsColumn( title: String, text: String? = null, + textAlign: TextAlign = TextAlign.Center, + dismissible: Boolean = true, onDismissRequest: (() -> Unit)? = null, hostDevice: Pair? = null, + belowTextContent: @Composable (() -> Unit) = {}, buttons: @Composable () -> Unit, ) { showAlert { AlertDialog( - onDismissRequest = { onDismissRequest?.invoke(); hideAlert() }, + onDismissRequest = { onDismissRequest?.invoke(); if (dismissible) hideAlert() }, title = alertTitle(title), buttons = { - AlertContent(text, hostDevice, extraPadding = true) { + AlertContent(text, hostDevice, extraPadding = true, textAlign = textAlign, belowTextContent = belowTextContent) { buttons() } }, @@ -286,7 +289,14 @@ private fun alertTitle(title: String): (@Composable () -> Unit)? { } @Composable -private fun AlertContent(text: String?, hostDevice: Pair?, extraPadding: Boolean = false, content: @Composable (() -> Unit)) { +private fun AlertContent( + text: String?, + hostDevice: Pair?, + extraPadding: Boolean = false, + textAlign: TextAlign = TextAlign.Center, + belowTextContent: @Composable (() -> Unit) = {}, + content: @Composable (() -> Unit) +) { BoxWithConstraints { Column( Modifier @@ -300,17 +310,20 @@ private fun AlertContent(text: String?, hostDevice: Pair?, extraP CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) { if (text != null) { Column(Modifier.heightIn(max = this@BoxWithConstraints.maxHeight * 0.7f) + .padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING) .verticalScroll(rememberScrollState()) ) { SelectionContainer { Text( escapedHtmlToAnnotatedString(text, LocalDensity.current), - Modifier.fillMaxWidth().padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING * 1.5f), + Modifier.fillMaxWidth(), fontSize = 16.sp, - textAlign = TextAlign.Center, + textAlign = textAlign, color = MaterialTheme.colors.secondary ) } + belowTextContent() + Spacer(Modifier.height(DEFAULT_PADDING * 1.5f)) } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt index c7ae522684..c830916a7e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt @@ -126,6 +126,5 @@ private fun TopAppBar( val AppBarHeight = 56.dp val AppBarHorizontalPadding = 4.dp -val BottomAppBarHeight = 60.dp private val TitleInsetWithoutIcon = DEFAULT_PADDING - AppBarHorizontalPadding val TitleInsetWithIcon = 72.dp diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt index 58255f21b5..9faee4532a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt @@ -152,7 +152,7 @@ private fun NewChatSheetLayout( } FloatingActionButton( onClick = { if (!stopped) closeNewChatSheet(true) }, - Modifier.padding(end = DEFAULT_PADDING, bottom = DEFAULT_PADDING + BottomAppBarHeight).size(AppBarHeight * fontSizeSqrtMultiplier), + Modifier.padding(end = DEFAULT_PADDING, bottom = DEFAULT_PADDING).size(AppBarHeight * fontSizeSqrtMultiplier), elevation = FloatingActionButtonDefaults.elevation( defaultElevation = 0.dp, pressedElevation = 0.dp, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt index 4e3b70405d..0dae98559c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt @@ -66,7 +66,7 @@ private fun LinkAMobileLayout( SectionView(generalGetString(MR.strings.this_device_name).uppercase()) { DeviceNameField(deviceName.value ?: "") { updateDeviceName(it) } SectionTextFooter(generalGetString(MR.strings.this_device_name_shared_with_mobile)) - PreferenceToggle(stringResource(MR.strings.multicast_discoverable_via_local_network), remember { ChatModel.controller.appPrefs.offerRemoteMulticast.state }.value) { + PreferenceToggle(stringResource(MR.strings.multicast_discoverable_via_local_network), checked = remember { ChatModel.controller.appPrefs.offerRemoteMulticast.state }.value) { ChatModel.controller.appPrefs.offerRemoteMulticast.set(it) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt index caf021a381..340346f5b3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt @@ -118,13 +118,8 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) { featureDescription(painterResource(feature.icon), feature.titleId, feature.descrId, feature.link) } - val uriHandler = LocalUriHandler.current if (v.post != null) { - Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(top = DEFAULT_PADDING.div(4))) { - Text(stringResource(MR.strings.whats_new_read_more), color = MaterialTheme.colors.primary, - modifier = Modifier.clickable { uriHandler.openUriCatching(v.post) }) - Icon(painterResource(MR.images.ic_open_in_new), stringResource(MR.strings.whats_new_read_more), tint = MaterialTheme.colors.primary) - } + ReadMoreButton(v.post) } if (!viaSettings) { @@ -149,6 +144,16 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) { } } +@Composable +fun ReadMoreButton(url: String) { + val uriHandler = LocalUriHandler.current + Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(top = DEFAULT_PADDING.div(4))) { + Text(stringResource(MR.strings.whats_new_read_more), color = MaterialTheme.colors.primary, + modifier = Modifier.clickable { uriHandler.openUriCatching(url) }) + Icon(painterResource(MR.images.ic_open_in_new), stringResource(MR.strings.whats_new_read_more), tint = MaterialTheme.colors.primary) + } +} + private data class FeatureDescription( val icon: ImageResource, val titleId: StringResource, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt index d201ac482a..b5349e826d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt @@ -432,14 +432,14 @@ private fun LinkedDesktopsView(remoteCtrls: SnapshotStateList) { SectionDividerSpaced() SectionView(stringResource(MR.strings.linked_desktop_options).uppercase()) { - PreferenceToggle(stringResource(MR.strings.verify_connections), remember { controller.appPrefs.confirmRemoteSessions.state }.value) { + PreferenceToggle(stringResource(MR.strings.verify_connections), checked = remember { controller.appPrefs.confirmRemoteSessions.state }.value) { controller.appPrefs.confirmRemoteSessions.set(it) } - PreferenceToggle(stringResource(MR.strings.discover_on_network), remember { controller.appPrefs.connectRemoteViaMulticast.state }.value) { + PreferenceToggle(stringResource(MR.strings.discover_on_network), checked = remember { controller.appPrefs.connectRemoteViaMulticast.state }.value) { controller.appPrefs.connectRemoteViaMulticast.set(it) } if (remember { controller.appPrefs.connectRemoteViaMulticast.state }.value) { - PreferenceToggle(stringResource(MR.strings.multicast_connect_automatically), remember { controller.appPrefs.connectRemoteViaMulticastAuto.state }.value) { + PreferenceToggle(stringResource(MR.strings.multicast_connect_automatically), checked = remember { controller.appPrefs.connectRemoteViaMulticastAuto.state }.value) { controller.appPrefs.connectRemoteViaMulticastAuto.set(it) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt index e13b86258d..d8c9557863 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt @@ -97,7 +97,7 @@ fun ConnectMobileLayout( SectionView(generalGetString(MR.strings.this_device_name).uppercase()) { DeviceNameField(deviceName.value ?: "") { updateDeviceName(it) } SectionTextFooter(generalGetString(MR.strings.this_device_name_shared_with_mobile)) - PreferenceToggle(stringResource(MR.strings.multicast_discoverable_via_local_network), remember { controller.appPrefs.offerRemoteMulticast.state }.value) { + PreferenceToggle(stringResource(MR.strings.multicast_discoverable_via_local_network), checked = remember { controller.appPrefs.offerRemoteMulticast.state }.value) { controller.appPrefs.offerRemoteMulticast.set(it) } SectionDividerSpaced(maxBottomPadding = false) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt index a7b3896ce2..88018dd1c9 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt @@ -175,10 +175,16 @@ private fun UseServerSection( Text(stringResource(MR.strings.smp_servers_test_server), color = if (valid && !testing) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary) ShowTestStatus(server) } - val enabled = rememberUpdatedState(server.enabled == ServerEnabled.Enabled) - PreferenceToggle(stringResource(MR.strings.smp_servers_use_server_for_new_conn), enabled.value) { enable -> - onUpdate(server.copy(enabled = if (enable) ServerEnabled.Enabled else ServerEnabled.Disabled)) + + val enabled = rememberUpdatedState(server.enabled) + PreferenceToggle( + stringResource(MR.strings.smp_servers_use_server_for_new_conn), + disabled = server.tested != true && !server.preset, + checked = enabled.value + ) { + onUpdate(server.copy(enabled = it)) } + SectionItemView(onDelete, disabled = testing) { Text(stringResource(MR.strings.smp_servers_delete_server), color = if (testing) MaterialTheme.colors.secondary else MaterialTheme.colors.error) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServersView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServersView.kt index bbf3e07c93..5d5f1d039a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServersView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServersView.kt @@ -28,13 +28,13 @@ import chat.simplex.res.MR @Composable fun ModalData.ProtocolServersView(m: ChatModel, rhId: Long?, serverProtocol: ServerProtocol, close: () -> Unit) { - var presetServers by remember(rhId) { mutableStateOf(emptyList()) } + var presetServers by remember(rhId) { mutableStateOf(emptyList()) } var servers by remember { stateGetOrPut("servers") { emptyList() } } var serversAlreadyLoaded by remember { stateGetOrPut("serversAlreadyLoaded") { false } } val currServers = remember(rhId) { mutableStateOf(servers) } val testing = rememberSaveable(rhId) { mutableStateOf(false) } val serversUnchanged = remember(servers) { derivedStateOf { servers == currServers.value || testing.value } } - val allServersDisabled = remember { derivedStateOf { servers.none { it.enabled == ServerEnabled.Enabled } } } + val allServersDisabled = remember { derivedStateOf { servers.none { it.enabled } } } val saveDisabled = remember(servers) { derivedStateOf { servers.isEmpty() || @@ -198,12 +198,42 @@ private fun ProtocolServersLayout( ) { AppBarTitle(stringResource(if (serverProtocol == ServerProtocol.SMP) MR.strings.your_SMP_servers else MR.strings.your_XFTP_servers)) - SectionView(stringResource(if (serverProtocol == ServerProtocol.SMP) MR.strings.smp_servers else MR.strings.xftp_servers).uppercase()) { - for (srv in servers) { - SectionItemView({ showServer(srv) }, disabled = testing) { - ProtocolServerView(serverProtocol, srv, servers, testing) + val configuredServers = servers.filter { it.preset || it.enabled } + val otherServers = servers.filter { !(it.preset || it.enabled) } + + if (configuredServers.isNotEmpty()) { + SectionView(stringResource(if (serverProtocol == ServerProtocol.SMP) MR.strings.smp_servers_configured else MR.strings.xftp_servers_configured).uppercase()) { + for (srv in configuredServers) { + SectionItemView({ showServer(srv) }, disabled = testing) { + ProtocolServerView(serverProtocol, srv, servers, testing) + } } } + SectionTextFooter( + remember(currentUser?.displayName) { + buildAnnotatedString { + append(generalGetString(MR.strings.smp_servers_per_user) + " ") + withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { + append(currentUser?.displayName ?: "") + } + append(".") + } + } + ) + SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false) + } + + if (otherServers.isNotEmpty()) { + SectionView(stringResource(if (serverProtocol == ServerProtocol.SMP) MR.strings.smp_servers_other else MR.strings.xftp_servers_other).uppercase()) { + for (srv in otherServers.filter { !(it.preset || it.enabled) }) { + SectionItemView({ showServer(srv) }, disabled = testing) { + ProtocolServerView(serverProtocol, srv, servers, testing) + } + } + } + } + + SectionView { SettingsActionItem( painterResource(MR.images.ic_add), stringResource(MR.strings.smp_servers_add), @@ -212,19 +242,9 @@ private fun ProtocolServersLayout( textColor = if (testing) MaterialTheme.colors.secondary else MaterialTheme.colors.primary, iconColor = if (testing) MaterialTheme.colors.secondary else MaterialTheme.colors.primary ) + SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) } - SectionTextFooter( - remember(currentUser?.displayName) { - buildAnnotatedString { - append(generalGetString(MR.strings.smp_servers_per_user) + " ") - withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { - append(currentUser?.displayName ?: "") - } - append(".") - } - } - ) - SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false) + SectionView { SectionItemView(resetServers, disabled = serversUnchanged) { Text(stringResource(MR.strings.reset_verb), color = if (!serversUnchanged) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary) @@ -250,12 +270,12 @@ private fun ProtocolServerView(serverProtocol: ServerProtocol, srv: ServerCfg, s val address = parseServerAddress(srv.server) when { address == null || !address.valid || address.serverProtocol != serverProtocol || !uniqueAddress(srv, address, servers) -> InvalidServer() - srv.enabled != ServerEnabled.Enabled -> Icon(painterResource(MR.images.ic_do_not_disturb_on), null, tint = MaterialTheme.colors.secondary) + !srv.enabled -> Icon(painterResource(MR.images.ic_do_not_disturb_on), null, tint = MaterialTheme.colors.secondary) else -> ShowTestStatus(srv) } Spacer(Modifier.padding(horizontal = 4.dp)) val text = address?.hostnames?.firstOrNull() ?: srv.server - if (srv.enabled == ServerEnabled.Enabled) { + if (srv.enabled) { Text(text, color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.onBackground, maxLines = 1) } else { Text(text, maxLines = 1, color = MaterialTheme.colors.secondary) @@ -285,21 +305,21 @@ private fun uniqueAddress(s: ServerCfg, address: ServerAddress, servers: List, servers: List, m: ChatModel): Boolean = +private fun hasAllPresets(presetServers: List, servers: List, m: ChatModel): Boolean = presetServers.all { hasPreset(it, servers) } ?: true -private fun addAllPresets(rhId: Long?, presetServers: List, servers: List, m: ChatModel): List { +private fun addAllPresets(rhId: Long?, presetServers: List, servers: List, m: ChatModel): List { val toAdd = ArrayList() for (srv in presetServers) { if (!hasPreset(srv, servers)) { - toAdd.add(ServerCfg(remoteHostId = rhId, srv, preset = true, tested = null, enabled = ServerEnabled.Enabled)) + toAdd.add(srv) } } return toAdd } -private fun hasPreset(srv: String, servers: List): Boolean = - servers.any { it.server == srv } +private fun hasPreset(srv: ServerCfg, servers: List): Boolean = + servers.any { it.server == srv.server } private suspend fun testServers(testing: MutableState, servers: List, m: ChatModel, onUpdated: (List) -> Unit) { val resetStatus = resetTestStatus(servers) @@ -319,7 +339,7 @@ private suspend fun testServers(testing: MutableState, servers: List): List { val copy = ArrayList(servers) for ((index, server) in servers.withIndex()) { - if (server.enabled == ServerEnabled.Enabled) { + if (server.enabled) { copy.removeAt(index) copy.add(index, server.copy(tested = null)) } @@ -331,7 +351,7 @@ private suspend fun runServersTest(servers: List, m: ChatModel, onUpd val fs: MutableMap = mutableMapOf() val updatedServers = ArrayList(servers) for ((index, server) in servers.withIndex()) { - if (server.enabled == ServerEnabled.Enabled) { + if (server.enabled) { interruptIfCancelled() val (updatedServer, f) = testServerConnection(server, m) updatedServers.removeAt(index) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ScanProtocolServer.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ScanProtocolServer.kt index c1951341a4..7c2c578d6a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ScanProtocolServer.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ScanProtocolServer.kt @@ -7,7 +7,6 @@ import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import chat.simplex.common.model.ServerAddress.Companion.parseServerAddress import chat.simplex.common.model.ServerCfg -import chat.simplex.common.model.ServerEnabled import chat.simplex.common.ui.theme.DEFAULT_PADDING import chat.simplex.common.views.helpers.* import chat.simplex.common.views.newchat.QRCodeScanner @@ -26,7 +25,7 @@ fun ScanProtocolServerLayout(rhId: Long?, onNext: (ServerCfg) -> Unit) { QRCodeScanner { text -> val res = parseServerAddress(text) if (res != null) { - onNext(ServerCfg(remoteHostId = rhId, text, false, null, ServerEnabled.Enabled)) + onNext(ServerCfg(remoteHostId = rhId, text, false, null, false)) } else { AlertManager.shared.showAlertMsg( title = generalGetString(MR.strings.smp_servers_invalid_address), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt index cef457de2e..3dfe8c3590 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt @@ -73,6 +73,9 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit, drawerSt withAuth = ::doWithAuth, drawerState = drawerState, ) + KeyChangeEffect(chatModel.updatingProgress.value != null) { + drawerState.close() + } } val simplexTeamUri = @@ -416,13 +419,15 @@ fun SettingsPreferenceItem( @Composable fun PreferenceToggle( text: String, + disabled: Boolean = false, checked: Boolean, onChange: (Boolean) -> Unit = {}, ) { - SettingsActionItemWithContent(null, text, extraPadding = true,) { + SettingsActionItemWithContent(null, text, disabled = disabled, extraPadding = true,) { DefaultSwitch( checked = checked, onCheckedChange = onChange, + enabled = !disabled ) } } diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml index ef4edcf0cd..f7c6e03811 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml @@ -31,7 +31,7 @@ أضِف إلى جهاز آخر سيتم حذف جميع الدردشات والرسائل - لا يمكن التراجع عن هذا! الوصول إلى الخوادم عبر بروكسي SOCKS على المنفذ %d؟ يجب بدء تشغيل الوكيل قبل تمكين هذا الخيار. - أضِف خادم… + أضِف خادم إعدادات الشبكة المتقدمة سيبقى جميع أعضاء المجموعة على اتصال. السماح باختفاء الرسائل فقط إذا سمحت جهة اتصالك بذلك. @@ -1856,4 +1856,19 @@ \nError: %s تحسين تسليم الرسائل مع انخفاض استخدام البطارية. + مفتاح خاطئ أو عنوان مجموعة الملف غير معروف - على الأرجح حُذف الملف. + خطأ في خادم الملفات: %1$s + خطأ في الملف + خطأ في الملف مؤقت + حالة الرسالة + لم يتم العثور على الملف - على الأرجح حُذف الملف أو إلغاؤه. + حالة الملف + حالة الملف: %s + حالة الرسالة: %s + خطأ في النسخ + تم استخدام هذا الرابط مع جهاز محمول آخر، يُرجى إنشاء رابط جديد على سطح المكتب. + يُرجى التحقق من اتصال الهاتف المحمول وسطح المكتب بنفس الشبكة المحلية، وأن جدار حماية سطح المكتب يسمح بالاتصال. +\nيُرجى مشاركة أي مشاكل أُخرى مع المطورين. + لا يمكن إرسال الرسالة + تفضيلات الدردشة المحدّدة تحظر هذه الرسالة. \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index c05cfe6780..806c2522a5 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -112,6 +112,10 @@ Connection timeout Connection error Please check your network connection with %1$s and try again. + Server address is incompatible with network settings: %1$s. + Server version is incompatible with your app: %1$s. + Private routing error + Please try later. Error sending message Error creating message Error loading details @@ -688,9 +692,11 @@ SimpleX Lock Chat console SMP servers + Configured SMP servers + Other SMP servers Preset server address Add preset servers - Add server… + Add server Test server Test servers Save servers @@ -710,6 +716,8 @@ The servers for new connections of your current chat profile Save servers? XFTP servers + Configured XFTP servers + Other XFTP servers Subscription percentage Install SimpleX Chat for terminal Star on GitHub @@ -787,6 +795,25 @@ App build: %s Core version: v%s simplexmq: v%s (%2s) + Check for updates + Disabled + Stable + Beta + Update available: %s + Download %s (%s) + Skip this version + Downloading app update, don\'t close the app + App update is downloaded + Open file location + Install update + Installed successfully + Please restart the app. + Update download canceled + Remind later + Check for updates + To be notified about the new releases, turn on periodic check for Stable or Beta versions. + Disable + Show: Hide: Show developer options diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml index ca9070cbd6..81f537133c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml @@ -4,7 +4,7 @@ %1$s иска да се свърже с вас чрез 1 минута Добави сървъри чрез сканиране на QR кодове. - Добави сървър… + Добави сървър админ Добави съобщение при посрещане Всички данни се изтриват при въвеждане. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/bn/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/bn/strings.xml index 13e322f078..bb448339bd 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/bn/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/bn/strings.xml @@ -28,7 +28,7 @@ আনুষঙ্গিক রং অ্যাডমিনরা গ্রুপে যোগদানের সংযোগ-সূত্র তৈরি করতে পারবেন। QR কোড স্ক্যান করে সার্ভার যুক্ত করুন। - সার্ভার যুক্ত করুন… + সার্ভার যুক্ত করুন ঠিকানা ঠিকানা পরিবর্তন বাতিল করা হবে। বার্তা গ্রহণের পুরনো ঠিকানা ব্যবহার করা হবে। অ্যাপের সকল তথ্য মুছে ফেলা হয়েছে। diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml index e80b2d88ff..5a73805093 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml @@ -8,7 +8,7 @@ Přidat přednastavené servery Pokročilá nastavení sítě Přijmout - Přidat server… + Přidat server Přistupovat k serverům přes SOCKS proxy na portu %d\? Před povolením této možnosti musí být spuštěna proxy. Přijmout Povolit svým kontaktům odesílat mizící zprávy. @@ -1771,4 +1771,87 @@ koncovým šifrováním s dokonalým dopředným utajením, odmítnutím a obnovením po vloupání.]]> Pokročilé nastavení Všechny barevné režimy + Překročená kapacita - příjemci neobdrží dříve poslané zprávy. + Vždy + Použít na + Potvrdit soubory z neznámých serverů. + Tmavý mód + Téma aplikace + Vždy užít soukromé směrování. + Povolit downgrade + Kopírovat chybu + Barvy chatu + Téma chatu + Další zbarvení 2 + Černé + Mód barvy + Tmavé + Mód tmavých barev + Informace o frontě zpráv + Světlý mód + Upravtesi svůj chat, aby vypadal jinak! + Chyba cílového serveru: %1$s + Chyba: %1$s + Předávací server: %1$s +\nChyba cílového serveru: %2$s + Předávací server: %1$s +\nChyba: %2$s + Upozornění doručování zpráv + Problémy se sítí - zpráva vypršela po mnoha pokusech o odeslání. + Soukromé směrování + Soubor nebyl nalezen - s největší pravděpodobností byl soubor odstraněn nebo zrušen. + Chyba souboru serveru: %1$s + Nelze odeslat zprávu + Chyba souboru + NEpoužívat soukromé směrování. + Záložní směrování zpráv + Režim přeposílání zpráv + Nikdy + Chyba inicializace WebView. Aktualizujte systém na novou verzi. Prosím kontaktujte vývojáře. +\nChyba: %s + Ochrana IP adresy + Status souboru + Status zprávy + Status souboru: %s + Stav zprávy: %s + žádné + Vyplnit + Opakovat + Obnovit uživatelské téma + Obnovit téma aplikace + Bezpečné přijímání souborů + Nové motivy chatu + Soukromé směrování zpráv 🚀 + Chraňte vaši IP adresu před relé zpráv, které jste si vybrali. +\nPovolit v nastavení *Síť & servery*. + Vylepšené doručování zpráv + Perské UI + Prosím zkontrolujte, že mobil a desktop jsou připojeny ke stejné místní síti, a že stolní firewall umožňuje připojení. +\nProsím sdělte jakékoli další problémy vývojářům. + Ne + NEposílejte zprávy přímo, i když váš nebo cílový server nepodporuje soukromé směrování. + SOUBORY + SOUKROMÉ SMĚROVÁNÍ ZPRÁV + Téma profilu + Přijata odpověď + Obnovit barvu + Dobré odpoledne! + Odebrat obrázek + Dobré ráno! + Světlé + Špatný klíč nebo neznámé spojení - pravděpodobně je spojení smazáno. + Špatný klíč nebo neznámá adresa části souboru - soubor je pravděpodobně odstraněn. + Nechráněno + Použít soukromé směrování s neznámými servery. + Použit soukromé směrování s neznámými servery, když IP adresa není chráněna. + Bez Tor nebo VPN bude vaše IP adresa viditelná souborovým serverům. + Ladit doručování + Snížena spotřeba baterie. + Neznámé servery! + Bez Tor nebo VPN bude vaše IP adresa viditelná pro tyto XFTP relé: +\n%1$s. + Když je IP adresa skryta + Ano + Zbarvení tapety + Pozadí tapety \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml index df264384a5..cdc5720e37 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml @@ -355,7 +355,7 @@ SMP-Server Voreingestellte Serveradresse Füge voreingestellte Server hinzu - Füge Server hinzu… + Füge Server hinzu Teste Server Teste alle Server Alle Server speichern @@ -1807,7 +1807,7 @@ weitergeleitet Netzwerkverbindung Keine Netzwerkverbindung - Zellulär + Mobilfunknetz Andere WiFi Kabelgebundenes Netzwerk @@ -1939,4 +1939,19 @@ Server-Warteschlangen-Information: %1$s \n \nZuletzt empfangene Nachricht: %2$s + Datei nicht gefunden - höchstwahrscheinlich wurde die Datei gelöscht oder der Transfer abgebrochen. + Datei-Server-Fehler: %1$s + Falscher Schlüssel oder unbekannte Datei-Chunk-Adresse - höchstwahrscheinlich wurde die Datei gelöscht. + Datei-Fehler + Nachrichten-Status + Nachrichten-Status: %s + Datei-Status + Datei-Status: %s + Temporärer Datei-Fehler + Fehlermeldung kopieren + Dieser Link wurde schon mit einem anderen Mobiltelefon genutzt. Bitte erstellen sie einen neuen Link in der Desktop-App. + Bitte überprüfen Sie, ob sich das Mobiltelefon und die Desktop-App im gleichen lokalen Netzwerk befinden, und die Desktop-Firewall die Verbindung erlaubt. +\nBitte teilen Sie weitere mögliche Probleme den Entwicklern mit. + Nachricht wurde nicht gesendet + Diese Nachricht ist wegen der gewählten Chat-Einstellungen nicht erlaubt. \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml index 811257ff39..baa85f07f4 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml @@ -42,7 +42,7 @@ Αποδοχή αιτήματος σύνδεσης; αποδεκτή κλήση Πρόσβαση στους διακομιστές μέσω SOCKS proxy στην πόρτα %d; Ο διακομιστής μεσολάβησης (proxy server) πρέπει να είναι ενεργός πριν ενεργοποιηθεί αυτή η ρύθμιση. - Προσθήκη διακομιστή… + Προσθήκη διακομιστή Προχωρημένες ρυθμίσεις δικτύου Προσθήκη διακομιστών μέσω σάρωσης QR κωδικών. Οι διαχειριστές μπορούν να δημιουργήσουν τους συνδέσμους συμμετοχής σε ομάδες. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml index 0c013f0bbc..dcf6b25181 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml @@ -30,7 +30,7 @@ ¿Aceptar solicitud de conexión\? Aceptar incógnito Se eliminarán todos los mensajes SOLO para tí. ¡No podrá deshacerse! - Añadir servidor… + Añadir servidor ¿Acceder a los servidores a través del proxy SOCKS en el puerto %d\? El proxy debe iniciarse antes de activar esta opción. Todos tus contactos permanecerán conectados. Apariencia @@ -153,7 +153,7 @@ Eliminar en %d seg El contácto ya existe - Error conexión (Autenticación) + Error de conexión (Autenticación) Eliminar para mí Desconectado Conectado @@ -328,7 +328,7 @@ Error al crear dirección Error al eliminar perfil Activar Bloqueo SimpleX - Enlace de invitación de un uso + Enlace de invitación de un solo uso Servidores SMP Características experimentales Error al importar base de datos @@ -355,8 +355,8 @@ Si has recibido un enlace de invitación a SimpleX Chat puedes abrirlo en tu navegador: Si seleccionas rechazar, el remitente NO será notificado. ¡Enlace no válido! - escanear el código QR en la videollamada, o tu contacto puede compartir un enlace de invitación.]]> - muestra el código QR en la videollamada, o comparte el enlace.]]> + escanear el código QR por videollamada, o tu contacto puede compartir un enlace de invitación.]]> + muestra el código QR por videollamada, o comparte el enlace.]]> Cómo Ignorar Error al eliminar base de datos @@ -616,7 +616,7 @@ imagen del perfil No se permiten mensajes de voz. Proteger la pantalla de la aplicación - repositorio GitHub .]]> + repositorio GitHub .]]> Grabar mensaje de voz ha expulsado a %1$s Enviar previsualizacion de enlaces @@ -660,7 +660,7 @@ confirmación recibida… Periódico Privacidad redefinida - Saber más en nuestro repositorio GitHub. + Conoce más en nuestro repositorio GitHub. Rechazar Abrir Llamada pendiente @@ -670,7 +670,7 @@ Introduce la contraseña anterior después de restaurar la copia de seguridad de la base de datos. Esta acción no se puede deshacer. te ha expulsado Recibiendo vía - Tiempo de espera del protocolo + Timeout protocolo seg Datos del perfil y conexiones No se permiten mensajes temporales. @@ -707,8 +707,8 @@ Guardar y notificar contacto ¿Guardar preferencias\? Guardar y notificar grupo - A menos que tu contacto haya eliminado la conexión o que este enlace ya se haya usado, podría ser un error. Por favor, notifícalo. -\nPara conectarte, pide a tu contacto que cree otro enlace de conexión y comprueba que tienes buena conexión de red. + A menos que tu contacto haya eliminado la conexión o el enlace haya sido usado, podría ser un error. Por favor, notifícalo. +\nPara conectarte pide a tu contacto que cree otro enlace y comprueba la conexión de red. La aplicación recoge nuevos mensajes periódicamente lo que consume un pequeño porcentaje de batería al día. La aplicación no usa notificaciones push por tanto los datos de tu dispositivo no se envían a los servidores push. Bloqueo SimpleX Desbloquear @@ -747,7 +747,7 @@ Altavoz activado Para habilitar las acciones sobre la base de datos, debes parar Chat ¡La conexión que has aceptado se cancelará! - La base de datos no funciona correctamente. Pulsa para saber más + La base de datos no funciona correctamente. Pulsa para conocer más El mensaje será marcado como moderado para todos los miembros. La nueva generación de mensajería privada Esta acción es irreversible. Se eliminarán todos los archivos y multimedia recibidos y enviados. Las imágenes de baja resolución permanecerán. @@ -763,7 +763,7 @@ Para proteger tu privacidad, en lugar de los identificadores de usuario que usan el resto de plataformas, SimpleX dispone de identificadores para las colas de mensajes, independientes para cada uno de tus contactos. Para proteger tu información, activa el Bloqueo SimpleX. \nSe te pedirá que completes la autenticación antes de activar esta función. - Al actualizar la configuración, el cliente se reconectará a todos los servidores. + Al actualizar la configuración el cliente se reconectará a todos los servidores. ¿Usar servidores SimpleX Chat\? Enlace de grupo SimpleX Invitación única SimpleX @@ -809,7 +809,7 @@ %s segundo(s) Pulsa para unirte ha actualizado el perfil del grupo - Tiempo de espera de la conexión TCP agotado + Timeout de la conexión TCP Tema Establece preferencias de grupo SOPORTE SIMPLEX CHAT @@ -883,7 +883,7 @@ Tu perfil aleatorio Te conectarás cuando tu solicitud se acepte, por favor espera o compruébalo más tarde. Te conectarás cuando el dispositivo de tu contacto esté en línea, por favor espera o compruébalo más tarde. - Se te pedirá identificarte cuándo inicies o continues usando la aplicación tras 30 segundos en segundo plano. + Se te pedirá autenticarte cuando inicies la aplicación o sigas usándola tras 30 segundos en segundo plano. Estás intentando invitar a un contacto con el que compartes un perfil incógnito a un grupo en el que usas tu perfil principal Mediante navegador mediante %1$s @@ -955,7 +955,7 @@ Tu servidor Dirección de tu servidor Tu perfil actual - Tu perfil se almacena en tu dispositivo y sólo se comparte con tus contactos. Los servidores SimpleX no pueden ver tu perfil. + Tu perfil es almacenado en tu dispositivo y solamente se comparte con tus contactos. Los servidores SimpleX no pueden ver tu perfil. Sistema Añadir mensaje de bienvenida Llamadas y videollamadas @@ -1043,7 +1043,7 @@ Servidores XFTP Puerto puerto %d - Usar hosts .onion a No si el proxy SOCKS no los admite.]]> + Usar hosts .onion como No si el proxy SOCKS no los admite.]]> Descargar archivo Usar proxy SOCKS Host @@ -1116,14 +1116,14 @@ ¡Rápido y sin necesidad de esperar a que el remitente esté en línea! Abrir perfiles Más información - Si no puedes reunirte en persona, **muestra el código QR por videollamada**, o comparte el enlace. + Si no puedes reunirte en persona, muestra el código QR por videollamada o comparte el enlace. Para conectarse, tu contacto puede escanear el código QR o usar el enlace en la aplicación. Crear dirección SimpleX Auto aceptar Vista previa Abriendo base de datos… Error al introducir dirección - Guía de Usuario.]]> + Guía de Usuario.]]> Enlace un uso Dirección SimpleX Cuando alguien solicite conectarse podrás aceptar o rechazar su solicitud. @@ -1243,7 +1243,7 @@ Personalizar y compartir temas de color. ¡Por fin los tenemos! 🚀 Reacciones a los mensajes - Saber más + Conoce más Interfaz en japonés y portugués sin texto Algunos errores no críticos ocurrieron durante la importación - para más detalles puedes ver la consola de Chat. @@ -1268,7 +1268,7 @@ Se permite enviar archivos y multimedia Favorito Sólo los propietarios del grupo pueden activar los archivos y multimedia. - Timeout de protocolo por KB + Timeout protocolo por KB renegociación de cifrado permitida para %s cifrado acordado cifrado ok @@ -1533,26 +1533,26 @@ Enviar hasta 100 últimos mensajes a los miembros nuevos. Añadir contacto: crea un enlace de invitación nuevo o usa un enlace recibido.]]> No enviar historial a miembros nuevos. - O mostrar este código + O muestra este código QR Hasta 100 últimos mensajes son enviados a los miembros nuevos. El código QR escaneado no es un enlace SimpleX. El texto pegado no es un enlace SimpleX. Permitir acceso a la cámara Podrás ver el enlace de invitación en detalles de conexión. ¿Guardar invitación no usada? - Compartir este enlace de un uso + Comparte este enlace de un solo uso Crear grupo: crea un grupo nuevo.]]> Historial visible Código acceso app Nuevo chat Cargando chats… Creando enlace… - O escanear código QR + O escanea el código QR Código QR no válido Añadir contacto Pulsa para escanear Guardar - Pulsa para pegar enlace + Pulsa para pegar el enlace Buscar o pegar enlace SimpleX Con uso reducido de batería. bloqueado por administrador @@ -1779,17 +1779,17 @@ Problema en la red - el mensaje ha expirado tras muchos intentos de envío. La versión del servidor es incompatible con la configuración de red. Enrutamiento privado - Servidor de retransmisión desconocido + Con servidores desconocidos NO usar enrutamiento privado. Enrutamiento de mensajes alternativo Modo de enrutamiento de mensajes No Estado del mensaje - Usar enrutamiento privado con servidores desconocidos cuando la dirección IP no está protegida. + Usar enrutamiento privado con servidores desconocidos cuando tu dirección IP no está protegida. Con IP oculta Si Enviar mensajes directamente cuando tu servidor o el de destino no admitan enrutamiento privado. - Para proteger tu dirección IP, el enrutamiento privado usa tus servidores SMP para enviar mensajes. + Para proteger tu dirección IP, el enrutamiento privado usa tu lista de servidores SMP para enviar mensajes. NO enviar mensajes directamente incluso si tu servidor o el de destino no soportan enrutamiento privado. Siempre Permitir versión anterior @@ -1798,9 +1798,9 @@ Nunca ENRUTAMIENTO PRIVADO DE MENSAJES La dirección del servidor es incompatible con la configuración de la red. - Desprotegido + Con IP desprotegida Clave incorrecta o conexión desconocida - probablemente esta conexión fue eliminada - Usar enrutamiento privado con servidores desconocidos. + Usar enrutamiento privado con servidores de retransmisión desconocidos. Enviar mensajes directamente cuando tu dirección IP está protegida y tu servidor o el de destino no admitan enrutamiento privado. ¡Servidores desconocidos! Sin Tor o VPN, tu dirección IP será visible para estos relés XFTP: @@ -1848,7 +1848,7 @@ Con uso reducido de la batería. Tema de la app Confirma archivos de servidores desconocidos. - Entrega de debug + Informe debug ¡Cambia el aspecto de tus chats! Nuevos temas de chat Información cola de mensajes @@ -1859,4 +1859,19 @@ Error al inicializar WebView. Actualiza tu sistema a la última versión. Por favor, ponte en contacto con los desarrolladores. \nError: %s Interfaz en persa + Clave incorrecta o dirección de bloque de datos del archivo desconocida - lo más probable es que el archivo se haya borrado. + Archivo no encontrado - el archivo probablemente ha sido borrado o cancelado. + Error del servidor de archivos: %1$s + Error de archivo + Error de archivo temporal + Estado del mensaje: %s + Estado del mensaje + Estado del archivo: %s + Estado del archivo + Comprueba que el móvil y el ordenador están conectados a la misma red local y que el firewall del ordenador permite la conexión. +\nPor favor, comparte cualquier otro problema con los desarrolladores. + Error al copiar + Este enlace ha sido usado en otro dispositivo móvil, por favor crea un enlace nuevo en el ordenador. + No se puede enviar el mensaje + Las preferencias seleccionadas no permiten este mensaje. \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/fa/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/fa/strings.xml index 10daae4c52..c18c163483 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/fa/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/fa/strings.xml @@ -539,7 +539,7 @@ ایده‌ها و سوالات را ارسال کنید به ما ایمیل بفرستید قفل SimpleX - افزودن سرور… + افزودن سرور آزمایش سرورها ذخیره سرورها عدم موفقیت آزمایش سرور! @@ -716,7 +716,7 @@ حذف تمام پرونده‌ها اصلاح نام به %s؟ بعدا از طریق تنظیمات قابل تغییر است. - تماس بی‌پاسخ + تماس پذیرفته نشده هش پیام ناصحیح هش پیام قبلی متفاوت است. شناسه پیام ناصحیح @@ -753,7 +753,7 @@ صدا خاموش بلندگو خاموش بلندگو روشن - در حال اتصال + در حال اتصال تماس فعال کردن قفل کد عبور تعیین شد! کد عبور تغییر کرد! @@ -1351,11 +1351,11 @@ اجازه ارسال پرونده‌ها و رسانه را می‌دهید. اعضای گروه می‌توانند پیام‌های ارسالی را به صورت غیرقابل برگشت حذف کنند. (۲۴ ساعت) حذف بعد از - تنظیمات گپ + تنظیمات گفت‌و‌گو پرونده‌ها و رسانه تماس‌های صوتی/تصویری " -\nموجود در v5.1" +\nموجود در نسخه 5.1" به مخاطبان خود اجازه ارسال پیام‌های صوتی می‌دهید. فقط زمانی اجازه حذف پیام‌ها به صورت غیرقابل برگشت را می‌دهید که مخاطب شما این اجازه را به شما بدهد. (۲۴ ساعت) پیام‌های ناپدید شونده در این گروه ممنوع هستند. @@ -1853,4 +1853,17 @@ از نشانی IP خود در برابر واسطه‌های پیام‌رسانی انتخاب شده توسط مخاطبانتان محافظت کنید. \nدر تنظیمات «شبکه و سرورها» فعال کنید. دریافت امن پرونده‌ها + پرونده یافت نشد - احتمالا حذف یا لغو شده. + کلید اشتباه یا نشانی پرونده ناشناخته - به احتمال زیاد پرونده حذف شده است. + خطای پرونده + خطای پرونده موقت + وضعیت پرونده + وضعیت پیام + وضعیت پرونده: %s + وضعیت پیام: %s + خطای کپی + لطفا بررسی کنید که تلفن همراه و کامپیوتر به شبکه محلی یکسانی متصل هستند، و فایروال کامپیوتر شما اجازه اتصال را میدهد. +\nلطفا هر مشکل دیگری را با توسعه‌دهندگان به اشتراک بگذارید. + این لینک توسط موبایل دیگری استفاده شده است، لطفا لینک جدیدی در کامپیوتر بسازید. + خطای سرور پرونده:%1$s \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml index 62a01fdd64..b89f0ddb62 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml @@ -16,7 +16,7 @@ 30 sekuntia 5 minuuttia Salli katoavat viestit vain, jos kontaktisi sallii ne. - Lisää palvelin… + Lisää palvelin Lisää tervetuloviesti Salli ääniviestien lähettäminen. Kertakäyttölinkki @@ -94,7 +94,7 @@ Puhelu on jo päättynyt! Tumma teema Yhdistetäänkö kontaktilinkin kautta\? - Yhdistetäänkö ryhmälinkin kautta\? + Liitytäänkö ryhmään? Yhdistetäänkö kutsulinkin kautta\? Yhdistä yhdistää @@ -456,7 +456,7 @@ Virhe roolin vaihdossa %dw Ryhmän moderointi - Näyttönimi: + Profiilin nimi: Virhe käynnistettäessä keskustelua Virhe keskustelun lopettamisessa Virhe asetuksen muuttamisessa @@ -558,7 +558,7 @@ Virheellinen QR-koodi näytä QR-koodi videopuhelussa tai jaa linkki.]]> Virheellinen palvelimen osoite! - Näyttönimi + Kirjoita nimesi: Käännä kamera Se voi tapahtua, kun sinä tai kontaktisi käytitte vanhaa varmuuskopiota tietokannasta. Väärä pääsykoodi @@ -589,7 +589,7 @@ Vanhentunut kutsu! kutsuttu epäsuora (%1$s) - Ryhmän näyttönimi: + Kirjoita ryhmän nimi: Syötä salasana hakuun Ryhmän asetukset Ryhmän jäsenet voivat lisätä viestireaktioita. @@ -956,7 +956,7 @@ Järjestelmä Vain sinä voit soittaa puheluita. Varmista, että WebRTC ICE -palvelinosoitteet ovat oikeassa muodossa, rivieroteltuina ja että ne eivät ole päällekkäisiä. - Verkko &; palvelimet + Verkko & palvelimet QR-koodi Skannaa koodi alkaa… @@ -1132,7 +1132,7 @@ SMP-palvelimesi XFTP-palvelimesi Käytä SimpleX Chat palvelimia\? - TEEMAN VÄRIT + KÄYTTÖLIITTYMÄN VÄRIT Päivitä kuljetuksen eristystila\? Voit luoda sen myöhemmin Voit paljastaa piilotetun profiilisi kirjoittamalla koko salasanan Keskusteluprofiilit-sivun hakukenttään. @@ -1382,4 +1382,139 @@ 6 uutta käyttöliittymän kieltä Löydä ryhmiä ja liity niihin Luo uusi profiili työpöytäsovelluksessa. 💻 + Virheellinen linkki + Virheellinen QR-koodi + Ei verkkoyhteyttä + %s ladattu + Päivitä + %s ja %s + Istuntokoodi + Vahvista tietokannan tunnuslause + %1$s!]]> + Tämä on oma SimpleX-osoitteesi! + Vahvista tunnuslause + %1$s.]]> + Salli SimpleX-linkkien lähettäminen. + Lisää kontakti + Tai näytä tämä koodi + Lataus epäonnistui + Historiaa ei lähetetä uusille jäsenille. + Arkistoidaan tietokanta + Varoitus: arkisto poistetaan.]]> + Kamera ja mikrofoni + Tarkista internetyhteys ja yritä uudelleen + Yhdistä automaattisesti + Poista tietokanta tältä laitteelta + Virhe selainta avatessa + Tiedoston tila: %s + Laajenna + Hyvää huomenta! + Lisäasetukset + Aseta oletusteema + Vaalea tila + Virhe: %1$s + kaikki jäsenet + Aseta tunnuslause + Älä lähetä historiaa uusille jäsenille. + Kyllä + Tiedosto poistettiin tai linkki on virheellinen + Äänipuhelu + Lopeta puhelu + Videopuhelu + Napauta skannataksesi + Kehittäjävalinnat + Lataa + Tiedostovirhe + Näytä viestin tila + Bluetooth + Kaiutin + Kuulokkeet + Vahvista yhteydet + Sovelluksen teema + Kaikki väritilat + Ryhmäjäsenet voivat lähettää SimpleX-linkkejä. + (uusi)]]> + VIestiä ei voi lähettää + SimpleX-linkit eivät ole sallittuja + Ladataan tiedostoa + Kaikki viestit poistetaan - tätä ei voi perua! + Virheellinen nimi! + Profiilin teema + %s yhdistetty + %s, %s ja %d jäsentä + tuntematon tila + Virhe kutsua lähettäessä + Tiedoston tila + Viestin tila + Viestin tila: %s + Poistetaanko jäsen? + Luo ryhmä + Musta + Väritila + Tumma + Tumman tilan värit + Tumma tila + Hyvää iltapäivää! + Laitteet + Kirjoita tunnuslause + Virhe tietokantaa poistaessa + Viimeistele migraatio toisella laitteella. + tallennettu + Tallennettu + Toteuta + Tuonti epäonnistui + WiFi + Kiinteä ethernet + Sisäinen virhe + Vahvista verkkoasetukset + Viimeistele migraatio + Virheellinen näyttönimi! + Napauta liittääksesi linkin + Virheellinen tiedostopolku + Verkkoyhteys + Katkaise yhteys + Kamera ei saatavilla + Luodaan linkki… + Tai skannaa QR-koodi + Aina + Ei koskaan + Ei + Kamera + Avaa asetukset + Suojaa IP-osoite + TIEDOSTOT + Profiilikuvat + tuntematon + Poista jäsen + SimpleX-linkit + Kvanttiturvallinen salaus + Verkon hallinta + Kirjoita tämän laitteen nimi… + Vahvista yhteys + Työpöytälaitteet + Ei yhteensopiva! + Satunnainen + Ryhmä on jo olemassa! + Kriittinen virhe + Virhe asetuksia tallentaessa + Virhe + Tietokannan migraatio on käynnissä. +\nTämä saattaa kestää muutaman minuutin. + Yritä uudelleen + Näytä sisäiset virheet + Näytä hitaat API-kutsut + Luo profiili + Tämä on oma kertakäyttöinen linkkisi! + Virhe + Hidas funktio + Napauta yhdistääksesi + Viesti on liian pitkä + Virhe viestiä luotaessa + Mikrofoni + Vaalea + Järjestelmä + Poista kuva + Yhteensopimaton versio + Uusi mobiililaite + Tämä laite \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml index a9d9f0188b..92091ef126 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml @@ -313,7 +313,7 @@ Scannez le code de sécurité depuis l\'application de votre contact. Pour vérifier le chiffrement de bout en bout avec votre contact, comparez (ou scannez) le code sur vos appareils. scanner un code QR lors d\'un appel vidéo, ou votre contact peut partager un lien d\'invitation.]]> - Ajouter un serveur… + Ajouter un serveur Markdown dans les messages Ajouter des serveurs prédéfinis Utiliser les serveurs SimpleX Chat \? @@ -1858,4 +1858,19 @@ Système Erreur d\'initialisation de WebView. Mettez votre système à jour avec la nouvelle version. Veuillez contacter les développeurs. \nErreur : %s + Fichier introuvable - le fichier a probablement été supprimé ou annulé. + Mauvaise clé ou adresse inconnue du bloc de données du fichier - le fichier est probablement supprimé. + Erreur du serveur de fichiers : %1$s + Erreur de fichier + Erreur de fichier temporaire + Statut du fichier + Statut du fichier: %s + Statut du message + Statut du message: %s + Erreur de copie + Veuillez vérifier que le mobile et l\'ordinateur sont connectés au même réseau local et que le pare-feu de l\'ordinateur autorise la connexion. +\nVeuillez faire part de tout autre problème aux développeurs. + Ce lien a été utilisé avec un autre appareil mobile, veuillez créer un nouveau lien sur le desktop. + Impossible d\'envoyer le message + Les paramètres de chat sélectionnés ne permettent pas l\'envoi de ce message. \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/hi/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/hi/strings.xml index 61b9ad8de6..9c283a98e9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/hi/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/hi/strings.xml @@ -36,7 +36,7 @@ गुप्त स्वीकार करें पूर्वनिर्धारित सर्वर जोड़ें प्रोफ़ाइल जोड़ें - सर्वर जोड़े… + सर्वर जोड़े हमेशा बने रहें संलग्न करना उन्नत संजाल समायोजन diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml index 94db4f4618..66ea969b09 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml @@ -9,16 +9,16 @@ 6 új kezelőfelületi nyelv 5 perc 1 perc - A SimpleX azonosítóról + A SimpleX címről Címváltoztatás megszakítása? Megszakítás 30 másodperc Egyszer használatos hivatkozás %1$s szeretne kapcsolatba lépni önnel ezen keresztül: - A SimpleX Chat névjegye + A SimpleX Chat-ről 1 nap Címváltoztatás megszakítása - A SimpleX névjegye + A SimpleX-ről Kiemelés fogadott hívás Hozzáférés a kiszolgálókhoz SOCKS proxy segítségével a %d porton? A proxyt el kell indítani, mielőtt engedélyezné ezt az opciót. @@ -29,7 +29,7 @@ Kapcsolódási kérelem elfogadása? Elfogadás Elfogadás - Azonosító hozzáadása a profilhoz, hogy az ismerősei megoszthassák másokkal. A profilfrissítés elküldésre kerül az ismerősök számára. + Cím hozzáadása a profilhoz, hogy az ismerősei megoszthassák másokkal. A profilfrissítés elküldésre kerül az ismerősök számára. További kiemelés hiba a hívásban Csoporttagok letiltása @@ -74,7 +74,7 @@ Minden üzenet törlésre kerül - ez a művelet nem vonható vissza! Az üzenetek CSAK az ön számára törlődnek. Hívás befejeződött HÍVÁSOK - és %d további esemény + és további %d esemény Cím Csatlakozás folyamatban! Automatikus elfogadás @@ -141,12 +141,12 @@ Jobb üzenetek A cím módosítása megszakad. A régi fogadási cím kerül felhasználásra. Engedélyezés - Hibás számítógép-azonosító + Hibás számítógép cím Profil hozzáadása Csatolás Alkalmazás jelkód Felkérték a kép fogadására - Fényképező + Kamera A Keystore-hoz nem sikerül hozzáférni az adatbázis jelszó mentése végett hívás folyamatban Fotók automatikus elfogadása @@ -156,7 +156,7 @@ Az eltűnő üzenetek küldése engedélyezve van. Az eltűnő üzenetek küldése kizárólag abban az esetben van engedélyezve, ha az ismerőse is engedélyezi. Hang kikapcsolva - A közvetlen üzenetek küldése a tagok számára engedélyezve van. + A közvetlen üzenetek küldése a tagok között engedélyezve van. Alkalmazás Hívás folyamatban Mindkét fél küldhet üzenetreakciókat. @@ -165,7 +165,7 @@ Minden %s által írt új üzenet elrejtésre kerül! Alkalmazás verzió: v%s A hívások kezdeményezése kizárólag abban az esetben van engedélyezve, ha az ismerőse is engedélyezi. - Kiszolgáló hozzáadása… + Kiszolgáló hozzáadása Hang bekapcsolva hanghívás (nem e2e titkosított) letiltva @@ -205,8 +205,8 @@ Kapcsolódás egy hivatkozás / QR-kód által Kapcsolódási hiba (AUTH) Ismerős neve - Kapcsolódik a kapcsolattartási azonosítón keresztül? - Azonosító létrehozása + Kapcsolódik a kapcsolattartási címen keresztül? + Cím létrehozása Másolás Folytatás Kapcsolódás egy hivatkozáson keresztül? @@ -240,7 +240,7 @@ \n- gyorsabb és stabilabb. Hozzájárulás kapcsolódás (bemutatkozó meghívó) - SimpleX azonosító létrehozása + SimpleX cím létrehozása törölt ismerős Csoporttag üzenet törlése? A csevegés fut @@ -276,7 +276,7 @@ Jelenleg támogatott legnagyobb fájl méret: %1$s. Fájl törlése Hamarosan! - azonosító megváltoztatása erre: %s… + cím megváltoztatása nála: %s … Csevegési adatbázis importálva CSEVEGÉSI ARCHÍVUM Üzenetek törlése @@ -301,7 +301,7 @@ Csoport törlése? Adatbázis frissítés megerősítése Saját profil létrehozása - azonosító megváltoztatása… + cím megváltoztatása… kapcsolódás… Hívás kapcsolása Fájlok és a médiatartalmak törlése? @@ -331,7 +331,7 @@ Várólista törlése Ismerős törlése Létrehozva ekkor: %1$s - címek megváltoztatása… + cím megváltoztatása… Csatlakoztatva a mobilhoz Jelenlegi jelmondat… Fájl kiválasztás @@ -341,7 +341,7 @@ Kiürítés Ismerős törlése? Kiürítés - Azonosító létrehozása, hogy az emberek kapcsolatba léphessenek önnel. + Cím létrehozása, hogy az emberek kapcsolatba léphessenek önnel. Biztonsági kódok összehasonlítása az ismerőseiével. Fájl összehasonlítás Csevegések @@ -367,9 +367,9 @@ Engedélyezés minden csoport számára engedélyezve az ismerős számára Az eltűnő üzenetek küldése le van tiltva ebben a csoportban. - Azonosító törlése + Cím törlése %d hét - Számítógép azonosítója + Számítógép címe %dmp Kézbesítési jelentések! Eszközhitelesítés nem engedélyezett.A SimpleX zárolás bekapcsolható a Beállításokon keresztül, miután az eszköz hitelesítés engedélyezésre került. @@ -379,7 +379,7 @@ Törlés %d óra %d hónap - Azonosító törlése? + Cím törlése? Üzenet kézbesítési jelentések letiltása? Az adatbázis jelmondat eltérő a Keystore-ba elmentettől. Közvetlen üzenetek @@ -396,7 +396,7 @@ Helyi csoportok felfedezése és csatlakozás %1$d üzenet moderálva lett %2$s által Eltűnő üzenet - Ne hozzon létre azonosítót + Ne hozzon létre címet Ne mutasd újra SimpleX zárolás kikapcsolása e2e titkosított @@ -455,7 +455,7 @@ Archívum törlése Az eltűnő üzenetek küldése le van tiltva ebben a csevegésben. alap (%s) - duplikálódott üzenet + duplikált üzenet Számítógép leválasztása? Számítógép kliens verziója %s nem kompatibilis ezzel az alkalmazással. Kézbesítés @@ -473,7 +473,7 @@ Hiba a csoport törlésekor Kilépés mentés nélkül Tárolt fájlok és médiatartalmak titkosítása - Hiba az azonosító beállításakor + Hiba a cím beállításakor A csoport meghívó lejárt Hiba az ICE kiszolgálók mentésekor Hiba @@ -481,8 +481,8 @@ Hiba az XFTP kiszolgálók betöltésekor Hiba az SMP kiszolgálók betöltésekor Hiba a hálózat konfigurációjának frissítésekor - TCP életben tartásának engedélyezése - Fényképezőgép megfordítása + TCP életben tartása + Kamera váltás Üdv! \nCsatlakozzon hozzám SimpleX Chat-en keresztül: %s A megjelenített név nem tartalmazhat szóközöket. @@ -526,7 +526,7 @@ A zárolási képernyőn megjelenő hívások engedélyezése a Beállításokban. titkosítás egyeztetve Üzenet kézbesítési jelentések engedélyezése? - Hiba a csoport profil mentésekor + Hiba a csoportprofil mentésekor hiba A fájl törölve lesz a kiszolgálóról. Akkor is, ha le van tiltva a beszélgetésben. @@ -569,7 +569,7 @@ Hiba a beállítás megváltoztatásakor Hiba a csoport hivatkozás frissítésekor a csoport törölve - csoport profil frissítve + csoportprofil frissítve Hiba a függőben lévő ismerős kapcsolatának törlésekor Hiba a csevegési adatbázis importálásakor Hiba a kézbesítési jelentések engedélyezésekor! @@ -590,7 +590,7 @@ segítség Önmegsemmisítő jelkód engedélyezése KÍSÉRLETI - Hiba az azonosító megváltoztatásának megszakításakor + Hiba a cím megváltoztatásának megszakításakor Hiba a fájl fogadásakor titkosítás rendben Hiba az ismerős kérelem törlésekor @@ -608,14 +608,14 @@ Titkosítás javítása az adatmentések helyreállítása után. Hiba a csevegési adatbázis törlésekor Teljes hivatkozás - Hiba az azonosító megváltoztatásakor + Hiba a cím megváltoztatásakor A csoport tagjai küldhetnek hangüzeneteket. Csoport beállítások Hiba: %s Eltűnő üzenetek SimpleX zárolás engedélyezése Hiba a kapcsolat szinkronizálása során - Hiba az azonosító létrehozásakor + Hiba a cím létrehozásakor engedélyezve Hiba a részletek betöltésekor Hiba történt a kapcsolatfelvételi kérelem elfogadásakor @@ -704,7 +704,7 @@ Nincs kézbesítési információ moderált A tag eltávolítása a csoportból - ez a művelet nem vonható vissza! - Győződjön meg róla, hogy az XFTP-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nem duplikáltak. + Győződjön meg róla, hogy az XFTP kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nincsenek duplikálva. Nem kerültek ismerősök kiválasztásra Nincsenek fogadott, vagy küldött fájlok Megnyitás mobil alkalmazásban, majd koppintson a Kapcsolódás gombra az alkalmazásban.]]> @@ -730,7 +730,7 @@ Új asztali alkalmazás! Most már az adminok is: \n- törölhetik a tagok üzeneteit. -\n- letilthatnak tagokat (\"megfigyelő\" szerepkör) +\n- letilthatnak tagokat („megfigyelő” szerepkör) meghívta őt: %1$s Az üzenetreakciók küldése le van tiltva ebben a csoportban. Nem @@ -738,7 +738,7 @@ TAG Ez később a beállításokon keresztül módosítható. Új tag szerepköre - Ki + Kikapcsolva Érvénytelen hivatkozás! A kapcsolódáshoz Onion kiszolgálókra lesz szükség. Változások a %s verzióban @@ -747,7 +747,7 @@ k soha (új)]]> - Győződjön meg arról, hogy az SMP-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nincsenek duplikálva. + Győződjön meg arról, hogy az SMP kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nincsenek duplikálva. Onion kiszolgálók nem lesznek használva. perc Tudjon meg többet @@ -762,7 +762,7 @@ A meghívó lejárt! (csak a csoporttagok tárolják) Moderálás - be + bekapcsolva Japán és portugál kezelőfelület Az üzenetek végleges törlése le van tiltva ebben a csoportban. Onion kiszolgálók nem lesznek használva. @@ -776,7 +776,7 @@ elhagyta a csoportot Az üzenetek végleges törlése le van tiltva ebben a csevegésben. Max 40 másodperc, azonnal fogadható. - inkognitó a kapcsolattartási azonosító-hivatkozáson keresztül + inkognitó a kapcsolattartási cím-hivatkozáson keresztül A kapcsolódáshoz Onion kiszolgálókra lesz szükség. \nFigyelem: .onion cím nélkül nem fog tudni kapcsolódni a kiszolgálókhoz. Olasz kezelőfelület @@ -789,7 +789,7 @@ Rendben Nincsenek szűrt csevegések érvénytelen adat - Győződjön meg arról, hogy a WebRTC ICE-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nem duplikáltak. + Győződjön meg arról, hogy a WebRTC ICE kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nincsenek duplikálva. Csak a csoporttulajdonosok engedélyezhetik a fájlok- és a médiatartalmak küldését. A fájl betöltése Nincs hozzáadandó ismerős @@ -821,7 +821,7 @@ érvénytelen üzenet formátum Csatlakozás Az értesítések az alkalmazás elindításáig nem fognak működni - ki` + kikapcsolva` (ez az eszköz: v%s)]]> ajánlott %s Csoport elhagyása @@ -896,7 +896,7 @@ Kapcsolódási kérés megismétlése? Véglegesen csak ön törölhet üzeneteket (ismerőse csak törlésre jelölheti őket ). (24 óra) Szerepkör - SimpleX kapcsolattartási azonosító + SimpleX kapcsolattartási cím Megállítás Előre beállított kiszolgáló Új csevegés kezdése @@ -911,9 +911,9 @@ PING időköze Eltűnő üzenet küldése Önmegsemmisítési jelkód - Mentés és csoport profil frissítése + Mentés és csoportprofil frissítése Adatvédelem - SimpleX azonosító + Az ön SimpleX címe Jelentse a fejlesztőknek. Az emberek csak az ön által megosztott hivatkozáson keresztül kapcsolódhatnak. Az eltűnő üzenetek küldése le van tiltva. @@ -984,7 +984,7 @@ egyszer használatos hivatkozást osztott meg A hivatkozás megnyitása a böngészőben gyengítheti az adatvédelmet és a biztonságot. A megbízhatatlan SimpleX hivatkozások pirossal vannak kiemelve. ICE kiszolgálók - Kapcsolódás elfogadva + Kapcsolat létrehozása Elutasítás Ismerős és üzenet megjelenítése BEÁLLÍTÁSOK @@ -1019,7 +1019,7 @@ Elküldve ekkor: %s Jelenlegi profil használata Ez az eszköz - Megosztja az azonosítót az ismerőseivel? + Megosztja a címet az ismerőseivel? Profiljelszó Téma Jelmondat eltávolítása a beállításokból? @@ -1085,7 +1085,7 @@ Adatbázis jelmondat beállítása Elküldött üzenet Időszakosan indul - Ez a SimpleX azonosítója! + Ez az ön SimpleX címe! eltávolítva Megosztás SimpleX csapat @@ -1104,7 +1104,7 @@ SOCKS PROXY Mentés Újraindítás - Üzenetküldő (SMP) kiszolgálók + SMP kiszolgálók Videó Automatikus elfogadási beállítások mentése Újraegyzetetés @@ -1135,7 +1135,7 @@ ÖN port %d Kapcsolódás hivatkozáson keresztül - Azonosító megosztása + Cím megosztása A kiszolgáló QR-kódjának beolvasása Megállítás Címmegosztás megállítása? @@ -1146,7 +1146,7 @@ Biztosan eltávolítja? Biztonsági kód ellenőrzése eltávolítottak - SimpleX azonosító + SimpleX cím Megjelenítés: fogadott válasz… Adatbázismentés visszaállítása? @@ -1207,7 +1207,7 @@ videóhívás Kedvenc törlése Üzenet kézbesítési jelentések küldése - SimpleX azonosító + SimpleX cím Koppintson a Mentés és ismerős értesítése Elutasított hívás @@ -1229,7 +1229,7 @@ Jelmondat mentése és csevegés megnyitása Beállítások mentése? Az első csevegési rendszer bármiféle felhasználó azonosító nélkül - privátra lett tervezre. - A közvetlen üzenetek küldése le van tiltva a tagok között. + A közvetlen üzenetek küldése a tagok között le van tiltva. SOCKS proxy használata? Hangszóró kikapcsolva hét @@ -1290,7 +1290,7 @@ Csevegési profil felfedése Videók és fájlok 1Gb méretig TCP kapcsolat időtúllépés - A(z) %1$s nevű profiljának SimpleX azonosítója megosztásra fog kerülni. + A(z) %1$s nevű profiljának SimpleX címe megosztásra fog kerülni. Ön már kapcsolódott ehhez: %1$s. Jelenlegi csevegési adatbázis TÖRLÉSRE és FELCSERÉLÉSRE kerül az importált által! \nEz a művelet nem vonható vissza - profiljai, ismerősei, csevegési üzenetei és fájljai véglegesen törölve lesznek! @@ -1303,17 +1303,17 @@ Várakozás a mobiltelefon társítására: Kapcsolat biztonságának ellenőrzése fájlok küldése egyelőre még nem támogatott - azonosítója erre változott: %s + cím megváltoztatva nála: %s fájlok fogadása egyelőre még nem támogatott - Csoport profil mentése + Csoportprofil mentése Alaphelyzetbe állítás Hacsak az ismerőse nem törölte a kapcsolatot, vagy ez a hivatkozás már használatban volt, lehet hogy ez egy hiba – jelentse a problémát. \nA kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsolati hivatkozást, és ellenőrizze, hogy a hálózati kapcsolat stabil-e. videóhívás (nem e2e titkosított) Alkalmazás új kapcsolatokhoz Az új üzenetek rendszeresen letöltésre kerülnek az alkalmazás által – naponta néhány százalékot használ az akkumulátorból. Az alkalmazás nem használ push értesítéseket – az eszközről származó adatok nem kerülnek elküldésre a kiszolgálóknak. - Számítógép azonosítójának beillesztése - kapcsolattartási azonosító-hivatkozáson keresztül + Számítógép címének beillesztése + kapcsolattartási cím-hivatkozáson keresztül SimpleX háttérszolgáltatást használja - az akkumulátor néhány százalékát használja naponta.]]> Az ismerősének online kell lennie ahhoz, hogy a kapcsolat létrejöjjön. \nVisszavonhatja ezt a kapcsolatfelvételt és törölheti az ismerőst (ezt később ismét megpróbálhatja egy új hivatkozással). @@ -1390,7 +1390,7 @@ Akkor lesz kapcsolódva, amikor az ismerősének az eszköze online lesz, várjon, vagy ellenőrizze később! Kéretlen üzenetek elrejtése. Használja az .onion kiszolgálókat NEM értékre, ha a SOCKS proxy nem támogatja őket.]]> - Megoszthatja azonosítóját hivatkozásként vagy QR-kódként – így bárki kapcsolódhat önhöz. + Megoszthatja a címét egy hivatkozásként vagy egy QR-kódként – így bárki kapcsolódhat önhöz. Létrehozás később Profilja az eszközön van tárolva és csak az ismerőseivel kerül megosztásra. A SimpleX kiszolgálók nem láthatják a profilját. %s szerepkörét megváltoztatta erre: %s @@ -1411,7 +1411,7 @@ Hangüzeneteket küldéséhez engedélyeznie kell azok küldését az ismerősei számára. fogadja az üzeneteket, ismerősöket – a kiszolgálók, amelyeket az üzenetküldéshez használ.]]> %1$s csoport tagja.]]> - azonosítója megváltoztatva + cím megváltoztatva Ismerősei engedélyezhetik a teljes üzenet törlést. A jelmondatot minden alkalommal meg kell adnia, amikor az alkalmazás elindul - nem az eszközön kerül tárolásra. Ha engedélyezni szeretné, hogy egy mobilalkalmazás csatlakozzon a számítógéphez, akkor nyissa meg ezt a portot a tűzfalában, ha engedélyezte azt @@ -1420,7 +1420,7 @@ Ez a karakterlánc nem egy meghívó hivatkozás! Új csevegés kezdése A kapcsolódás már folyamatban van ezen az egyszer használatos hivatkozáson keresztül! - Nem veszíti el az ismerőseit, ha később törli az azonosítóját. + Nem veszíti el az ismerőseit, ha később törli a címét. A beállítások frissítése a kiszolgálókhoz való újra kapcsolódással jár. kapcsolatba akar lépni veled! saját szerepköre erre változott: %s @@ -1442,8 +1442,8 @@ Az időzóna védelme érdekében a kép-/hangfájlok UTC-t használnak. A kapcsolódási kérelem elküldésre kerül ezen csoporttag számára Inkognitóprofil megosztása esetén a rendszer azt a profilt fogja használni azokhoz a csoportokhoz, amelyekbe meghívást kapott. - Már kért egy kapcsolódási kérelmet ezen az azonosítón keresztül! - Megoszthatja ezt a SimpleX azonosítót az ismerőseivel, hogy kapcsolatba léphessenek vele: %s. + Már kért egy kapcsolódási kérelmet ezen a címen keresztül! + Megoszthatja ezt a SimpleX címet az ismerőseivel, hogy kapcsolatba léphessenek vele: %s. Amikor az emberek kapcsolódást kérelmeznek, ön elfogadhatja vagy elutasíthatja azokat. Megjelenítendő üzenet beállítása az új tagok számára! Köszönet a felhasználóknak - hozzájárulás a Weblaten! @@ -1472,7 +1472,7 @@ Kézbesítési jelentések le vannak tiltva a(z) %d csoportban Néhány nem végzetes hiba történt az importálás során – további részletekért a csevegési konzolban olvashat. Köszönet a felhasználóknak - hozzájárulás a Weblaten! - Az átjátszó kiszolgáló csak szükség esetén kerül használatra. Egy másik fél megfigyelheti az IP-címét. + Az átjátszó kiszolgáló csak szükség esetén kerül használatra. Egy másik fél megfigyelheti az IP-címet. Rendszerhitelesítés helyetti beállítás. 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. A csevegés megállítása a csevegő adatbázis exportálásához, importálásához, vagy törléséhez. A csevegés megállítása alatt nem tud üzeneteket fogadni és küldeni. @@ -1481,12 +1481,12 @@ Jelmondat mentése a beállításokban Ennek a csoportnak több mint %1$d tagja van, a kézbesítési jelentések nem kerülnek elküldésre. A második jelölés, amit kihagytunk! ✅ - Az átjátszó kiszolgáló megvédi IP-címét, de megfigyelheti a hívás időtartamát. + Az átjátszó kiszolgáló megvédi az IP-címet, de megfigyelheti a hívás időtartamát. További információ a GitHub tárolónkban. Az utolsó üzenet tervezetének megőrzése a mellékletekkel együtt. A mentett WebRTC ICE-kiszolgálók eltávolításra kerülnek. Kézbesítési jelentések engedélyezve vannak a(z) %d csoportban - A szerepkör meg fog változni erre: \"%s\". A csoportban mindenki értesítve lesz. + A szerepkör meg fog változni erre: „%s”. A csoportban mindenki értesítve lesz. Profil és kiszolgálókapcsolatok Egy üzenetküldő- és alkalmazásplatform, amely védi az ön adatait és biztonságát. A profil aktiválásához koppintson az ikonra. @@ -1506,7 +1506,7 @@ A jelenlegi csevegési profilhoz tartozó új kapcsolatok kiszolgálói Fogadás ezen keresztül: Tárolja el biztonságosan jelmondát, mert ha elveszti azt, akkor NEM férhet hozzá a csevegéshez. - A tag szerepköre erre fog változni: \"%s\". A tag új meghívót fog kapni. + A tag szerepköre erre fog változni: „%s”. A tag új meghívót fog kapni. profilkép helyőrző A titkosítás működik, és új titkosítási egyezményre nincs szükség. Ez kapcsolati hibákat eredményezhet! Ez a művelet nem vonható vissza - profiljai, ismerősei, üzenetei és fájljai véglegesen törlésre kerülnek. @@ -1536,7 +1536,7 @@ A csevegés leállt. Ha már használta ezt az adatbázist egy másik eszközön, úgy visszaállítás szükséges a csevegés megkezdése előtt. Az előzmények nem kerülnek elküldésre az új tagok számára. Újrapróbálkozás - A fényképező nem elérhető + A kamera nem elérhető Az utolsó 100 üzenet elküldése az új tagok számára. Az előzmények ne kerüljenek elküldésre az új tagok számára. Vagy mutassa meg ezt a kódot @@ -1585,13 +1585,13 @@ Fejlesztői beállítások A funkció végrehajtása túl sokáig tart: %1$d másodperc: %2$s %s mobil eszköz elfoglalt]]> - Legutóbbi tag %1$s + Már nem tag - %1$s ismeretlen státusz %1$s megváltoztatta a nevét erre: %2$s - törölt kapcsolattartási azonosító + törölt kapcsolattartási cím törölt profilkép - új kapcsolattartási azonosító beállítása - új profilkép beállítása + új kapcsolattartási cím beállítása + új profilképet állított be frissített profil %1$s megváltoztatta a nevét erre: %2$s Privát jegyzetek @@ -1616,8 +1616,8 @@ letiltva letiltva az admin által Letiltva az admin által - %s letiltva - Mindenki számára letiltva + letiltotta őt: %s + Letiltás mindenki számára Mindenki számára letiltja ezt a tagot? %d üzenet letiltva az admin által Letiltás feloldása mindenki számára @@ -1791,14 +1791,14 @@ Üzenet útválasztási mód Közvetlen üzenetküldés, ha az IP-cím védett és az ön kiszolgálója vagy a célkiszolgáló nem támogatja a privát útválasztást. Közvetlen üzenetküldés, ha az ön kiszolgálója vagy a célkiszolgáló nem támogatja a privát útválasztást. - Az IP-címe védelme érdekében a privát útválasztás az SMP-kiszolgálókat használja az üzenetek kézbesítéséhez. + Az IP-cím védelmének érdekében a privát útválasztás az SMP-kiszolgálókat használja az üzenetek kézbesítéséhez. Üzenet útválasztási tartalék PRIVÁT ÜZENET ÚTVÁLASZTÁS Privát útválasztás használata ismeretlen kiszolgálókkal, ha az IP-cím nem védett. Ne küldjön üzeneteket közvetlenül, még akkor sem, ha az ön kiszolgálója vagy a célkiszolgáló nem támogatja a privát útválasztást. Tor vagy VPN nélkül az IP-címe látható lesz a fájlkiszolgálók számára. FÁJLOK - Az IP-cím védelme + IP-cím védelem Az alkalmazás kérni fogja az ismeretlen fájlkiszolgálókról történő letöltések megerősítését (kivéve, ha az .onion vagy a SOCKS proxy engedélyezve van). Ismeretlen kiszolgálók! Tor vagy VPN nélkül az IP-címe látható lesz az XFTP átjátszók számára: @@ -1821,7 +1821,7 @@ Csevegőlista megjelenítése új ablakban Világos Világos mód - Kapott válasz + Fogadott válasz Kép eltávolítása Mozaik Szín visszaállítása @@ -1849,7 +1849,22 @@ Felhasználó által létrehozott téma visszaállítása Üzenet várakoztatási információ nincs - Hibakeresés kézbesítés + Kézbesítési hibák felderítése Kiszolgáló várakoztatási infó: %1$s \nUtoljára kézbesített üzenet: %2$s + Hibás kulcs vagy ismeretlen fájltöredék cím - valószínűleg a fájl törlődött. + Ideiglenes fájlhiba + Üzenetállapot + Üzenetállapot: %s + Fájlhiba + A fájl nem található - valószínűleg a fájlt törölték vagy visszavonták. + Fájlkiszolgáló hiba: %1$s + Fájlállapot + Fájlállapot: %s + Másolási hiba + Ezt a hivatkozást egy másik mobilleszközön már használták, hozzon létre egy új hivatkozást az asztali számítógépén. + Ellenőrizze, hogy a mobil és az asztali számítógép ugyanahhoz a helyi hálózathoz csatlakozik-e, valamint az asztali számítógép tűzfalában engedélyezve van-e a kapcsolat. +\nMinden további problémát osszon meg a fejlesztőkkel. + Nem lehet üzenetet küldeni + A kiválasztott csevegési beállítások tiltják ezt az üzenetet. \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/in/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/in/strings.xml new file mode 100644 index 0000000000..3cace47d15 --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/resources/MR/in/strings.xml @@ -0,0 +1,49 @@ + + + %1$s ANGGOTA + Alamat + %1$d pesan dihapus admin %2$s + 1 menit + 30 detik + 5 menit + Semua pesan akan dihapus - ini tidak bisa dikembalikan! Pesan akan HANYA dihapus untukmu. + Terima permintaan relasi? + Tentang alamat SimpleX + Tambah kontak + Tentang SimpleX + %1$d gagal mendekripsi pesan. + Tolong laporkan hal ini ke pengembang. + 1 bulan + 1 minggu + Terima + %1$s.]]> + Panggilan suara + Batal + izinkan pesan suara? + Terima + Versi aplikasi + Versi aplikasi: v%s + panggilan suara + 1 hari + Buat pesan sambutan + Batalkan penggantian alamat + Tambah profil + Corak + Tambahan sekunder + Motif aplikasi + selalu + diizinkan mengirim pesan suara. + semua anggota + Panggilan suara dan video + Hal-hal lain + Sudah menghubungi! + Sudah bergabung dengan grup! + %1$s ingin menghubungimu lewat + Batalkan penggantian alamat? + diatas, lalu: + Tambahkan ke perangkat lain + Boleh + Selalu + APLIKASI + Tampilan + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml index 2ea3c53514..690c826549 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml @@ -249,7 +249,7 @@ Accetta in incognito Tutti i messaggi verranno eliminati, non è reversibile! I messaggi verranno eliminati SOLO per te. Aggiungi server preimpostati - Aggiungi server… + Aggiungi server Impostazioni di rete avanzate Riguardo SimpleX chiamata accettata @@ -1797,7 +1797,7 @@ NON inviare messaggi direttamente, anche se il tuo server o quello di destinazione non supporta l\'instradamento privato. NON usare l\'instradamento privato. No - INSTRADAMENTO PRIVATO MESSAGGI + INSTRADAMENTO PRIVATO DEI MESSAGGI Invia messaggi direttamente quando l\'indirizzo IP è protetto e il tuo server o quello di destinazione non supporta l\'instradamento privato. Per proteggere il tuo indirizzo IP, l\'instradamento privato usa i tuoi server SMP per consegnare i messaggi. Non protetto @@ -1858,4 +1858,19 @@ \n \nultimo msg ricevuto: %2$s Debug della consegna + Stato del messaggio: %s + Stato del file: %s + Chiave sbagliata o indirizzo sconosciuto per frammento del file - probabilmente il file è stato eliminato. + File non trovato - probabilmente è stato eliminato o annullato. + Stato del messaggio + Stato del file + Errore del server del file: %1$s + Errore del file + Errore del file temporaneo + Controlla che mobile e desktop siano collegati alla stessa rete locale e che il firewall del desktop consenta la connessione. +\nSi prega di condividere qualsiasi altro problema con gli sviluppatori. + Questo link è stato usato con un altro dispositivo mobile, creane uno nuovo sul desktop. + Copia errore + Impossibile inviare il messaggio + Le preferenze della chat selezionata vietano questo messaggio. \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml index e335c199d0..c35b750c01 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml @@ -18,7 +18,7 @@ כל ההודעות יימחקו – לא ניתן לבטל זאת! ההודעות יימחקו רק עבורך. אשר זהות נסתרת הוסף שרתים מוגדרים מראש - הוסף שרת… + הוסף שרת לגשת לשרתים דרך פרוקסי SOCKS בפורט %d\? הפרוקסי חייב לפעול לפני הפעלת אפשרות זו. הגדרות רשת מתקדמות מראה @@ -1715,4 +1715,129 @@ %1$s.]]> הסר משתתף הסתיים פסק הזמן הקצוב להתחברות למחשב השולחני + חיבור רשת יותר אמין. + מתי שהIP מוסתר + השתמש במסלול פרטי עם שרתים לא ידועים + אזהרה על אופן שליחת ההודעה + הראה סטטוס הודעה + מסלול פרטי להודעה 🚀 + סטטוס הודעה:%s + אנא וודא שהמכשיר והמחשב מחוברים לאותה רשת מקומית, ושהפיירוול של המחשב מאפשר את החיבור. +\nאנא תשתף כל בעיות אחרות עם המפתחים. + "אשר קבלת קבצים משרתים לא מוכרים" + שגיאת רשת - ההודעה פגה תוקף לאחר ריבוי ניסיונות שליחה + שגיאה:%1$s + כל החברים + הודעת המקור נשארת פרטית + רינגטון ל שיחה נכנסת + קובץ לא נמצא - ככל הנראה הקובץ נמחק או בוטל + שגיאת שרת קבצים:%1$s + הורדה + לא + ערכת נושא חדשה לצא\'ט + מרובע, עיגול, או כל דבר ביניהם + העבר ושמור הודעות + מתי שמתחבר שחיות קוליות ווידאו. + לא מצליח לשלוח הודעה + הודעות קוליות לא מאופשרות + שגיאת קובץ זמני + קבצים ומדיה לא מאופשרים + שגיאת קובץ + השתמש במסלול פרטי עם שרתים לא ידועים מתי שכתובת הIP לא מוגנת. + שלח הודעות ישירות מתי שכתובת הIP מוגנת ואתה או שרת היעד לא תומך במסלול פרטי. + כדי להגן על כתובת הIP שלך, מסלול פרטי משתמש בשרתי הSMP שלך כדי להעביר את ההודעות. + אל תשתמש במסלול פרטי + תמיד השתמש בנתיב פרטי + תאפשר בהגדרות + תאפשר הרשאות בשביל להתקשר + מצלמה ומיקרופון + פתח הגדרות + מצא את ההרשאה בהגדרות המכשיר ותאפשר אותה ידנית + רמקול + אוזניות + אוזניות + ערכת נושא לפרופיל + צבעי הצא\'ט + הראה רשימת צא\'טים בחלון חדש + מצב הקובץ + סטטוס הודעה + מצב הקובץ:%s + ריק + כהה + מצב צבעוני + שחור + בהיר + אפס צבע + ערכת נושא לאפליקציה + שלח תגובה + התקבל תגובה + טפט רקע + הסר תמונה + חזור + מלא + אפס ערכת נושא לאפליקציה + התאם + צהריים טובים + בוקר טוב! + הגדרות מתקדמות + הגדר ערכת נושא ברירת מחדל + אפס ערכת נושא למשתמש + החל ל + מצב כל הצבעים + חברי הקבוצה יכולים לשלוח קישורי SimpleX + עשה שהצאט\'ים שלך יראו אחרת! + הגדרות רשת + הקישור הזה שומש כבר במכשיר אחר, אנא צור קישור חדש במחשב. + חיבור קווי + סלולרי + נשמר + נשמר מ%s + הועבר + הועבר + מחובר לרשת + Wi-Fi אלחוטי + שגיאה בהעתקה + ערכת נושא כהה + ערכת נושא + צבעי מצב כהה + שגיאה בשרת היעד:%1$s + "אל תשלח הודעות ישירות אפילו אם שרת היעד לא תומך במסלול פרטי" + שיפור בשליחת הודעות + מצלמה + אפשר שליחת קישורי SimpleX + בעלים + מנהלים + מופעל עבור + שרתים לא ידועים! + בלי טור או VPN, כתובת הIP שלך תהיה חשופה למתווכי XFTP האלה: +\n%1$s + הועבר מ + נשמר + נשמר מ + מקבלי ההודעה לא יוכלו לראות מי שלח את ההודעה + הועבר + מעביר הודעה… + קישורי SimpleX לא מאופשרים + מסלול פרטי + לא מוגן + תמיד + מתווכים לא ידועים + לעולם לא + כן + אפשר שינמוך + שלח הודעות ישירות מתי שאתה או שרת היעד לא תומך במסלול פרטי + מיקרופון + הרשאות שניתנו + כתובת IP מוגנת + האפליקציה תשאל כדי לאשר הורדות משרתי קבצים לא ידועים (למעט שרתי טור או מתי שפרוקסי SOCKS מופעל). + בלי טור או VPN, כתובת הIP שלך תהיה גלויה לשרתי קבצים. + קבצים + תמונות פרופיל + מסלול הודעה פרטית + קישורי SimpleX + אין חיבור לרשת + אחר + ערכת נושא בהירה + מערכת + שגיאה בהצגת התראה, צור קשר עם המפתחים \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml index 41f1d0d6a8..ac3f75780e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml @@ -21,7 +21,7 @@ QRコードでサーバを追加 別の端末に追加 プロフィールを追加 - サーバを追加… + サーバを追加 SOCKSプロキシ(ポート%d)経由で接続しますか?(※設定する前にプロキシ起動が必要※) 全チャットとメッセージが削除されます(※元に戻せません※)! 送信相手からの音声メッセージを許可する。 @@ -298,7 +298,7 @@ ファイル保存でエラー発生 接続中 確認待ち - 中止 + キャンセル 使い捨ての招待リンク 音声メッセージを録音 ギャラリーから @@ -1034,7 +1034,7 @@ メンバーのメッセージを削除しますか? テーマのインポート ポート - テーマカラー + インターフェースカラー 共有を停止 友人を招待する 後からでも作成できます @@ -1084,7 +1084,7 @@ Bluetoothのサポートおよびその他の機能も改善されました。 中継サーバーは必要な場合にのみ使用されます。 別の当事者があなたの IP アドレスを監視できます。 アドレス共有の停止? - 送信 + 送信メッセージ 受信したメッセージ 以前のメッセージとハッシュ値が異なります。 次のメッセージの ID が正しくありません (前のメッセージより小さいか等しい)。 @@ -1594,8 +1594,8 @@ ステータス不明 プライベートノート メッセージ配信の改善 - エンドツーエンドの暗号化によって保護されます。]]> - 耐量子E2E暗号化によって保護されます。]]> + エンドツーエンドの暗号化によって保護されます。]]> + 耐量子E2E暗号化によって保護されます。]]> このチャットはエンドツーエンド暗号化により保護されています。 このチャットは耐量子エンドツーエンド暗号化により保護されています。 プライベートノート @@ -1796,4 +1796,42 @@ 壁紙の背景 チャットカラー チャットテーマ + ファイルエラー + ファイルサーバーエラー: %1$s + ファイルステータス + ファイルステータス: %s + ペルシャ語UI + ファイルが見つかりません - 削除されたかキャンセルされた可能性があります。 + チャットの見た目を変更できます! + ファイル + ネットワークエラー - 複数回送信が試行されましたが、メッセージが期限切れになりました + 無効 + メッセージステータス + ファイルの安全な受け取り + プロフィールテーマ + メッセージステータス:%s + 色のリセット + 受信した返信元メッセージ + 送信した返信元メッセージ + 画像を削除 + 拡大縮小 + フィットさせる + 画像全体 + アプリのテーマをリセット + ユーザーテーマをリセット + デフォルトのテーマを設定 + プライベートメッセージルーティング 🚀 + 不明なサーバーからのファイルを確認できます + バッテリーの使用量が減少しました + メッセージ配信の改善 + 不明なサーバーです! + プライベートルーティングを使用しない + IPアドレス保護 + コピーエラー + 新しいチャットテーマ + 連絡先が選択したメッセージリレーからあなたのIPアドレスを保護します。 +\n*ネットワークとサーバー*設定から有効にして下さい。 + いいえ + はい + メッセージルーティングモード \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml index 3caa99bc59..9d7088d742 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml @@ -43,7 +43,7 @@ 연결 요청이 전송되었습니다! 링크로 연결 프리셋 서버 추가 - 서버 추가… + 서버 추가 채팅 콘솔 서버 주소를 확인 후 다시 시도해 주세요. ICE 서버 설정 @@ -938,4 +938,33 @@ 이미지 기다리는 중 음성 메시지 %1$d개의 메시지의 해독에 실패했습니다. + 추가 강조 색상 2 + 백업 복원 후 암호화 수정. + 채팅 더 빠르게 찾기 + 그룹 링크 + 읽지 않은 채팅과 즐겨찾기 채팅 필터링. + 고급 설정 + 연결 유지하기 + 소유자 + %1$d개의 메시지가 %2$s에 의해 삭제되었습니다 + 6개의 새로운 인터페이스 언어 + 연락처 추가 + 관리자 + 관리자는 모든 멤버를 위해 특정 멤버를 차단할 수 있습니다. + 메시지 전달 확인서! + 우리가 놓친 두 번째 체크! ✅ + 주소 변경 중지 + - 최대 5분의 음성 메시지. +\n- 사용자 정의 소멸 시간. +\n- 편집 기록. + 사용자 여러분께 감사드립니다 – Weblate를 통해 기여하세요! + 주소 변경이 중지됩니다. 이전 수신 주소가 사용됩니다. + 일본어 및 포르투갈어 UI + 주소 변경을 중지하시겠습니까? + 모든 멤버 + 위해 활성화됨 + 새로운 기능 + 더 보기 + 보안 평가 + SimpleX Chat 보안은 Trail of Bits에 의해 감사되었습니다. \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml index b5191f342d..a98aba3ff6 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml @@ -6,7 +6,7 @@ 1 diena a + b Apie SimpleX - Pridėti serverį… + Pridėti serverį Pridėti serverius nuskanuojant QR kodus. Išvaizda Programėlės versija @@ -1763,4 +1763,26 @@ SimpleX nuorodos neleidžiamos Kai jungiami garso ir vaizdo skambučiai. Bus įjungta tiesioginiuose pokalbiuose! + Juodo režimo spalvos + Patvirtinkite failus iš nežinomų serverių. + Paskirties serverio klaida: %1$s + Klaida: %1$s + Tamsu + Spalvos režimas + Programėlės tema + Pridėtinis akcentas 2 + Pažangūs nustatymai + Visi spalvų režimai + Visada + Pokalbio spalvos + Juodas režimas + Juoda + Talpa viršyta – gavėjas negavo anksčiau išsiųstų žinučių. + Pokalbio tema + NESIŲSTI žinučių tiesiogiai, net jei jūsų ar paskirties serveris nepalaiko privataus maršruto. + Visada naudoti privatų maršrutą. + NENAUDOTI privataus maršruto. + Taip + Kopijavimo klaida + Pritaikyti prie \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml index 455f9d53bd..b807789c08 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml @@ -109,7 +109,7 @@ തിരികെ നിശബ്ദമാക്കുക സഹായം - സെർവർ ചേർക്കുക… + സെർവർ ചേർക്കുക മറ്റൊരു ഉപകരണത്തിലേക്ക് ചേർക്കുക സ്വയമേവ സ്വീകരിക്കുക സ്ഥിരീകരണത്തിനായി കാത്തിരിക്കുന്നു… diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml index 4fa3ba4f51..ef66bf6e10 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml @@ -39,7 +39,7 @@ Accepteer incognito Vooraf ingestelde servers toevoegen Profiel toevoegen - Server toevoegen… + Server toevoegen Toevoegen aan een ander apparaat Beheerders kunnen de uitnodiging links naar groepen aanmaken. Servers toevoegen door QR-codes te scannen. @@ -1856,4 +1856,19 @@ informatie over serverwachtrij: %1$s \n \nlaatst ontvangen bericht: %2$s + Bestand niet gevonden - hoogstwaarschijnlijk is het bestand verwijderd of geannuleerd. + Verkeerde sleutel of onbekend bestanddeeladres - hoogstwaarschijnlijk is het bestand verwijderd. + Bestandsserverfout: %1$s + Bestandsfout + Tijdelijke bestandsfout + Kopieerfout + Controleer of mobiel en desktop met hetzelfde lokale netwerk zijn verbonden en of de desktopfirewall de verbinding toestaat. +\nDeel eventuele andere problemen met de ontwikkelaars. + Deze link is gebruikt met een ander mobiel apparaat. Maak een nieuwe link op de desktop. + Bestandsstatus + Berichtstatus: %s + Bestandsstatus: %s + Berichtstatus + Kan bericht niet verzenden + Geselecteerde chatvoorkeuren verbieden dit bericht. \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml index 4853fdf127..ce2e3751a5 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml @@ -290,7 +290,7 @@ Zostaniesz połączony do grupy, gdy urządzenie gospodarza grupy będzie online, proszę czekać lub sprawdzić później! Zostaniesz połączony, gdy urządzenie Twojego kontaktu będzie online, proszę czekać lub sprawdzić później! Dodaj gotowe serwery - Dodaj serwer… + Dodaj serwer Dodaj do innego urządzenia Konsola czatu Sprawdź adres serwera i spróbuj ponownie. @@ -1858,4 +1858,19 @@ Motyw aplikacji Zresetuj do motywu aplikacji Zresetuj do motywu użytkownika + Nie odnaleziono pliku - najprawdopodobniej plik został usunięty lub anulowany. + Status pliku + Status wiadomości + Status pliku: %s + Status wiadomości: %s + Kopiuj błąd + Ten link dostał użyty z innym urządzeniem mobilnym, proszę stworzyć nowy link na komputerze. + Błąd pliku + Błąd serwera plików: %1$s + Sprawdź, czy telefon i komputer są podłączone do tej samej sieci lokalnej i czy zapora sieciowa komputera umożliwia połączenie. +\nProszę podzielić się innymi problemami z deweloperami. + Tymczasowy błąd pliku + Zły klucz lub nieznany adres fragmentu pliku - najprawdopodobniej plik został usunięty. + Nie można wysłać wiadomości + Wybrane preferencje czatu zabraniają tej wiadomości. \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml index 7d4570e561..bf14ac248d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml @@ -110,7 +110,7 @@ Conectar via link/QR code Todas as mensagens serão excluídas - isso não pode ser desfeito! As mensagens serão excluídas APENAS para você. Adicionar servidores pré-definidos - Adicionar servidor… + Adicionar servidor Crie seu perfil Ícone de contexto Contato e todas as mensagens serão excluídas - isso não pode ser desfeito! @@ -1637,4 +1637,25 @@ Criar novo perfil no aplicativo de desktop. 💻 Criptografar arquivos armazenados & arquivos de mídia Novo aplicativo de desktop! + Arquivando banco de dados + Cancelar migração + Por Favor, note que: usando o mesmo banco de dados em dois dispositivos vai quebrar a descriptografia das mensagens das suas conexões, como proteção de segurança.]]> + Aplicar + Tema do aplicativo + Preto + Bluetooth + Arquivar e enviar + Aplicar para + Administradores podem bloquear um membro para todos. + Migração de dados do aplicativo + Todos os seus contatos,conversas e arquivos irão ser criptografados seguramente e enviados em partes para relays de XFTP configurados. + Aviso: o arquivo irá ser deletado.]]> + Rede móvel + Sempre + Sempre usar roteamento privado. + Câmera + Câmera e microfone + Permitir o envio de links do SimpleX. + Todos os membros + Configurações avançadas \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml index 4bb442faf8..65ffeef271 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml @@ -122,7 +122,7 @@ 1 semana Aceitar aceitar chamada - Adicionar servidor… + Adicionar servidor Aceitar Aceitar pedido de ligação\? Aceitar modo anónimo diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ro/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ro/strings.xml index ae03ebd1ae..4c8865f464 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ro/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ro/strings.xml @@ -5,7 +5,7 @@ 30 secunde Acceptă Acceptă incognito - Adaugă server… + Adaugă server Setări de rețea avansate %1$s dorește să se conecteze cu tine prin Acceptă @@ -154,7 +154,7 @@ autor Arabă, Bulgară, Finlandeză, Ebraică, Thailandeză și Ucraineană - mulțumită utilizatorilor și Weblate. Apelurile audio/video sunt interzise. - (prezent) + (actual) Poză de profil eliminată Temă întunecată eliminat @@ -320,4 +320,359 @@ Arată ultimul mesaj Trimite mesaj direct Setează tema implicită + SimpleX + SimpleX nu poate rula în fundal. Vei primi notificările doar când aplicația rulează. + Serviciu SimpleX Chat + Adresă SimpleX + Închide + Link-uri SimpleX + Link-urile SimpleX sunt interzise în acest grup. + Securitatea SimpleX Chat a fost verificată de Trail of Bits. + Mesaje SimpleX Chat + Apeluri SimpleX Chat + Adresă SimpleX + simplexmq: v%s (%2s) + Link-uri SimpleX nepermise + Echipa SimpleX + Închizi? + Adresă de contact SimpleX + Link de grup SimpleX + Link-uri SimpleX + Invitație unică SimpleX + Siglă SimpleX + Grupuri mici (max 20) + Mod incognito simplificat + Pătrat, cerc, sau orice între. + %s nu este verificat + %s este verificat + Servere SMP + %s, %s și %d alți membri s-au conectat + %s, %s și %d membri + Difuzor + %s, %s și %s s-au conectat + %s: %s + Niște servere au eșuat testul: + Difuzor oprit + Difuzor pornit + Copie de rezervă a datelor aplicației + Tema aplicației + Accent suplimentar 2 + Începe conversația + Toate modurile de culoare + Folosește mereu releu + Aplică pentru + Începe o nouă conversație + Stea pe GitHub + Criptare de la capăt la capăt standard + Pornește periodic + Mereu + Folosește mereu rutare privată. + Toate contactele vor rămâne conectate. Actualizarea profilului va fi trimisă contactelor tale. + pornire… + %s secunde + Începi conversația? + Setări avansate + Adresă desktop rea + ID de mesaj incorect + Hash de mesaj incorect + ID de mesaj incorect + Hash de mesaj incorect + Schimbă adresa de primire + Conversația este oprită. Dacă ai folosit deja această bază de date pe alt dispozitiv, ar trebui să o transferi înapoi înainte de a porni conversația. + APELURI + ai schimbat rolul pentru tine la %s + Capacitate depășită - destinatarul nu a primit mesajele trimise anterior. + Schimbă codul de acces autodistructibil + Conversația este oprită + se schimbă adresa… + Contact verificat + Creat la + Migrează de pe alt dispozitiv pe dispozitivul nou și scanează codul QR.]]> + Te conectezi prin adresa de contact? + Te conectezi printr-un link unic? + Conectare incognito + Contactul deja există + Schimbă codul de acces + Poți porni Blocare SimpleX din Setări. + Conversații + Alege un fișier + Contactul tău trebuie să fie online pentru a se completa conexiunea. +\nPoți anula această conexiune și elimina contactul (și poți încerca mai târziu cu un nou link). + eroare apel + Apelurile tale + Schimbă + Schimbă rolul + Contactul permite + Grupuri mai bune + Desktop conectat + Preferințe contact + Te conectezi cu %1$s? + Anulează previzualizarea imaginii + Discută cu dezvoltatorii + Trebuie să introduci fraza de acces de fiecare dată când aplicația pornește - nu este stocată pe dispozitiv. + blocat + Preferințe conversație + Mod întunecat + Interfață chineză și spaniolă + Crează un grup folosind un profil aleatoriu. + Blochează membrii grupului + Mobil conectat + Conectat la desktop + Anulează migrarea + Celular + Nu poți trimite mesaje! + Schimbi adresa de primire? + Contactul nu este conectat încă! + Conectare prin link + Poți vedea linkul de invitație din nou în detaliile conexiunii. + Profilurile tale de conversație + Crează profil de conversație + apel terminat %1$s + Crează + Bluetooth + Camera + Apeluri pe ecranul de blocare: + contactul are criptare e2e + contactul nu are criptare e2e + Contacte + CONVERSAȚII + BAZĂ DE DATE CONVERSAȚIE + Baza de date a conversației ștearsă + Conversația rulează + Baza ta de date a conversațiilor + Baza ta de date a conversațiilor nu este criptată - setează frază de acces pentru a o proteja. + Fraza de acces de criptare a bazei de date va fi actualizată și stocată în setări. + Creat pe %1$s + ai schimbat rolul %s la %s + Nu se pot invita contactele! + Te-ai alăturat grupului + Nu se poate invita contactul! + se conectează (acceptat) + Creat la: %s + Blochează + Blochează membru + Conectare directă? + Profilul tău de conversație va fi trimis membrilor grupului + Întunecat + Culori mod întunecat + Și tu și contactul tău puteți face apeluri. + %s anulat + Conectat la mobil + Eroare copiere + Te conectezi prin link? + Nu ai putut fi verificat(ă); te rog încearcă din nou. + Copiază + Anulează mesajul live + Conectare prin link / cod QR + Contactele tale vor rămâne conectate. + Fraza de acces de criptare a bazei de date va fi actualizată. + Contactele tale pot permite ștergerea totală a mesajelor. + Trebuie să permiți contactului tău să trimită mesaje vocale pentru a le putea trimite. + Versiunede bază: v%s + Creează o adresă pentru a permite oamenilor să se conecteze cu tine. + %s blocat + ai schimbat adresa + ai schimbat adresa pentru %s + se schimbă adresa… + se schimbă adresa pentru %s… + Și tu și contactul tău puteți trimite mesaje temporare. + Nu se pot primi fișiere + Poate fi dezactivat în setări – notificările vor fi încă afișate cât timp aplicația rulează.]]> + Verifică mesajele noi la fiecare 10 minute timp de până la 1 minut + Nu ai conversații + Contactul și toate mesajele vor fi șterse - acest lucru nu poate fi anulat! + Copiat în clipboard + Camera + Ai invitat un contact + Profilul tău de conversație va fi trimis +\ncontactului tău + Contribuie + Profil conversație + aldin + Poți folosi markdown pentru a formata mesaje: + Apelând… + Schimbă modul de autodistrugere + Baza de date a conversației importată + Trebuie să folosești cea mai recentă versiune a bazei de date a conversațiilor DOAR pe un singur dispozitiv, altfel se poate să nu mai primești mesajele de la unele contacte. + Nu se poate accesa Keystore pentru a salva parola bazei de date + Conversație migrată! + Continuă + apel în curs + Apel în curs + Și tu și contactul tău puteți trimite mesaje vocale. + Contact ascuns: + Nume contact + Crează adresă + Bază de date criptată! + Schimbi fraza de acces a bazei de date? + Conversația este oprită + Poți porni conversația prin Setările aplicației / Bază de date sau repornind aplicația. + ai ieșit + Blochezi membrul? + Blocat de admin + Și tu și contactul tău puteți adăuga reacții la mesaje. + Mesaje mai bune + blocat + blocat de admin + Nu se poate inițializa baza de date + Contactul tău a trimis un fișier care este mai mare decât dimensiunea maximă suportată în prezent (%1$s). + anulează previzualizarea link-ului + Verifică adresa serverului și încearcă din nou. + Tu îți controlezi conversația! + Apel deja terminat! + Apel terminat + Blochează pentru toți + Ai cerut deja conexiunea prin această adresă! + Te conectezi la tine? + Verifică conexiunea la internet și încearcă din nou + Culori conversație + Temă conversație + Bun pentru baterie. +\nServiciul în fundal verifică mesaje la fiecare 10 minute. Ai putea rata apeluri sau mesaje urgente. + Negru + Blochezi membrul pentru toți? + Și tu și contactul tău puteți șterge ireversibil mesajele trimise. (24 de ore) + Folosește mai multă baterie! +\nServiciul în fundal rulează mereu – notificările sunt afișate imediat ce mesajele sunt disponibile. + Nu se poate trimite mesajul + Ștergeți + Confirmați fișiere de la servere necunoscute. + schimbat adresa pentru dumneavoastră + Confirmați parola nouă… + Conectare + conexiune %1$d + conexiune stabilită + Eroare de conexiune + Conexiune expirată + se conectează + Confirmare + În curând! + se conectează… + Schimbați modul de blocare + Versiunea aplicației: %s + pentru fiecare profil de conversație pe care le aveți în aplicație]]> + Permiteți downgrade-ul + O conexiune separată TCP (și SOCKS credential) va fi folosită pentru fiecare contact și membru de grup +\nVa rugăm considerați că: dacă aveți prea multe conexiuni, consumul dumneavoastră de baterie și trafic de internet pot fi considerabil mai mari, iar unele conexiuni pot eșua. + Conexiune terminată + Se conectează la desktop + Rugat să primească imaginea + Cerere de conexiune trimisă! + Vă rugăm să rețineți: mesajele și releurile pentru fișiere sunt conectate printr-un proxy SOCKS. Apelurile ți trimiterea de previzualizări a link-urilor folosesc o conexiune directă.]]> + conectat + Confirmați codul de access + Confirmare actualizare bază de date + "schimbat rolul lui %s la %s" + conectat + se conectează (introdus) + conectat + se conectează + Schimbați rolul de grup? + Modul color + Prin profil de conversație (implicit) sau prin conexiune (BETA). + Comparați codurile de securitate cu contactele dumneavoastră. + Conexiune oprită + Conexiune oprită + Conectare la desktop + Conexiunea la desktop este într-o stare proastă + Conectare + Conexiune + Ștergeți notițele private? + Conectare automată + se conectează apelul… + se conectează (invetație la introducere) + se conectează… + %s este într-o stare proastă]]> + Confirmați setările de rețea + se conectează… + Eroare de conexiune (AUTENTIFICARE) + Optimizarea pentru baterie este activă, vom opri serviciile din fundal și cererile periodice pentru mesaje noi. Le puteți reactiva din setări. + conectat + Crează un grup: pentru a crea un nou grup.]]> + Ștergeți conversația? + Ștergeți + Ștergeți conversația + Conectare + Consolă conversație + Confirmați parola + colorat + Arhivă conversație + Toate contactele, conversațiile și fișierele dumneavoastră vor fi encriptate într-un mod sigur și încărcate pe bucăți pe releurile XFTP configurate. + Rugat să primească videoclipul + Comparați fișierul + Vă rugăm să rețineți: nu veți putea recupera sau schimba parola dacă o veți pierde.]]> + schimbat rolul dumneavoastră la %s + conectat + se conectează + conectat + Ștergeți + Buton de închidere + Ștergeți verificarea + Configurare servere ICE + conectat direct + se conectează (anunțat) + Cel mai bun pentru baterie. Veți primi notificări doar când aplicația rulează (FĂRĂ servicii de fundal).]]> + Se conectează apelul + complet + Vă rugăm să rețineți: folosind aceeași bază de date pe două dispozitive, va intrerupe decripția mesajelor de la conexiunile dumneavoastră, ca protecție de securitate.]]> + Confirmați încărcarea + Confirmați că țineți minte parola de la baza de date pentru a o migra. + ARHIVĂ CONVERSAȚIE + Conexiune + Ștergi profilul de conversație? + Șterge pentru mine + %dd + șters + Șterge contact + Șters la + Versiunea aplicației desktop %s nu este compatibilă cu această aplicație. + Ștergi mesajul membrului? + Șterge arhiva + Șterge grup + Șterge și notifică contactele + Decentralizat + grup șters + %d contact(e) selectat(e) + Șters la: %s + Ștergi profilul de conversație? + Șterge profil + implicit (%s) + Confirmări de livrare! + Confirmările de livrare sunt dezactivate! + Adresă desktop + Dispozitive desktop + Desktop + Eroare decriptare + Șterge imagine + Șterge după + Șterge pentru toată lumea + Descriere + Șterge fișier + Șterge coadă + Ștergi contactul? + Șterge + Șterge + Ștergi fișiere și media? + Ștergi arhiva conversației? + %d zile + %d zi + Șterge adresa + Șterge mesaje + Ștergi %d mesaje? + Ștergi adresa? + Șterge toate fișierele + Șterge link + Ștergi link? + zile + Șterge + Ștergi mesajul? + Livrare + Ștergi conexiunea în așteptare? + Șterge server + Șterge baza de date + contact șters + Ștergi grupul? + Șterge baza de date de pe acest dispozitiv + Șterge profil de conversație + Șterge fișiere pentru toate profilurile de conversație \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml index 88dd4c2783..0e5b329669 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml @@ -354,7 +354,7 @@ SMP серверы Адрес сервера по умолчанию Добавить серверы по умолчанию - Добавить сервер… + Добавить сервер Тестировать сервер Тестировать серверы Сохранить серверы diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml index f6988ca367..ef020efb54 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml @@ -46,7 +46,7 @@ ขอรับภาพ ขอรับวิดีโอ ข้อความทั้งหมดจะถูกลบ - การดำเนินการนี้ไม่สามารถยกเลิกได้! ข้อความจะถูกลบสำหรับคุณเท่านั้น - เพิ่มเซิร์ฟเวอร์… + เพิ่มเซิร์ฟเวอร์ เวอร์ชันแอป เวอร์ชันแอป: v%s ผู้ติดต่อทั้งหมดของคุณจะยังคงเชื่อมต่ออยู่. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml index f25811fef7..1d67d2a0a9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml @@ -38,7 +38,7 @@ Adres değişikliği iptal edilecek. Eski alıcı adresi kullanılacaktır. 1 dakika Tüm mesajlar silinecektir. Bu, geri alınamaz! Mesajlar, YALNIZCA senin için silinecektir. - Sunucu ekle… + Sunucu ekle Veri tabanı ayarları tek kullanımlık bağlantı Gelişmiş ağ ayarları @@ -1853,4 +1853,10 @@ Azaltılmış pil kullanımı ile. Uygulama teması Uygulama temasına sıfırla + Hata ayıklama teslimatı + Mesaj kuyruğu bilgisi + hiçbiri + sunucu kuyruk bilgisi: %1$s +\n +\nson alınan msj: %2$s \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml index b8d802450d..abdf0dd8e0 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml @@ -55,7 +55,7 @@ Після перезапуску додатка або зміни ключової фрази буде використано сховище ключів Android для безпечного збереження ключової фрази - це дозволить отримувати сповіщення. Дозвольте вашим контактам надсилати голосові повідомлення. Прийняти інкогніто - Додати сервер… + Додати сервер адміністратор Додати привітання Всі члени групи залишаться підключеними. @@ -1850,4 +1850,10 @@ Скинути колір Система Без Tor або VPN ваша IP-адреса буде видимою для файлових серверів. + немає + Доставка налагодження + Інформація про чергу повідомлень + інформація про чергу на сервері: %1$s +\n +\nостаннє отримане повідомлення: %2$s \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/vi/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/vi/strings.xml index 735ef63237..85a7037cb6 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/vi/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/vi/strings.xml @@ -10,7 +10,7 @@ liên kết dùng một lần Thêm liên hệ Thông tin về SimpleX Chat - Thêm máy chủ… + Thêm máy chủ Thông tin về SimpleX quản trị viên Thêm lời chào @@ -24,7 +24,7 @@ Chấp nhận Thêm máy chủ bằng cách quét mã QR. Cài đặt mạng nâng cao - Tất cả các cuộc hội thoại và tin nhắn sẽ bị xóa - quá trình này không thể được hoàn tác! + Tất cả các cuộc trò chuyện và tin nhắn sẽ bị xóa - quá trình này không thể được hoàn tác! Hủy bỏ việc đổi địa chỉ? Việc thay đổi địa chỉ sẽ bị hủy bỏ. Địa chỉ nhận cũ tiếp tục được sử dụng. 30 giây @@ -96,12 +96,12 @@ ỨNG DỤNG Di chuyển dữ liệu ứng dụng Sao lưu dữ liệu ứng dụng - Mật mã ứng dụng đã được thay thế bằng mật mã tự hủy. + Mã truy cập ứng dụng đã được thay thế bằng mã tự hủy. Ứng dụng mã hóa các tệp cục bộ mới (trừ video). Áp dụng - Mật mã ứng dụng + Mã truy cập ứng dụng BIỂU TƯỢNG ỨNG DỤNG - Mật mã ứng dụng + Mã truy cập Phiên bản ứng dụng: v%s Phiên bản ứng dụng Tiếng Ả Rập, tiếng Bungari, tiếng Phần Lan, tiếng Do Thái, tiếng Thái và tiếng Ukraina - trân thành gửi lời cảm ơn tới các tình nguyện viên dịch thuật và Weblate. @@ -199,4 +199,287 @@ Cài đặt nâng cao Tất cả chế độ màu Camera và mic + Không thể mời liên hệ! + Không thể truy cập Keystore để lưu mật khẩu cơ sở dữ liệu + hủy bỏ xem trước liên kết + Hủy bỏ di chuyển + Chủ đề ứng dụng + Không thể nhận tệp + Không thể khởi tạo cơ sở dữ liệu + đã hủy bỏ %s + Không thể mời liên hệ! + Hủy bỏ tin nhắn động + đã thay đổi quyền hạn của %s thành %s + Dung lượng lưu trữ vượt quá giới hạn - người nhận không thể nhận được tin nhắn vừa gửi trước đó. + đã thay đổi địa chỉ cho bạn + Thay đổi mật khẩu cơ sở dữ liệu? + đã thay đổi quyền hạn của bạn thành %s + Thay đổi chế độ khóa + Di động + Đổi mật khẩu + Thay đổi quyền hạn của nhóm? + Thay đổi + Thay đổi địa chỉ nhận? + Thay đổi địa chỉ nhận + Thay đổi chế độ tự hủy + Thay đổi mã tự hủy + Thay đổi quyền hạn + đang thay đổi địa chỉ… + đang thay đổi địa chỉ… + KHO LƯU TRỮ SIMPLEX CHAT + Kho lưu trữ SimpleX Chat + Bảng điều khiển trò chuyện + Ứng dụng SimpleX Chat đang hoạt động + Cơ sở dữ liệu SimpleX Chat đã bị xóa + Ứng dụng SimpleX Chat đã được dừng lại. Nếu bạn đã sử dụng cơ sở dữ liệu này trên một thiết bị khác, bạn nên chuyển nó trở lại trước khi bắt đầu ứng dụng. + Cơ sở dữ liệu SimpleX Chat đã được nhập + Ứng dụng SimpleX Chat đã được dừng lại + đang thay đổi địa chỉ cho %s… + Tùy chọn trò chuyện + Màu trò chuyện + CƠ SỞ DỮ LIỆU SIMPLEX CHAT + Ứng dụng SimpleX Chat đã được dừng lại + Cơ sở dữ liệu đã được di chuyển! + Các cuộc trò chuyện + CÁC CUỘC TRÒ CHUYỆN + Kiểm tra tin nhắn mới mỗi 10 phút trong tối đa 1 phút + Giao diện Trung Quốc và Tây Ban Nha + Trò chuyện với nhà phát triển + Kiểm tra lại địa chỉ server và thử lại. + Chọn một tệp + Hồ sơ trò chuyện + Kiểm tra kết nối internet của bạn và thử lại + Chủ đề trò chuyện + Chế độ màu + Xác minh xóa + Xóa + Nút đóng + Xóa ghi chú riêng tư? + có màu + Xóa cuộc trò chuyện + Xóa + Sắp ra mắt! + Di chuyển từ một thiết bị kháctrên thiết bị mới và quét mã QR.]]> + Xóa + Xóa cuộc trò chuyện? + Cài đặt cấu hình cho các máy chủ ICE + Xác nhận các cài đặt mạng + Xác nhận mã truy cập + hoàn thành + Xác nhận mật khẩu + Xác nhận nâng cấp cơ sở dữ liệu + So sánh mã bảo mật với liên hệ của bạn. + Xác nhận + So sánh tệp + Xác nhận các tệp từ những máy chủ không xác định. + Xác nhận mật khẩu mới… + Xác nhận tải lên + Xác nhận rằng bạn nhớ mật khẩu cơ sở dữ liệu để chuyển nó đi. + Kết nối + đã kết nối + Đã kết nối + đã kết nối + Kết nối trực tiếp? + Kết nối + đã kết nối + Tự động kết nối + đã kết nối + Đã kết nối + Xác nhận thông tin đăng nhập của bạn + Kết nối + Máy tính đã được kết nối + đã kết nối trực tiếp + đang kết nối (đã được chấp nhận) + đang kết nối… + Đã kết nối tới điện thoại + Điện thoại đã được kết nối + đang kết nối + đang kết nối… + đang kết nối… + Kết nối ẩn danh + đang kết nối + Đã kết nối tới máy tính + đang kết nối (đã được thông báo) + đang kết nối… + đang kết nối (đã được giới thiệu) + đang kết nối (lời mời giới thiệu) + Kết nối tới máy tính đang ở trong tình trạng không tốt + Kết nối đã bị ngắt + Kết nối thông qua liên kết / mã QR + Kết nối tới chính bạn? + Yêu cầu kết nối đã được gửi! + Kết nối thông qua liên kết + Đang kết nối cuộc gọi + Kết nối đã bị ngắt + Đang kết nối tới máy tính + - kết nối tới dịch vụ thư mục (BETA)! +\n- đánh dấu đã nhận (tối đa 20 thành viên). +\n- nhanh hơn và ổn định hơn. + Kết nối đã bị ngắt + %s đang ở trong tình trạng không tốt]]> + Kết nối tới máy tính + Hết thời gian chờ kết nối + Lỗi kết nối + Kết nối + Kết nối thông qua liên kết? + kết nối %1$d + kết nối đã được tạo lập + Kết nối với %1$s? + Lỗi kết nối (AUTH) + Kết nối + đang kết nối cuộc gọi… + Kết nối thông qua địa chỉ liên lạc? + Kết nối thông qua liên kết dùng một lần? + Liên hệ đã được kiểm tra + Các liên hệ + Liên hệ có cho phép + Liên hệ đã tồn tại + liện hệ %1$s đã thay đổi thành %2$s + Liên hệ này vẫn chưa được kết nối! + Liên hệ ẩn: + Liên hệ và tất cả tin nhắn sẽ bị xóa - quá trình này không thể hoàn tác được! + Tên liên hệ + liên hệ có bảo mật đầu cuối + liên hệ không có bảo mật đầu cuối + Tùy chọn liên hệ + Sao chép + Tạo + Liên hệ có thể đánh dấu tin nhắn để xóa; bạn vẫn sẽ có thể xem được chúng. + Biểu tượng ngữ cảnh + Tiếp tục + Đóng góp + Đã sao chép vào bộ nhớ đệm + Phiên bản lõi: v%s + Sửa tên thành %s? + Sao chép lỗi + Tạo nhóm bằng một hồ sơ ngẫu nhiên. + Tạo hồ sơ mới trong ứng dụng trên máy tính. 💻 + Không thể gửi tin nhắn + Tạo tệp + Tạo một địa chỉ để cho mọi người kết nối với bạn. + Tạo liên kết nhóm + Tạo liên kết + Được tạo ra tại + Tạo địa chỉ + Được tạo ra vào %1$s + Được tạo ra tại: %s + Tạo hồ sơ trò chuyện + Tạo nhóm + Chủ đề tối + Mật khẩu hiện tại… + Cơ sở dữ liệu đã được mã hóa! + Mật khẩu mã hóa cơ sở dữ liệu sẽ đượ cập nhật và lưu trữ trong Keystore. + (hiện tại) + Tối + Các màu chế độ tối + Tối + Lỗi nghiêm trọng + Tạo liên kết lời mời dùng một lần + Đang tạo liên kết… + Tạo hồ sơ + Tùy chỉnh và chia sẻ các chủ đề màu sắc. + Các chủ đề tùy chỉnh + Kích cỡ tệp hiện đang được hỗ trợ tối đa là %1$s. + Tạo hồ sơ của bạn + Người sáng tạo + Tạo nhóm bí mật + Mã truy cập hiện tại + Tạo nhóm bí mật + Mật khẩu mã hóa cơ sở dữ liệu sẽ được cập nhật và lưu trữ trong cài đặt. + Thời lượng tùy chỉnh + Mật khẩu mã hóa cơ sở dữ liệu sẽ được cập nhật. + Tùy chỉnh chủ đề + Tạo địa chỉ SimpleX + Tạo hồ sơ + Tạo hàng đợi + Tạo liên kết lưu trữ + tùy chỉnh + Chủ đề tối + Hạ cấp cơ sở dữ liệu + %d liên hệ đã được chọn + ID cơ sở dữ liệu: %d + Cơ sở dữ liệu sẽ được mã hóa và mật khẩu thì được lưu trữ trong Keystore. + Nâng cấp cơ sở dữ liệu + Phiên bản cơ sở dữ liệu mới hơn so với ứng dụng, nhưng không có hạ cấp cho: %s + ID cơ sở dữ liệu + ngày + Cơ sở dữ liệu được mã hóa bằng một mật khẩu ngẫu nhiên. Vui lòng đổi mật khẩu trước khi xuất dữ liệu. + Cơ sở dữ liệu được mã hóa bằng một mật khẩu ngẫu nhiên, bạn có thể thay đổi nó. + Mật khẩu cơ sở dữ liệu + Cơ sở dữ liệu sẽ được mã hóa và mật khẩu thì được lưu trữ trong phần cài đặt. + %d ngày + Các ID cơ sở dữ liệu và tùy chọn cách ly truyền tải. + %dd + %d ngày + Cơ sở dữ liệu sẽ được mã hóa. + Việc di chuyển cơ sở dữ liệu đang diễn ra. +\nQuá trình này có thể mất một vài phút. + Mật khẩu cơ sở dữ liệu và xuất dữ liệu + Mật khẩu cơ sở dữ liệu khác với mật khẩu được lưu trong Keystore. + Mật khẩu cơ sở dữ liệu là cần thiết để mở ứng dụng SimpleX Chat. + Lỗi cơ sở dữ liệu + Xóa + Xóa địa chỉ? + Xóa hồ sơ trò chuyện? + Xóa %d tin nhắn? + Xóa địa chỉ + Phi tập trung + Xóa + Xóa cơ sở dữ liệu khỏi thiết bị này + Xóa sau + đã xóa liên hệ + Gỡ lỗi truyền tải + Đã xóa vào: %s + Lỗi chuyển đổi + Xóa và thông báo tới liên hệ + Xóa liên hệ + Xóa + Xóa cơ sở dữ liệu + Xóa tất cả các tệp + Xóa tệp và đa phương tiện? + Xóa kho lữu trữ + mặc định (%s) + Xóa kho lữu trữ SimpleX Chat? + đã xóa nhóm + Xóa tệp + Xóa liên hệ? + Đã xóa vào + Lỗi giải mã + đã xóa + Xóa hồ sơ trò chuyện + Xóa hồ sơ trò chuyện? + Xóa tin nhắn thành viên? + Xóa chỉ mình tôi + Xóa nhóm + Xóa kết nối đang chờ? + Xóa tệp cho tất cả các hồ sơ trò chuyện + Xóa liên kết? + Xóa hồ sơ + Xóa cho mọi người + Xóa liên kết + Xóa ảnh + Xóa các tin nhắn + Xóa nhóm? + Xóa tin nhắn? + Phiên bản ứng dụng trên máy tính %s không tương thích với ứng dụng này. + Máy tính đang bận + Máy tính đang không hoạt động + Máy tính đã bị ngắt kết nối + Quét mã QR.]]> + Xóa máy chủ + Xóa hàng đợi + Công cụ nhà phát triển + THIẾT BỊ + Tùy chọn nhà phát triển + Xác thực thiết bị đã bị vô hiệu hóa. Tắt Khóa SimpleX. + Lỗi máy chủ đích: %1$s + Chỉ báo đã nhận! + Chỉ báo đã nhận bị vô hiệu hóa! + Máy tính có mã mời sai + Mô tả + Chuyển gửi + Các thiết bị máy tính + Máy tính + Địa chỉ máy tính + Máy tính có một phiên bản không được hỗ trợ. Vui lòng đảm bảo rằng bạn sử dụng cùng một phiên bản ở cả hai thiết bị. \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml index bd9c8fa5c2..3bb4d1b72b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml @@ -15,7 +15,7 @@ 已接受通话 接受 通过在 %d 端口的 SOCKS 代理访问服务器?启用该选项前必须先启动代理。 - 添加服务器…… + 添加服务器 添加另一设备 管理员 扫描二维码来添加服务器。 @@ -1858,4 +1858,19 @@ \n \n上一则收到的信息:%2$s + 未找到文件 - 最有可能的情况是文件被删或被取消了 + 错误的密钥或未知的文件块地址 - 最可能的情况是文件被删了。 + 文件错误 + 文件服务器错误:%1$s + 文件状态 + 消息状态 + 临时性文件错误 + 文件状态:%s + 消息状态:%s + 请检查移动设备和桌面设备连接到的是同一个本地网络,且桌面防火墙允许连接。 +\n请和开发者分享任何其他问题。 + 此链接用于另一台移动设备,请在桌面上创建新的链接。 + 复制错误 + 无法发送消息 + 选择的聊天首选项禁止此条消息。 \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml index b6434c39db..21298376d9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml @@ -15,7 +15,7 @@ 管理員 然後,選按: 新增預設伺服器 - 新增伺服器… + 新增伺服器 接受 認證無效 允許 diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt index 905e25566b..38d87fc497 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt @@ -1,15 +1,19 @@ package chat.simplex.common.platform import chat.simplex.common.model.* +import chat.simplex.common.simplexWindowState import chat.simplex.common.views.call.RcvCallInvitation import chat.simplex.common.views.helpers.* import java.util.* import chat.simplex.res.MR +import java.io.File actual val appPlatform = AppPlatform.DESKTOP actual val deviceName = generalGetString(MR.strings.desktop_device) +actual fun isAppVisibleAndFocused() = simplexWindowState.windowFocused.value + @Suppress("ConstantLocale") val defaultLocale: Locale = Locale.getDefault() diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Files.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Files.desktop.kt index 5f33e2a943..eeeb13e5cc 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Files.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Files.desktop.kt @@ -26,9 +26,13 @@ actual val databaseExportDir: File = tmpDir actual val remoteHostsDir: File = File(dataDir.absolutePath + File.separator + "remote_hosts") actual fun desktopOpenDatabaseDir() { + desktopOpenDir(dataDir) +} + +actual fun desktopOpenDir(dir: File) { if (Desktop.isDesktopSupported()) { try { - Desktop.getDesktop().open(dataDir); + Desktop.getDesktop().open(dir); } catch (e: IOException) { Log.e(TAG, e.stackTraceToString()) AlertManager.shared.showAlertMsg( diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Platform.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Platform.desktop.kt index 9217551a8d..97de08b07e 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Platform.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Platform.desktop.kt @@ -8,12 +8,12 @@ private val unixConfigPath = (System.getenv("XDG_CONFIG_HOME") ?: "$home/.config private val unixDataPath = (System.getenv("XDG_DATA_HOME") ?: "$home/.local/share") + "/simplex" val desktopPlatform = detectDesktopPlatform() -enum class DesktopPlatform(val libExtension: String, val configPath: String, val dataPath: String) { - LINUX_X86_64("so", unixConfigPath, unixDataPath), - LINUX_AARCH64("so", unixConfigPath, unixDataPath), - WINDOWS_X86_64("dll", System.getenv("AppData") + File.separator + "SimpleX", System.getenv("AppData") + File.separator + "SimpleX"), - MAC_X86_64("dylib", unixConfigPath, unixDataPath), - MAC_AARCH64("dylib", unixConfigPath, unixDataPath); +enum class DesktopPlatform(val libExtension: String, val configPath: String, val dataPath: String, val githubAssetName: String) { + LINUX_X86_64("so", unixConfigPath, unixDataPath, "simplex-desktop-x86_64.AppImage"), + LINUX_AARCH64("so", unixConfigPath, unixDataPath, " simplex-desktop-aarch64.AppImage"), + WINDOWS_X86_64("dll", System.getenv("AppData") + File.separator + "SimpleX", System.getenv("AppData") + File.separator + "SimpleX", "simplex-desktop-windows-x86_64.msi"), + MAC_X86_64("dylib", unixConfigPath, unixDataPath, "simplex-desktop-macos-x86_64.dmg"), + MAC_AARCH64("dylib", unixConfigPath, unixDataPath, "simplex-desktop-macos-aarch64.dmg"); fun isLinux() = this == LINUX_X86_64 || this == LINUX_AARCH64 fun isWindows() = this == WINDOWS_X86_64 diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/AppUpdater.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/AppUpdater.kt new file mode 100644 index 0000000000..faef957705 --- /dev/null +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/AppUpdater.kt @@ -0,0 +1,394 @@ +package chat.simplex.common.views.helpers + +import SectionItemView +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextAlign +import chat.simplex.common.BuildConfigCommon +import chat.simplex.common.model.ChatController.appPrefs +import chat.simplex.common.model.ChatController.getNetCfg +import chat.simplex.common.model.json +import chat.simplex.common.platform.* +import chat.simplex.common.ui.theme.WarningOrange +import chat.simplex.common.views.onboarding.ReadMoreButton +import chat.simplex.res.MR +import kotlinx.coroutines.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import okhttp3.OkHttpClient +import okhttp3.Request +import java.io.Closeable +import java.io.File +import java.net.InetSocketAddress +import java.net.Proxy + +@Serializable +data class GitHubRelease( + @SerialName("tag_name") + val tagName: String, + @SerialName("html_url") + val htmlUrl: String, + val name: String, + val draft: Boolean, + val prerelease: Boolean, + val body: String, + @SerialName("published_at") + val publishedAt: String, + val assets: List +) + +@Serializable +data class GitHubAsset( + @SerialName("browser_download_url") + val browserDownloadUrl: String, + val name: String, + val size: Long, + + val isAppImage: Boolean = name.lowercase().contains(".appimage") +) + +fun showAppUpdateNotice() { + AlertManager.shared.showAlertDialogButtonsColumn( + generalGetString(MR.strings.app_check_for_updates_notice_title), + text = generalGetString(MR.strings.app_check_for_updates_notice_desc), + buttons = { + Column { + SectionItemView({ + AlertManager.shared.hideAlert() + appPrefs.appUpdateChannel.set(AppUpdatesChannel.STABLE) + setupUpdateChecker() + }) { + Text(generalGetString(MR.strings.app_check_for_updates_stable), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + } + + SectionItemView({ + AlertManager.shared.hideAlert() + appPrefs.appUpdateChannel.set(AppUpdatesChannel.BETA) + setupUpdateChecker() + }) { + Text(generalGetString(MR.strings.app_check_for_updates_beta), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + } + + SectionItemView({ + AlertManager.shared.hideAlert() + appPrefs.appUpdateChannel.set(AppUpdatesChannel.DISABLED) + }) { + Text(generalGetString(MR.strings.app_check_for_updates_notice_disable), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + } + } + } + ) +} + +private var updateCheckerJob: Job = Job() +fun setupUpdateChecker() = withLongRunningApi { + updateCheckerJob.cancel() + if (appPrefs.appUpdateChannel.get() == AppUpdatesChannel.DISABLED) { + return@withLongRunningApi + } + checkForUpdate() + createUpdateJob() +} + +private fun createUpdateJob() { + updateCheckerJob = withLongRunningApi { + delay(24 * 60 * 60 * 1000) + checkForUpdate() + createUpdateJob() + } +} + + +fun checkForUpdate() { + Log.d(TAG, "Checking for update") + val client = setupHttpClient() + try { + val request = Request.Builder().url("https://api.github.com/repos/simplex-chat/simplex-chat/releases").addHeader("User-agent", "curl").build() + client.newCall(request).execute().use { response -> + response.body?.use { + val body = it.string() + val releases = json.decodeFromString>(body).filterNot { it.draft } + val release = when (appPrefs.appUpdateChannel.get()) { + AppUpdatesChannel.STABLE -> releases.firstOrNull { !it.prerelease } + AppUpdatesChannel.BETA -> releases.firstOrNull() + AppUpdatesChannel.DISABLED -> return + } ?: return + val currentVersionName = "v" + (if (appPlatform.isAndroid) BuildConfigCommon.ANDROID_VERSION_NAME else BuildConfigCommon.DESKTOP_VERSION_NAME) + val redactedCurrentVersionName = when { + currentVersionName.contains('-') && currentVersionName.substringBefore('-').count { it == '.' } == 1 -> "${currentVersionName.substringBefore('-')}.0-${currentVersionName.substringAfter('-')}" + currentVersionName.substringBefore('-').count { it == '.' } == 1 -> "${currentVersionName}.0" + else -> currentVersionName + } + if (release.tagName == appPrefs.appSkippedUpdate.get() || release.tagName == currentVersionName || release.tagName == redactedCurrentVersionName) { + Log.d(TAG, "Skipping update because of the same version or skipped version") + return + } + val assets = chooseGitHubReleaseAssets(release) + // No need to show an alert if no suitable packages were found. But for Flatpak users it's useful to see release notes anyway + if (assets.isEmpty() && !isRunningFromFlatpak()) { + Log.d(TAG, "No assets to download for current system") + return + } + val lines = ArrayList() + for (line in release.body.lines()) { + if (line == "Commits:") break + lines.add(line) + } + val text = lines.joinToString("\n") + AlertManager.shared.showAlertDialogButtonsColumn( + generalGetString(MR.strings.app_check_for_updates_update_available).format(release.name), + text = text, + textAlign = TextAlign.Start, + dismissible = false, + belowTextContent = { + ReadMoreButton(release.htmlUrl) + }, + buttons = { + Column { + for (asset in assets) { + SectionItemView({ + AlertManager.shared.hideAlert() + chatModel.updatingProgress.value = 0f + withLongRunningApi { + try { + downloadAsset(asset) + } finally { + chatModel.updatingProgress.value = null + } + } + }) { + Text( + generalGetString(MR.strings.app_check_for_updates_button_download).format( + if (asset.name.length > 34) "…" + asset.name.substringAfter("simplex-desktop-") else asset.name, + formatBytes(asset.size)), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary + ) + } + } + + SectionItemView({ + AlertManager.shared.hideAlert() + skipRelease(release) + }) { + Text(generalGetString(MR.strings.app_check_for_updates_button_skip), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = WarningOrange) + } + + SectionItemView({ + AlertManager.shared.hideAlert() + }) { + Text(generalGetString(MR.strings.app_check_for_updates_button_remind_later), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + } + } + } + ) + } + } + } catch (e: Exception) { + Log.e(TAG, "Failed to get the latest release: ${e.stackTraceToString()}") + } +} + +private fun setupHttpClient(): OkHttpClient { + val netCfg = getNetCfg() + var proxy: Proxy? = null + if (netCfg.useSocksProxy && netCfg.socksProxy != null) { + val hostname = netCfg.socksProxy.substringBefore(":").ifEmpty { "localhost" } + val port = netCfg.socksProxy.substringAfter(":").toIntOrNull() + if (port != null) { + proxy = Proxy(Proxy.Type.SOCKS, InetSocketAddress(hostname, port)) + } + } + return OkHttpClient.Builder().proxy(proxy).followRedirects(true).build() +} + +private fun skipRelease(release: GitHubRelease) { + appPrefs.appSkippedUpdate.set(release.tagName) +} + +private suspend fun downloadAsset(asset: GitHubAsset) { + withContext(Dispatchers.Main) { + showToast(generalGetString(MR.strings.app_check_for_updates_download_started)) + } + val progressListener = object: ProgressListener { + override fun update(bytesRead: Long, contentLength: Long, done: Boolean) { + if (contentLength != -1L) { + chatModel.updatingProgress.value = if (done) 1f else bytesRead / contentLength.toFloat() + } + } + } + val client = setupHttpClient().newBuilder() + .addNetworkInterceptor { chain -> + val originalResponse = chain.proceed(chain.request()) + val body = originalResponse.body + if (body != null) { + originalResponse.newBuilder().body(ProgressResponseBody(body, progressListener)).build() + } else { + originalResponse + } + } + .build() + + try { + val request = Request.Builder().url(asset.browserDownloadUrl).addHeader("User-agent", "curl").build() + val call = client.newCall(request) + chatModel.updatingRequest = Closeable { + call.cancel() + withApi { + showToast(generalGetString(MR.strings.app_check_for_updates_canceled)) + } + } + call.execute().use { response -> + response.body?.use { body -> + body.byteStream().use { stream -> + createTmpFileAndDelete { file -> + // It's important to close output stream (with use{}), otherwise, Windows cannot rename the file + file.outputStream().use { output -> + stream.copyTo(output) + } + val newFile = File(file.parentFile, asset.name) + file.renameTo(newFile) + + AlertManager.shared.showAlertDialogButtonsColumn( + generalGetString(MR.strings.app_check_for_updates_download_completed_title), + dismissible = false, + buttons = { + Column { + // It's problematic to install .deb package because it requires either root or GUI package installer which is not available on + // Debian by default. Let the user install it manually only + if (!asset.name.lowercase().endsWith(".deb")) { + SectionItemView({ + AlertManager.shared.hideAlert() + chatModel.updatingProgress.value = -1f + withLongRunningApi { + try { + installAppUpdate(newFile) + } finally { + chatModel.updatingProgress.value = null + } + } + }) { + Text(generalGetString(MR.strings.app_check_for_updates_button_install), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + } + } + + SectionItemView({ + desktopOpenDir(newFile.parentFile) + }) { + Text(generalGetString(MR.strings.app_check_for_updates_button_open), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + } + + SectionItemView({ + AlertManager.shared.hideAlert() + newFile.delete() + }) { + Text(generalGetString(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = Color.Red) + } + } + } + ) + } + } + } + } + } catch (e: Exception) { + Log.e(TAG, "Failed to download the asset from release: ${e.stackTraceToString()}") + } +} + +private fun isRunningFromFlatpak(): Boolean = System.getenv("container") == "flatpak" + +private fun chooseGitHubReleaseAssets(release: GitHubRelease): List { + val res = if (isRunningFromFlatpak()) { + // No need to show download options for Flatpak users + emptyList() + } else if (Runtime.getRuntime().exec("which dpkg").onExit().join().exitValue() == 0) { + // Show all available .deb packages and user will choose the one that works on his system (for Debian derivatives) + release.assets.filter { it.name.lowercase().endsWith(".deb") } + } else { + release.assets.filter { it.name == desktopPlatform.githubAssetName } + } + return res +} + +private suspend fun installAppUpdate(file: File) = withContext(Dispatchers.IO) { + when { + desktopPlatform.isLinux() -> { + val process = Runtime.getRuntime().exec("xdg-open ${file.absolutePath}").onExit().join() + val startedInstallation = process.exitValue() == 0 && process.children().count() > 0 + if (!startedInstallation) { + Log.e(TAG, "Error starting installation: ${process.inputReader().use { it.readLines().joinToString("\n") }}${process.errorStream.use { String(it.readAllBytes()) }}") + // Failed to start installation. show directory with the file for manual installation + desktopOpenDir(file.parentFile) + } else { + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.app_check_for_updates_installed_successfully_title), + text = generalGetString(MR.strings.app_check_for_updates_installed_successfully_desc) + ) + file.delete() + } + } + desktopPlatform.isWindows() -> { + val process = Runtime.getRuntime().exec("msiexec /i ${file.absolutePath}"/* /qb */).onExit().join() + val startedInstallation = process.exitValue() == 0 + if (!startedInstallation) { + Log.e(TAG, "Error starting installation: ${process.inputReader().use { it.readLines().joinToString("\n") }}${process.errorStream.use { String(it.readAllBytes()) }}") + // Failed to start installation. show directory with the file for manual installation + desktopOpenDir(file.parentFile) + } else { + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.app_check_for_updates_installed_successfully_title), + text = generalGetString(MR.strings.app_check_for_updates_installed_successfully_desc) + ) + file.delete() + } + } + desktopPlatform.isMac() -> { + // Default mount point if no other DMGs were mounted before + var volume = "/Volumes/SimpleX" + try { + val process = Runtime.getRuntime().exec("hdiutil mount ${file.absolutePath}").onExit().join() + val startedInstallation = process.exitValue() == 0 + val lines = process.inputReader().use { it.readLines() } + // This is needed for situations when mount point has non-default path. + // For example, when a user already had mounted SimpleX.dmg before and default mount point is not available. + // Mac will make volume like /Volumes/SimpleX 1 + val lastLine = lines.lastOrNull()?.substringAfterLast('\t') + if (!startedInstallation || lastLine == null || !lastLine.lowercase().contains("/volumes/")) { + Log.e(TAG, "Error starting installation: ${process.inputReader().use { it.readLines().joinToString("\n") }}${process.errorStream.use { String(it.readAllBytes()) }}") + // Failed to start installation. show directory with the file for manual installation + desktopOpenDir(file.parentFile) + return@withContext + } + volume = lastLine + File("/Applications/SimpleX.app").renameTo(File("/Applications/SimpleX-old.app")) + val process2 = Runtime.getRuntime().exec(arrayOf("cp", "-R", "${volume}/SimpleX.app", "/Applications")).onExit().join() + val copiedSuccessfully = process2.exitValue() == 0 + if (!copiedSuccessfully) { + Log.e(TAG, "Error copying the app: ${process2.inputReader().use { it.readLines().joinToString("\n") }}${process2.errorStream.use { String(it.readAllBytes()) }}") + // Failed to start installation. show directory with the file for manual installation + desktopOpenDir(file.parentFile) + } else { + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.app_check_for_updates_installed_successfully_title), + text = generalGetString(MR.strings.app_check_for_updates_installed_successfully_desc) + ) + file.delete() + } + } finally { + try { + Runtime.getRuntime().exec(arrayOf("hdiutil", "unmount", volume)).onExit().join() + } finally { + if (!File("/Applications/SimpleX.app").exists()) { + File("/Applications/SimpleX-old.app").renameTo(File("/Applications/SimpleX.app")) + } else { + Runtime.getRuntime().exec("rm -rf /Applications/SimpleX-old.app").onExit().join() + } + } + } + } + } + Unit +} diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/OkHttpProgressListener.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/OkHttpProgressListener.kt new file mode 100644 index 0000000000..24fa0b8ef1 --- /dev/null +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/OkHttpProgressListener.kt @@ -0,0 +1,46 @@ +package chat.simplex.common.views.helpers + +import okhttp3.MediaType +import okhttp3.ResponseBody +import okio.* + +// https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/Progress.java +class ProgressResponseBody( + val responseBody: ResponseBody, + val progressListener: ProgressListener +): ResponseBody() { + private var bufferedSource: BufferedSource? = null + + override fun contentType(): MediaType? { + return responseBody.contentType() + } + + override fun contentLength(): Long { + return responseBody.contentLength() + } + + override fun source(): BufferedSource { + if (bufferedSource == null) { + bufferedSource = source(responseBody.source()).buffer() + } + return bufferedSource!! + } + + private fun source(source: Source): Source { + return object: ForwardingSource(source) { + var totalBytesRead = 0L + + override fun read(sink: Buffer, byteCount: Long): Long { + val bytesRead = super.read(sink, byteCount) + // read() returns the number of bytes read, or -1 if this source is exhausted. + totalBytesRead += if (bytesRead != -1L) bytesRead else 0L + progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1L) + return bytesRead; + } + } + } +} + +interface ProgressListener { + fun update(bytesRead: Long, contentLength: Long, done: Boolean); +} diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.desktop.kt index 5a42b4b756..ed1d820259 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.desktop.kt @@ -1,9 +1,16 @@ package chat.simplex.common.views.usersettings import SectionView +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.model.ChatModel -import chat.simplex.common.views.helpers.ModalData +import chat.simplex.common.platform.AppUpdatesChannel +import chat.simplex.common.ui.theme.DEFAULT_PADDING_HALF +import chat.simplex.common.views.helpers.* import chat.simplex.res.MR import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource @@ -17,6 +24,14 @@ actual fun SettingsSectionApp( ) { SectionView(stringResource(MR.strings.settings_section_title_app)) { SettingsActionItem(painterResource(MR.images.ic_code), stringResource(MR.strings.settings_developer_tools), showSettingsModal { DeveloperView(it, showCustomModal, withAuth) }, extraPadding = true) + val selectedChannel = remember { appPrefs.appUpdateChannel.state } + val values = AppUpdatesChannel.entries.map { it to it.text } + Box(Modifier.padding(start = DEFAULT_PADDING_HALF * 1.4f)) { + ExposedDropDownSettingRow(stringResource(MR.strings.app_check_for_updates), values, selectedChannel) { + appPrefs.appUpdateChannel.set(it) + setupUpdateChecker() + } + } AppVersionItem(showVersion) } } diff --git a/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt b/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt index f69cf817e5..d6ee659dbf 100644 --- a/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt +++ b/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt @@ -8,10 +8,12 @@ import androidx.compose.runtime.* import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.input.pointer.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.platform.* import chat.simplex.common.platform.DesktopPlatform import chat.simplex.common.showApp import chat.simplex.common.views.helpers.* +import chat.simplex.common.views.onboarding.OnboardingStage import kotlinx.coroutines.* import java.io.File @@ -20,6 +22,7 @@ fun main() { //System.setProperty("skiko.renderApi", "SOFTWARE") initHaskell() runMigrations() + setupUpdateChecker() initApp() tmpDir.deleteRecursively() tmpDir.mkdir() @@ -75,6 +78,31 @@ private fun initHaskell() { override fun desktopScrollBar(state: ScrollState, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) { DesktopScrollBar(rememberScrollbarAdapter(scrollState = state), modifier, scrollBarAlpha, scrollJob, reversed) } + + @Composable + override fun desktopShowAppUpdateNotice() { + fun showNoticeIfNeeded() { + if ( + !chatModel.controller.appPrefs.appUpdateNoticeShown.get() + && chatModel.controller.appPrefs.onboardingStage.get() == OnboardingStage.OnboardingComplete + && chatModel.chats.size > 3 + && chatModel.activeCallInvitation.value == null + ) { + appPrefs.appUpdateNoticeShown.set(true) + showAppUpdateNotice() + } + } + // Will show notice if chats were loaded before that moment and number of chats > 3 + LaunchedEffect(Unit) { + showNoticeIfNeeded() + } + // Will show notice if chats were loaded later (a lot of chats/slow query) and number of chats > 3 + KeyChangeEffect(chatModel.chats.size) { oldSize -> + if (oldSize == 0) { + showNoticeIfNeeded() + } + } + } } } diff --git a/cabal.project b/cabal.project index dbf6fd8556..bcaf9f2abd 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 017469b2de65c7e3ef1d680c2da466b320d1b061 + tag: e56bd0b47b22781f9b5936e3b8a9d51cc3f9e8d5 source-repository-package type: git diff --git a/scripts/ios/import-localizations.sh b/scripts/ios/import-localizations.sh index e323865f2d..0f04cd0cde 100755 --- a/scripts/ios/import-localizations.sh +++ b/scripts/ios/import-localizations.sh @@ -12,7 +12,6 @@ for lang in "${langs[@]}"; do xcodebuild -importLocalizations \ -project ./apps/ios/SimpleX.xcodeproj \ -localizationPath ./apps/ios/SimpleX\ Localizations/$lang.xcloc \ - -disableAutomaticPackageResolution \ -skipPackageUpdates sleep 10 done diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 126ed9af03..195589ae83 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."017469b2de65c7e3ef1d680c2da466b320d1b061" = "1c6aap31sa4wdv7x771q2l8bs499qg58rrnx80blj33y2zl877c9"; + "https://github.com/simplex-chat/simplexmq.git"."e56bd0b47b22781f9b5936e3b8a9d51cc3f9e8d5" = "11ghsddgyrlnddxqvvb0xlqvnnhnnsbixz1kg01x3gd6vpdqkz47"; "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/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 9198a4c9d9..8f5295705b 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -95,7 +95,7 @@ import qualified Simplex.FileTransfer.Transport as XFTP import Simplex.FileTransfer.Types (FileErrorType (..), RcvFileId, SndFileId) import Simplex.Messaging.Agent as Agent import Simplex.Messaging.Agent.Client (SubInfo (..), agentClientStore, getAgentQueuesInfo, getAgentWorkersDetails, getAgentWorkersSummary, getNetworkConfig', ipAddressProtected, withLockMap) -import Simplex.Messaging.Agent.Env.SQLite (AgentConfig (..), InitialAgentServers (..), createAgentStore, defaultAgentConfig) +import Simplex.Messaging.Agent.Env.SQLite (AgentConfig (..), InitialAgentServers (..), ServerCfg (..), createAgentStore, defaultAgentConfig, enabledServerCfg, presetServerCfg) import Simplex.Messaging.Agent.Lock (withLock) import Simplex.Messaging.Agent.Protocol import qualified Simplex.Messaging.Agent.Protocol as AP (AgentErrorType (..)) @@ -112,7 +112,7 @@ import qualified Simplex.Messaging.Crypto.Ratchet as CR import Simplex.Messaging.Encoding import Simplex.Messaging.Encoding.String import Simplex.Messaging.Parsers (base64P) -import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType (..), EntityId, ErrorType (..), MsgBody, MsgFlags (..), NtfServer, ProtoServerWithAuth (..), ProtocolServer, ProtocolTypeI, SProtocolType (..), SubscriptionMode (..), UserProtocol, XFTPServer, userProtocol) +import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType (..), EntityId, ErrorType (..), MsgBody, MsgFlags (..), NtfServer, ProtoServerWithAuth (..), ProtocolServer, ProtocolType (..), ProtocolTypeI (..), SProtocolType (..), SubscriptionMode (..), UserProtocol, XFTPServer, userProtocol) import qualified Simplex.Messaging.Protocol as SMP import Simplex.Messaging.ServiceScheme (ServiceScheme (..)) import qualified Simplex.Messaging.TMap as TM @@ -148,7 +148,7 @@ defaultChatConfig = DefaultAgentServers { smp = _defaultSMPServers, ntf = _defaultNtfServers, - xftp = defaultXFTPServers, + xftp = L.map (presetServerCfg True) defaultXFTPServers, netCfg = defaultNetworkConfig }, tbqSize = 1024, @@ -172,15 +172,29 @@ defaultChatConfig = chatHooks = defaultChatHooks } -_defaultSMPServers :: NonEmpty SMPServerWithAuth +_defaultSMPServers :: NonEmpty (ServerCfg 'PSMP) _defaultSMPServers = - L.fromList - [ "smp://h--vW7ZSkXPeOUpfxlFGgauQmXNFOzGoizak7Ult7cw=@smp15.simplex.im,oauu4bgijybyhczbnxtlggo6hiubahmeutaqineuyy23aojpih3dajad.onion", - "smp://hejn2gVIqNU6xjtGM3OwQeuk8ZEbDXVJXAlnSBJBWUA=@smp16.simplex.im,p3ktngodzi6qrf7w64mmde3syuzrv57y55hxabqcq3l5p6oi7yzze6qd.onion", - "smp://ZKe4uxF4Z_aLJJOEsC-Y6hSkXgQS5-oc442JQGkyP8M=@smp17.simplex.im,ogtwfxyi3h2h5weftjjpjmxclhb5ugufa5rcyrmg7j4xlch7qsr5nuqd.onion", - "smp://PtsqghzQKU83kYTlQ1VKg996dW4Cw4x_bvpKmiv8uns=@smp18.simplex.im,lyqpnwbs2zqfr45jqkncwpywpbtq7jrhxnib5qddtr6npjyezuwd3nqd.onion", - "smp://N_McQS3F9TGoh4ER0QstUf55kGnNSd-wXfNPZ7HukcM=@smp19.simplex.im,i53bbtoqhlc365k6kxzwdp5w3cdt433s7bwh3y32rcbml2vztiyyz5id.onion" - ] + L.fromList $ + map + (presetServerCfg True) + [ "smp://h--vW7ZSkXPeOUpfxlFGgauQmXNFOzGoizak7Ult7cw=@smp15.simplex.im,oauu4bgijybyhczbnxtlggo6hiubahmeutaqineuyy23aojpih3dajad.onion", + "smp://hejn2gVIqNU6xjtGM3OwQeuk8ZEbDXVJXAlnSBJBWUA=@smp16.simplex.im,p3ktngodzi6qrf7w64mmde3syuzrv57y55hxabqcq3l5p6oi7yzze6qd.onion", + "smp://ZKe4uxF4Z_aLJJOEsC-Y6hSkXgQS5-oc442JQGkyP8M=@smp17.simplex.im,ogtwfxyi3h2h5weftjjpjmxclhb5ugufa5rcyrmg7j4xlch7qsr5nuqd.onion", + "smp://PtsqghzQKU83kYTlQ1VKg996dW4Cw4x_bvpKmiv8uns=@smp18.simplex.im,lyqpnwbs2zqfr45jqkncwpywpbtq7jrhxnib5qddtr6npjyezuwd3nqd.onion", + "smp://N_McQS3F9TGoh4ER0QstUf55kGnNSd-wXfNPZ7HukcM=@smp19.simplex.im,i53bbtoqhlc365k6kxzwdp5w3cdt433s7bwh3y32rcbml2vztiyyz5id.onion" + ] + <> map + (presetServerCfg False) + [ "smp://u2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU=@smp4.simplex.im,o5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion", + "smp://hpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg=@smp5.simplex.im,jjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion", + "smp://PQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo=@smp6.simplex.im,bylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion", + "smp://0YuTwO05YJWS8rkjn9eLJDjQhFKvIYd8d4xG8X1blIU=@smp8.simplex.im,beccx4yfxxbvyhqypaavemqurytl6hozr47wfc7uuecacjqdvwpw2xid.onion", + "smp://SkIkI6EPd2D63F4xFKfHk7I1UGZVNn6k1QWZ5rcyr6w=@smp9.simplex.im,jssqzccmrcws6bhmn77vgmhfjmhwlyr3u7puw4erkyoosywgl67slqqd.onion", + "smp://6iIcWT_dF2zN_w5xzZEY7HI2Prbh3ldP07YTyDexPjE=@smp10.simplex.im,rb2pbttocvnbrngnwziclp2f4ckjq65kebafws6g4hy22cdaiv5dwjqd.onion", + "smp://1OwYGt-yqOfe2IyVHhxz3ohqo3aCCMjtB-8wn4X_aoY=@smp11.simplex.im,6ioorbm6i3yxmuoezrhjk6f6qgkc4syabh7m3so74xunb5nzr4pwgfqd.onion", + "smp://UkMFNAXLXeAAe0beCa4w6X_zp18PwxSaSjY17BKUGXQ=@smp12.simplex.im,ie42b5weq7zdkghocs3mgxdjeuycheeqqmksntj57rmejagmg4eor5yd.onion", + "smp://enEkec4hlR3UtKx2NMpOUK_K4ZuDxjWBO1d9Y4YXVaA=@smp14.simplex.im,aspkyu2sopsnizbyfabtsicikr2s4r3ti35jogbcekhm3fsoeyjvgrid.onion" + ] _defaultNtfServers :: [NtfServer] _defaultNtfServers = @@ -301,8 +315,8 @@ newChatController configServers :: DefaultAgentServers configServers = let DefaultAgentServers {smp = defSmp, xftp = defXftp} = defaultServers - smp' = fromMaybe defSmp (nonEmpty smpServers) - xftp' = fromMaybe defXftp (nonEmpty xftpServers) + smp' = maybe defSmp (L.map enabledServerCfg) (nonEmpty smpServers) + xftp' = maybe defXftp (L.map enabledServerCfg) (nonEmpty xftpServers) in defaultServers {smp = smp', xftp = xftp', netCfg = updateNetworkConfig defaultNetworkConfig simpleNetCfg} agentServers :: ChatConfig -> IO InitialAgentServers agentServers config@ChatConfig {defaultServers = defServers@DefaultAgentServers {ntf, netCfg}} = do @@ -311,15 +325,15 @@ newChatController xftp' <- getUserServers users SPXFTP pure InitialAgentServers {smp = smp', xftp = xftp', ntf, netCfg} where - getUserServers :: forall p. (ProtocolTypeI p, UserProtocol p) => [User] -> SProtocolType p -> IO (Map UserId (NonEmpty (ProtoServerWithAuth p))) + getUserServers :: forall p. (ProtocolTypeI p, UserProtocol p) => [User] -> SProtocolType p -> IO (Map UserId (NonEmpty (ServerCfg p))) getUserServers users protocol = case users of [] -> pure $ M.fromList [(1, cfgServers protocol defServers)] _ -> M.fromList <$> initialServers where - initialServers :: IO [(UserId, NonEmpty (ProtoServerWithAuth p))] + initialServers :: IO [(UserId, NonEmpty (ServerCfg p))] initialServers = mapM (\u -> (aUserId u,) <$> userServers u) users - userServers :: User -> IO (NonEmpty (ProtoServerWithAuth p)) - userServers user' = activeAgentServers config protocol <$> withTransaction chatStore (`getProtocolServers` user') + userServers :: User -> IO (NonEmpty (ServerCfg p)) + userServers user' = useServers config protocol <$> withTransaction chatStore (`getProtocolServers` user') updateNetworkConfig :: NetworkConfig -> SimpleNetCfg -> NetworkConfig updateNetworkConfig cfg SimpleNetCfg {socksProxy, smpProxyMode_, smpProxyFallback_, tcpTimeout_, logTLSErrors} = @@ -362,14 +376,10 @@ withFileLock :: String -> Int64 -> CM a -> CM a withFileLock name = withEntityLock name . CLFile {-# INLINE withFileLock #-} -activeAgentServers :: UserProtocol p => ChatConfig -> SProtocolType p -> [ServerCfg p] -> NonEmpty (ProtoServerWithAuth p) -activeAgentServers ChatConfig {defaultServers} p = - fromMaybe (cfgServers p defaultServers) - . nonEmpty - . map (\ServerCfg {server} -> server) - . filter (\ServerCfg {enabled} -> enabled == SEEnabled) +useServers :: UserProtocol p => ChatConfig -> SProtocolType p -> [ServerCfg p] -> NonEmpty (ServerCfg p) +useServers ChatConfig {defaultServers} p = fromMaybe (cfgServers p defaultServers) . nonEmpty -cfgServers :: UserProtocol p => SProtocolType p -> (DefaultAgentServers -> NonEmpty (ProtoServerWithAuth p)) +cfgServers :: UserProtocol p => SProtocolType p -> (DefaultAgentServers -> NonEmpty (ServerCfg p)) cfgServers p DefaultAgentServers {smp, xftp} = case p of SPSMP -> smp SPXFTP -> xftp @@ -529,18 +539,17 @@ processChatCommand' vr = \case atomically . writeTVar u $ Just user pure $ CRActiveUser user where - chooseServers :: (ProtocolTypeI p, UserProtocol p) => SProtocolType p -> CM (NonEmpty (ProtoServerWithAuth p), [ServerCfg p]) + chooseServers :: (ProtocolTypeI p, UserProtocol p) => SProtocolType p -> CM (NonEmpty (ServerCfg p), [ServerCfg p]) chooseServers protocol | sameServers = asks currentUser >>= readTVarIO >>= \case Nothing -> throwChatError CENoActiveUser - Just user -> do - servers <- withStore' (`getProtocolServers` user) - cfg <- asks config - pure (activeAgentServers cfg protocol servers, servers) - | otherwise = do - defServers <- asks $ defaultServers . config - pure (cfgServers protocol defServers, []) + Just user -> chosenServers =<< withStore' (`getProtocolServers` user) + | otherwise = chosenServers [] + where + chosenServers servers = do + cfg <- asks config + pure (useServers cfg protocol servers, servers) storeServers user servers = unless (null servers) . withStore $ \db -> overwriteProtocolServers db user servers @@ -1307,20 +1316,18 @@ processChatCommand' vr = \case withStore (\db -> Just <$> getConnectionEntity db vr user agentConnId) `catchChatError` (\e -> toView (CRChatError (Just user) e) $> Nothing) pure CRNtfMessages {user_, connEntity_, msgTs = msgTs', ntfMessages = map ntfMsgInfo msgs} APIGetUserProtoServers userId (AProtocolType p) -> withUserId userId $ \user -> withServerProtocol p $ do - ChatConfig {defaultServers} <- asks config + cfg@ChatConfig {defaultServers} <- asks config servers <- withStore' (`getProtocolServers` user) - let defServers = cfgServers p defaultServers - servers' = fromMaybe (L.map toServerCfg defServers) $ nonEmpty servers - pure $ CRUserProtoServers user $ AUPS $ UserProtoServers p servers' defServers - where - toServerCfg server = ServerCfg {server, preset = True, tested = Nothing, enabled = SEEnabled} + pure $ CRUserProtoServers user $ AUPS $ UserProtoServers p (useServers cfg p servers) (cfgServers p defaultServers) GetUserProtoServers aProtocol -> withUser $ \User {userId} -> processChatCommand $ APIGetUserProtoServers userId aProtocol - APISetUserProtoServers userId (APSC p (ProtoServersConfig servers)) -> withUserId userId $ \user -> withServerProtocol p $ do - withStore $ \db -> overwriteProtocolServers db user servers - cfg <- asks config - lift $ withAgent' $ \a -> setProtocolServers a (aUserId user) $ activeAgentServers cfg p servers - ok user + APISetUserProtoServers userId (APSC p (ProtoServersConfig servers)) + | null servers || any (\ServerCfg {enabled} -> enabled) servers -> withUserId userId $ \user -> withServerProtocol p $ do + withStore $ \db -> overwriteProtocolServers db user servers + cfg <- asks config + lift $ withAgent' $ \a -> setProtocolServers a (aUserId user) $ useServers cfg p servers + ok user + | otherwise -> withUserId userId $ \user -> pure $ chatCmdError (Just user) "all servers are disabled" SetUserProtoServers serversConfig -> withUser $ \User {userId} -> processChatCommand $ APISetUserProtoServers userId serversConfig APITestProtoServer userId srv@(AProtoServerWithAuth _ server) -> withUserId userId $ \user -> @@ -2253,19 +2260,14 @@ processChatCommand' vr = \case DebugEvent event -> toView event >> ok_ GetAgentServersSummary userId -> withUserId userId $ \user -> do agentServersSummary <- lift $ withAgent' getAgentServersSummary - users <- withStore' getUsers - smpServers <- getUserServers user SPSMP - xftpServers <- getUserServers user SPXFTP + cfg <- asks config + (users, smpServers, xftpServers) <- + withStore' $ \db -> (,,) <$> getUsers db <*> getServers db cfg user SPSMP <*> getServers db cfg user SPXFTP let presentedServersSummary = toPresentedServersSummary agentServersSummary users user smpServers xftpServers pure $ CRAgentServersSummary user presentedServersSummary where - getUserServers :: forall p. (ProtocolTypeI p, UserProtocol p) => User -> SProtocolType p -> CM [ProtocolServer p] - getUserServers users protocol = do - ChatConfig {defaultServers} <- asks config - let defServers = cfgServers protocol defaultServers - servers <- map (\ServerCfg {server} -> server) <$> withStore' (`getProtocolServers` users) - let srvs = if null servers then L.toList defServers else servers - pure $ map protoServer srvs + getServers :: (ProtocolTypeI p, UserProtocol p) => DB.Connection -> ChatConfig -> User -> SProtocolType p -> IO (NonEmpty (ProtocolServer p)) + getServers db cfg user p = L.map (\ServerCfg {server} -> protoServer server) . useServers cfg p <$> getProtocolServers db user ResetAgentServersStats -> withAgent resetAgentServersStats >> ok_ GetAgentWorkers -> lift $ CRAgentWorkersSummary <$> withAgent' getAgentWorkersSummary GetAgentWorkersDetails -> lift $ CRAgentWorkersDetails <$> withAgent' getAgentWorkersDetails @@ -3224,10 +3226,8 @@ receiveViaCompleteFD user fileId RcvFileDescr {fileDescrText, fileDescrComplete} S.toList $ S.fromList $ concatMap (\FD.FileChunk {replicas} -> map (\FD.FileChunkReplica {server} -> server) replicas) chunks getUnknownSrvs :: [XFTPServer] -> CM [XFTPServer] getUnknownSrvs srvs = do - ChatConfig {defaultServers = DefaultAgentServers {xftp = defXftp}} <- asks config - storedSrvs <- map (\ServerCfg {server} -> protoServer server) <$> withStore' (`getProtocolServers` user) - let defXftp' = L.map protoServer defXftp - knownSrvs = fromMaybe defXftp' $ nonEmpty storedSrvs + cfg <- asks config + knownSrvs <- L.map (\ServerCfg {server} -> protoServer server) . useServers cfg SPXFTP <$> withStore' (`getProtocolServers` user) pure $ filter (`notElem` knownSrvs) srvs ipProtectedForSrvs :: [XFTPServer] -> CM Bool ipProtectedForSrvs srvs = do @@ -6301,7 +6301,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = updateDirectItemsStatus ct conn msgIds newStatus = do cis_ <- withStore' $ \db -> forM msgIds $ \msgId -> runExceptT $ updateDirectItemStatus' db ct conn msgId newStatus -- only send the last expired item event to view - case catMaybes $ rights $ reverse cis_ of + case reverse $ catMaybes $ rights cis_ of ci : _ -> toView $ CRChatItemStatusUpdated user (AChatItem SCTDirect SMDSnd (DirectChat ct) ci) _ -> pure () @@ -6786,7 +6786,7 @@ deliverMessagesB msgReqs = do sendGroupMessage :: MsgEncodingI e => User -> GroupInfo -> [GroupMember] -> ChatMsgEvent e -> CM (SndMessage, GroupSndResult) sendGroupMessage user gInfo members chatMsgEvent = do when shouldSendProfileUpdate $ - sendProfileUpdate `catchChatError` (\e -> toView (CRChatError (Just user) e)) + sendProfileUpdate `catchChatError` (toView . CRChatError (Just user)) sendGroupMessage' user gInfo members chatMsgEvent where User {profile = p, userMemberProfileUpdatedAt} = user @@ -6891,7 +6891,7 @@ memberSendAction gInfo chatMsgEvent members m = case memberConn m of sendGroupMemberMessage :: MsgEncodingI e => User -> GroupInfo -> GroupMember -> ChatMsgEvent e -> Maybe Int64 -> CM () -> CM () sendGroupMemberMessage user gInfo@GroupInfo {groupId} m@GroupMember {groupMemberId} chatMsgEvent introId_ postDeliver = do msg <- createSndMessage chatMsgEvent (GroupId groupId) - messageMember msg `catchChatError` (\e -> toView (CRChatError (Just user) e)) + messageMember msg `catchChatError` (toView . CRChatError (Just user)) where messageMember :: SndMessage -> CM () messageMember SndMessage {msgId, msgBody} = forM_ (memberSendAction gInfo chatMsgEvent [m] m) $ \case @@ -7124,7 +7124,7 @@ agentXFTPDeleteSndFilesRemote user sndFiles = do (sfsNoDescr, sfsWithDescr) <- partitionSndDescr sndFilesAll' [] [] withAgent' $ \a -> xftpDeleteSndFilesInternal a sfsNoDescr withAgent' $ \a -> xftpDeleteSndFilesRemote a (aUserId user) sfsWithDescr - void . withStoreBatch' $ \db -> map (setSndFTAgentDeleted db user . (\(_, fId) -> fId)) sndFilesAll' + void . withStoreBatch' $ \db -> map (setSndFTAgentDeleted db user . snd) sndFilesAll' where mapRedirectMeta :: FileTransferMeta -> Maybe (XFTPSndFile, FileTransferId) mapRedirectMeta FileTransferMeta {fileId = fileId, xftpSndFile = Just sndFileRedirect} = Just (sndFileRedirect, fileId) @@ -7444,9 +7444,9 @@ chatCommandP = "/xftp test " *> (TestProtoServer . AProtoServerWithAuth SPXFTP <$> strP), "/ntf test " *> (TestProtoServer . AProtoServerWithAuth SPNTF <$> strP), "/_servers " *> (APISetUserProtoServers <$> A.decimal <* A.space <*> srvCfgP), - "/smp " *> (SetUserProtoServers . APSC SPSMP . ProtoServersConfig . map toServerCfg <$> protocolServersP), + "/smp " *> (SetUserProtoServers . APSC SPSMP . ProtoServersConfig . map enabledServerCfg <$> protocolServersP), "/smp default" $> SetUserProtoServers (APSC SPSMP $ ProtoServersConfig []), - "/xftp " *> (SetUserProtoServers . APSC SPXFTP . ProtoServersConfig . map toServerCfg <$> protocolServersP), + "/xftp " *> (SetUserProtoServers . APSC SPXFTP . ProtoServersConfig . map enabledServerCfg <$> protocolServersP), "/xftp default" $> SetUserProtoServers (APSC SPXFTP $ ProtoServersConfig []), "/_servers " *> (APIGetUserProtoServers <$> A.decimal <* A.space <*> strP), "/smp" $> GetUserProtoServers (AProtocolType SPSMP), @@ -7785,7 +7785,6 @@ chatCommandP = (Just <$> (AutoAccept <$> (" incognito=" *> onOffP <|> pure False) <*> optional (A.space *> msgContentP))) (pure Nothing) srvCfgP = strP >>= \case AProtocolType p -> APSC p <$> (A.space *> jsonP) - toServerCfg server = ServerCfg {server, preset = False, tested = Nothing, enabled = SEEnabled} rcCtrlAddressP = RCCtrlAddress <$> ("addr=" *> strP) <*> (" iface=" *> (jsonP <|> text1P)) text1P = safeDecodeUtf8 <$> A.takeTill (== ' ') char_ = optional . A.char diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index fdb07b0bd9..6c127264d2 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -69,8 +69,8 @@ import Simplex.Chat.Types.UITheme import Simplex.Chat.Util (liftIOEither) import Simplex.FileTransfer.Description (FileDescriptionURI) import Simplex.Messaging.Agent (AgentClient, SubscriptionsInfo) -import Simplex.Messaging.Agent.Client (AgentLocks, ServerQueueInfo, AgentQueuesInfo (..), AgentWorkersDetails (..), AgentWorkersSummary (..), ProtocolTestFailure, UserNetworkInfo) -import Simplex.Messaging.Agent.Env.SQLite (AgentConfig, NetworkConfig) +import Simplex.Messaging.Agent.Client (AgentLocks, AgentQueuesInfo (..), AgentWorkersDetails (..), AgentWorkersSummary (..), ProtocolTestFailure, ServerQueueInfo, UserNetworkInfo) +import Simplex.Messaging.Agent.Env.SQLite (AgentConfig, NetworkConfig, ServerCfg) import Simplex.Messaging.Agent.Lock import Simplex.Messaging.Agent.Protocol import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation, SQLiteStore, UpMigration, withTransaction) @@ -84,7 +84,7 @@ import Simplex.Messaging.Crypto.Ratchet (PQEncryption) import Simplex.Messaging.Encoding.String import Simplex.Messaging.Notifications.Protocol (DeviceToken (..), NtfTknStatus) import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, enumJSON, parseAll, parseString, sumTypeJSON) -import Simplex.Messaging.Protocol (AProtoServerWithAuth, AProtocolType (..), CorrId, NtfServer, ProtoServerWithAuth, ProtocolTypeI, QueueId, SMPMsgMeta (..), SProtocolType, SubscriptionMode (..), UserProtocol, XFTPServer, XFTPServerWithAuth, userProtocol) +import Simplex.Messaging.Protocol (AProtoServerWithAuth, AProtocolType (..), CorrId, NtfServer, ProtocolType (..), ProtocolTypeI, QueueId, SMPMsgMeta (..), SProtocolType, SubscriptionMode (..), UserProtocol, XFTPServer, userProtocol) import Simplex.Messaging.TMap (TMap) import Simplex.Messaging.Transport (TLS, simplexMQVersion) import Simplex.Messaging.Transport.Client (SocksProxy, TransportHost) @@ -173,9 +173,9 @@ defaultChatHooks = } data DefaultAgentServers = DefaultAgentServers - { smp :: NonEmpty SMPServerWithAuth, + { smp :: NonEmpty (ServerCfg 'PSMP), ntf :: [NtfServer], - xftp :: NonEmpty XFTPServerWithAuth, + xftp :: NonEmpty (ServerCfg 'PXFTP), netCfg :: NetworkConfig } @@ -930,7 +930,7 @@ deriving instance Show AProtoServersConfig data UserProtoServers p = UserProtoServers { serverProtocol :: SProtocolType p, protoServers :: NonEmpty (ServerCfg p), - presetServers :: NonEmpty (ProtoServerWithAuth p) + presetServers :: NonEmpty (ServerCfg p) } deriving (Show) diff --git a/src/Simplex/Chat/Stats.hs b/src/Simplex/Chat/Stats.hs index f14353f0e0..e1d0372080 100644 --- a/src/Simplex/Chat/Stats.hs +++ b/src/Simplex/Chat/Stats.hs @@ -6,6 +6,7 @@ module Simplex.Chat.Stats where import qualified Data.Aeson.TH as J +import Data.List.NonEmpty (NonEmpty) import Data.Map.Strict (Map) import qualified Data.Map.Strict as M import Data.Maybe (fromMaybe, isJust) @@ -106,7 +107,7 @@ data XFTPServerSummary = XFTPServerSummary -- - users are passed to exclude hidden users from totalServersSummary; -- - if currentUser is hidden, it should be accounted in totalServersSummary; -- - known is set only in user level summaries based on passed userSMPSrvs and userXFTPSrvs -toPresentedServersSummary :: AgentServersSummary -> [User] -> User -> [SMPServer] -> [XFTPServer] -> PresentedServersSummary +toPresentedServersSummary :: AgentServersSummary -> [User] -> User -> NonEmpty SMPServer -> NonEmpty XFTPServer -> PresentedServersSummary toPresentedServersSummary agentSummary users currentUser userSMPSrvs userXFTPSrvs = do let (userSMPSrvsSumms, allSMPSrvsSumms) = accSMPSrvsSummaries (userSMPTotals, allSMPTotals) = (accSMPTotals userSMPSrvsSumms, accSMPTotals allSMPSrvsSumms) @@ -149,7 +150,7 @@ toPresentedServersSummary agentSummary users currentUser userSMPSrvs userXFTPSrv AgentServersSummary {statsStartedAt, smpServersSessions, smpServersSubs, smpServersStats, xftpServersSessions, xftpServersStats, xftpRcvInProgress, xftpSndInProgress, xftpDelInProgress} = agentSummary countUserInAll auId = countUserInAllStats (AgentUserId auId) currentUser users accSMPTotals :: Map SMPServer SMPServerSummary -> SMPTotals - accSMPTotals = M.foldr addTotals initialTotals + accSMPTotals = M.foldr' addTotals initialTotals where initialTotals = SMPTotals {sessions = ServerSessions 0 0 0, subs = SMPServerSubs 0 0, stats = newAgentSMPServerStatsData} addTotals SMPServerSummary {sessions, subs, stats} SMPTotals {sessions = accSess, subs = accSubs, stats = accStats} = @@ -159,7 +160,7 @@ toPresentedServersSummary agentSummary users currentUser userSMPSrvs userXFTPSrv stats = maybe accStats (accStats `addSMPStatsData`) stats } accXFTPTotals :: Map XFTPServer XFTPServerSummary -> XFTPTotals - accXFTPTotals = M.foldr addTotals initialTotals + accXFTPTotals = M.foldr' addTotals initialTotals where initialTotals = XFTPTotals {sessions = ServerSessions 0 0 0, stats = newAgentXFTPServerStatsData} addTotals XFTPServerSummary {sessions, stats} XFTPTotals {sessions = accSess, stats = accStats} = @@ -168,7 +169,7 @@ toPresentedServersSummary agentSummary users currentUser userSMPSrvs userXFTPSrv stats = maybe accStats (accStats `addXFTPStatsData`) stats } smpSummsIntoCategories :: Map SMPServer SMPServerSummary -> ([SMPServerSummary], [SMPServerSummary], [SMPServerSummary]) - smpSummsIntoCategories = foldr partitionSummary ([], [], []) + smpSummsIntoCategories = M.foldr' partitionSummary ([], [], []) where partitionSummary srvSumm (curr, prev, prox) | isCurrentlyUsed srvSumm = (srvSumm : curr, prev, prox) @@ -182,7 +183,7 @@ toPresentedServersSummary agentSummary users currentUser userSMPSrvs userXFTPSrv Just AgentSMPServerStatsData {_sentDirect, _sentProxied, _sentDirectAttempts, _sentProxiedAttempts, _recvMsgs, _connCreated, _connSecured, _connSubscribed, _connSubAttempts} -> _sentDirect > 0 || _sentProxied > 0 || _sentDirectAttempts > 0 || _sentProxiedAttempts > 0 || _recvMsgs > 0 || _connCreated > 0 || _connSecured > 0 || _connSubscribed > 0 || _connSubAttempts > 0 xftpSummsIntoCategories :: Map XFTPServer XFTPServerSummary -> ([XFTPServerSummary], [XFTPServerSummary]) - xftpSummsIntoCategories = foldr partitionSummary ([], []) + xftpSummsIntoCategories = M.foldr' partitionSummary ([], []) where partitionSummary srvSumm (curr, prev) | isCurrentlyUsed srvSumm = (srvSumm : curr, prev) diff --git a/src/Simplex/Chat/Store/Profiles.hs b/src/Simplex/Chat/Store/Profiles.hs index a740389c6a..cad06448e6 100644 --- a/src/Simplex/Chat/Store/Profiles.hs +++ b/src/Simplex/Chat/Store/Profiles.hs @@ -84,6 +84,7 @@ import Simplex.Chat.Types import Simplex.Chat.Types.Preferences import Simplex.Chat.Types.Shared import Simplex.Chat.Types.UITheme +import Simplex.Messaging.Agent.Env.SQLite (ServerCfg (..)) import Simplex.Messaging.Agent.Protocol (ACorrId, ConnId, UserId) import Simplex.Messaging.Agent.Store.SQLite (firstRow, maybeFirstRow) import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB @@ -523,10 +524,9 @@ getProtocolServers db User {userId} = (userId, decodeLatin1 $ strEncode protocol) where protocol = protocolTypeI @p - toServerCfg :: (NonEmpty TransportHost, String, C.KeyHash, Maybe Text, Bool, Maybe Bool, Int) -> ServerCfg p - toServerCfg (host, port, keyHash, auth_, preset, tested, enabledInt) = + toServerCfg :: (NonEmpty TransportHost, String, C.KeyHash, Maybe Text, Bool, Maybe Bool, Bool) -> ServerCfg p + toServerCfg (host, port, keyHash, auth_, preset, tested, enabled) = let server = ProtoServerWithAuth (ProtocolServer protocol host port keyHash) (BasicAuth . encodeUtf8 <$> auth_) - enabled = toServerEnabled enabledInt in ServerCfg {server, preset, tested, enabled} overwriteProtocolServers :: forall p. ProtocolTypeI p => DB.Connection -> User -> [ServerCfg p] -> ExceptT StoreError IO () @@ -543,7 +543,7 @@ overwriteProtocolServers db User {userId} servers = (protocol, host, port, key_hash, basic_auth, preset, tested, enabled, user_id, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?) |] - ((protocol, host, port, keyHash, safeDecodeUtf8 . unBasicAuth <$> auth_) :. (preset, tested, fromServerEnabled enabled, userId, currentTs, currentTs)) + ((protocol, host, port, keyHash, safeDecodeUtf8 . unBasicAuth <$> auth_) :. (preset, tested, enabled, userId, currentTs, currentTs)) pure $ Right () where protocol = decodeLatin1 $ strEncode $ protocolTypeI @p diff --git a/src/Simplex/Chat/Terminal.hs b/src/Simplex/Chat/Terminal.hs index 2060e529eb..ca9b2edb65 100644 --- a/src/Simplex/Chat/Terminal.hs +++ b/src/Simplex/Chat/Terminal.hs @@ -21,6 +21,7 @@ import Simplex.Chat.Options import Simplex.Chat.Terminal.Input import Simplex.Chat.Terminal.Output import Simplex.FileTransfer.Client.Presets (defaultXFTPServers) +import Simplex.Messaging.Agent.Env.SQLite (presetServerCfg) import Simplex.Messaging.Client (defaultNetworkConfig) import Simplex.Messaging.Util (raceAny_) import System.IO (hFlush, hSetEcho, stdin, stdout) @@ -31,13 +32,15 @@ terminalChatConfig = { defaultServers = DefaultAgentServers { smp = - L.fromList - [ "smp://u2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU=@smp4.simplex.im,o5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion", - "smp://hpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg=@smp5.simplex.im,jjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion", - "smp://PQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo=@smp6.simplex.im,bylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion" - ], + L.fromList $ + map + (presetServerCfg True) + [ "smp://u2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU=@smp4.simplex.im,o5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion", + "smp://hpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg=@smp5.simplex.im,jjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion", + "smp://PQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo=@smp6.simplex.im,bylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion" + ], ntf = ["ntf://FB-Uop7RTaZZEG0ZLD2CIaTjsPh-Fw0zFAnb7QyA8Ks=@ntf2.simplex.im,ntg7jdjy2i3qbib3sykiho3enekwiaqg3icctliqhtqcg6jmoh6cxiad.onion"], - xftp = defaultXFTPServers, + xftp = L.map (presetServerCfg True) defaultXFTPServers, netCfg = defaultNetworkConfig }, deviceNameForRemote = "SimpleX CLI" diff --git a/src/Simplex/Chat/Types.hs b/src/Simplex/Chat/Types.hs index 07c9afa2e2..04cc2bcc6f 100644 --- a/src/Simplex/Chat/Types.hs +++ b/src/Simplex/Chat/Types.hs @@ -53,7 +53,6 @@ import Simplex.Messaging.Crypto.File (CryptoFileArgs (..)) import Simplex.Messaging.Crypto.Ratchet (PQEncryption (..), PQSupport, pattern PQEncOff) import Simplex.Messaging.Encoding.String import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, enumJSON, fromTextField_, sumTypeJSON, taggedObjectJSON) -import Simplex.Messaging.Protocol (ProtoServerWithAuth, ProtocolTypeI) import Simplex.Messaging.Util (safeDecodeUtf8, (<$?>)) import Simplex.Messaging.Version import Simplex.Messaging.Version.Internal @@ -1628,46 +1627,6 @@ data NoteFolder = NoteFolder type NoteFolderId = Int64 -data ServerCfg p = ServerCfg - { server :: ProtoServerWithAuth p, - preset :: Bool, - tested :: Maybe Bool, - enabled :: ServerEnabled - } - deriving (Show) - -data ServerEnabled - = SEDisabled - | SEEnabled - | -- server is marked as known, but it's not in the list of configured servers; - -- e.g., it may be added via an unknown server dialogue and user didn't manually configure it, - -- meaning server wasn't tested (or at least such option wasn't presented in UI) - -- and it may be inoperable for user due to server password - SEKnown - deriving (Eq, Show) - -pattern DBSEDisabled :: Int -pattern DBSEDisabled = 0 - -pattern DBSEEnabled :: Int -pattern DBSEEnabled = 1 - -pattern DBSEKnown :: Int -pattern DBSEKnown = 2 - -toServerEnabled :: Int -> ServerEnabled -toServerEnabled = \case - DBSEDisabled -> SEDisabled - DBSEEnabled -> SEEnabled - DBSEKnown -> SEKnown - _ -> SEDisabled - -fromServerEnabled :: ServerEnabled -> Int -fromServerEnabled = \case - SEDisabled -> DBSEDisabled - SEEnabled -> DBSEEnabled - SEKnown -> DBSEKnown - data ChatVersion instance VersionScope ChatVersion @@ -1795,12 +1754,3 @@ $(JQ.deriveJSON defaultJSON ''Contact) $(JQ.deriveJSON defaultJSON ''ContactRef) $(JQ.deriveJSON defaultJSON ''NoteFolder) - -$(JQ.deriveJSON (enumJSON $ dropPrefix "SE") ''ServerEnabled) - -instance ProtocolTypeI p => ToJSON (ServerCfg p) where - toEncoding = $(JQ.mkToEncoding defaultJSON ''ServerCfg) - toJSON = $(JQ.mkToJSON defaultJSON ''ServerCfg) - -instance ProtocolTypeI p => FromJSON (ServerCfg p) where - parseJSON = $(JQ.mkParseJSON defaultJSON ''ServerCfg) diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs index 04c06103ea..4dffa41dea 100644 --- a/src/Simplex/Chat/View.hs +++ b/src/Simplex/Chat/View.hs @@ -52,7 +52,7 @@ import Simplex.Chat.Types.Shared import Simplex.Chat.Types.UITheme import qualified Simplex.FileTransfer.Transport as XFTP import Simplex.Messaging.Agent.Client (ProtocolTestFailure (..), ProtocolTestStep (..), SubscriptionsInfo (..)) -import Simplex.Messaging.Agent.Env.SQLite (NetworkConfig (..)) +import Simplex.Messaging.Agent.Env.SQLite (NetworkConfig (..), ServerCfg (..)) import Simplex.Messaging.Agent.Protocol import Simplex.Messaging.Agent.Store.SQLite.DB (SlowQueryStats (..)) import Simplex.Messaging.Client (SMPProxyFallback, SMPProxyMode (..)) @@ -62,7 +62,7 @@ import qualified Simplex.Messaging.Crypto.Ratchet as CR import Simplex.Messaging.Encoding import Simplex.Messaging.Encoding.String import Simplex.Messaging.Parsers (dropPrefix, taggedObjectJSON) -import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType, ProtoServerWithAuth, ProtocolServer (..), ProtocolTypeI, SProtocolType (..)) +import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType, ProtocolServer (..), ProtocolTypeI, SProtocolType (..)) import qualified Simplex.Messaging.Protocol as SMP import Simplex.Messaging.Transport.Client (TransportHost (..)) import Simplex.Messaging.Util (safeDecodeUtf8, tshow) @@ -1183,8 +1183,8 @@ viewUserServers (AUPS UserProtoServers {serverProtocol = p, protoServers, preset pName = protocolName p customServers = if null protoServers - then ("no " <> pName <> " servers saved, using presets: ") : viewServers id presetServers - else viewServers (\ServerCfg {server} -> server) protoServers + then ("no " <> pName <> " servers saved, using presets: ") : viewServers presetServers + else viewServers protoServers protocolName :: ProtocolTypeI p => SProtocolType p -> StyledString protocolName = plain . map toUpper . T.unpack . decodeLatin1 . strEncode @@ -1281,8 +1281,8 @@ viewConnectionStats ConnectionStats {rcvQueuesInfo, sndQueuesInfo} = ["receiving messages via: " <> viewRcvQueuesInfo rcvQueuesInfo | not $ null rcvQueuesInfo] <> ["sending messages via: " <> viewSndQueuesInfo sndQueuesInfo | not $ null sndQueuesInfo] -viewServers :: ProtocolTypeI p => (a -> ProtoServerWithAuth p) -> NonEmpty a -> [StyledString] -viewServers f = map (plain . B.unpack . strEncode . f) . L.toList +viewServers :: ProtocolTypeI p => NonEmpty (ServerCfg p) -> [StyledString] +viewServers = map (plain . B.unpack . strEncode . (\ServerCfg {server} -> server)) . L.toList viewRcvQueuesInfo :: [RcvQueueInfo] -> StyledString viewRcvQueuesInfo = plain . intercalate ", " . map showQueueInfo diff --git a/website/langs/cs.json b/website/langs/cs.json index 674351f63a..7e3e9530b9 100644 --- a/website/langs/cs.json +++ b/website/langs/cs.json @@ -28,7 +28,7 @@ "copyright-label": "© 2020-2024 SimpleX | Projekt s otevřeným zdrojovým kódem", "simplex-chat-protocol": "SimpleX Chat protokol", "terminal-cli": "Terminálové rozhraní příkazového řádku", - "terms-and-privacy-policy": "Podmínky a zásady ochrany osobních údajů", + "terms-and-privacy-policy": "Ochrana soukromí", "hero-header": "Nová definice ochrany osobních údajů", "hero-subheader": "První messenger
bez uživatelských ID", "hero-overlay-1-textlink": "Proč jsou uživatelská ID špatná pro soukromí?", @@ -40,7 +40,7 @@ "feature-3-title": "E2E-šifrované decentralizované skupiny — pouze uživatelé vědí, že existují", "feature-4-title": "Hlasové zprávy šifrované E2E", "feature-6-title": "E2E šifrované
hlasové a videohovory", - "feature-7-title": "Přenosné šifrované ůložiště aplikace — přeneste profil do jiného zařízení", + "feature-7-title": "Přenosné šifrované úložiště aplikace — přesuňte profil do jiného zařízení", "feature-8-title": "režim Inkognito —
Unikátní pro SimpleX Chat", "simplex-network-overlay-1-title": "Srovnání s protokoly zpráv P2P", "simplex-private-2-title": "Další vrstva
šifrování serveru", @@ -253,5 +253,7 @@ "hero-overlay-card-3-p-2": "Trail of Bits přezkoumala kryptografii a síťové komponenty SimpleX platformy v listopadu 2022.", "hero-overlay-card-3-p-3": "Přečtěte si více v ohlášení.", "docs-dropdown-9": "Ke stažení", - "docs-dropdown-10": "Transparentnost" + "docs-dropdown-10": "Transparentnost", + "docs-dropdown-11": "FAQ (často kladené dotazy)", + "docs-dropdown-12": "Bezpečnost" } diff --git a/website/langs/es.json b/website/langs/es.json index f91ab5a92a..443f04b2ac 100644 --- a/website/langs/es.json +++ b/website/langs/es.json @@ -12,7 +12,7 @@ "donate": "Donación", "copyright-label": "© 2020-2024 SimpleX | Proyecto de Código Abierto", "simplex-chat-protocol": "Protocolo de SimpleX Chat", - "terms-and-privacy-policy": "Términos y Política de Privacidad", + "terms-and-privacy-policy": "Política de Privacidad", "hero-header": "Privacidad redefinida", "hero-overlay-1-textlink": "¿Por qué los ID de usuario son perjudiciales para la privacidad?", "hero-overlay-2-textlink": "¿Cómo funciona SimpleX?", @@ -242,7 +242,7 @@ "stable-versions-built-by-f-droid-org": "Versión estable compilada por F-Droid.org", "f-droid-page-f-droid-org-repo-section-text": "Los repositorios de SimpleX Chat y F-Droid.org firman con distinto certificado. Para cambiar, por favor exportar la base de datos y reinstala la aplicación.", "signing-key-fingerprint": "Huella digital de la clave de firma (SHA-256)", - "releases-to-this-repo-are-done-1-2-days-later": "Las versiones aparecen 1-2 días más tarde en este repositorio", + "releases-to-this-repo-are-done-1-2-days-later": "Las versiones aparecen varios días más tarde en este repositorio", "comparison-section-list-point-4a": "Los servidores de retransmisión no pueden comprometer la encriptación e2e. Para evitar posibles ataques, verifique el código de seguridad mediante un canal alternativo", "hero-overlay-3-title": "Evaluación de la seguridad", "hero-overlay-card-3-p-2": "Trail of Bits revisó la criptografía y los componentes de red de la plataforma SimpleX en noviembre de 2022.", @@ -253,5 +253,7 @@ "docs-dropdown-9": "Descargas", "please-enable-javascript": "Habilita JavaScript para ver el código QR.", "please-use-link-in-mobile-app": "Usa el enlace en la apliación móvil,", - "docs-dropdown-10": "Transparencia" + "docs-dropdown-10": "Transparencia", + "docs-dropdown-11": "FAQ", + "docs-dropdown-12": "Seguridad" } diff --git a/website/langs/fr.json b/website/langs/fr.json index 7a59ead53f..678753d1e6 100644 --- a/website/langs/fr.json +++ b/website/langs/fr.json @@ -234,7 +234,7 @@ "docs-dropdown-4": "Hébergement d'un serveur SMP", "on-this-page": "Sur cette page", "glossary": "Glossaire", - "releases-to-this-repo-are-done-1-2-days-later": "Les mises à jour de ce dépôt sont faites 1 à 2 jours plus tard", + "releases-to-this-repo-are-done-1-2-days-later": "Les mises à jour de ce dépôt sont faites quelques jours plus tard", "f-droid-page-f-droid-org-repo-section-text": "Les dépôts SimpleX Chat et F-Droid.org signent les builds avec des clés différentes. Pour changer, veuillez exporter la base de données des chats et réinstaller l'application.", "docs-dropdown-8": "Service de répertoire SimpleX", "simplex-chat-via-f-droid": "SimpleX Chat via F-Droid", diff --git a/website/langs/he.json b/website/langs/he.json index 9effb8474b..72411c8cd1 100644 --- a/website/langs/he.json +++ b/website/langs/he.json @@ -12,7 +12,7 @@ "simplex-explained-tab-2-text": "2. איך זה עובד", "simplex-chat-protocol": "פרוטוקול SimpleX Chat", "terminal-cli": "ממשק שורת פקודה", - "terms-and-privacy-policy": "תנאים ומדיניות פרטיות", + "terms-and-privacy-policy": "מדיניות הפרטיות", "hero-header": "פרטיות מוגדרת מחדש", "hero-subheader": "מערכת העברת ההודעות הראשונה
ללא מזהי שתמש", "hero-overlay-1-textlink": "מדוע מזהי משתמש מזיקים לפרטיות?", @@ -53,7 +53,7 @@ "smp-protocol": "פרוטוקול SMP", "chat-protocol": "פרוטוקול צ'אט", "donate": "תרומה", - "copyright-label": "© 2020-2023 SimpleX | פרויקט קוד פתוח", + "copyright-label": "© 2020-2024 SimpleX | פרויקט קוד פתוח", "hero-p-1": "לאפליקציות אחרות יש מזהי משתמש: Signal, Matrix, Session, Briar, Jami, Cwtch וכו'.
ל-SimpleX אין, אפילו לא מספרים אקראיים.
זה משפר באופן קיצוני את הפרטיות שלך.", "hero-overlay-2-title": "מדוע מזהי משתמש מזיקים לפרטיות?", "feature-6-title": "שיחות שמע ווידאו
מוצפנות מקצה לקצה", @@ -242,7 +242,7 @@ "simplex-chat-via-f-droid": "SimpleX Chat דרך F-Droid", "glossary": "מילון מונחים", "jobs": "הצטרפו לצוות", - "releases-to-this-repo-are-done-1-2-days-later": "גרסאות למאגר זה משוחררות לאחר יום או יומיים", + "releases-to-this-repo-are-done-1-2-days-later": "גרסאות למאגר זה משוחררות לאחר כמה ימים", "f-droid-org-repo": "מאגר F-Droid.org", "stable-versions-built-by-f-droid-org": "גרסאות יציבות שנבנו על ידי F-Droid.org", "back-to-top": "חזרה למעלה", @@ -252,5 +252,8 @@ "docs-dropdown-8": "שירות מדריך כתובות SimpleX", "f-droid-page-f-droid-org-repo-section-text": "מאגרי SimpleX Chat ו-F-Droid.org חותמים על גרסאות עם מפתחות שונים. כדי לעבור, אנא ייצא את מסד הנתונים של הצ'אט והתקן מחדש את האפליקציה.", "please-enable-javascript": "אנא הפעל JavaScript כדי לראות את קוד ה-QR.", - "please-use-link-in-mobile-app": "אנא השתמש בקישור באפליקציה במכשיר נייד" + "please-use-link-in-mobile-app": "אנא השתמש בקישור באפליקציה במכשיר נייד", + "docs-dropdown-10": "שקיפות", + "docs-dropdown-11": "שאלות ותשובות", + "docs-dropdown-12": "אבטחה" } diff --git a/website/langs/hu.json b/website/langs/hu.json index b4aa44f12e..7b6b856065 100644 --- a/website/langs/hu.json +++ b/website/langs/hu.json @@ -26,7 +26,7 @@ "terms-and-privacy-policy": "Adatvédelmi irányelvek", "hero-header": "Újradefiniált adatvédelem", "hero-subheader": "Az első üzenetküldő
felhasználói azonosítók nélkül", - "hero-p-1": "Más alkalmazások felhasználói azonosítókkal rendelkeznek: Signal, Matrix, Session, Briar, Jami, Cwtch, stb.
A SimpleX nem, még véletlenszerű számok sem.
Ez radikálisan javítja az adatvédelmet.", + "hero-p-1": "Más alkalmazások felhasználói azonosítókkal rendelkeznek: Signal, Matrix, Session, Briar, Jami, Cwtch, stb.
A SimpleX nem, még véletlenszerű számokkal sem.
Ez radikálisan javítja az adatvédelmet.", "hero-overlay-1-textlink": "Miért ártanak a felhasználói azonosítók az adatvédelemnek?", "hero-overlay-2-textlink": "Hogyan működik a SimpleX?", "hero-overlay-3-textlink": "A biztonság értékelése", @@ -93,7 +93,7 @@ "hero-overlay-card-2-p-1": "Ha a felhasználók állandó azonosítóval rendelkeznek, még akkor is, ha ez csak egy véletlenszerű szám, például egy munkamenet-azonosító, fennáll annak a veszélye, hogy a szolgáltató vagy egy támadó megfigyelheti, hogyan kapcsolódnak a felhasználók, és hány üzenetet küldenek.", "hero-overlay-card-2-p-2": "Ezt az információt aztán összefüggésbe hozhatják a meglévő nyilvános közösségi hálózatokkal, és meghatározhatnak néhány valódi személyazonosságot.", "hero-overlay-card-2-p-3": "Még a Tor v3 szolgáltatásokat használó, legprivátabb alkalmazások esetében is, ha két különböző kapcsolattartóval beszél ugyanazon a profilon keresztül, bizonyítani tudják, hogy ugyanahhoz a személyhez kapcsolódnak.", - "hero-overlay-card-2-p-4": "A SimpleX úgy védekezik ezek ellen a támadások ellen, hogy nem tartalmaz felhasználói azonosítókat. Ha pedig használja az inkognitó módot, akkor minden egyes létrejött kapcsolatban más-más felhasználó név jelenik meg, így elkerülhető a közöttük lévő összefüggések bizonyítása.", + "hero-overlay-card-2-p-4": "A SimpleX úgy védekezik ezen támadások ellen, hogy nem tartalmaz felhasználói azonosítókat. Ha pedig használja az inkognitó módot, akkor minden egyes létrejött kapcsolatban más-más felhasználó név jelenik meg, így elkerülhető a közöttük lévő összefüggések bizonyítása.", "hero-overlay-card-3-p-1": "Trail of Bits egy vezető biztonsági és technológiai tanácsadó cég, amelynek ügyfelei közé tartoznak a nagy technológiai cégek, kormányzati ügynökségek és jelentős blokklánc projektek.", "hero-overlay-card-3-p-2": "A Trail of Bits 2022 novemberében áttekintette a SimpleX platform kriptográfiai és hálózati komponenseit.", "simplex-network-overlay-card-1-li-1": "A P2P-hálózatok az üzenetek továbbítására a DHT valamelyik változatát használják. A DHT kialakításakor egyensúlyt kell teremteni a kézbesítési garancia és a késleltetés között. A SimpleX jobb kézbesítési garanciával és alacsonyabb késleltetéssel rendelkezik, mint a P2P, mivel az üzenet redundánsan, a címzett által kiválasztott kiszolgálók segítségével több kiszolgálón keresztül párhuzamosan továbbítható. A P2P-hálózatokban az üzenet O(log N) csomóponton halad át szekvenciálisan, az algoritmus által kiválasztott csomópontok segítségével.", @@ -127,15 +127,15 @@ "simplex-unique-card-1-p-1": "A SimpleX védi az ön profiljához tartozó kapcsolatait és metaadatait, elrejtve azokat a SimpleX platform kiszolgálói és a megfigyelők elől.", "simplex-unique-card-1-p-2": "Minden más létező üzenetküldő platformtól eltérően a SimpleX nem rendelkezik a felhasználókhoz rendelt azonosítókkal — még véletlenszerű számokkal sem.", "simplex-unique-card-2-p-1": "Mivel a SimpleX platformon nincs azonosítója vagy állandó címe, senki sem tud kapcsolatba lépni önnel, hacsak nem oszt meg egy egyszeri vagy ideiglenes felhasználói címet, például QR-kódot vagy hivatkozást.", - "simplex-unique-card-3-p-1": "A SimpleX Chat az összes felhasználói adatot kizárólag az klienseken tárolja egy hordozható titkosított adatbázis-formátumban —, amely exportálható és átvihető bármely más támogatott eszközre.", - "simplex-unique-card-3-p-2": "A végpontok között titkosított üzenetek átmenetileg a SimpleX átjátszó-kiszolgálókon tartózkodnak, amíg be nem érkeznek a címzetthez, majd végleges törlésre kerülnek.", + "simplex-unique-card-3-p-1": "A SimpleX Chat az összes felhasználói adatot kizárólag a klienseken tárolja egy hordozható titkosított adatbázis-formátumban —, amely exportálható és átvihető bármely más támogatott eszközre.", + "simplex-unique-card-3-p-2": "A végpontok között titkosított üzenetek átmenetileg a SimpleX átjátszó-kiszolgálókon tartózkodnak, míg meg nem érkeznek a címzetthez, majd ezt követően végleges törlésre kerülnek.", "simplex-unique-card-4-p-1": "A SimpleX hálózat teljesen decentralizált és független bármely kriptopénztől vagy bármely más platformtól, kivéve az internetet.", "simplex-unique-card-4-p-2": "Használhatja a SimpleX-et saját kiszolgálóival vagy az általunk biztosított kiszolgálókkal, és továbbra is kapcsolódhat bármely felhasználóhoz.", "join": "Csatlakozás", "we-invite-you-to-join-the-conversation": "Meghívjuk önt, hogy csatlakozzon a beszélgetéshez", "join-the-REDDIT-community": "Csatlakozzon a REDDIT közösséghez", "join-us-on-GitHub": "Csatlakozzon hozzánk a GitHubon", - "donate-here-to-help-us": "Adományozzon itt, hogy segítsen nekünk", + "donate-here-to-help-us": "Adományozzon és segítsen nekünk", "sign-up-to-receive-our-updates": "Regisztráljon az oldalra, hogy megkapja frissítéseinket", "enter-your-email-address": "Adja meg az e-mail címét", "get-simplex": "SimpleX Desktop alkalmazás letöltése", diff --git a/website/langs/zh_Hans.json b/website/langs/zh_Hans.json index 01f6149669..03da9db140 100644 --- a/website/langs/zh_Hans.json +++ b/website/langs/zh_Hans.json @@ -57,7 +57,7 @@ "simplex-chat-protocol": "SimpleX 聊天协议", "smp-protocol": "SMP协议", "chat-protocol": "聊天协议", - "copyright-label": "© 2020-2023 SimpleX | 开源项目", + "copyright-label": "© 2020-2024 SimpleX | 开源项目", "terminal-cli": "命令行程式", "simplex-explained-tab-1-p-1": "您可以创建联系人和群组,并进行双向对话,就像是任何其他即时通讯软件一样。", "hero-p-1": "其他应用——如Signal、Matrix、Session、Briar、Jami、Cwtch 等——都需要用户 ID。
而SimpleX 不需要用户ID,连随机生成的也不需要。
这从根本上改善了您的隐私。",