From 5fa78394a304818b907524e2cfe314156ad0bad7 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 8 Jul 2021 15:56:52 +0800 Subject: [PATCH 1/4] feat: add "Using default browser open link" preference option. ticket: #20625EEA --- .../CoreData.xcdatamodel/contents | 3 +- CoreDataStack/Entity/Setting.swift | 7 +++ Localization/app.json | 12 ++--- Mastodon.xcodeproj/project.pbxproj | 4 ++ Mastodon/Coordinator/SceneCoordinator.swift | 8 +++- Mastodon/Diffiable/Item/SettingsItem.swift | 1 + .../Diffiable/Section/SettingsSection.swift | 2 + Mastodon/Generated/Strings.swift | 18 ++++---- Mastodon/Preference/AppPreference.swift | 20 ++++++++ .../Resources/ar.lproj/Localizable.strings | 6 ++- .../Resources/en.lproj/Localizable.strings | 6 ++- .../Settings/SettingsViewController.swift | 20 ++++++++ .../Scene/Settings/SettingsViewModel.swift | 17 +++++-- Mastodon/Service/AuthenticationService.swift | 20 -------- Mastodon/Service/SettingService.swift | 46 +++++++++++++++---- 15 files changed, 137 insertions(+), 53 deletions(-) create mode 100644 Mastodon/Preference/AppPreference.swift diff --git a/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents b/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents index 1d517412a..98ed7f356 100644 --- a/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents +++ b/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents @@ -191,6 +191,7 @@ + @@ -282,7 +283,7 @@ - + diff --git a/CoreDataStack/Entity/Setting.swift b/CoreDataStack/Entity/Setting.swift index 88768eda4..0be80f973 100644 --- a/CoreDataStack/Entity/Setting.swift +++ b/CoreDataStack/Entity/Setting.swift @@ -16,6 +16,7 @@ public final class Setting: NSManagedObject { @NSManaged public var appearanceRaw: String @NSManaged public var preferredTrueBlackDarkMode: Bool @NSManaged public var preferredStaticAvatar: Bool + @NSManaged public var preferredUsingDefaultBrowser: Bool @NSManaged public private(set) var createdAt: Date @NSManaged public private(set) var updatedAt: Date @@ -62,6 +63,12 @@ extension Setting { self.preferredStaticAvatar = preferredStaticAvatar didUpdate(at: Date()) } + + public func update(preferredUsingDefaultBrowser: Bool) { + guard preferredUsingDefaultBrowser != self.preferredUsingDefaultBrowser else { return } + self.preferredUsingDefaultBrowser = preferredUsingDefaultBrowser + didUpdate(at: Date()) + } public func didUpdate(at networkDate: Date) { self.updatedAt = networkDate diff --git a/Localization/app.json b/Localization/app.json index 5c8dd5cc0..50abb54b8 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -495,12 +495,8 @@ "dark": "Always Dark" }, "appearance_settings": { - "dark_mode": { - "title": "True black Dark Mode" - }, - "avatar_animation": { - "title": "Disable avatar animation" - } + "true_black_dark_mode": "True black Dark Mode", + "disable_avatar_animation": "Disable avatar animation" }, "notifications": { "title": "Notifications", @@ -516,6 +512,10 @@ "title": "Notify me when" } }, + "preference": { + "title": "Preference", + "using_default_browser": "Using default browser open link" + }, "boringzone": { "title": "The Boring zone", "terms": "Terms of Service", diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index b6c0cf11b..26e91f96d 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -416,6 +416,7 @@ DBA0A11325FB3FC10079C110 /* ComposeToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA0A11225FB3FC10079C110 /* ComposeToolbarView.swift */; }; DBA1DB80268F84F80052DB59 /* NotificationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA1DB7F268F84F80052DB59 /* NotificationType.swift */; }; DBA465932696B495002B41DB /* APIService+WebFinger.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA465922696B495002B41DB /* APIService+WebFinger.swift */; }; + DBA465952696E387002B41DB /* AppPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA465942696E387002B41DB /* AppPreference.swift */; }; DBA5E7A3263AD0A3004598BB /* PhotoLibraryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A2263AD0A3004598BB /* PhotoLibraryService.swift */; }; DBA5E7A5263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A4263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift */; }; DBA5E7A9263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5E7A8263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift */; }; @@ -1046,6 +1047,7 @@ DBA0A11225FB3FC10079C110 /* ComposeToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeToolbarView.swift; sourceTree = ""; }; DBA1DB7F268F84F80052DB59 /* NotificationType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationType.swift; sourceTree = ""; }; DBA465922696B495002B41DB /* APIService+WebFinger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+WebFinger.swift"; sourceTree = ""; }; + DBA465942696E387002B41DB /* AppPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPreference.swift; sourceTree = ""; }; DBA5E7A2263AD0A3004598BB /* PhotoLibraryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLibraryService.swift; sourceTree = ""; }; DBA5E7A4263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuImagePreviewViewModel.swift; sourceTree = ""; }; DBA5E7A8263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuImagePreviewViewController.swift; sourceTree = ""; }; @@ -1987,6 +1989,7 @@ isa = PBXGroup; children = ( DB5086BD25CC0D9900C2C187 /* SplashPreference.swift */, + DBA465942696E387002B41DB /* AppPreference.swift */, DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */, DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */, DB1D842F26566512000346B3 /* KeyboardPreference.swift */, @@ -3228,6 +3231,7 @@ DBAC649B267DF8C8007FE9FD /* ActivityIndicatorNode.swift in Sources */, DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */, 2DA504692601ADE7008F4E6C /* SawToothView.swift in Sources */, + DBA465952696E387002B41DB /* AppPreference.swift in Sources */, DB87D4572609DD5300D12C0D /* DeleteBackwardResponseTextField.swift in Sources */, 2D8434F525FF465D00EECE90 /* HomeTimelineNavigationBarTitleViewModel.swift in Sources */, DB938F0F2624119800E5B6C1 /* ThreadViewModel+LoadThreadState.swift in Sources */, diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index b918e1812..f1f288fa1 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -192,8 +192,12 @@ extension SceneCoordinator { sender?.navigationController?.pushViewController(viewController, animated: true) case .safariPresent(let animated, let completion): - viewController.modalPresentationCapturesStatusBarAppearance = true - presentingViewController.present(viewController, animated: animated, completion: completion) + if UserDefaults.shared.preferredUsingDefaultBrowser, case let .safari(url) = scene { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } else { + viewController.modalPresentationCapturesStatusBarAppearance = true + presentingViewController.present(viewController, animated: animated, completion: completion) + } case .alertController(let animated, let completion): viewController.modalPresentationCapturesStatusBarAppearance = true diff --git a/Mastodon/Diffiable/Item/SettingsItem.swift b/Mastodon/Diffiable/Item/SettingsItem.swift index aca02474e..7320e9fc5 100644 --- a/Mastodon/Diffiable/Item/SettingsItem.swift +++ b/Mastodon/Diffiable/Item/SettingsItem.swift @@ -13,6 +13,7 @@ enum SettingsItem: Hashable { case appearanceDarkMode(settingObjectID: NSManagedObjectID) case appearanceDisableAvatarAnimation(settingObjectID: NSManagedObjectID) case notification(settingObjectID: NSManagedObjectID, switchMode: NotificationSwitchMode) + case preferenceUsingDefaultBrowser(settingObjectID: NSManagedObjectID) case boringZone(item: Link) case spicyZone(item: Link) } diff --git a/Mastodon/Diffiable/Section/SettingsSection.swift b/Mastodon/Diffiable/Section/SettingsSection.swift index 9a248dca3..46ac82a1a 100644 --- a/Mastodon/Diffiable/Section/SettingsSection.swift +++ b/Mastodon/Diffiable/Section/SettingsSection.swift @@ -11,6 +11,7 @@ enum SettingsSection: Hashable { case appearance case appearanceSettings case notifications + case preference case boringZone case spicyZone @@ -19,6 +20,7 @@ enum SettingsSection: Hashable { case .appearance: return L10n.Scene.Settings.Section.Appearance.title case .appearanceSettings: return "" case .notifications: return L10n.Scene.Settings.Section.Notifications.title + case .preference: return L10n.Scene.Settings.Section.Preference.title case .boringZone: return L10n.Scene.Settings.Section.Boringzone.title case .spicyZone: return L10n.Scene.Settings.Section.Spicyzone.title } diff --git a/Mastodon/Generated/Strings.swift b/Mastodon/Generated/Strings.swift index ab2b75f40..6ea2504a4 100644 --- a/Mastodon/Generated/Strings.swift +++ b/Mastodon/Generated/Strings.swift @@ -934,14 +934,10 @@ internal enum L10n { internal static let title = L10n.tr("Localizable", "Scene.Settings.Section.Appearance.Title") } internal enum AppearanceSettings { - internal enum AvatarAnimation { - /// Disable avatar animation - internal static let title = L10n.tr("Localizable", "Scene.Settings.Section.AppearanceSettings.AvatarAnimation.Title") - } - internal enum DarkMode { - /// True black Dark Mode - internal static let title = L10n.tr("Localizable", "Scene.Settings.Section.AppearanceSettings.DarkMode.Title") - } + /// Disable avatar animation + internal static let disableAvatarAnimation = L10n.tr("Localizable", "Scene.Settings.Section.AppearanceSettings.DisableAvatarAnimation") + /// True black Dark Mode + internal static let trueBlackDarkMode = L10n.tr("Localizable", "Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode") } internal enum Boringzone { /// Privacy Policy @@ -975,6 +971,12 @@ internal enum L10n { internal static let title = L10n.tr("Localizable", "Scene.Settings.Section.Notifications.Trigger.Title") } } + internal enum Preference { + /// Preference + internal static let title = L10n.tr("Localizable", "Scene.Settings.Section.Preference.Title") + /// Using default browser open link + internal static let usingDefaultBrowser = L10n.tr("Localizable", "Scene.Settings.Section.Preference.UsingDefaultBrowser") + } internal enum Spicyzone { /// Clear Media Cache internal static let clear = L10n.tr("Localizable", "Scene.Settings.Section.Spicyzone.Clear") diff --git a/Mastodon/Preference/AppPreference.swift b/Mastodon/Preference/AppPreference.swift new file mode 100644 index 000000000..4ede61cf8 --- /dev/null +++ b/Mastodon/Preference/AppPreference.swift @@ -0,0 +1,20 @@ +// +// AppPreference.swift +// Mastodon +// +// Created by MainasuK Cirno on 2021-7-8. +// + +import UIKit + +extension UserDefaults { + + @objc dynamic var preferredUsingDefaultBrowser: Bool { + get { + register(defaults: [#function: false]) + return bool(forKey: #function) + } + set { self[#function] = newValue } + } + +} diff --git a/Mastodon/Resources/ar.lproj/Localizable.strings b/Mastodon/Resources/ar.lproj/Localizable.strings index f6211e838..82663ba28 100644 --- a/Mastodon/Resources/ar.lproj/Localizable.strings +++ b/Mastodon/Resources/ar.lproj/Localizable.strings @@ -317,8 +317,8 @@ any server."; "Scene.Settings.Section.Appearance.Dark" = "Always Dark"; "Scene.Settings.Section.Appearance.Light" = "Always Light"; "Scene.Settings.Section.Appearance.Title" = "Appearance"; -"Scene.Settings.Section.AppearanceSettings.AvatarAnimation.Title" = "Disable avatar animation"; -"Scene.Settings.Section.AppearanceSettings.DarkMode.Title" = "True black Dark Mode"; +"Scene.Settings.Section.AppearanceSettings.DisableAvatarAnimation" = "Disable avatar animation"; +"Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode" = "True black Dark Mode"; "Scene.Settings.Section.Boringzone.Privacy" = "Privacy Policy"; "Scene.Settings.Section.Boringzone.Terms" = "Terms of Service"; "Scene.Settings.Section.Boringzone.Title" = "The Boring zone"; @@ -332,6 +332,8 @@ any server."; "Scene.Settings.Section.Notifications.Trigger.Follower" = "a follower"; "Scene.Settings.Section.Notifications.Trigger.Noone" = "no one"; "Scene.Settings.Section.Notifications.Trigger.Title" = "Notify me when"; +"Scene.Settings.Section.Preference.Title" = "Preference"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Using default browser open link"; "Scene.Settings.Section.Spicyzone.Clear" = "Clear Media Cache"; "Scene.Settings.Section.Spicyzone.Signout" = "Sign Out"; "Scene.Settings.Section.Spicyzone.Title" = "The spicy zone"; diff --git a/Mastodon/Resources/en.lproj/Localizable.strings b/Mastodon/Resources/en.lproj/Localizable.strings index f6211e838..82663ba28 100644 --- a/Mastodon/Resources/en.lproj/Localizable.strings +++ b/Mastodon/Resources/en.lproj/Localizable.strings @@ -317,8 +317,8 @@ any server."; "Scene.Settings.Section.Appearance.Dark" = "Always Dark"; "Scene.Settings.Section.Appearance.Light" = "Always Light"; "Scene.Settings.Section.Appearance.Title" = "Appearance"; -"Scene.Settings.Section.AppearanceSettings.AvatarAnimation.Title" = "Disable avatar animation"; -"Scene.Settings.Section.AppearanceSettings.DarkMode.Title" = "True black Dark Mode"; +"Scene.Settings.Section.AppearanceSettings.DisableAvatarAnimation" = "Disable avatar animation"; +"Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode" = "True black Dark Mode"; "Scene.Settings.Section.Boringzone.Privacy" = "Privacy Policy"; "Scene.Settings.Section.Boringzone.Terms" = "Terms of Service"; "Scene.Settings.Section.Boringzone.Title" = "The Boring zone"; @@ -332,6 +332,8 @@ any server."; "Scene.Settings.Section.Notifications.Trigger.Follower" = "a follower"; "Scene.Settings.Section.Notifications.Trigger.Noone" = "no one"; "Scene.Settings.Section.Notifications.Trigger.Title" = "Notify me when"; +"Scene.Settings.Section.Preference.Title" = "Preference"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Using default browser open link"; "Scene.Settings.Section.Spicyzone.Clear" = "Clear Media Cache"; "Scene.Settings.Section.Spicyzone.Signout" = "Sign Out"; "Scene.Settings.Section.Spicyzone.Title" = "The spicy zone"; diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift index 6a08bd45d..aa2ff0cf9 100644 --- a/Mastodon/Scene/Settings/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/SettingsViewController.swift @@ -364,6 +364,9 @@ extension SettingsViewController: UITableViewDelegate { case .notification: // do nothing break + case .preferenceUsingDefaultBrowser: + // do nothing + break case .boringZone(let link), .spicyZone(let link): switch link { case .termsOfService, .privacyPolicy: @@ -501,7 +504,24 @@ extension SettingsViewController: SettingsToggleCellDelegate { // do nothing } .store(in: &disposeBag) + case .preferenceUsingDefaultBrowser(let settingObjectID): + let managedObjectContext = context.backgroundManagedObjectContext + managedObjectContext.performChanges { + let setting = managedObjectContext.object(with: settingObjectID) as! Setting + setting.update(preferredUsingDefaultBrowser: isOn) + } + .sink { result in + switch result { + case .success: + UserDefaults.shared.preferredUsingDefaultBrowser = isOn + case .failure(let error): + assertionFailure(error.localizedDescription) + break + } + } + .store(in: &disposeBag) default: + assertionFailure() break } } diff --git a/Mastodon/Scene/Settings/SettingsViewModel.swift b/Mastodon/Scene/Settings/SettingsViewModel.swift index 142de7dcf..5d60f1669 100644 --- a/Mastodon/Scene/Settings/SettingsViewModel.swift +++ b/Mastodon/Scene/Settings/SettingsViewModel.swift @@ -102,13 +102,18 @@ extension SettingsViewModel { ] snapshot.appendSections([.appearanceSettings]) snapshot.appendItems(appearanceSettingItems, toSection: .appearanceSettings) - + + // notification let notificationItems = SettingsItem.NotificationSwitchMode.allCases.map { mode in SettingsItem.notification(settingObjectID: setting.objectID, switchMode: mode) } snapshot.appendSections([.notifications]) snapshot.appendItems(notificationItems, toSection: .notifications) + // preference + snapshot.appendSections([.preference]) + snapshot.appendItems([.preferenceUsingDefaultBrowser(settingObjectID: setting.objectID)], toSection: .preference) + // boring zone let boringZoneSettingsItems: [SettingsItem] = { let links: [SettingsItem.Link] = [ @@ -170,7 +175,8 @@ extension SettingsViewModel { cell.delegate = settingsAppearanceTableViewCellDelegate return cell case .appearanceDarkMode(let objectID), - .appearanceDisableAvatarAnimation(let objectID): + .appearanceDisableAvatarAnimation(let objectID), + .preferenceUsingDefaultBrowser(let objectID): let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell cell.delegate = settingsToggleCellDelegate self.context.managedObjectContext.performAndWait { @@ -231,11 +237,14 @@ extension SettingsViewModel { ) { switch item { case .appearanceDarkMode: - cell.textLabel?.text = L10n.Scene.Settings.Section.AppearanceSettings.DarkMode.title + cell.textLabel?.text = L10n.Scene.Settings.Section.AppearanceSettings.trueBlackDarkMode cell.switchButton.isOn = setting.preferredTrueBlackDarkMode case .appearanceDisableAvatarAnimation: - cell.textLabel?.text = L10n.Scene.Settings.Section.AppearanceSettings.AvatarAnimation.title + cell.textLabel?.text = L10n.Scene.Settings.Section.AppearanceSettings.disableAvatarAnimation cell.switchButton.isOn = setting.preferredStaticAvatar + case .preferenceUsingDefaultBrowser: + cell.textLabel?.text = L10n.Scene.Settings.Section.Preference.usingDefaultBrowser + cell.switchButton.isOn = setting.preferredUsingDefaultBrowser default: assertionFailure() } diff --git a/Mastodon/Service/AuthenticationService.swift b/Mastodon/Service/AuthenticationService.swift index 4a460b1d0..a0bbca57a 100644 --- a/Mastodon/Service/AuthenticationService.swift +++ b/Mastodon/Service/AuthenticationService.swift @@ -81,26 +81,6 @@ final class AuthenticationService: NSObject { .assign(to: \.value, on: activeMastodonAuthenticationBox) .store(in: &disposeBag) - activeMastodonAuthenticationBox - .receive(on: RunLoop.main) - .sink { [weak self] authenticationBox in - guard let _ = self else { return } - guard let authenticationBox = authenticationBox else { return } - let request = Setting.sortedFetchRequest - request.predicate = Setting.predicate(domain: authenticationBox.domain, userID: authenticationBox.userID) - guard let setting = managedObjectContext.safeFetch(request).first else { return } - - let themeName: ThemeName = setting.preferredTrueBlackDarkMode ? .system : .mastodon - if UserDefaults.shared.currentThemeNameRawValue != themeName.rawValue { - ThemeService.shared.set(themeName: themeName) - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: update theme style", ((#file as NSString).lastPathComponent), #line, #function) - } - if UserDefaults.shared.preferredStaticAvatar != setting.preferredStaticAvatar { - UserDefaults.shared.preferredStaticAvatar = setting.preferredStaticAvatar - } - } - .store(in: &disposeBag) - do { try mastodonAuthenticationFetchedResultsController.performFetch() mastodonAuthentications.value = mastodonAuthenticationFetchedResultsController.fetchedObjects ?? [] diff --git a/Mastodon/Service/SettingService.swift b/Mastodon/Service/SettingService.swift index 7a25d6c7b..7da8c3683 100644 --- a/Mastodon/Service/SettingService.swift +++ b/Mastodon/Service/SettingService.swift @@ -91,20 +91,16 @@ final class SettingService { self.currentSettingUpdateSubscription = nil return } - + + SettingService.updatePreference(setting: setting) self.currentSettingUpdateSubscription = ManagedObjectObserver.observe(object: setting) .sink(receiveCompletion: { _ in // do nothing }, receiveValue: { change in guard case .update(let object) = change.changeType, let setting = object as? Setting else { return } - - // observe apparance mode - switch setting.appearance { - case .automatic: UserDefaults.shared.customUserInterfaceStyle = .unspecified - case .light: UserDefaults.shared.customUserInterfaceStyle = .light - case .dark: UserDefaults.shared.customUserInterfaceStyle = .dark - } + + SettingService.updatePreference(setting: setting) }) } .store(in: &disposeBag) @@ -187,3 +183,37 @@ extension SettingService { } } + +extension SettingService { + + static func updatePreference(setting: Setting) { + // set appearance + let userInterfaceStyle: UIUserInterfaceStyle = { + switch setting.appearance { + case .automatic: return .unspecified + case .light: return .light + case .dark: return .dark + } + }() + if UserDefaults.shared.customUserInterfaceStyle != userInterfaceStyle { + UserDefaults.shared.customUserInterfaceStyle = userInterfaceStyle + } + + // set theme + let themeName: ThemeName = setting.preferredTrueBlackDarkMode ? .system : .mastodon + if UserDefaults.shared.currentThemeNameRawValue != themeName.rawValue { + ThemeService.shared.set(themeName: themeName) + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: update theme style", ((#file as NSString).lastPathComponent), #line, #function) + } + + // set avatar mode + if UserDefaults.shared.preferredStaticAvatar != setting.preferredStaticAvatar { + UserDefaults.shared.preferredStaticAvatar = setting.preferredStaticAvatar + } + + // set browser + if UserDefaults.shared.preferredUsingDefaultBrowser != setting.preferredUsingDefaultBrowser { + UserDefaults.shared.preferredUsingDefaultBrowser = setting.preferredUsingDefaultBrowser + } + } +} From d9c0c75782a311d1674e7aeb767073c772a997ba Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 8 Jul 2021 16:55:46 +0800 Subject: [PATCH 2/4] fix: app may not response to link for some server issue. ticket: #18624MBA --- Mastodon.xcodeproj/project.pbxproj | 2 +- .../xcschemes/xcschememanagement.plist | 4 +- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../StatusProvider/StatusProviderFacade.swift | 40 +++++++++++++------ 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 26e91f96d..b8b64df83 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4841,7 +4841,7 @@ repositoryURL = "https://github.com/TwidereProject/MetaTextView.git"; requirement = { kind = exactVersion; - version = 1.3.0; + version = 1.3.1; }; }; DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = { diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index ecde1bcc5..ca6031c48 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -12,7 +12,7 @@ CoreDataStack.xcscheme_^#shared#^_ orderHint - 20 + 21 Mastodon - ASDK.xcscheme_^#shared#^_ @@ -37,7 +37,7 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 21 + 22 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1f3cc3145..5118c78b0 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -114,8 +114,8 @@ "repositoryURL": "https://github.com/TwidereProject/MetaTextView.git", "state": { "branch": null, - "revision": "e2049e14ef411c6810d53c1baf553b5161c6678f", - "version": "1.3.0" + "revision": "9021b330dd72898583f62ee7f4c98768d72e7654", + "version": "1.3.1" } }, { diff --git a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift index eff4ad124..e732789ef 100644 --- a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift +++ b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift @@ -128,12 +128,10 @@ extension StatusProviderFacade { static func responseToStatusActiveLabelAction(provider: StatusProvider, cell: UITableViewCell, activeLabel: ActiveLabel, didTapEntity entity: ActiveEntity) { switch entity.type { - case .hashtag(let text, _): - let hashtagTimelienViewModel = HashtagTimelineViewModel(context: provider.context, hashtag: text) - provider.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelienViewModel), from: provider, transition: .show) - case .mention(let text, _): - coordinateToStatusMentionProfileScene(for: .primary, provider: provider, cell: cell, mention: text) - case .url(_, _, let url, _): + case .url(_, _, let url, _), + .mention(let url, _) where url.lowercased().hasPrefix("http"): + // note: + // some server mark the normal url as "u-url" class. : guard let url = URL(string: url) else { return } if let domain = provider.context.authenticationService.activeMastodonAuthenticationBox.value?.domain, url.host == domain, url.pathComponents.count >= 4, @@ -146,6 +144,12 @@ extension StatusProviderFacade { } else { provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil)) } + case .hashtag(let text, _): + let hashtagTimelienViewModel = HashtagTimelineViewModel(context: provider.context, hashtag: text) + provider.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelienViewModel), from: provider, transition: .show) + case .mention(let text, let userInfo): + let href = userInfo?["href"] as? String + coordinateToStatusMentionProfileScene(for: .primary, provider: provider, cell: cell, mention: text, href: href) default: break } @@ -153,7 +157,10 @@ extension StatusProviderFacade { static func responseToStatusMetaTextAction(provider: StatusProvider, cell: UITableViewCell, metaText: MetaText, didSelectMeta meta: Meta) { switch meta { - case .url(_, _, let url, _): + case .url(_, _, let url, _), + .mention(_, let url, _) where url.lowercased().hasPrefix("http"): + // note: + // some server mark the normal url as "u-url" class. highlighted content is a URL guard let url = URL(string: url) else { return } if let domain = provider.context.authenticationService.activeMastodonAuthenticationBox.value?.domain, url.host == domain, url.pathComponents.count >= 4, @@ -169,8 +176,9 @@ extension StatusProviderFacade { case .hashtag(_, let hashtag, _): let hashtagTimelineViewModel = HashtagTimelineViewModel(context: provider.context, hashtag: hashtag) provider.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: provider, transition: .show) - case .mention(_, let mention, _): - coordinateToStatusMentionProfileScene(for: .primary, provider: provider, cell: cell, mention: mention) + case .mention(_, let mention, let userInfo): + let href = userInfo?["href"] as? String + coordinateToStatusMentionProfileScene(for: .primary, provider: provider, cell: cell, mention: mention, href: href) default: break } @@ -208,17 +216,17 @@ extension StatusProviderFacade { } #endif - private static func coordinateToStatusMentionProfileScene(for target: Target, provider: StatusProvider, cell: UITableViewCell, mention: String) { + private static func coordinateToStatusMentionProfileScene(for target: Target, provider: StatusProvider, cell: UITableViewCell, mention: String, href: String?) { provider.status(for: cell, indexPath: nil) .sink { [weak provider] status in guard let provider = provider else { return } guard let status = status else { return } - coordinateToStatusMentionProfileScene(for: target, provider: provider, status: status, mention: mention) + coordinateToStatusMentionProfileScene(for: target, provider: provider, status: status, mention: mention, href: href) } .store(in: &provider.disposeBag) } - private static func coordinateToStatusMentionProfileScene(for target: Target, provider: StatusProvider, status: Status, mention: String) { + private static func coordinateToStatusMentionProfileScene(for target: Target, provider: StatusProvider, status: Status, mention: String, href: String?) { guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { return } let domain = activeMastodonAuthenticationBox.domain @@ -230,7 +238,13 @@ extension StatusProviderFacade { }() // cannot continue without meta - guard let mentionMeta = (status.mentions ?? Set()).first(where: { $0.username == mention }) else { return } + guard let mentionMeta = (status.mentions ?? Set()).first(where: { $0.username == mention }) else { + // present web page if possible + if let url = href.flatMap({ URL(string: $0) }) { + provider.coordinator.present(scene: .safari(url: url), from: provider, transition: .safariPresent(animated: true, completion: nil)) + } + return + } let userID = mentionMeta.id From 20b3bed99fa19b87bf38d381e901902879291ea4 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 8 Jul 2021 17:07:53 +0800 Subject: [PATCH 3/4] fix: timeline gap wrong theme color issue --- Mastodon/Scene/Share/View/Decoration/SawToothView.swift | 2 +- .../View/TableviewCell/TimelineLoaderTableViewCell.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mastodon/Scene/Share/View/Decoration/SawToothView.swift b/Mastodon/Scene/Share/View/Decoration/SawToothView.swift index 94dab47fa..e344b62ef 100644 --- a/Mastodon/Scene/Share/View/Decoration/SawToothView.swift +++ b/Mastodon/Scene/Share/View/Decoration/SawToothView.swift @@ -52,7 +52,7 @@ final class SawToothView: UIView { } bezierPath.addLine(to: CGPoint(x: 0, y: bottomY)) bezierPath.close() - ThemeService.shared.currentTheme.value.systemBackgroundColor.setFill() + ThemeService.shared.currentTheme.value.tableViewCellBackgroundColor.setFill() bezierPath.fill() bezierPath.lineWidth = 0 bezierPath.stroke() diff --git a/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift index b18314df2..8c329d31e 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift @@ -86,7 +86,7 @@ class TimelineLoaderTableViewCell: UITableViewCell { loadMoreButton.heightAnchor.constraint(equalToConstant: TimelineLoaderTableViewCell.buttonHeight).priority(.required - 1), ]) - // use stack view to alignlment content center + // use stack view to alignment content center stackView.spacing = 4 stackView.axis = .horizontal stackView.alignment = .center @@ -127,7 +127,7 @@ class TimelineLoaderTableViewCell: UITableViewCell { } private func setupBackgroundColor(theme: Theme) { - loadMoreButton.backgroundColor = theme.systemBackgroundColor + loadMoreButton.backgroundColor = theme.tableViewCellBackgroundColor } } From ae58230581192f006473e952ef87736e8b0ba820 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 8 Jul 2021 17:22:52 +0800 Subject: [PATCH 4/4] fix: dismiss image may crash issue due to source view gone --- .../MediaPreview/MediaPreviewableViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mastodon/Scene/Transition/MediaPreview/MediaPreviewableViewController.swift b/Mastodon/Scene/Transition/MediaPreview/MediaPreviewableViewController.swift index 63cf10c3e..1fedf0d40 100644 --- a/Mastodon/Scene/Transition/MediaPreview/MediaPreviewableViewController.swift +++ b/Mastodon/Scene/Transition/MediaPreview/MediaPreviewableViewController.swift @@ -18,9 +18,9 @@ extension MediaPreviewableViewController { case .mosaic(let mosaicImageViewContainer): guard index < mosaicImageViewContainer.imageViews.count else { return nil } let imageView = mosaicImageViewContainer.imageViews[index] - return imageView.superview!.convert(imageView.frame, to: nil) + return imageView.superview?.convert(imageView.frame, to: nil) case .profileAvatar(let profileHeaderView): - return profileHeaderView.avatarImageView.superview!.convert(profileHeaderView.avatarImageView.frame, to: nil) + return profileHeaderView.avatarImageView.superview?.convert(profileHeaderView.avatarImageView.frame, to: nil) case .profileBanner: return nil // fallback to snapshot.frame }