diff --git a/apps/ios/Shared/Model/AppAPITypes.swift b/apps/ios/Shared/Model/AppAPITypes.swift index 9b3a5b2511..71faebe9b1 100644 --- a/apps/ios/Shared/Model/AppAPITypes.swift +++ b/apps/ios/Shared/Model/AppAPITypes.swift @@ -1198,6 +1198,21 @@ enum ChatResponse2: Decodable, ChatAPIResult { case let .archiveExported(archiveErrors): return String(describing: archiveErrors) case let .archiveImported(archiveErrors): return String(describing: archiveErrors) case let .appSettings(appSettings): return String(describing: appSettings) + case let .nameStatus(u, nameHasWallet, nameKeySaved, nameAnySeed): return withUser(u, "nameHasWallet: \(nameHasWallet)\nnameKeySaved: \(nameKeySaved)\nnameAnySeed: \(nameAnySeed)") + case let .nameAddress(u, nameAddress, nameAccount, nameMetaAddress): return withUser(u, "nameAddress: \(nameAddress)\nnameAccount: \(nameAccount)\nnameMetaAddress: \(nameMetaAddress)") + case let .namesOwned(u, ownedNames): return withUser(u, String(describing: ownedNames)) + case let .nameQuoted(u, nameLabel, nameAvailable, namePriceCents): return withUser(u, "nameLabel: \(nameLabel)\nnameAvailable: \(nameAvailable)\nnamePriceCents: \(namePriceCents)") + case let .nameRegistered(u, nameFqdn, nameTxHash): return withUser(u, "nameFqdn: \(nameFqdn)\nnameTxHash: \(nameTxHash)") + case let .nameInfo(u, nameFqdn, nameOwner, nameContact, nameChannel, nameExpires, nameEditCredits): return withUser(u, "nameFqdn: \(nameFqdn)\nnameOwner: \(nameOwner)\nnameContact: \(nameContact)\nnameChannel: \(nameChannel)\nnameExpires: \(nameExpires)\nnameEditCredits: \(nameEditCredits)") + case let .nameIntentRelayed(u, nameAction, nameFqdn, nameTxHash): return withUser(u, "nameAction: \(nameAction)\nnameFqdn: \(nameFqdn)\nnameTxHash: \(nameTxHash)") + case let .nameGifted(u, nameFqdn, nameTxHash, nameEphemeralPubKey): return withUser(u, "nameFqdn: \(nameFqdn)\nnameTxHash: \(nameTxHash)\nnameEphemeralPubKey: \(nameEphemeralPubKey)") + case let .nameRenewed(u, nameFqdn, nameExpires, nameReRegistered): return withUser(u, "nameFqdn: \(nameFqdn)\nnameExpires: \(nameExpires)\nnameReRegistered: \(nameReRegistered)") + case let .namesIncoming(u, incomingNames): return withUser(u, String(describing: incomingNames)) + case let .nameAccepted(u, nameOneTimeAddr, acceptedNames): return withUser(u, "nameOneTimeAddr: \(nameOneTimeAddr)\nacceptedNames: \(acceptedNames)") + case let .nameDeclined(u, nameOneTimeAddr): return withUser(u, "nameOneTimeAddr: \(nameOneTimeAddr)") + case let .nameKeyExported(u, nameOneTimeAddr, nameOneTimeKey): return withUser(u, "nameOneTimeAddr: \(nameOneTimeAddr)\nnameOneTimeKey: \(nameOneTimeKey)") + case let .nameRescanned(u, rescanFound): return withUser(u, "rescanFound: \(rescanFound)") + case let .nameRecoveryKey(u, _, recoveryKeySaved): return withUser(u, "recoveryPhrase: ***\nrecoveryKeySaved: \(recoveryKeySaved)") } } } diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 9b82c81943..95cf6d75de 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -2660,7 +2660,7 @@ func processReceivedMsg(_ res: ChatEvent) async { } // A name arriving is the one incoming event with no other // signal, so the settings badge is bumped on arrival. - if case .sndReceived = cItem.meta.itemStatus {} else if case .rcvNew = cItem.meta.itemStatus, case .assetTransfer = cItem.content.msgContent { + if !cItem.chatDir.sent, case .assetTransfer = cItem.content.msgContent { m.namesWaiting += 1 } if !active(user) && cItem.isRcvNew && cInfo.ntfsEnabled(chatItem: cItem) { diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index 54f8597ffc..c85bad4238 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -1616,6 +1616,8 @@ struct ComposeView: View { case let .chat(_, chatLink, ownerSig): let text = msgText.isEmpty ? chatLink.connLinkStr : msgText + "\n" + chatLink.connLinkStr return .chat(text: text, chatLink: chatLink, ownerSig: ownerSig) + case .assetTransfer: + return msgContent case .unknown(let type, _): return .unknown(type: type, text: msgText) } diff --git a/apps/ios/Shared/Views/UserSettings/SimplexNames/BuyNameView.swift b/apps/ios/Shared/Views/UserSettings/SimplexNames/BuyNameView.swift index 6898f0aebd..eb22c1ac3b 100644 --- a/apps/ios/Shared/Views/UserSettings/SimplexNames/BuyNameView.swift +++ b/apps/ios/Shared/Views/UserSettings/SimplexNames/BuyNameView.swift @@ -13,7 +13,7 @@ struct BuyNameView: View { @State private var pointAtMe = true private var myLink: String? { - ChatModel.shared.userAddress?.connLinkContact.simplexChatUri + ChatModel.shared.userAddress?.connLinkContact.simplexChatUri() } private var validLabel: Bool { let l = label.trimmingCharacters(in: .whitespaces).lowercased() @@ -22,7 +22,7 @@ struct BuyNameView: View { var body: some View { List { - Section("Choose a name") { + Section { HStack { TextField("yourname", text: $label) .autocorrectionDisabled() @@ -30,12 +30,16 @@ struct BuyNameView: View { Text(".simplex").foregroundColor(.secondary) statusIcon } + } header: { + Text("Choose a name") } footer: { statusFooter } - Section("How long") { + Section { Stepper(value: $years, in: 1...10) { Text(years == 1 ? "1 year" : "\(years) years") } + } header: { + Text("How long") } footer: { Text("You pay once for the whole period. Nothing renews automatically, and the app will not remind you — note the end date.") } @@ -108,7 +112,7 @@ struct BuyNameView: View { Task { buying = true defer { buying = false } - let key = "buy:\(ChatModel.shared.remoteHostId ?? -1):\(l):\(years)" + let key = "buy:\(l):\(years)" guard let token = NamePayment.purchaseFor(key, years: years) else { return } let link = pointAtMe ? myLink : nil if let fqdn = await apiNameBuy(l, years: years, payment: token, link: link) { diff --git a/apps/ios/Shared/Views/UserSettings/SimplexNames/GiveNameView.swift b/apps/ios/Shared/Views/UserSettings/SimplexNames/GiveNameView.swift index 3c9d778bee..d4f6e96b51 100644 --- a/apps/ios/Shared/Views/UserSettings/SimplexNames/GiveNameView.swift +++ b/apps/ios/Shared/Views/UserSettings/SimplexNames/GiveNameView.swift @@ -16,14 +16,16 @@ struct GiveNameView: View { var body: some View { List { - Section("Give to") { + Section { if canReceive.isEmpty { Text("None of your contacts can receive a name yet.").foregroundColor(.secondary) } else { ForEach(canReceive) { ct in - Button(ct.profile.profileViewName) { confirm(ct) } + Button(ct.chatViewName) { confirm(ct) } } } + } header: { + Text("Give to") } footer: { if cannotReceive == 1 { Text("One of your contacts cannot receive names yet — they need a newer app version, or to turn receiving on.") } else if cannotReceive > 0 { Text(String.localizedStringWithFormat(NSLocalizedString("%d of your contacts cannot receive names yet — they need a newer app version, or to turn receiving on.", comment: ""), cannotReceive)) } @@ -35,14 +37,14 @@ struct GiveNameView: View { private func confirm(_ ct: Contact) { showAlert(NSLocalizedString("Give the name away?", comment: "alert"), - message: String.localizedStringWithFormat(NSLocalizedString("%1$@ will belong to %2$@. Only they will be able to change or move it after this.", comment: "alert"), fqdn, ct.profile.profileViewName), + message: String.localizedStringWithFormat(NSLocalizedString("%1$@ will belong to %2$@. Only they will be able to change or move it after this.", comment: "alert"), fqdn, ct.chatViewName), actions: {[ UIAlertAction(title: NSLocalizedString("Give it away", comment: ""), style: .destructive) { _ in Task { if await apiNameGift(label, recipient: "@\(ct.localDisplayName)") { if let u = try? await apiGetActiveUser() { await MainActor.run { ChatModel.shared.updateUser(u) } } await MainActor.run { - showAlert(NSLocalizedString("Name given away", comment: "alert"), message: String.localizedStringWithFormat(NSLocalizedString("%1$@ now belongs to %2$@. It appears under names given to them.", comment: "alert"), fqdn, ct.profile.profileViewName)) + showAlert(NSLocalizedString("Name given away", comment: "alert"), message: String.localizedStringWithFormat(NSLocalizedString("%1$@ now belongs to %2$@. It appears under names given to them.", comment: "alert"), fqdn, ct.chatViewName)) dismiss() } } diff --git a/apps/ios/Shared/Views/UserSettings/SimplexNames/ImportRecoveryKeyView.swift b/apps/ios/Shared/Views/UserSettings/SimplexNames/ImportRecoveryKeyView.swift index 022a99da51..2bbc4df12e 100644 --- a/apps/ios/Shared/Views/UserSettings/SimplexNames/ImportRecoveryKeyView.swift +++ b/apps/ios/Shared/Views/UserSettings/SimplexNames/ImportRecoveryKeyView.swift @@ -17,9 +17,16 @@ struct ImportRecoveryKeyView: View { if hasWallet == true { Section { Text("This profile already has a recovery key, so you cannot import a different one here. To use another key, set up a new profile and import it there.").foregroundColor(.secondary) } } else { - Section("Recovery key") { - TextField("your recovery words, separated by spaces", text: $phrase, axis: .vertical) - .disabled(working) + Section { + if #available(iOS 16.0, *) { + TextField("your recovery words, separated by spaces", text: $phrase, axis: .vertical) + .disabled(working) + } else { + TextField("your recovery words, separated by spaces", text: $phrase) + .disabled(working) + } + } header: { + Text("Recovery key") } footer: { if phrase.isEmpty { Text("Enter the words in the order they were shown to you.") } else if words.count == 1 { Text("1 word entered — a recovery key has 12, 15, 18, 21 or 24.").foregroundColor(looksComplete ? .secondary : .orange) } diff --git a/apps/ios/Shared/Views/UserSettings/SimplexNames/IncomingNamesView.swift b/apps/ios/Shared/Views/UserSettings/SimplexNames/IncomingNamesView.swift index eafa6a684c..e594242346 100644 --- a/apps/ios/Shared/Views/UserSettings/SimplexNames/IncomingNamesView.swift +++ b/apps/ios/Shared/Views/UserSettings/SimplexNames/IncomingNamesView.swift @@ -24,7 +24,7 @@ struct IncomingNamesView: View { Text("Your profile already carries everything your contacts need to send you a name — there is nothing to set up. Anything sent to you appears here, and nothing is added to your profile until you accept it.") } } else { - Section("Waiting for your decision") { + Section { ForEach(incoming, id: \.inAddress) { item in VStack(alignment: .leading, spacing: 8) { Text(item.inNames.joined(separator: ", ")).fontWeight(.medium) @@ -34,6 +34,8 @@ struct IncomingNamesView: View { } } } + } header: { + Text("Waiting for your decision") } footer: { Text("Accepting adds the name to your names. Declining removes it from this list and tells no one.") } diff --git a/apps/ios/Shared/Views/UserSettings/SimplexNames/NameDetailView.swift b/apps/ios/Shared/Views/UserSettings/SimplexNames/NameDetailView.swift index df2efa0371..e5ed47f566 100644 --- a/apps/ios/Shared/Views/UserSettings/SimplexNames/NameDetailView.swift +++ b/apps/ios/Shared/Views/UserSettings/SimplexNames/NameDetailView.swift @@ -8,7 +8,7 @@ struct NameDetailView: View { @State private var loadFailed = false @State private var busy = false - private var myLink: String? { ChatModel.shared.userAddress?.connLinkContact.simplexChatUri } + private var myLink: String? { ChatModel.shared.userAddress?.connLinkContact.simplexChatUri() } var body: some View { List { @@ -27,9 +27,11 @@ struct NameDetailView: View { Text("This name points at this profile.").foregroundColor(.green) } } - Section("How long you have it") { + Section { HStack { Text("Expires"); Spacer(); Text(expiryText(expires)).foregroundColor(expiryColor(expires)) } HStack { Text("Changes left"); Spacer(); Text("\(credits)").foregroundColor(.secondary) } + } header: { + Text("How long you have it") } footer: { Text("Pointing this name somewhere new uses one change. Extending the name adds 10 more.\nNothing renews automatically. After it expires, anyone can take the name.") } @@ -70,7 +72,7 @@ struct NameDetailView: View { UIAlertAction(title: NSLocalizedString("Extend this name", comment: ""), style: .default) { _ in Task { busy = true; defer { busy = false } - let key = "renew:\(ChatModel.shared.remoteHostId ?? -1):\(fqdn)" + let key = "renew:\(fqdn)" guard let token = NamePayment.purchaseFor(key, years: 1) else { return } if let r = await apiNameRenew(fqdn, years: 1, payment: token) { NamePayment.spent(key); await reload() @@ -84,6 +86,47 @@ struct NameDetailView: View { ]}) } + // The app sends no expiry notifications, so the only reminder that will + // actually reach the user is one in their own calendar. Sharing an .ics + // needs no calendar access: the user's calendar app asks before adding it, + // as the prefilled intent does on Android. The alarm is a week early - + // extending needs a purchase, so the day itself is too late to act. + private func addExpiryReminder(_ e: Int) { + let day = DateFormatter() + day.dateFormat = "yyyyMMdd" + day.timeZone = TimeZone(secondsFromGMT: 0) + let stamp = DateFormatter() + stamp.dateFormat = "yyyyMMdd'T'HHmmss'Z'" + stamp.timeZone = TimeZone(secondsFromGMT: 0) + let expires = Date(timeIntervalSince1970: TimeInterval(e)) + let ics = """ + BEGIN:VCALENDAR + VERSION:2.0 + PRODID:-//SimpleX Chat//names//EN + BEGIN:VEVENT + UID:name-\(fqdn)-\(e)@simplex.chat + DTSTAMP:\(stamp.string(from: Date())) + DTSTART;VALUE=DATE:\(day.string(from: expires)) + DTEND;VALUE=DATE:\(day.string(from: expires.addingTimeInterval(86400))) + SUMMARY:\(String.localizedStringWithFormat(NSLocalizedString("SimpleX name %@ expires", comment: "calendar reminder"), fqdn)) + DESCRIPTION:\(NSLocalizedString("Extend it in SimpleX to keep it. You have 90 days after it expires; after that anyone can take it.", comment: "calendar reminder")) + BEGIN:VALARM + TRIGGER:-P7D + ACTION:DISPLAY + DESCRIPTION:\(String.localizedStringWithFormat(NSLocalizedString("SimpleX name %@ expires", comment: "calendar reminder"), fqdn)) + END:VALARM + END:VEVENT + END:VCALENDAR + """ + let url = getTempFilesDirectory().appendingPathComponent("\(fqdn).ics") + do { + try ics.write(to: url, atomically: true, encoding: .utf8) + showShareSheet(items: [url]) + } catch { + showAlert(NSLocalizedString("No calendar app to add a reminder to.", comment: "alert")) + } + } + private func expiryDays(_ e: Int) -> Int { Int(floor(Double(Int64(e) - Int64(Date().timeIntervalSince1970)) / 86400)) } private func expiryText(_ e: Int) -> String { let d = expiryDays(e) diff --git a/apps/ios/Shared/Views/UserSettings/SimplexNames/NameRecoveryKeyView.swift b/apps/ios/Shared/Views/UserSettings/SimplexNames/NameRecoveryKeyView.swift index f5a0adfb55..5c9b5d5166 100644 --- a/apps/ios/Shared/Views/UserSettings/SimplexNames/NameRecoveryKeyView.swift +++ b/apps/ios/Shared/Views/UserSettings/SimplexNames/NameRecoveryKeyView.swift @@ -23,9 +23,11 @@ struct NameRecoveryKeyView: View { Button { revealed = true } label: { Label("Show recovery key", systemImage: "eye").foregroundColor(.accentColor) } } footer: { Text("Make sure no one can see your screen.") } } else { - Section("Your recovery key") { + Section { Text(phrase!).font(.body.monospaced()).fontWeight(.medium) Button("Copy") { UIPasteboard.general.string = phrase }.foregroundColor(.accentColor) + } header: { + Text("Your recovery key") } footer: { Text("Write these words down and keep them somewhere safe and offline. Anyone who takes a photo of this screen can take your names.") } diff --git a/apps/ios/Shared/Views/UserSettings/SimplexNames/SimplexNamesView.swift b/apps/ios/Shared/Views/UserSettings/SimplexNames/SimplexNamesView.swift index 6d965f5288..28e10aab23 100644 --- a/apps/ios/Shared/Views/UserSettings/SimplexNames/SimplexNamesView.swift +++ b/apps/ios/Shared/Views/UserSettings/SimplexNames/SimplexNamesView.swift @@ -13,7 +13,7 @@ struct SimplexNamesView: View { var body: some View { List { - Section(NSLocalizedString("Your names", comment: "section")) { + Section { if loadFailed { Text("Could not load your names. Check your connection and reopen this screen.") .foregroundColor(.orange) @@ -37,6 +37,8 @@ struct SimplexNamesView: View { } } } + } header: { + Text(NSLocalizedString("Your names", comment: "section")) } footer: { Text("A SimpleX name lets people find you without sharing a link. If you save your recovery key, you can point the name at a new profile after losing this device.") } diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 0f7dab1eba..da34df4c22 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -97,6 +97,15 @@ 5CB634AD29E46CF70066AD6B /* LocalAuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB634AC29E46CF70066AD6B /* LocalAuthView.swift */; }; 5CB634AF29E4BB7D0066AD6B /* SetAppPasscodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB634AE29E4BB7D0066AD6B /* SetAppPasscodeView.swift */; }; 5CB634B129E5EFEA0066AD6B /* PasscodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB634B029E5EFEA0066AD6B /* PasscodeView.swift */; }; + 64F1A0000000000000000102 /* SimplexNamesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1A0000000000000000101 /* SimplexNamesView.swift */; }; + 64F1A0000000000000000104 /* BuyNameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1A0000000000000000103 /* BuyNameView.swift */; }; + 64F1A0000000000000000106 /* NameDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1A0000000000000000105 /* NameDetailView.swift */; }; + 64F1A0000000000000000108 /* GiveNameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1A0000000000000000107 /* GiveNameView.swift */; }; + 64F1A000000000000000010A /* IncomingNamesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1A0000000000000000109 /* IncomingNamesView.swift */; }; + 64F1A000000000000000010C /* NameRecoveryKeyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1A000000000000000010B /* NameRecoveryKeyView.swift */; }; + 64F1A000000000000000010E /* ImportRecoveryKeyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1A000000000000000010D /* ImportRecoveryKeyView.swift */; }; + 64F1A0000000000000000110 /* WalletSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1A000000000000000010F /* WalletSetupView.swift */; }; + 64F1A0000000000000000112 /* NamePayment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1A0000000000000000111 /* NamePayment.swift */; }; 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 */; }; @@ -183,8 +192,8 @@ 64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; }; 64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; }; 64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; }; - 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo-ghc9.6.3.a */; }; - 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo.a */; }; + 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-7.1.0.0-inplace-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.1.0.0-inplace-ghc9.6.3.a */; }; + 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-7.1.0.0-inplace.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.1.0.0-inplace.a */; }; 64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; }; 64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; }; 64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; }; @@ -472,6 +481,15 @@ 5CB634AC29E46CF70066AD6B /* LocalAuthView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthView.swift; sourceTree = ""; }; 5CB634AE29E4BB7D0066AD6B /* SetAppPasscodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetAppPasscodeView.swift; sourceTree = ""; }; 5CB634B029E5EFEA0066AD6B /* PasscodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasscodeView.swift; sourceTree = ""; }; + 64F1A0000000000000000101 /* SimplexNamesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplexNamesView.swift; sourceTree = ""; }; + 64F1A0000000000000000103 /* BuyNameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuyNameView.swift; sourceTree = ""; }; + 64F1A0000000000000000105 /* NameDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NameDetailView.swift; sourceTree = ""; }; + 64F1A0000000000000000107 /* GiveNameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GiveNameView.swift; sourceTree = ""; }; + 64F1A0000000000000000109 /* IncomingNamesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingNamesView.swift; sourceTree = ""; }; + 64F1A000000000000000010B /* NameRecoveryKeyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NameRecoveryKeyView.swift; sourceTree = ""; }; + 64F1A000000000000000010D /* ImportRecoveryKeyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportRecoveryKeyView.swift; sourceTree = ""; }; + 64F1A000000000000000010F /* WalletSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletSetupView.swift; sourceTree = ""; }; + 64F1A0000000000000000111 /* NamePayment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NamePayment.swift; sourceTree = ""; }; 5CB924D627A8563F00ACCCDD /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; wrapsLines = 0; }; 5CB924E027A867BA00ACCCDD /* UserProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfile.swift; sourceTree = ""; }; 5CB9250C27A9432000ACCCDD /* ChatListNavLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListNavLink.swift; sourceTree = ""; }; @@ -563,8 +581,8 @@ 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = ""; }; 64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; 64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo-ghc9.6.3.a"; sourceTree = ""; }; - 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo.a"; sourceTree = ""; }; + 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.1.0.0-inplace-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-7.1.0.0-inplace-ghc9.6.3.a"; sourceTree = ""; }; + 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.1.0.0-inplace.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-7.1.0.0-inplace.a"; sourceTree = ""; }; 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = ""; }; 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = ""; }; @@ -735,8 +753,8 @@ 64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */, 64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */, 64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */, - 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo-ghc9.6.3.a in Frameworks */, - 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo.a in Frameworks */, + 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-7.1.0.0-inplace-ghc9.6.3.a in Frameworks */, + 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-7.1.0.0-inplace.a in Frameworks */, CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -822,8 +840,8 @@ 64C829992D54AEEE006B9E89 /* libffi.a */, 64C829982D54AEED006B9E89 /* libgmp.a */, 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */, - 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo-ghc9.6.3.a */, - 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.11-SNj2VtVeH9ARktfFtATBo.a */, + 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.1.0.0-inplace-ghc9.6.3.a */, + 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.1.0.0-inplace.a */, ); path = Libraries; sourceTree = ""; @@ -1000,6 +1018,7 @@ 5CB924DF27A8678B00ACCCDD /* UserSettings */ = { isa = PBXGroup; children = ( + 64F1A0000000000000000113 /* SimplexNames */, 643B3B4C2CCFD34B0083A2CF /* NetworkAndServers */, 5CB924D627A8563F00ACCCDD /* SettingsView.swift */, 5CB346E62868D76D001FD2EF /* NotificationsView.swift */, @@ -1147,6 +1166,22 @@ path = Database; sourceTree = ""; }; + 64F1A0000000000000000113 /* SimplexNames */ = { + isa = PBXGroup; + children = ( + 64F1A0000000000000000101 /* SimplexNamesView.swift */, + 64F1A0000000000000000103 /* BuyNameView.swift */, + 64F1A0000000000000000105 /* NameDetailView.swift */, + 64F1A0000000000000000107 /* GiveNameView.swift */, + 64F1A0000000000000000109 /* IncomingNamesView.swift */, + 64F1A000000000000000010B /* NameRecoveryKeyView.swift */, + 64F1A000000000000000010D /* ImportRecoveryKeyView.swift */, + 64F1A000000000000000010F /* WalletSetupView.swift */, + 64F1A0000000000000000111 /* NamePayment.swift */, + ); + path = SimplexNames; + sourceTree = ""; + }; 643B3B4C2CCFD34B0083A2CF /* NetworkAndServers */ = { isa = PBXGroup; children = ( @@ -1516,6 +1551,15 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 64F1A0000000000000000102 /* SimplexNamesView.swift in Sources */, + 64F1A0000000000000000104 /* BuyNameView.swift in Sources */, + 64F1A0000000000000000106 /* NameDetailView.swift in Sources */, + 64F1A0000000000000000108 /* GiveNameView.swift in Sources */, + 64F1A000000000000000010A /* IncomingNamesView.swift in Sources */, + 64F1A000000000000000010C /* NameRecoveryKeyView.swift in Sources */, + 64F1A000000000000000010E /* ImportRecoveryKeyView.swift in Sources */, + 64F1A0000000000000000110 /* WalletSetupView.swift in Sources */, + 64F1A0000000000000000112 /* NamePayment.swift in Sources */, 64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */, 8CC317442D4FEB9B00292A20 /* EndlessScrollView.swift in Sources */, 640417CE2B29B8C200CCB412 /* NewChatView.swift in Sources */, diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 4a3b6ce705..6689336dd1 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -2200,7 +2200,7 @@ public enum GroupChatScopeInfo: Decodable, Hashable { public struct Contact: Identifiable, Decodable, NamedChat, Hashable { public var contactId: Int64 - var localDisplayName: ContactName + public var localDisplayName: ContactName public var profile: LocalProfile public var activeConn: Connection? public var viaGroup: Int64?