diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 8cf8830ad..955e68941 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -15,6 +15,7 @@ struct ChatListView: View { @State private var searchMode = false @FocusState private var searchFocussed @State private var searchText = "" + @State private var searchShowingSimplexLink = false @State private var newChatMenuOption: NewChatMenuOption? = nil @State private var userPickerVisible = false @State private var showConnectDesktop = false @@ -145,9 +146,14 @@ struct ChatListView: View { VStack { List { if !chatModel.chats.isEmpty { - ChatListSearchBar(searchMode: $searchMode, searchFocussed: $searchFocussed, searchText: $searchText) - .listRowSeparator(.hidden) - .frame(maxWidth: .infinity) + ChatListSearchBar( + searchMode: $searchMode, + searchFocussed: $searchFocussed, + searchText: $searchText, + searchShowingSimplexLink: $searchShowingSimplexLink + ) + .listRowSeparator(.hidden) + .frame(maxWidth: .infinity) } ForEach(cs, id: \.viewId) { chat in ChatListNavLink(chat: chat) @@ -221,7 +227,7 @@ struct ChatListView: View { private func filteredChats() -> [Chat] { let s = searchText.trimmingCharacters(in: .whitespaces).localizedLowercase - return s == "" && !showUnreadAndFavorites + return (s == "" && !showUnreadAndFavorites || searchShowingSimplexLink) ? chatModel.chats : chatModel.chats.filter { chat in let cInfo = chat.chatInfo @@ -260,6 +266,7 @@ struct ChatListSearchBar: View { @Binding var searchMode: Bool @FocusState.Binding var searchFocussed: Bool @Binding var searchText: String + @Binding var searchShowingSimplexLink: Bool @State private var cancelVisible = false @State private var pasteboardHasString = false @State private var showScanCodeSheet = false @@ -272,11 +279,10 @@ struct ChatListSearchBar: View { HStack(spacing: 4) { Image(systemName: "magnifyingglass") TextField("Search or paste SimpleX link", text: $searchText) - .truncationMode(.middle) .focused($searchFocussed) .foregroundColor(.primary) .frame(maxWidth: .infinity) - if searchMode { + if searchMode || searchShowingSimplexLink { Image(systemName: "xmark.circle.fill") .opacity(searchText == "" ? 0 : 1) .onTapGesture { @@ -328,7 +334,7 @@ struct ChatListSearchBar: View { .onChange(of: searchFocussed) { sf in if sf { withAnimation { searchMode = true } - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { withAnimation { cancelVisible = true } } } else { @@ -339,12 +345,16 @@ struct ChatListSearchBar: View { } } .onChange(of: searchText) { t in - let link = t.trimmingCharacters(in: .whitespaces) - if strIsSimplexLink(link) { // if SimpleX link is pasted, show connection dialogue + if let link = strHasSingleSimplexLink(t.trimmingCharacters(in: .whitespaces)) { // if SimpleX link is pasted, show connection dialogue searchFocussed = false - connect(link) - } else if t != "" { // if some other text is pasted, enter search mode - searchFocussed = true + searchText = link.text + searchShowingSimplexLink = true + connect(link.text) + } else { + if t != "" { // if some other text is pasted, enter search mode + searchFocussed = true + } + searchShowingSimplexLink = false } } .alert(item: $alert) { a in diff --git a/apps/ios/Shared/Views/NewChat/NewChatView.swift b/apps/ios/Shared/Views/NewChat/NewChatView.swift index 92562766f..ef48e1e65 100644 --- a/apps/ios/Shared/Views/NewChat/NewChatView.swift +++ b/apps/ios/Shared/Views/NewChat/NewChatView.swift @@ -330,9 +330,8 @@ private struct ConnectView: View { if pastedLink == "" { Button { if let str = UIPasteboard.general.string { - let link = str.trimmingCharacters(in: .whitespaces) - if strIsSimplexLink(link) { - pastedLink = link + if let link = strHasSingleSimplexLink(str.trimmingCharacters(in: .whitespaces)) { + pastedLink = link.text // It would be good to hide it, but right now it is not clear how to release camera in CodeScanner // https://github.com/twostraws/CodeScanner/issues/121 // No known tricks worked (changing view ID, wrapping it in another view, etc.) @@ -350,7 +349,14 @@ private struct ConnectView: View { } .frame(maxWidth: .infinity, alignment: .center) } else { - linkTextView(pastedLink) + HStack { + linkTextView(pastedLink) + Button { + pastedLink = "" + } label: { + Image(systemName: "xmark.circle") + } + } } } @@ -406,7 +412,7 @@ private struct ConnectView: View { switch resp { case let .success(r): let link = r.string - if strIsSimplexLink(link) { + if strIsSimplexLink(r.string) { connect(link) } else { alert = .newChatSomeAlert(alert: .someAlert( @@ -470,6 +476,19 @@ func strIsSimplexLink(_ str: String) -> Bool { } } +func strHasSingleSimplexLink(_ str: String) -> FormattedText? { + if let parsedMd = parseSimpleXMarkdown(str) { + let parsedLinks = parsedMd.filter({ $0.format?.isSimplexLink ?? false }) + if parsedLinks.count == 1 { + return parsedLinks[0] + } else { + return nil + } + } else { + return nil + } +} + struct IncognitoToggle: View { @Binding var incognitoEnabled: Bool @State private var showIncognitoSheet = false diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index dc4cdda46..4f82382b3 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -3120,6 +3120,15 @@ public enum Format: Decodable, Equatable { case simplexLink(linkType: SimplexLinkType, simplexUri: String, smpHosts: [String]) case email case phone + + public var isSimplexLink: Bool { + get { + switch (self) { + case .simplexLink: return true + default: return false + } + } + } } public enum SimplexLinkType: String, Decodable {