ios: connection plan improvements; remove browser mode for simplex links (#3237)

This commit is contained in:
spaced4ndy 2023-10-17 12:56:12 +04:00 committed by GitHub
parent 99c458406f
commit d8d47d706d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 88 additions and 39 deletions

View file

@ -292,10 +292,7 @@ struct ContentView: View {
var path = url.path
if (path == "/contact" || path == "/invitation") {
path.removeFirst()
// TODO normalize in backend; revert
// let link = url.absoluteString.replacingOccurrences(of: "///\(path)", with: "/\(path)")
var link = url.absoluteString.replacingOccurrences(of: "///\(path)", with: "/\(path)")
link = link.starts(with: "simplex:/") ? link.replacingOccurrences(of: "simplex:/", with: "https://simplex.chat/") : link
let link = url.absoluteString.replacingOccurrences(of: "///\(path)", with: "/\(path)")
planAndConnect(
link,
showAlert: showPlanAndConnectAlert,

View file

@ -168,9 +168,9 @@ struct ChatInfoView: View {
if let contactLink = contact.contactLink {
Section {
QRCode(uri: contactLink)
SimpleXLinkQRCode(uri: contactLink)
Button {
showShareSheet(items: [contactLink])
showShareSheet(items: [simplexChatLink(contactLink)])
} label: {
Label("Share address", systemImage: "square.and.arrow.up")
}

View file

@ -121,13 +121,11 @@ private func formatText(_ ft: FormattedText, _ preview: Bool) -> Text {
case .secret: return Text(t).foregroundColor(.clear).underline(color: .primary)
case let .colored(color): return Text(t).foregroundColor(color.uiColor)
case .uri: return linkText(t, t, preview, prefix: "")
case let .simplexLink(linkType, simplexUri, trustedUri, smpHosts):
case let .simplexLink(linkType, simplexUri, smpHosts):
switch privacySimplexLinkModeDefault.get() {
case .description: return linkText(simplexLinkText(linkType, smpHosts), simplexUri, preview, prefix: "")
case .full: return linkText(t, simplexUri, preview, prefix: "")
case .browser: return trustedUri
? linkText(t, t, preview, prefix: "")
: linkText(t, t, preview, prefix: "", color: .red, uiColor: .red)
case .browser: return linkText(t, simplexUri, preview, prefix: "")
}
case .email: return linkText(t, t, preview, prefix: "mailto:")
case .phone: return linkText(t, t.replacingOccurrences(of: " ", with: ""), preview, prefix: "tel:")

View file

@ -41,9 +41,9 @@ struct GroupLinkView: View {
}
}
.frame(height: 36)
QRCode(uri: groupLink)
SimpleXLinkQRCode(uri: groupLink)
Button {
showShareSheet(items: [groupLink])
showShareSheet(items: [simplexChatLink(groupLink)])
} label: {
Label("Share link", systemImage: "square.and.arrow.up")
}

View file

@ -94,9 +94,9 @@ struct GroupMemberInfoView: View {
if let contactLink = member.contactLink {
Section {
QRCode(uri: contactLink)
SimpleXLinkQRCode(uri: contactLink)
Button {
showShareSheet(items: [contactLink])
showShareSheet(items: [simplexChatLink(contactLink)])
} label: {
Label("Share address", systemImage: "square.and.arrow.up")
}

View file

@ -61,7 +61,7 @@ struct ContactConnectionInfo: View {
if contactConnection.initiated,
let connReqInv = contactConnection.connReqInv {
QRCode(uri: connReqInv)
SimpleXLinkQRCode(uri: simplexChatLink(connReqInv))
incognitoEnabled()
shareLinkButton(connReqInv)
oneTimeLinkLearnMoreButton()

View file

@ -21,7 +21,7 @@ struct AddContactView: View {
List {
Section {
if connReqInvitation != "" {
QRCode(uri: connReqInvitation)
SimpleXLinkQRCode(uri: connReqInvitation)
} else {
ProgressView()
.progressViewStyle(.circular)
@ -99,7 +99,7 @@ func sharedProfileInfo(_ incognito: Bool) -> Text {
func shareLinkButton(_ connReqInvitation: String) -> some View {
Button {
showShareSheet(items: [connReqInvitation])
showShareSheet(items: [simplexChatLink(connReqInvitation)])
} label: {
settingsRow("square.and.arrow.up") {
Text("Share 1-time link")

View file

@ -62,7 +62,9 @@ enum PlanAndConnectAlert: Identifiable {
case ownInvitationLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool)
case invitationLinkConnecting(connectionLink: String)
case ownContactAddressConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool)
case contactAddressConnectingConfirmReconnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool)
case groupLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool)
case groupLinkConnectingConfirmReconnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool)
case groupLinkConnecting(connectionLink: String, groupInfo: GroupInfo?)
var id: String {
@ -70,7 +72,9 @@ enum PlanAndConnectAlert: Identifiable {
case let .ownInvitationLinkConfirmConnect(connectionLink, _, _): return "ownInvitationLinkConfirmConnect \(connectionLink)"
case let .invitationLinkConnecting(connectionLink): return "invitationLinkConnecting \(connectionLink)"
case let .ownContactAddressConfirmConnect(connectionLink, _, _): return "ownContactAddressConfirmConnect \(connectionLink)"
case let .contactAddressConnectingConfirmReconnect(connectionLink, _, _): return "contactAddressConnectingConfirmReconnect \(connectionLink)"
case let .groupLinkConfirmConnect(connectionLink, _, _): return "groupLinkConfirmConnect \(connectionLink)"
case let .groupLinkConnectingConfirmReconnect(connectionLink, _, _): return "groupLinkConnectingConfirmReconnect \(connectionLink)"
case let .groupLinkConnecting(connectionLink, _): return "groupLinkConnecting \(connectionLink)"
}
}
@ -103,6 +107,16 @@ func planAndConnectAlert(_ alert: PlanAndConnectAlert, dismiss: Bool) -> Alert {
),
secondaryButton: .cancel()
)
case let .contactAddressConnectingConfirmReconnect(connectionLink, connectionPlan, incognito):
return Alert(
title: Text("Repeat connection request?"),
message: Text("You have already requested connection via this address!"),
primaryButton: .destructive(
Text(incognito ? "Connect incognito" : "Connect"),
action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito) }
),
secondaryButton: .cancel()
)
case let .groupLinkConfirmConnect(connectionLink, connectionPlan, incognito):
return Alert(
title: Text("Join group?"),
@ -113,6 +127,16 @@ func planAndConnectAlert(_ alert: PlanAndConnectAlert, dismiss: Bool) -> Alert {
),
secondaryButton: .cancel()
)
case let .groupLinkConnectingConfirmReconnect(connectionLink, connectionPlan, incognito):
return Alert(
title: Text("Repeat join request?"),
message: Text("You are already joining the group via this link!"),
primaryButton: .destructive(
Text(incognito ? "Join incognito" : "Join"),
action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito) }
),
secondaryButton: .cancel()
)
case let .groupLinkConnecting(_, groupInfo):
if let groupInfo = groupInfo {
return Alert(
@ -130,13 +154,13 @@ func planAndConnectAlert(_ alert: PlanAndConnectAlert, dismiss: Bool) -> Alert {
enum PlanAndConnectActionSheet: Identifiable {
case askCurrentOrIncognitoProfile(connectionLink: String, connectionPlan: ConnectionPlan?, title: LocalizedStringKey)
case ownLinkAskCurrentOrIncognitoProfile(connectionLink: String, connectionPlan: ConnectionPlan, title: LocalizedStringKey)
case askCurrentOrIncognitoProfileDestructive(connectionLink: String, connectionPlan: ConnectionPlan, title: LocalizedStringKey)
case ownGroupLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool?, groupInfo: GroupInfo)
var id: String {
switch self {
case let .askCurrentOrIncognitoProfile(connectionLink, _, _): return "askCurrentOrIncognitoProfile \(connectionLink)"
case let .ownLinkAskCurrentOrIncognitoProfile(connectionLink, _, _): return "ownLinkAskCurrentOrIncognitoProfile \(connectionLink)"
case let .askCurrentOrIncognitoProfileDestructive(connectionLink, _, _): return "askCurrentOrIncognitoProfileDestructive \(connectionLink)"
case let .ownGroupLinkConfirmConnect(connectionLink, _, _, _): return "ownGroupLinkConfirmConnect \(connectionLink)"
}
}
@ -153,7 +177,7 @@ func planAndConnectActionSheet(_ sheet: PlanAndConnectActionSheet, dismiss: Bool
.cancel()
]
)
case let .ownLinkAskCurrentOrIncognitoProfile(connectionLink, connectionPlan, title):
case let .askCurrentOrIncognitoProfileDestructive(connectionLink, connectionPlan, title):
return ActionSheet(
title: Text(title),
buttons: [
@ -211,7 +235,7 @@ func planAndConnect(
if let incognito = incognito {
showAlert(.ownInvitationLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito))
} else {
showActionSheet(.ownLinkAskCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect to yourself?\nThis is your own one-time link!"))
showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect to yourself?\nThis is your own one-time link!"))
}
case let .connecting(contact_):
logger.debug("planAndConnect, .invitationLink, .connecting, incognito=\(incognito?.description ?? "nil")")
@ -238,10 +262,17 @@ func planAndConnect(
if let incognito = incognito {
showAlert(.ownContactAddressConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito))
} else {
showActionSheet(.ownLinkAskCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect to yourself?\nThis is your own SimpleX address!"))
showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect to yourself?\nThis is your own SimpleX address!"))
}
case let .connecting(contact):
logger.debug("planAndConnect, .contactAddress, .connecting, incognito=\(incognito?.description ?? "nil")")
case .connectingConfirmReconnect:
logger.debug("planAndConnect, .contactAddress, .connectingConfirmReconnect, incognito=\(incognito?.description ?? "nil")")
if let incognito = incognito {
showAlert(.contactAddressConnectingConfirmReconnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito))
} else {
showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "You have already requested connection!\nRepeat connection request?"))
}
case let .connectingProhibit(contact):
logger.debug("planAndConnect, .contactAddress, .connectingProhibit, incognito=\(incognito?.description ?? "nil")")
openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyConnectingAlert(contact)) }
case let .known(contact):
logger.debug("planAndConnect, .contactAddress, .known, incognito=\(incognito?.description ?? "nil")")
@ -258,8 +289,15 @@ func planAndConnect(
case let .ownLink(groupInfo):
logger.debug("planAndConnect, .groupLink, .ownLink, incognito=\(incognito?.description ?? "nil")")
showActionSheet(.ownGroupLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito, groupInfo: groupInfo))
case let .connecting(groupInfo_):
logger.debug("planAndConnect, .groupLink, .connecting, incognito=\(incognito?.description ?? "nil")")
case .connectingConfirmReconnect:
logger.debug("planAndConnect, .groupLink, .connectingConfirmReconnect, incognito=\(incognito?.description ?? "nil")")
if let incognito = incognito {
showAlert(.groupLinkConnectingConfirmReconnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito))
} else {
showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "You are already joining the group!\nRepeat join request?"))
}
case let .connectingProhibit(groupInfo_):
logger.debug("planAndConnect, .groupLink, .connectingProhibit, incognito=\(incognito?.description ?? "nil")")
showAlert(.groupLinkConnecting(connectionLink: connectionLink, groupInfo: groupInfo_))
case let .known(groupInfo):
logger.debug("planAndConnect, .groupLink, .known, incognito=\(incognito?.description ?? "nil")")

View file

@ -28,6 +28,22 @@ struct MutableQRCode: View {
}
}
struct SimpleXLinkQRCode: View {
let uri: String
var withLogo: Bool = true
var tintColor = UIColor(red: 0.023, green: 0.176, blue: 0.337, alpha: 1)
var body: some View {
QRCode(uri: simplexChatLink(uri), withLogo: withLogo, tintColor: tintColor)
}
}
func simplexChatLink(_ uri: String) -> String {
uri.starts(with: "simplex:/")
? uri.replacingOccurrences(of: "simplex:/", with: "https://simplex.chat/")
: uri
}
struct QRCode: View {
let uri: String
var withLogo: Bool = true

View file

@ -31,7 +31,7 @@ struct CreateSimpleXAddress: View {
Spacer()
if let userAddress = m.userAddress {
QRCode(uri: userAddress.connReqContact)
SimpleXLinkQRCode(uri: userAddress.connReqContact)
.frame(maxHeight: g.size.width)
shareQRCodeButton(userAddress)
.frame(maxWidth: .infinity)
@ -126,7 +126,7 @@ struct CreateSimpleXAddress: View {
private func shareQRCodeButton(_ userAddress: UserContactLink) -> some View {
Button {
showShareSheet(items: [userAddress.connReqContact])
showShareSheet(items: [simplexChatLink(userAddress.connReqContact)])
} label: {
Label("Share", systemImage: "square.and.arrow.up")
}

View file

@ -93,7 +93,9 @@ struct PrivacySettings: View {
}
settingsRow("link") {
Picker("SimpleX links", selection: $simplexLinkMode) {
ForEach(SimpleXLinkMode.values) { mode in
ForEach(
SimpleXLinkMode.values + (SimpleXLinkMode.values.contains(simplexLinkMode) ? [] : [simplexLinkMode])
) { mode in
Text(mode.text)
}
}
@ -104,10 +106,6 @@ struct PrivacySettings: View {
}
} header: {
Text("Chats")
} footer: {
if case .browser = simplexLinkMode {
Text("Opening the link in the browser may reduce connection privacy and security. Untrusted SimpleX links will be red.")
}
}
Section {

View file

@ -93,7 +93,7 @@ enum SimpleXLinkMode: String, Identifiable {
case full
case browser
static var values: [SimpleXLinkMode] = [.description, .full, .browser]
static var values: [SimpleXLinkMode] = [.description, .full]
public var id: Self { self }

View file

@ -190,7 +190,7 @@ struct UserAddressView: View {
@ViewBuilder private func existingAddressView(_ userAddress: UserContactLink) -> some View {
Section {
MutableQRCode(uri: Binding.constant(userAddress.connReqContact))
MutableQRCode(uri: Binding.constant(simplexChatLink(userAddress.connReqContact)))
shareQRCodeButton(userAddress)
if MFMailComposeViewController.canSendMail() {
shareViaEmailButton(userAddress)
@ -248,7 +248,7 @@ struct UserAddressView: View {
private func shareQRCodeButton(_ userAddress: UserContactLink) -> some View {
Button {
showShareSheet(items: [userAddress.connReqContact])
showShareSheet(items: [simplexChatLink(userAddress.connReqContact)])
} label: {
settingsRow("square.and.arrow.up") {
Text("Share address")

View file

@ -886,14 +886,16 @@ public enum InvitationLinkPlan: Decodable {
public enum ContactAddressPlan: Decodable {
case ok
case ownLink
case connecting(contact: Contact)
case connectingConfirmReconnect
case connectingProhibit(contact: Contact)
case known(contact: Contact)
}
public enum GroupLinkPlan: Decodable {
case ok
case ownLink(groupInfo: GroupInfo)
case connecting(groupInfo_: GroupInfo?)
case connectingConfirmReconnect
case connectingProhibit(groupInfo_: GroupInfo?)
case known(groupInfo: GroupInfo)
}

View file

@ -3068,7 +3068,7 @@ public enum Format: Decodable, Equatable {
case secret
case colored(color: FormatColor)
case uri
case simplexLink(linkType: SimplexLinkType, simplexUri: String, trustedUri: Bool, smpHosts: [String])
case simplexLink(linkType: SimplexLinkType, simplexUri: String, smpHosts: [String])
case email
case phone
}