ios: UX for making connections (#1088)

* ios: UX for making connections

* combine paste and scan into one view

* translations
This commit is contained in:
Evgeny Poberezkin
2022-09-22 08:36:39 +01:00
committed by GitHub
parent b390630f4b
commit 9b75553ddc
12 changed files with 218 additions and 58 deletions

View File

@@ -10,14 +10,17 @@ import SwiftUI
import CoreImage.CIFilterBuiltins
struct AddContactView: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject private var chatModel: ChatModel
var connReqInvitation: String
var viaSettings = false
var body: some View {
ScrollView {
VStack(alignment: .leading) {
Text("One-time invitation link")
.font(.title)
.padding(.vertical)
.font(.largeTitle)
.bold()
.padding(viaSettings ? .bottom : .vertical)
Text("Your contact can scan it from the app.")
.padding(.bottom, 4)
if (chatModel.incognito) {
@@ -35,8 +38,15 @@ struct AddContactView: View {
}
.padding(.bottom)
}
QRCode(uri: connReqInvitation)
.padding(.bottom)
if connReqInvitation != "" {
QRCode(uri: connReqInvitation).padding(.bottom)
} else {
ProgressView()
.progressViewStyle(.circular)
.scaleEffect(2)
.frame(maxWidth: .infinity)
.padding(.vertical)
}
Text("If you can't meet in person, **show QR code in the video call**, or share the link.")
.padding(.bottom)
Button {
@@ -47,7 +57,7 @@ struct AddContactView: View {
.frame(maxWidth: .infinity, alignment: .center)
}
.padding()
.frame(maxHeight: .infinity, alignment: .top)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
}
}

View File

@@ -0,0 +1,42 @@
//
// ConnectViaLinkView.swift
// SimpleX (iOS)
//
// Created by Evgeny on 21/09/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
enum ConnectViaLinkTab: String {
case scan
case paste
}
struct ConnectViaLinkView: View {
@State private var selection: ConnectViaLinkTab = connectViaLinkTabDefault.get()
var body: some View {
TabView(selection: $selection) {
ScanToConnectView()
.tabItem {
Label("Scan QR code", systemImage: "qrcode")
}
.tag(ConnectViaLinkTab.scan)
PasteToConnectView()
.tabItem {
Label("Paste received link", systemImage: "doc.plaintext")
}
.tag(ConnectViaLinkTab.paste)
}
.onChange(of: selection) { _ in
connectViaLinkTabDefault.set(selection)
}
}
}
struct ConnectViaLinkView_Previews: PreviewProvider {
static var previews: some View {
ConnectViaLinkView()
}
}

View File

@@ -0,0 +1,66 @@
//
// CreateLinkView.swift
// SimpleX (iOS)
//
// Created by Evgeny on 21/09/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
enum CreateLinkTab {
case oneTime
case longTerm
}
struct CreateLinkView: View {
@State var selection: CreateLinkTab
@State var connReqInvitation: String = ""
@State private var creatingConnReq = false
var viaSettings = false
var body: some View {
TabView(selection: $selection) {
AddContactView(connReqInvitation: connReqInvitation, viaSettings: viaSettings)
.tabItem {
Label(
connReqInvitation == ""
? "Create one-time invitation link"
: "One-time invitation link",
systemImage: "1.circle"
)
}
.tag(CreateLinkTab.oneTime)
UserAddress(viaSettings: viaSettings)
.tabItem {
Label("Your contact address", systemImage: "infinity.circle")
}
.tag(CreateLinkTab.longTerm)
}
.onChange(of: selection) { _ in
if case .oneTime = selection, connReqInvitation == "" && !creatingConnReq {
createInvitation()
}
}
}
private func createInvitation() {
creatingConnReq = true
Task {
let connReq = await apiAddContact()
await MainActor.run {
if let connReq = connReq {
connReqInvitation = connReq
} else {
creatingConnReq = false
}
}
}
}
}
struct CreateLinkView_Previews: PreviewProvider {
static var previews: some View {
CreateLinkView(selection: CreateLinkTab.oneTime)
}
}

View File

@@ -11,15 +11,13 @@ import SimpleXChat
enum NewChatAction: Identifiable {
case createLink(link: String)
case pasteLink
case scanQRCode
case connectViaLink
case createGroup
var id: String {
switch self {
case let .createLink(link): return "createLink \(link)"
case .pasteLink: return "pasteLink"
case .scanQRCode: return "scanQRCode"
case .connectViaLink: return "connectViaLink"
case .createGroup: return "createGroup"
}
}
@@ -36,17 +34,16 @@ struct NewChatButton: View {
.scaledToFit()
.frame(width: 24, height: 24)
}
.confirmationDialog("Add contact to start a new chat", isPresented: $showAddChat, titleVisibility: .visible) {
Button("Create link / QR code") { addContactAction() }
Button("Paste received link") { actionSheet = .pasteLink }
Button("Scan QR code") { actionSheet = .scanQRCode }
.confirmationDialog("Start a new chat", isPresented: $showAddChat, titleVisibility: .visible) {
Button("Share one-time invitation link") { addContactAction() }
Button("Connect via link / QR code") { actionSheet = .connectViaLink }
Button("Create secret group") { actionSheet = .createGroup }
}
.sheet(item: $actionSheet) { sheet in
switch sheet {
case let .createLink(link): AddContactView(connReqInvitation: link)
case .pasteLink: PasteToConnectView()
case .scanQRCode: ScanToConnectView()
case let .createLink(link):
CreateLinkView(selection: .oneTime, connReqInvitation: link)
case .connectViaLink: ConnectViaLinkView()
case .createGroup: AddGroupView()
}
}

View File

@@ -16,7 +16,8 @@ struct PasteToConnectView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Connect via link")
.font(.title)
.font(.largeTitle)
.bold()
.padding(.vertical)
Text("Paste the link you received into the box below to connect with your contact.")
.padding(.bottom, 4)
@@ -73,7 +74,7 @@ struct PasteToConnectView: View {
Text("You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button.")
}
.padding()
.frame(maxHeight: .infinity, alignment: .top)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
private func connect() {

View File

@@ -16,7 +16,8 @@ struct ScanToConnectView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Scan QR code")
.font(.title)
.font(.largeTitle)
.bold()
.padding(.vertical)
if (chatModel.incognito) {
HStack {
@@ -43,7 +44,7 @@ struct ScanToConnectView: View {
.padding(.bottom)
}
.padding()
.frame(maxHeight: .infinity, alignment: .top)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
func processQRCode(_ resp: Result<ScanResult, ScanError>) {

View File

@@ -33,6 +33,7 @@ let DEFAULT_ACCENT_COLOR_RED = "accentColorRed"
let DEFAULT_ACCENT_COLOR_GREEN = "accentColorGreen"
let DEFAULT_ACCENT_COLOR_BLUE = "accentColorBlue"
let DEFAULT_USER_INTERFACE_STYLE = "userInterfaceStyle"
let DEFAULT_CONNECT_VIA_LINK_TAB = "connectViaLinkTab"
let appDefaults: [String: Any] = [
DEFAULT_SHOW_LA_NOTICE: false,
@@ -49,6 +50,7 @@ let appDefaults: [String: Any] = [
DEFAULT_ACCENT_COLOR_GREEN: 0.533,
DEFAULT_ACCENT_COLOR_BLUE: 1.000,
DEFAULT_USER_INTERFACE_STYLE: 0,
DEFAULT_CONNECT_VIA_LINK_TAB: "scan"
]
private var indent: CGFloat = 36
@@ -59,6 +61,8 @@ let encryptionStartedDefault = BoolDefault(defaults: UserDefaults.standard, forK
let encryptionStartedAtDefault = DateDefault(defaults: UserDefaults.standard, forKey: DEFAULT_ENCRYPTION_STARTED_AT)
let connectViaLinkTabDefault = EnumDefault<ConnectViaLinkTab>(defaults: UserDefaults.standard, forKey: DEFAULT_CONNECT_VIA_LINK_TAB, withDefault: .scan)
func setGroupDefaults() {
privacyAcceptImagesGroupDefault.set(UserDefaults.standard.bool(forKey: DEFAULT_PRIVACY_ACCEPT_IMAGES))
}
@@ -89,8 +93,8 @@ struct SettingsView: View {
.disabled(chatModel.chatRunning != true)
NavigationLink {
UserAddress()
.navigationTitle("Your chat address")
CreateLinkView(selection: .longTerm, viaSettings: true)
.navigationBarTitleDisplayMode(.inline)
} label: {
settingsRow("qrcode") { Text("Your SimpleX contact address") }
}

View File

@@ -10,8 +10,9 @@ import SwiftUI
import SimpleXChat
struct UserAddress: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject private var chatModel: ChatModel
@State private var alert: UserAddressAlert?
var viaSettings = false
private enum UserAddressAlert: Identifiable {
case deleteAddress
@@ -28,6 +29,10 @@ struct UserAddress: View {
var body: some View {
ScrollView {
VStack (alignment: .leading) {
Text("Your contact address")
.font(.largeTitle)
.bold()
.padding(viaSettings ? .bottom : .vertical)
Text("You can share your address as a link or as a QR code - anybody will be able to connect to you. You won't lose your contacts if you later delete it.")
.padding(.bottom)
if let userAdress = chatModel.userAddress {
@@ -71,7 +76,7 @@ struct UserAddress: View {
}
}
.padding()
.frame(maxHeight: .infinity, alignment: .top)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.alert(item: $alert) { alert in
switch alert {
case .deleteAddress:

View File

@@ -233,11 +233,6 @@
<target>Accept incognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add contact to start a new chat" xml:space="preserve">
<source>Add contact to start a new chat</source>
<target>Add contact to start a new chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Advanced network settings" xml:space="preserve">
<source>Advanced network settings</source>
<target>Advanced network settings</target>
@@ -453,6 +448,11 @@
<target>Connect via link</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via link / QR code" xml:space="preserve">
<source>Connect via link / QR code</source>
<target>Connect via link / QR code</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via one-time link?" xml:space="preserve">
<source>Connect via one-time link?</source>
<target>Connect via one-time link?</target>
@@ -553,9 +553,9 @@
<target>Create address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create link / QR code" xml:space="preserve">
<source>Create link / QR code</source>
<target>Create link / QR code</target>
<trans-unit id="Create one-time invitation link" xml:space="preserve">
<source>Create one-time invitation link</source>
<target>Create one-time invitation link</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create secret group" xml:space="preserve">
@@ -1998,6 +1998,11 @@ We will be adding server redundancy to prevent lost messages.</target>
<target>Share link</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share one-time invitation link" xml:space="preserve">
<source>Share one-time invitation link</source>
<target>Share one-time invitation link</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>
@@ -2033,6 +2038,11 @@ We will be adding server redundancy to prevent lost messages.</target>
<target>Somebody</target>
<note>notification title</note>
</trans-unit>
<trans-unit id="Start a new chat" xml:space="preserve">
<source>Start a new chat</source>
<target>Start a new chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Start chat" xml:space="preserve">
<source>Start chat</source>
<target>Start chat</target>
@@ -2557,11 +2567,6 @@ To connect, please ask your contact to create another connection link and check
<target>Your calls</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat address" xml:space="preserve">
<source>Your chat address</source>
<target>Your chat address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat database" xml:space="preserve">
<source>Your chat database</source>
<target>Your chat database</target>
@@ -2592,6 +2597,11 @@ To connect, please ask your contact to create another connection link and check
<target>Your chats</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contact address" xml:space="preserve">
<source>Your contact address</source>
<target>Your contact address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contact can scan it from the app." xml:space="preserve">
<source>Your contact can scan it from the app.</source>
<target>Your contact can scan it from the app.</target>

View File

@@ -233,11 +233,6 @@
<target>Принять инкогнито</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Add contact to start a new chat" xml:space="preserve">
<source>Add contact to start a new chat</source>
<target>Добавьте контакт, чтобы начать разговор</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Advanced network settings" xml:space="preserve">
<source>Advanced network settings</source>
<target>Настройки сети</target>
@@ -453,6 +448,11 @@
<target>Соединиться через ссылку</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via link / QR code" xml:space="preserve">
<source>Connect via link / QR code</source>
<target>Соединиться через ссылку / QR код</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via one-time link?" xml:space="preserve">
<source>Connect via one-time link?</source>
<target>Соединиться через одноразовую ссылку?</target>
@@ -553,9 +553,9 @@
<target>Создать адрес</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create link / QR code" xml:space="preserve">
<source>Create link / QR code</source>
<target>Создать ссылку / QR код</target>
<trans-unit id="Create one-time invitation link" xml:space="preserve">
<source>Create one-time invitation link</source>
<target>Создать ссылку-приглашение</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create secret group" xml:space="preserve">
@@ -1998,6 +1998,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="Share one-time invitation link" xml:space="preserve">
<source>Share one-time invitation link</source>
<target>Поделиться ссылкой-приглашением</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
<source>Show preview</source>
<target>Показывать уведомления</target>
@@ -2033,6 +2038,11 @@ We will be adding server redundancy to prevent lost messages.</source>
<target>Контакт</target>
<note>notification title</note>
</trans-unit>
<trans-unit id="Start a new chat" xml:space="preserve">
<source>Start a new chat</source>
<target>Начать новый разговор</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Start chat" xml:space="preserve">
<source>Start chat</source>
<target>Запустить чат</target>
@@ -2557,11 +2567,6 @@ To connect, please ask your contact to create another connection link and check
<target>Ваши звонки</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat address" xml:space="preserve">
<source>Your chat address</source>
<target>Ваш SimpleX адрес</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat database" xml:space="preserve">
<source>Your chat database</source>
<target>База данных</target>
@@ -2592,6 +2597,11 @@ To connect, please ask your contact to create another connection link and check
<target>Ваши чаты</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contact address" xml:space="preserve">
<source>Your contact address</source>
<target>Ваш SimpleX адрес</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contact can scan it from the app." xml:space="preserve">
<source>Your contact can scan it from the app.</source>
<target>Ваш контакт может сосканировать QR код в приложении</target>

View File

@@ -78,6 +78,8 @@
5CB0BA92282713FD00B3292C /* CreateProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB0BA91282713FD00B3292C /* CreateProfile.swift */; };
5CB0BA9A2827FD8800B3292C /* HowItWorks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB0BA992827FD8800B3292C /* HowItWorks.swift */; };
5CB2084F28DA4B4800D024EC /* RTCServers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB2084E28DA4B4800D024EC /* RTCServers.swift */; };
5CB2085128DB64CA00D024EC /* CreateLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB2085028DB64CA00D024EC /* CreateLinkView.swift */; };
5CB2085328DB7CAF00D024EC /* ConnectViaLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB2085228DB7CAF00D024EC /* ConnectViaLinkView.swift */; };
5CB346E52868AA7F001FD2EF /* SuspendChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB346E42868AA7F001FD2EF /* SuspendChat.swift */; };
5CB346E72868D76D001FD2EF /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB346E62868D76D001FD2EF /* NotificationsView.swift */; };
5CB346E92869E8BA001FD2EF /* PushEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB346E82869E8BA001FD2EF /* PushEnvironment.swift */; };
@@ -271,6 +273,8 @@
5CB0BA91282713FD00B3292C /* CreateProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateProfile.swift; sourceTree = "<group>"; };
5CB0BA992827FD8800B3292C /* HowItWorks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HowItWorks.swift; sourceTree = "<group>"; };
5CB2084E28DA4B4800D024EC /* RTCServers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RTCServers.swift; sourceTree = "<group>"; };
5CB2085028DB64CA00D024EC /* CreateLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateLinkView.swift; sourceTree = "<group>"; };
5CB2085228DB7CAF00D024EC /* ConnectViaLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectViaLinkView.swift; sourceTree = "<group>"; };
5CB346E42868AA7F001FD2EF /* SuspendChat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuspendChat.swift; sourceTree = "<group>"; };
5CB346E62868D76D001FD2EF /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
5CB346E82869E8BA001FD2EF /* PushEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushEnvironment.swift; sourceTree = "<group>"; };
@@ -541,6 +545,8 @@
3C8C548828133C84000A3EC7 /* PasteToConnectView.swift */,
5CC1C99127A6C7F5000D9FF6 /* QRCode.swift */,
6442E0B9287F169300CEC0F9 /* AddGroupView.swift */,
5CB2085028DB64CA00D024EC /* CreateLinkView.swift */,
5CB2085228DB7CAF00D024EC /* ConnectViaLinkView.swift */,
);
path = NewChat;
sourceTree = "<group>";
@@ -894,6 +900,7 @@
5CB0BA8E2827126500B3292C /* OnboardingView.swift in Sources */,
6442E0BE2880182D00CEC0F9 /* GroupChatInfoView.swift in Sources */,
5C2E261227A30FEA00F70299 /* TerminalView.swift in Sources */,
5CB2085128DB64CA00D024EC /* CreateLinkView.swift in Sources */,
5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */,
64E972072881BB22008DBC02 /* CIGroupInvitationView.swift in Sources */,
5CC1C99227A6C7F5000D9FF6 /* QRCode.swift in Sources */,
@@ -945,6 +952,7 @@
5C029EA82837DBB3004A9677 /* CICallItemView.swift in Sources */,
5CE4407227ADB1D0007B033A /* Emoji.swift in Sources */,
5C3F1D5A2844B4DE00EC8A82 /* ExperimentalFeaturesView.swift in Sources */,
5CB2085328DB7CAF00D024EC /* ConnectViaLinkView.swift in Sources */,
5C9CC7A928C532AB00BEF955 /* DatabaseErrorView.swift in Sources */,
5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */,
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */,

View File

@@ -152,9 +152,6 @@
/* call status */
"accepted call" = " принятый звонок";
/* No comment provided by engineer. */
"Add contact to start a new chat" = "Добавьте контакт, чтобы начать разговор";
/* No comment provided by engineer. */
"admin" = "админ";
@@ -317,6 +314,9 @@
/* No comment provided by engineer. */
"Connect via link" = "Соединиться через ссылку";
/* No comment provided by engineer. */
"Connect via link / QR code" = "Соединиться через ссылку / QR код";
/* No comment provided by engineer. */
"Connect via one-time link?" = "Соединиться через одноразовую ссылку?";
@@ -414,7 +414,7 @@
"Create address" = "Создать адрес";
/* No comment provided by engineer. */
"Create link / QR code" = "Создать ссылку / QR код";
"Create one-time invitation link" = "Создать ссылку-приглашение";
/* No comment provided by engineer. */
"Create secret group" = "Создать скрытую группу";
@@ -1382,6 +1382,9 @@
/* No comment provided by engineer. */
"Share link" = "Поделиться ссылкой";
/* No comment provided by engineer. */
"Share one-time invitation link" = "Поделиться ссылкой-приглашением";
/* No comment provided by engineer. */
"Show preview" = "Показывать уведомления";
@@ -1409,6 +1412,9 @@
/* notification title */
"Somebody" = "Контакт";
/* No comment provided by engineer. */
"Start a new chat" = "Начать новый разговор";
/* No comment provided by engineer. */
"Start chat" = "Запустить чат";
@@ -1769,9 +1775,6 @@
/* No comment provided by engineer. */
"Your calls" = "Ваши звонки";
/* No comment provided by engineer. */
"Your chat address" = "Ваш SimpleX адрес";
/* No comment provided by engineer. */
"Your chat database" = "База данных";
@@ -1790,6 +1793,9 @@
/* No comment provided by engineer. */
"Your chats" = "Ваши чаты";
/* No comment provided by engineer. */
"Your contact address" = "Ваш SimpleX адрес";
/* No comment provided by engineer. */
"Your contact can scan it from the app." = "Ваш контакт может сосканировать QR код в приложении";