diff --git a/Activities/OpenInSafariActivity.swift b/Activities/OpenInDefaultBrowserActivity.swift similarity index 88% rename from Activities/OpenInSafariActivity.swift rename to Activities/OpenInDefaultBrowserActivity.swift index 29daad3..04d6f02 100644 --- a/Activities/OpenInSafariActivity.swift +++ b/Activities/OpenInDefaultBrowserActivity.swift @@ -2,7 +2,7 @@ import UIKit -final class OpenInSafariActivity: UIActivity { +final class OpenInDefaultBrowserActivity: UIActivity { private var url: URL? override var activityType: UIActivity.ActivityType? { @@ -10,7 +10,7 @@ final class OpenInSafariActivity: UIActivity { } override var activityTitle: String? { - NSLocalizedString("Open in Safari", comment: "") + NSLocalizedString("activity.open-in-default-browser", comment: "") } override var activityImage: UIImage? { diff --git a/Localizations/Localizable.strings b/Localizations/Localizable.strings index b3082de..6d7b587 100644 --- a/Localizations/Localizable.strings +++ b/Localizations/Localizable.strings @@ -37,7 +37,7 @@ "account.unblock.confirm-%@" = "Unblock %@?"; "account.unfollow" = "Unfollow"; "account.unmute" = "Unmute"; -"activity.open-in-safari" = "Open in Safari"; +"activity.open-in-default-browser" = "Open in default browser"; "add" = "Add"; "apns-default-message" = "New notification"; "add-identity.instance-url" = "Instance URL"; @@ -180,6 +180,8 @@ "preferences.expand-media.hide-all" = "Hide all"; "preferences.reading-expand-spoilers" = "Always expand content warnings"; "preferences.filters" = "Filters"; +"preferences.links.open-in-default-browser" = "Open links in default browser"; +"preferences.links.use-universal-links" = "Open links in other apps when available"; "preferences.notification-types" = "Notification Types"; "preferences.notification-types.follow" = "Follow"; "preferences.notification-types.favourite" = "Favorite"; diff --git a/Metatext.xcodeproj/project.pbxproj b/Metatext.xcodeproj/project.pbxproj index 7ff056a..4563083 100644 --- a/Metatext.xcodeproj/project.pbxproj +++ b/Metatext.xcodeproj/project.pbxproj @@ -61,7 +61,7 @@ D036EBC2259FE2AD00EC1CFC /* UIVIewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E7AD3825870B13005F5E2D /* UIVIewController+Extensions.swift */; }; D03D87F425C23C44004DCBB2 /* SecondaryNavigationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03D87F325C23C44004DCBB2 /* SecondaryNavigationTitleView.swift */; }; D0477F1525C68BAC005C5368 /* PrefetchRequestModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0477F1425C68BAC005C5368 /* PrefetchRequestModifier.swift */; }; - D0477F2C25C6EBAD005C5368 /* OpenInSafariActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0477F2B25C6EBAD005C5368 /* OpenInSafariActivity.swift */; }; + D0477F2C25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0477F2B25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift */; }; D0477F4625C72E50005C5368 /* FollowsYouLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0477F4525C72E50005C5368 /* FollowsYouLabel.swift */; }; D04F9E8E259E9C950081B0C9 /* ViewModels in Frameworks */ = {isa = PBXBuildFile; productRef = D04F9E8D259E9C950081B0C9 /* ViewModels */; }; D05936CF25A8D79800754FDF /* EditAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05936CE25A8D79800754FDF /* EditAttachmentViewController.swift */; }; @@ -263,7 +263,7 @@ D036AA16254CA823009094DF /* StatusBodyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBodyView.swift; sourceTree = ""; }; D03D87F325C23C44004DCBB2 /* SecondaryNavigationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondaryNavigationTitleView.swift; sourceTree = ""; }; D0477F1425C68BAC005C5368 /* PrefetchRequestModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefetchRequestModifier.swift; sourceTree = ""; }; - D0477F2B25C6EBAD005C5368 /* OpenInSafariActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInSafariActivity.swift; sourceTree = ""; }; + D0477F2B25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInDefaultBrowserActivity.swift; sourceTree = ""; }; D0477F4525C72E50005C5368 /* FollowsYouLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowsYouLabel.swift; sourceTree = ""; }; D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; }; D05936CE25A8D79800754FDF /* EditAttachmentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAttachmentViewController.swift; sourceTree = ""; }; @@ -570,7 +570,7 @@ D0477F2A25C6EB90005C5368 /* Activities */ = { isa = PBXGroup; children = ( - D0477F2B25C6EBAD005C5368 /* OpenInSafariActivity.swift */, + D0477F2B25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift */, ); path = Activities; sourceTree = ""; @@ -998,7 +998,7 @@ D0C7D49A24F7616A001EBDBB /* TableView.swift in Sources */, D08B8D622540DE3B00B1EBEF /* ZoomTransitionController.swift in Sources */, D0F0B12E251A97E400942152 /* TableViewController.swift in Sources */, - D0477F2C25C6EBAD005C5368 /* OpenInSafariActivity.swift in Sources */, + D0477F2C25C6EBAD005C5368 /* OpenInDefaultBrowserActivity.swift in Sources */, D0DD50CB256B1F24004A04F7 /* ReportView.swift in Sources */, D0477F1525C68BAC005C5368 /* PrefetchRequestModifier.swift in Sources */, D097F41B25BE3E1A00859F2C /* SearchScope+Extensions.swift in Sources */, diff --git a/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift b/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift index bbc7b99..ccb9de2 100644 --- a/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift +++ b/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift @@ -186,6 +186,16 @@ public extension AppPreferences { get { self[.notificationAccountName] ?? false } set { self[.notificationAccountName] = newValue } } + + var openLinksInDefaultBrowser: Bool { + get { self[.openLinksInDefaultBrowser] ?? false } + set { self[.openLinksInDefaultBrowser] = newValue } + } + + var useUniversalLinks: Bool { + get { self[.useUniversalLinks] ?? true } + set { self[.useUniversalLinks] = newValue } + } } private extension AppPreferences { @@ -205,6 +215,8 @@ private extension AppPreferences { case notificationPictures case notificationAccountName case notificationSounds + case openLinksInDefaultBrowser + case useUniversalLinks } subscript(index: Item) -> T? { diff --git a/View Controllers/TableViewController.swift b/View Controllers/TableViewController.swift index aa121ba..2820d5a 100644 --- a/View Controllers/TableViewController.swift +++ b/View Controllers/TableViewController.swift @@ -228,7 +228,15 @@ extension TableViewController { case let .notification(notificationService): navigate(toNotification: notificationService.notification) case let .url(url): - present(SFSafariViewController(url: url), animated: true) + if viewModel.identityContext.appPreferences.useUniversalLinks { + UIApplication.shared.open(url, options: [.universalLinksOnly: true]) { success in + if !success { + self.open(url: url) + } + } + } else { + open(url: url) + } case .searchScope: break case .webfingerStart: @@ -449,6 +457,14 @@ private extension TableViewController { viewModel.select(indexPath: indexPath) } + func open(url: URL) { + if viewModel.identityContext.appPreferences.openLinksInDefaultBrowser { + UIApplication.shared.open(url) + } else { + present(SFSafariViewController(url: url), animated: true) + } + } + func present(attachmentViewModel: AttachmentViewModel, statusViewModel: StatusViewModel) { switch attachmentViewModel.attachment.type { case .audio, .video: @@ -552,7 +568,7 @@ private extension TableViewController { func share(url: URL) { let activityViewController = UIActivityViewController( activityItems: [url], - applicationActivities: [OpenInSafariActivity()]) + applicationActivities: [OpenInDefaultBrowserActivity()]) if UIDevice.current.userInterfaceIdiom == .pad { guard let sourceView = tableView.viewWithTag(url.hashValue) else { return } diff --git a/Views/SwiftUI/PreferencesView.swift b/Views/SwiftUI/PreferencesView.swift index 2287657..abc4cd4 100644 --- a/Views/SwiftUI/PreferencesView.swift +++ b/Views/SwiftUI/PreferencesView.swift @@ -75,6 +75,12 @@ struct PreferencesView: View { isOn: $identityContext.appPreferences.requireDoubleTapToReblog) Toggle("preferences.require-double-tap-to-favorite", isOn: $identityContext.appPreferences.requireDoubleTapToFavorite) + Toggle("preferences.links.open-in-default-browser", + isOn: $identityContext.appPreferences.openLinksInDefaultBrowser) + if !identityContext.appPreferences.openLinksInDefaultBrowser { + Toggle("preferences.links.use-universal-links", + isOn: $identityContext.appPreferences.useUniversalLinks) + } if accessibilityReduceMotion { Toggle("preferences.media.use-system-reduce-motion", isOn: $identityContext.appPreferences.useSystemReduceMotionForMedia)