diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index b1c27c759a..4d6aa8e62e 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -201,6 +201,8 @@ func chatRecvMsg() throws -> ChatResponse { } func apiGetActiveUser() throws -> User? { + let _ = getChatCtrl() + sleep(1) let r = try chatSendCmd(.showActiveUser) switch r { case let .activeUser(user): return user diff --git a/apps/ios/Shared/MyPlayground.playground/Contents.swift b/apps/ios/Shared/MyPlayground.playground/Contents.swift index 1b54844630..991679a8b4 100644 --- a/apps/ios/Shared/MyPlayground.playground/Contents.swift +++ b/apps/ios/Shared/MyPlayground.playground/Contents.swift @@ -24,3 +24,7 @@ for match in matches { let url = input[range] print(url) } + +let r = try! NSRegularExpression(pattern: "^\\+?[0-9\\.\\(\\)\\-]{7,20}$") + +print(r.firstMatch(in: "+44(0)7448-736-790", options: [], range: NSRange(location: 0, length: "+44(0)7448-736-790".count)) == nil) diff --git a/apps/ios/Shared/MyPlayground.playground/timeline.xctimeline b/apps/ios/Shared/MyPlayground.playground/timeline.xctimeline index 522d23c91f..ad2411a0b9 100644 --- a/apps/ios/Shared/MyPlayground.playground/timeline.xctimeline +++ b/apps/ios/Shared/MyPlayground.playground/timeline.xctimeline @@ -3,7 +3,7 @@ version = "3.0"> diff --git a/apps/ios/Shared/Views/Chat/ChatItem/TextItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/TextItemView.swift index 43c0c399bc..78f875d0e1 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/TextItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/TextItemView.swift @@ -8,6 +8,10 @@ import SwiftUI +private let emailRegex = try! NSRegularExpression(pattern: "^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$", options: .caseInsensitive) + +private let phoneRegex = try! NSRegularExpression(pattern: "^\\+?[0-9\\.\\(\\)\\-]{7,20}$") + struct TextItemView: View { var chatItem: ChatItem var width: CGFloat @@ -17,22 +21,25 @@ struct TextItemView: View { let sent = chatItem.chatDir.sent let minWidth = min(200, width) let maxWidth = min(300, width * 0.78) - return VStack { - messageText(chatItem.content.text, sent: sent) - .padding(.top, 8) + let meta = getDateFormatter().string(from: chatItem.meta.itemTs) + + return ZStack(alignment: .bottomTrailing) { + (messageText(chatItem.content.text, sent: sent) + reserveSpaceForMeta(meta)) + .padding(.top, 6) + .padding(.bottom, 7) .padding(.horizontal, 12) .frame(minWidth: minWidth, maxWidth: maxWidth, alignment: .leading) .foregroundColor(sent ? .white : .primary) .textSelection(.enabled) - Text(getDateFormatter().string(from: chatItem.meta.itemTs)) + Text(meta) .font(.caption) - .foregroundColor(sent ? .white : .secondary) - .padding(.bottom, 8) + .foregroundColor(sent ? Color(uiColor: .secondarySystemBackground) : .secondary) + .padding(.bottom, 4) .padding(.horizontal, 12) - .frame(minWidth: minWidth, maxWidth: maxWidth, alignment: .trailing) + .frame(minWidth: minWidth, maxWidth: maxWidth, alignment: .bottomTrailing) } .background(sent ? .blue : Color(uiColor: .tertiarySystemGroupedBackground)) - .cornerRadius(10) + .cornerRadius(18) .padding(.horizontal) .frame( minWidth: 200, @@ -43,7 +50,7 @@ struct TextItemView: View { ) } - private func messageText(_ s: String, sent: Bool = false) -> Text { + private func messageText(_ s: String, sent: Bool) -> Text { if s == "" { return Text("") } let parts = s.split(separator: " ") var res = wordToText(parts[0], sent) @@ -55,14 +62,22 @@ struct TextItemView: View { return res } + private func reserveSpaceForMeta(_ meta: String) -> Text { + Text(AttributedString(" \(meta)", attributes: AttributeContainer([ + .font: UIFont.preferredFont(forTextStyle: .caption1) as Any, + .foregroundColor: UIColor.clear as Any, + ]))) + } + private func wordToText(_ s: String.SubSequence, _ sent: Bool) -> Text { + let str = String(s) switch true { case s.starts(with: "http://") || s.starts(with: "https://"): - let str = String(s) - return Text(AttributedString(str, attributes: AttributeContainer([ - .link: NSURL(string: str) as Any, - .foregroundColor: (sent ? UIColor.white : nil) as Any - ]))).underline() + return linkText(str, prefix: "", sent: sent) + case match(str, emailRegex): + return linkText(str, prefix: "mailto:", sent: sent) + case match(str, phoneRegex): + return linkText(str, prefix: "tel:", sent: sent) default: if (s.count > 1) { switch true { @@ -78,6 +93,17 @@ struct TextItemView: View { } } + private func match(_ s: String, _ regex: NSRegularExpression) -> Bool { + regex.firstMatch(in: s, options: [], range: NSRange(location: 0, length: s.count)) != nil + } + + private func linkText(_ s: String, prefix: String, sent: Bool) -> Text { + Text(AttributedString(s, attributes: AttributeContainer([ + .link: NSURL(string: prefix + s) as Any, + .foregroundColor: (sent ? UIColor.white : nil) as Any + ]))).underline() + } + private func mdText(_ s: String.SubSequence) -> Text { Text(s[s.index(s.startIndex, offsetBy: 1)..