ios: connection information/alias sheet (#1178)

* ios: connection information/alias sheet

* add swipe button

* add localizations

* fix padding

* fix intermittent bug with multiple edits
This commit is contained in:
Evgeny Poberezkin
2022-10-06 15:02:58 +01:00
committed by GitHub
parent 3649321b67
commit 868f0abaaf
14 changed files with 305 additions and 221 deletions
@@ -23,7 +23,7 @@ struct AddGroupMembersView: View {
private enum AddGroupMembersAlert: Identifiable {
case prohibitedToInviteIncognito
case error(title: LocalizedStringKey, error: String = "")
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
var id: String {
switch self {
@@ -101,7 +101,7 @@ struct AddGroupMembersView: View {
message: Text("You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile")
)
case let .error(title, error):
return Alert(title: Text(title), message: Text("\(error)"))
return Alert(title: Text(title), message: Text(error))
}
}
}
@@ -128,14 +128,8 @@ struct AddGroupMembersView: View {
await MainActor.run { dismiss() }
if let cb = addedMembersCb { cb(selectedContacts) }
} catch {
switch error as? ChatResponse {
case .chatCmdError(.errorAgent(.BROKER(.TIMEOUT))):
alert = .error(title: "Connection timeout", error: NSLocalizedString("Please check your network connection and try again.", comment: "alert message"))
case .chatCmdError(.errorAgent(.BROKER(.NETWORK))):
alert = .error(title: "Connection error", error: NSLocalizedString("Please check your network connection and try again.", comment: "alert message"))
default:
alert = .error(title: "Error adding member(s)", error: responseError(error))
}
let a = getErrorAlert(error, "Error adding member(s)")
alert = .error(title: a.title, error: a.message)
}
}
}
@@ -22,7 +22,7 @@ struct GroupMemberInfoView: View {
enum GroupMemberInfoViewAlert: Identifiable {
case removeMemberAlert
case changeMemberRoleAlert(role: GroupMemberRole)
case error(title: LocalizedStringKey, error: String)
case error(title: LocalizedStringKey, error: LocalizedStringKey)
var id: String {
switch self {
@@ -176,7 +176,8 @@ struct GroupMemberInfoView: View {
}
} catch let error {
logger.error("apiRemoveMember error: \(responseError(error))")
alert = errorAlert(error, "Error removing member")
let a = getErrorAlert(error, "Error removing member")
alert = .error(title: a.title, error: a.message)
}
}
},
@@ -199,7 +200,8 @@ struct GroupMemberInfoView: View {
} catch let error {
newRole = member.memberRole
logger.error("apiMemberRole error: \(responseError(error))")
alert = errorAlert(error, "Error changing role")
let a = getErrorAlert(error, "Error changing role")
alert = .error(title: a.title, error: a.message)
}
}
},
@@ -208,17 +210,6 @@ struct GroupMemberInfoView: View {
}
)
}
private func errorAlert(_ error: Error, _ title: LocalizedStringKey) -> GroupMemberInfoViewAlert {
switch error as? ChatResponse {
case .chatCmdError(.errorAgent(.BROKER(.TIMEOUT))):
return .error(title: "Connection timeout", error: NSLocalizedString("Please check your network connection and try again.", comment: "alert message"))
case .chatCmdError(.errorAgent(.BROKER(.NETWORK))):
return .error(title: "Connection error", error: NSLocalizedString("Please check your network connection and try again.", comment: "alert message"))
default:
return .error(title: title, error: responseError(error))
}
}
}
struct GroupMemberInfoView_Previews: PreviewProvider {
@@ -30,6 +30,7 @@ struct ChatListNavLink: View {
@State var chat: Chat
@State private var showContactRequestDialog = false
@State private var showJoinGroupDialog = false
@State private var showContactConnectionInfo = false
var body: some View {
switch chat.chatInfo {
@@ -199,24 +200,32 @@ struct ChatListNavLink: View {
}
private func contactConnectionNavLink(_ contactConnection: PendingContactConnection) -> some View {
ContactConnectionView(contactConnection: contactConnection)
ContactConnectionView(chat: chat)
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button {
AlertManager.shared.showAlert(deleteContactConnectionAlert(contactConnection))
AlertManager.shared.showAlert(deleteContactConnectionAlert(contactConnection) { a in
AlertManager.shared.showAlertMsg(title: a.title, message: a.message)
})
} label: {
Label("Delete", systemImage: "trash")
}
.tint(.red)
Button {
showContactConnectionInfo = true
} label: {
Label("Name", systemImage: "pencil")
}
.tint(.accentColor)
}
.frame(height: rowHeights[dynamicTypeSize])
.sheet(isPresented: $showContactConnectionInfo) {
if case let .contactConnection(contactConnection) = chat.chatInfo {
ContactConnectionInfo(contactConnection: contactConnection)
}
}
.onTapGesture {
AlertManager.shared.showAlertMsg(
title: contactConnection.initiated
? "You invited your contact"
: "You accepted connection",
// below are the same messages that are shown in alert
message: contactConnectionText(contactConnection)
)
showContactConnectionInfo = true
}
}
@@ -279,29 +288,6 @@ struct ChatListNavLink: View {
)
}
private func deleteContactConnectionAlert(_ contactConnection: PendingContactConnection) -> Alert {
Alert(
title: Text("Delete pending connection?"),
message:
contactConnection.initiated
? Text("The contact you shared this link with will NOT be able to connect!")
: Text("The connection you accepted will be cancelled!"),
primaryButton: .destructive(Text("Delete")) {
Task {
do {
try await apiDeleteChat(type: .contactConnection, id: contactConnection.apiId)
DispatchQueue.main.async {
chatModel.removeChat(contactConnection.id)
}
} catch let error {
logger.error("ChatListNavLink.deleteContactConnectionAlert apiDeleteChat error: \(responseError(error))")
}
}
},
secondaryButton: .cancel()
)
}
private func pendingContactAlert(_ chat: Chat, _ contact: Contact) -> Alert {
Alert(
title: Text("Contact is not connected yet!"),
@@ -345,6 +331,32 @@ struct ChatListNavLink: View {
}
}
func deleteContactConnectionAlert(_ contactConnection: PendingContactConnection, showError: @escaping (ErrorAlert) -> Void, success: @escaping () -> Void = {}) -> Alert {
Alert(
title: Text("Delete pending connection?"),
message:
contactConnection.initiated
? Text("The contact you shared this link with will NOT be able to connect!")
: Text("The connection you accepted will be cancelled!"),
primaryButton: .destructive(Text("Delete")) {
Task {
do {
try await apiDeleteChat(type: .contactConnection, id: contactConnection.apiId)
await MainActor.run {
ChatModel.shared.removeChat(contactConnection.id)
success()
}
} catch let error {
await MainActor.run {
showError(getErrorAlert(error, "Error deleting connection"))
}
}
}
},
secondaryButton: .cancel()
)
}
func joinGroup(_ groupId: Int64) {
Task {
logger.debug("joinGroup")
@@ -361,15 +373,8 @@ func joinGroup(_ groupId: Int64) {
await deleteGroup()
}
} catch let error {
switch error as? ChatResponse {
case .chatCmdError(.errorAgent(.BROKER(.TIMEOUT))):
AlertManager.shared.showAlertMsg(title: "Connection timeout", message: "Please check your network connection and try again.")
case .chatCmdError(.errorAgent(.BROKER(.NETWORK))):
AlertManager.shared.showAlertMsg(title: "Connection error", message: "Please check your network connection and try again.")
default:
logger.error("apiJoinGroup error: \(responseError(error))")
AlertManager.shared.showAlertMsg(title: "Error joining group", message: "\(responseError(error))")
}
let a = getErrorAlert(error, "Error joining group")
AlertManager.shared.showAlertMsg(title: a.title, message: a.message)
}
func deleteGroup() async {
@@ -384,10 +389,20 @@ func joinGroup(_ groupId: Int64) {
}
}
func contactConnectionText(_ contactConnection: PendingContactConnection) -> LocalizedStringKey {
contactConnection.viaContactUri
? "You will be connected when your connection request is accepted, please wait or check later!"
: "You will be connected when your contact's device is online, please wait or check later!"
struct ErrorAlert {
var title: LocalizedStringKey
var message: LocalizedStringKey
}
func getErrorAlert(_ error: Error, _ title: LocalizedStringKey) -> ErrorAlert {
switch error as? ChatResponse {
case .chatCmdError(.errorAgent(.BROKER(.TIMEOUT))):
return ErrorAlert(title: "Connection timeout", message: "Please check your network connection and try again.")
case .chatCmdError(.errorAgent(.BROKER(.NETWORK))):
return ErrorAlert(title: "Connection error", message: "Please check your network connection and try again.")
default:
return ErrorAlert(title: title, message: "Error: \(responseError(error))")
}
}
struct ChatListNavLink_Previews: PreviewProvider {
@@ -2,7 +2,7 @@
// ContactConnectionInfo.swift
// SimpleX (iOS)
//
// Created by Evgeny on 30/09/2022.
// Created by Evgeny on 06/10/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
@@ -11,54 +11,128 @@ import SimpleXChat
struct ContactConnectionInfo: View {
@EnvironmentObject var m: ChatModel
var contactConnection: PendingContactConnection
var connReqInvitation: String
@Environment(\.dismiss) var dismiss: DismissAction
@State var contactConnection: PendingContactConnection
@State private var alert: CCInfoAlert?
@State private var showQRCodeView = false
@State private var localAlias = ""
@FocusState private var aliasTextFieldFocused: Bool
enum CCInfoAlert: Identifiable {
case deleteInvitationAlert
case error(title: LocalizedStringKey, error: LocalizedStringKey)
var id: String {
switch self {
case .deleteInvitationAlert: return "deleteInvitationAlert"
case let .error(title, _): return "error \(title)"
}
}
}
var body: some View {
ScrollView {
VStack(alignment: .leading) {
Text("Shared one-time link")
.font(.largeTitle)
.bold()
.padding(.vertical)
NavigationView {
List {
Group {
Text(contactConnection.initiated ? "You invited your contact" : "You accepted connection")
.font(.largeTitle)
.bold()
.padding(.bottom, 16)
HStack {
if contactConnection.incognito {
Image(systemName: "theatermasks").foregroundColor(.indigo).font(.footnote)
Spacer().frame(width: 8)
Text("A random profile will be sent to your contact").font(.footnote)
} else {
Image(systemName: "info.circle").foregroundColor(.secondary).font(.footnote)
Spacer().frame(width: 8)
Text("Your chat profile will be sent to your contact").font(.footnote)
Text(contactConnectionText(contactConnection))
}
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
.onTapGesture { aliasTextFieldFocused = false }
Section {
HStack(spacing: 20) {
Image(systemName: "pencil")
.foregroundColor(.secondary)
.padding(.leading, 6)
.onTapGesture { aliasTextFieldFocused = true }
TextField("Set contact name…", text: $localAlias)
.autocapitalization(.none)
.autocorrectionDisabled(true)
.focused($aliasTextFieldFocused)
.submitLabel(.done)
.onSubmit(setConnectionAlias)
}
if contactConnection.initiated && contactConnection.connReqInv != nil {
Button {
showQRCodeView = true
} label: {
Label("Show QR code", systemImage: "qrcode")
.foregroundColor(contactConnection.incognito ? .indigo : .accentColor)
}
}
Button(role: .destructive) {
alert = .deleteInvitationAlert
} label: {
Label("Delete connection", systemImage: "trash")
.foregroundColor(Color.red)
}
}
Text(contactConnectionText(contactConnection))
.padding(.top, 4)
.padding(.bottom, 8)
QRCode(uri: connReqInvitation).padding(.bottom)
Text("If you can't meet in person, **show QR code in the video call**, or share the link.")
.padding(.bottom)
Button {
showShareSheet(items: [connReqInvitation])
} label: {
Label("Share invitation link", systemImage: "square.and.arrow.up")
}
.frame(maxWidth: .infinity, alignment: .center)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.onAppear { m.connReqInv = connReqInvitation }
.onDisappear { m.connReqInv = nil }
.listStyle(.insetGrouped)
}
.sheet(isPresented: $showQRCodeView) {
if let connReqInv = contactConnection.connReqInv {
AddContactView(contactConnection: contactConnection, connReqInvitation: connReqInv)
}
}
.alert(item: $alert) { _alert in
switch _alert {
case .deleteInvitationAlert:
return deleteContactConnectionAlert(contactConnection) { a in
alert = .error(title: a.title, error: a.message)
} success: {
dismiss()
}
case let .error(title, error): return Alert(title: Text(title), message: Text(error))
}
}
.onAppear {
localAlias = contactConnection.localAlias
aliasTextFieldFocused = true
}
}
private func setConnectionAlias() {
if localAlias == contactConnection.localAlias {
aliasTextFieldFocused = false
return
}
Task {
let prevAlias = contactConnection.localAlias
contactConnection.localAlias = localAlias
do {
if let conn = try await apiSetConnectionAlias(connId: contactConnection.pccConnId, localAlias: localAlias) {
await MainActor.run {
contactConnection = conn
ChatModel.shared.updateContactConnection(conn)
dismiss()
}
}
} catch {
logger.error("setContactAlias error: \(responseError(error))")
contactConnection.localAlias = prevAlias
}
}
}
private func contactConnectionText(_ contactConnection: PendingContactConnection) -> LocalizedStringKey {
contactConnection.viaContactUri
? "You will be connected when your connection request is accepted, please wait or check later!"
: "You will be connected when your contact's device is online, please wait or check later!"
}
}
struct ContactConnectionInfo_Previews: PreviewProvider {
static var previews: some View {
ContactConnectionInfo(contactConnection: PendingContactConnection.getSampleData(), connReqInvitation: "")
ContactConnectionInfo(contactConnection: PendingContactConnection.getSampleData())
}
}
@@ -11,80 +11,41 @@ import SimpleXChat
struct ContactConnectionView: View {
@EnvironmentObject var m: ChatModel
@State var contactConnection: PendingContactConnection
@State private var editLocalAlias = false
@ObservedObject var chat: Chat
@State private var localAlias = ""
@FocusState private var aliasTextFieldFocused: Bool
@State private var showContactConnectionInfo = false
var body: some View {
if case let .contactConnection(conn) = chat.chatInfo {
contactConnectionView(conn)
}
}
func contactConnectionView(_ contactConnection: PendingContactConnection) -> some View {
HStack(spacing: 8) {
Group {
if contactConnection.initiated {
let v = Image(systemName: "qrcode")
.resizable()
.scaledToFill()
.frame(width: 40, height: 40)
if contactConnection.connReqInv == nil {
v.foregroundColor(Color(uiColor: .secondarySystemBackground))
} else {
v.foregroundColor(contactConnection.incognito ? .indigo : .accentColor)
.onTapGesture { showContactConnectionInfo = true }
}
} else {
Image(systemName: "link")
.resizable()
.scaledToFill()
.frame(width: 48, height: 48)
.foregroundColor(Color(uiColor: .secondarySystemBackground))
}
Image(systemName: contactConnection.initiated ? "link.badge.plus" : "link")
.resizable()
.scaledToFill()
.frame(width: 48, height: 48)
.foregroundColor(Color(uiColor: .secondarySystemBackground))
.onTapGesture { showContactConnectionInfo = true }
}
.frame(width: 63, height: 63)
.padding(.leading, 4)
VStack(alignment: .leading, spacing: 0) {
HStack(alignment: .top) {
Image(systemName: "pencil")
.resizable()
.scaledToFill()
.frame(width: 16, height: 16)
Text(contactConnection.chatViewName)
.font(.title3)
.bold()
.allowsTightening(false)
.foregroundColor(.secondary)
.padding(.leading, 8)
.padding(.top, 8)
.onTapGesture(perform: enableEditing)
if editLocalAlias {
let v = TextField("Set contact name…", text: $localAlias)
.font(.title3)
.disableAutocorrection(true)
.focused($aliasTextFieldFocused)
.submitLabel(.done)
.onSubmit(setConnectionAlias)
.foregroundColor(.secondary)
.padding(.trailing, 8)
.onTapGesture {}
.onChange(of: aliasTextFieldFocused) { focussed in
if !focussed {
editLocalAlias = false
}
}
if #available(iOS 16.0, *) {
v.bold()
} else {
v
}
} else {
Text(contactConnection.chatViewName)
.font(.title3)
.bold()
.allowsTightening(false)
.foregroundColor(.secondary)
.padding(.trailing, 8)
.padding(.top, 1)
.padding(.bottom, 0.5)
.frame(alignment: .topLeading)
.onTapGesture(perform: enableEditing)
}
.padding(.horizontal, 8)
.padding(.top, 1)
.padding(.bottom, 0.5)
.frame(alignment: .topLeading)
Spacer()
@@ -106,40 +67,7 @@ struct ContactConnectionView: View {
}
.frame(maxHeight: .infinity)
.sheet(isPresented: $showContactConnectionInfo) {
if let connReqInv = contactConnection.connReqInv {
ContactConnectionInfo(contactConnection: contactConnection, connReqInvitation: connReqInv)
}
}
}
}
private func enableEditing() {
editLocalAlias = true
aliasTextFieldFocused = true
localAlias = contactConnection.localAlias
}
private func setConnectionAlias() {
if localAlias == contactConnection.localAlias {
aliasTextFieldFocused = false
editLocalAlias = false
return
}
Task {
let prevAlias = contactConnection.localAlias
contactConnection.localAlias = localAlias
do {
if let conn = try await apiSetConnectionAlias(connId: contactConnection.pccConnId, localAlias: localAlias) {
await MainActor.run {
contactConnection = conn
ChatModel.shared.updateContactConnection(conn)
aliasTextFieldFocused = false
editLocalAlias = false
}
}
} catch {
logger.error("setContactAlias error: \(responseError(error))")
contactConnection.localAlias = prevAlias
ContactConnectionInfo(contactConnection: contactConnection)
}
}
}
@@ -147,7 +75,7 @@ struct ContactConnectionView: View {
struct ContactConnectionView_Previews: PreviewProvider {
static var previews: some View {
ContactConnectionView(contactConnection: PendingContactConnection.getSampleData())
ContactConnectionView(chat: Chat(chatInfo: ChatInfo.sampleData.contactConnection))
.previewLayout(.fixed(width: 360, height: 80))
}
}
@@ -8,9 +8,11 @@
import SwiftUI
import CoreImage.CIFilterBuiltins
import SimpleXChat
struct AddContactView: View {
@EnvironmentObject private var chatModel: ChatModel
var contactConnection: PendingContactConnection? = nil
var connReqInvitation: String
var viaSettings = false
@@ -23,7 +25,7 @@ struct AddContactView: View {
.padding(viaSettings ? .bottom : .vertical)
Text("Your contact can scan it from the app.")
.padding(.bottom, 4)
if (chatModel.incognito) {
if (contactConnection?.incognito ?? chatModel.incognito) {
HStack {
Image(systemName: "theatermasks").foregroundColor(.indigo).font(.footnote)
Spacer().frame(width: 8)
@@ -61,14 +61,8 @@ struct UserAddress: View {
}
} catch let error {
logger.error("UserAddress apiCreateUserAddress: \(error.localizedDescription)")
switch error as? ChatResponse {
case .chatCmdError(.errorAgent(.BROKER(.TIMEOUT))):
alert = .error(title: "Connection timeout", error: "Please check your network connection and try again.")
case .chatCmdError(.errorAgent(.BROKER(.NETWORK))):
alert = .error(title: "Connection error", error: "Please check your network connection and try again.")
default:
alert = .error(title: "Error creating address", error: "Error: \(responseError(error))")
}
let a = getErrorAlert(error, "Error creating address")
alert = .error(title: a.title, error: "\(a.message)")
}
}
} label: { Label("Create address", systemImage: "qrcode") }
@@ -746,6 +746,11 @@
<target>Chat-Profil löschen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete connection" xml:space="preserve">
<source>Delete connection</source>
<target>*** Delete connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete contact" xml:space="preserve">
<source>Delete contact</source>
<target>Kontakt löschen</target>
@@ -1021,6 +1026,11 @@
<target>Fehler beim Löschen des Chats!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
<target>*** Error deleting connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error deleting database" xml:space="preserve">
<source>Error deleting database</source>
<target>Fehler beim Löschen der Datenbank</target>
@@ -1573,6 +1583,11 @@ Wir werden Serverredundanzen hinzufügen, um verloren gegangene Nachrichten zu v
<target>Stummschalten</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Name" xml:space="preserve">
<source>Name</source>
<target>*** Name</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network &amp; servers" xml:space="preserve">
<source>Network &amp; servers</source>
<target>Netzwerk &amp; Server</target>
@@ -1766,7 +1781,7 @@ Wir werden Serverredundanzen hinzufügen, um verloren gegangene Nachrichten zu v
<trans-unit id="Please check your network connection and try again." xml:space="preserve">
<source>Please check your network connection and try again.</source>
<target>Bitte überprüfen Sie Ihre Netzwerkverbindung und versuchen Sie es erneut.</target>
<note>alert message</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please enter correct current passphrase." xml:space="preserve">
<source>Please enter correct current passphrase.</source>
@@ -2103,6 +2118,11 @@ Wir werden Serverredundanzen hinzufügen, um verloren gegangene Nachrichten zu v
<target>*** Shared one-time link</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<target>*** Show QR code</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Vorschau anzeigen</target>
@@ -746,6 +746,11 @@
<target>Delete chat profile?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete connection" xml:space="preserve">
<source>Delete connection</source>
<target>Delete connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete contact" xml:space="preserve">
<source>Delete contact</source>
<target>Delete contact</target>
@@ -1021,6 +1026,11 @@
<target>Error deleting chat!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
<target>Error deleting connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error deleting database" xml:space="preserve">
<source>Error deleting database</source>
<target>Error deleting database</target>
@@ -1573,6 +1583,11 @@ We will be adding server redundancy to prevent lost messages.</target>
<target>Mute</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Name" xml:space="preserve">
<source>Name</source>
<target>Name</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network &amp; servers" xml:space="preserve">
<source>Network &amp; servers</source>
<target>Network &amp; servers</target>
@@ -1766,7 +1781,7 @@ We will be adding server redundancy to prevent lost messages.</target>
<trans-unit id="Please check your network connection and try again." xml:space="preserve">
<source>Please check your network connection and try again.</source>
<target>Please check your network connection and try again.</target>
<note>alert message</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please enter correct current passphrase." xml:space="preserve">
<source>Please enter correct current passphrase.</source>
@@ -2103,6 +2118,11 @@ We will be adding server redundancy to prevent lost messages.</target>
<target>Shared one-time link</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<target>Show QR code</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Show preview</target>
@@ -746,6 +746,11 @@
<target>Удалить профиль?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete connection" xml:space="preserve">
<source>Delete connection</source>
<target>Удалить соединение</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete contact" xml:space="preserve">
<source>Delete contact</source>
<target>Удалить контакт</target>
@@ -1021,6 +1026,11 @@
<target>Ошибка при удалении чата!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error deleting connection" xml:space="preserve">
<source>Error deleting connection</source>
<target>Ошибка при удалении соединения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error deleting database" xml:space="preserve">
<source>Error deleting database</source>
<target>Ошибка при удалении данных чата</target>
@@ -1573,6 +1583,11 @@ We will be adding server redundancy to prevent lost messages.</source>
<target>Без звука</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Name" xml:space="preserve">
<source>Name</source>
<target>Имя</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network &amp; servers" xml:space="preserve">
<source>Network &amp; servers</source>
<target>Сеть &amp; серверы</target>
@@ -1766,7 +1781,7 @@ We will be adding server redundancy to prevent lost messages.</source>
<trans-unit id="Please check your network connection and try again." xml:space="preserve">
<source>Please check your network connection and try again.</source>
<target>Пожалуйста, проверьте ваше соединение с сетью и попробуйте еще раз.</target>
<note>alert message</note>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please enter correct current passphrase." xml:space="preserve">
<source>Please enter correct current passphrase.</source>
@@ -2103,6 +2118,11 @@ We will be adding server redundancy to prevent lost messages.</source>
<target>Одноразовая ссылка-приглашение</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<target>Показать QR код</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Показывать уведомления</target>
+4 -4
View File
@@ -18,6 +18,7 @@
5C029EAA283942EA004A9677 /* CallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA9283942EA004A9677 /* CallController.swift */; };
5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C05DF522840AA1D00C683F9 /* CallSettings.swift */; };
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; };
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */; };
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; };
5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; };
@@ -90,7 +91,6 @@
5CCD403427A5F6DF00368C90 /* AddContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403327A5F6DF00368C90 /* AddContactView.swift */; };
5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */; };
5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD472818589900503DA2 /* NotificationService.swift */; };
5CE1331028E7391000FFFD8C /* ContactConnectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE1330F28E7391000FFFD8C /* ContactConnectionInfo.swift */; };
5CE2BA702845308900EC33A6 /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; };
5CE2BA712845308900EC33A6 /* SimpleXChat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5CE2BA77284530BF00EC33A6 /* SimpleXChat.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE2BA76284530BF00EC33A6 /* SimpleXChat.h */; };
@@ -208,6 +208,7 @@
5C029EA9283942EA004A9677 /* CallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallController.swift; sourceTree = "<group>"; };
5C05DF522840AA1D00C683F9 /* CallSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSettings.swift; sourceTree = "<group>"; };
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = "<group>"; };
5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionInfo.swift; sourceTree = "<group>"; };
5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestView.swift; sourceTree = "<group>"; };
5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = "<group>"; };
5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
@@ -300,7 +301,6 @@
5CDCAD80281A7E2700503DA2 /* Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
5CE1330328E118CC00FFFD8C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = "de.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
5CE1330428E118CC00FFFD8C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
5CE1330F28E7391000FFFD8C /* ContactConnectionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionInfo.swift; sourceTree = "<group>"; };
5CE2BA682845308900EC33A6 /* SimpleXChat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SimpleXChat.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5CE2BA76284530BF00EC33A6 /* SimpleXChat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleXChat.h; sourceTree = "<group>"; };
5CE2BA78284530CC00EC33A6 /* SimpleXChat.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = SimpleXChat.docc; sourceTree = "<group>"; };
@@ -588,7 +588,7 @@
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */,
5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */,
5C13730A28156D2700F43030 /* ContactConnectionView.swift */,
5CE1330F28E7391000FFFD8C /* ContactConnectionInfo.swift */,
5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */,
);
path = ChatList;
sourceTree = "<group>";
@@ -891,6 +891,7 @@
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */,
5C4B3B0A285FB130003915F2 /* DatabaseView.swift in Sources */,
5CB2084F28DA4B4800D024EC /* RTCServers.swift in Sources */,
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */,
3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */,
3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */,
5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */,
@@ -908,7 +909,6 @@
5CB0BA8E2827126500B3292C /* OnboardingView.swift in Sources */,
6442E0BE2880182D00CEC0F9 /* GroupChatInfoView.swift in Sources */,
5C2E261227A30FEA00F70299 /* TerminalView.swift in Sources */,
5CE1331028E7391000FFFD8C /* ContactConnectionInfo.swift in Sources */,
5CB2085128DB64CA00D024EC /* CreateLinkView.swift in Sources */,
5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */,
64E972072881BB22008DBC02 /* CIGroupInvitationView.swift in Sources */,
+3 -1
View File
@@ -283,12 +283,14 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat {
public var direct: ChatInfo
public var group: ChatInfo
public var contactRequest: ChatInfo
public var contactConnection: ChatInfo
}
public static var sampleData: ChatInfo.SampleData = SampleData(
direct: ChatInfo.direct(contact: Contact.sampleData),
group: ChatInfo.group(groupInfo: GroupInfo.sampleData),
contactRequest: ChatInfo.contactRequest(contactRequest: UserContactRequest.sampleData)
contactRequest: ChatInfo.contactRequest(contactRequest: UserContactRequest.sampleData),
contactConnection: ChatInfo.contactConnection(contactConnection: PendingContactConnection.getSampleData())
)
}
+13 -1
View File
@@ -524,6 +524,9 @@
/* No comment provided by engineer. */
"Delete chat profile?" = "Chat-Profil löschen?";
/* No comment provided by engineer. */
"Delete connection" = "*** Delete connection";
/* No comment provided by engineer. */
"Delete contact" = "Kontakt löschen";
@@ -716,6 +719,9 @@
/* No comment provided by engineer. */
"Error deleting chat!" = "Fehler beim Löschen des Chats!";
/* No comment provided by engineer. */
"Error deleting connection" = "*** Error deleting connection";
/* No comment provided by engineer. */
"Error deleting database" = "Fehler beim Löschen der Datenbank";
@@ -1098,6 +1104,9 @@
/* No comment provided by engineer. */
"Mute" = "Stummschalten";
/* No comment provided by engineer. */
"Name" = "*** Name";
/* No comment provided by engineer. */
"Network & servers" = "Netzwerk & Server";
@@ -1230,7 +1239,7 @@
/* No comment provided by engineer. */
"Please check that you used the correct link or ask your contact to send you another one." = "Überprüfen Sie bitte, ob Sie den richtigen Link genutzt haben oder bitten Sie Ihren Kontakt nochmal darum, Ihnen einen Link zuzusenden.";
/* alert message */
/* No comment provided by engineer. */
"Please check your network connection and try again." = "Bitte überprüfen Sie Ihre Netzwerkverbindung und versuchen Sie es erneut.";
/* No comment provided by engineer. */
@@ -1455,6 +1464,9 @@
/* No comment provided by engineer. */
"Show preview" = "Vorschau anzeigen";
/* No comment provided by engineer. */
"Show QR code" = "*** Show QR code";
/* notification */
"SimpleX encrypted message or connection event" = "SimpleX verschlüsselte Nachricht oder Verbindungs-Ereignis";
+13 -1
View File
@@ -524,6 +524,9 @@
/* No comment provided by engineer. */
"Delete chat profile?" = "Удалить профиль?";
/* No comment provided by engineer. */
"Delete connection" = "Удалить соединение";
/* No comment provided by engineer. */
"Delete contact" = "Удалить контакт";
@@ -716,6 +719,9 @@
/* No comment provided by engineer. */
"Error deleting chat!" = "Ошибка при удалении чата!";
/* No comment provided by engineer. */
"Error deleting connection" = "Ошибка при удалении соединения";
/* No comment provided by engineer. */
"Error deleting database" = "Ошибка при удалении данных чата";
@@ -1098,6 +1104,9 @@
/* No comment provided by engineer. */
"Mute" = "Без звука";
/* No comment provided by engineer. */
"Name" = "Имя";
/* No comment provided by engineer. */
"Network & servers" = "Сеть & серверы";
@@ -1230,7 +1239,7 @@
/* No comment provided by engineer. */
"Please check that you used the correct link or ask your contact to send you another one." = "Пожалуйста, проверьте, что вы использовали правильную ссылку или попросите, чтобы ваш контакт отправил вам другую ссылку.";
/* alert message */
/* No comment provided by engineer. */
"Please check your network connection and try again." = "Пожалуйста, проверьте ваше соединение с сетью и попробуйте еще раз.";
/* No comment provided by engineer. */
@@ -1455,6 +1464,9 @@
/* No comment provided by engineer. */
"Show preview" = "Показывать уведомления";
/* No comment provided by engineer. */
"Show QR code" = "Показать QR код";
/* notification */
"SimpleX encrypted message or connection event" = "SimpleX: зашифрованное сообщение или соединение контакта";