diff --git a/ElementX/Sources/Other/Pills/MessageText.swift b/ElementX/Sources/Other/Pills/MessageText.swift index a0b8c21fe..634fc4c0b 100644 --- a/ElementX/Sources/Other/Pills/MessageText.swift +++ b/ElementX/Sources/Other/Pills/MessageText.swift @@ -128,6 +128,7 @@ struct MessageText: UIViewRepresentable { final class Coordinator: NSObject, UITextViewDelegate { var openURLAction: OpenURLAction + let permalinkBaseURL = ServiceLocator.shared.settings.permalinkBaseURL init(openURLAction: OpenURLAction) { self.openURLAction = openURLAction @@ -138,10 +139,28 @@ struct MessageText: UIViewRepresentable { } func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { - if interaction == .invokeDefaultAction { + switch interaction { + case .invokeDefaultAction: openURLAction.callAsFunction(URL) + return false + case .preview: + // We don't want to show a URL preview for permalinks + return PermalinkBuilder.detectPermalink(in: URL, baseURL: permalinkBaseURL) == nil + default: + return true + } + } + + @available(iOS 17.0, *) + func textView(_ textView: UITextView, menuConfigurationFor textItem: UITextItem, defaultMenu: UIMenu) -> UITextItem.MenuConfiguration? { + switch textItem.content { + case let .link(url): + // We don't want to show a URL preview for permalinks + let isPermalink = PermalinkBuilder.detectPermalink(in: url, baseURL: permalinkBaseURL) != nil + return .init(preview: isPermalink ? nil : .default, menu: defaultMenu) + default: + return nil } - return false } } } diff --git a/ElementX/Sources/Screens/RoomScreen/View/Style/LongPressWithFeedback.swift b/ElementX/Sources/Screens/RoomScreen/View/Style/LongPressWithFeedback.swift index 7ba8bf1ab..6c68f1d3e 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Style/LongPressWithFeedback.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Style/LongPressWithFeedback.swift @@ -30,7 +30,7 @@ struct LongPressWithFeedback: ViewModifier { .shadow(color: .black.opacity(isLongPressing ? 0.1 : 0.0), radius: isLongPressing ? 3 : 0) .scaleEffect(x: isLongPressing ? 1.05 : 1, y: isLongPressing ? 1.05 : 1) - .animation(.spring(response: 0.5).delay(isLongPressing ? 0.1 : 0).disabledDuringTests(), + .animation(.spring(response: 0.7).delay(isLongPressing ? 0.1 : 0).disabledDuringTests(), value: isLongPressing) // The minimum duration here doesn't actually invoke the perform block when elapsed (thus // the implementation below) but it does cancel other system gestures e.g. swipe to reply @@ -45,7 +45,8 @@ struct LongPressWithFeedback: ViewModifier { feedbackGenerator.prepare() triggerTask = Task { - try? await Task.sleep(for: .seconds(0.35)) + // The wait time needs to be at least 0.5 seconds or the long press gesture will take precedence over long pressing links. + try? await Task.sleep(for: .seconds(0.5)) if Task.isCancelled { return } diff --git a/changelog.d/2440.bugfix b/changelog.d/2440.bugfix new file mode 100644 index 000000000..c937b7cc0 --- /dev/null +++ b/changelog.d/2440.bugfix @@ -0,0 +1 @@ +Long pressing a link will give the preview and the context menu to copy it (or open it in Safari). \ No newline at end of file