diff --git a/AppShared/AppName.swift b/AppShared/AppName.swift index 9dbca78d..e2d35626 100644 --- a/AppShared/AppName.swift +++ b/AppShared/AppName.swift @@ -8,5 +8,5 @@ import Foundation public enum AppName { - public static let groupID = "group.org.joinmastodon.mastodon-temp" + public static let groupID = "group.org.joinmastodon.app" } diff --git a/AppShared/AppSecret.swift b/AppShared/AppSecret.swift index e2305ef1..7ef7a082 100644 --- a/AppShared/AppSecret.swift +++ b/AppShared/AppSecret.swift @@ -13,7 +13,7 @@ import Keys public final class AppSecret { - public static let keychain = Keychain(service: "org.joinmastodon.Mastodon.keychain", accessGroup: AppName.groupID) + public static let keychain = Keychain(service: "org.joinmastodon.app.keychain", accessGroup: AppName.groupID) static let notificationPrivateKeyName = "notification-private-key-base64" static let notificationAuthName = "notification-auth-base64" diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 5d765861..90d2a135 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -181,11 +181,9 @@ 87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */; }; B914FC6B0B8AF18573C0B291 /* Pods_NotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 374AA339A20E0FAC75BCDA6D /* Pods_NotificationService.framework */; }; DB00CA972632DDB600A54956 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB00CA962632DDB600A54956 /* CommonOSLog */; }; - DB0140A125C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140A025C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift */; }; - DB0140A825C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140A725C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift */; }; - DB0140AE25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140AD25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift */; }; DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB0140BC25C40D7500F9F3CF /* CommonOSLog */; }; DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.swift */; }; + DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB029E94266A20430062874E /* MastodonAuthenticationController.swift */; }; DB02CDAB26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDAA26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift */; }; DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDBE2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift */; }; DB040ECD26526EA600BEE9D8 /* ComposeCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB040ECC26526EA600BEE9D8 /* ComposeCollectionView.swift */; }; @@ -753,10 +751,8 @@ BB482D32A7B9825BF5327C4F /* Pods-Mastodon-MastodonUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.release.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.release.xcconfig"; sourceTree = ""; }; CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D7D7CF93E262178800077512 /* Pods-Mastodon-AppShared.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-AppShared.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-AppShared/Pods-Mastodon-AppShared.debug.xcconfig"; sourceTree = ""; }; - DB0140A025C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonPinBasedAuthenticationViewController.swift; sourceTree = ""; }; - DB0140A725C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift; sourceTree = ""; }; - DB0140AD25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonPinBasedAuthenticationViewModel.swift; sourceTree = ""; }; DB0140CE25C42AEE00F9F3CF /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; + DB029E94266A20430062874E /* MastodonAuthenticationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAuthenticationController.swift; sourceTree = ""; }; DB02CDAA26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadReplyLoaderTableViewCell.swift; sourceTree = ""; }; DB02CDBE2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveUserInterfaceStyleBarButtonItem.swift; sourceTree = ""; }; DB040ECC26526EA600BEE9D8 /* ComposeCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeCollectionView.swift; sourceTree = ""; }; @@ -1618,7 +1614,6 @@ DB68A03825E900CC00CFDF14 /* Share */, 0FAA0FDD25E0B5700017CCDE /* Welcome */, 0FAA102525E1125D0017CCDE /* PickServer */, - DB0140A625C40C0900F9F3CF /* PinBasedAuthentication */, DBE0821A25CD382900FD6BBD /* Register */, DB72602125E36A2500235243 /* ServerRules */, 2D364F7025E66D5B00204FDC /* ResendEmail */, @@ -1627,16 +1622,6 @@ path = Onboarding; sourceTree = ""; }; - DB0140A625C40C0900F9F3CF /* PinBasedAuthentication */ = { - isa = PBXGroup; - children = ( - DB0140A025C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift */, - DB0140AD25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift */, - DB0140A725C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift */, - ); - path = PinBasedAuthentication; - sourceTree = ""; - }; DB084B5125CBC56300F898ED /* CoreDataStack */ = { isa = PBXGroup; children = ( @@ -1921,6 +1906,7 @@ children = ( 2D82B9FE25E7863200E36F0F /* OnboardingViewControllerAppearance.swift */, DB2F073325E8ECF000957B2D /* AuthenticationViewModel.swift */, + DB029E94266A20430062874E /* MastodonAuthenticationController.swift */, ); path = Share; sourceTree = ""; @@ -3043,6 +3029,7 @@ DB49A62B25FF36C700B98345 /* APIService+CustomEmoji.swift in Sources */, DBCBED1D26132E1A00B49291 /* StatusFetchedResultsController.swift in Sources */, 2D79E701261EA5550011E398 /* APIService+CoreData+Tag.swift in Sources */, + DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */, 5B90C461262599800002E742 /* SettingsLinkTableViewCell.swift in Sources */, DB6180DD263918E30018D199 /* MediaPreviewViewController.swift in Sources */, DBE3CDEC261C6B2900430CC6 /* FavoriteViewController.swift in Sources */, @@ -3149,7 +3136,6 @@ DBB525562611EDCA002F1F29 /* UserTimelineViewModel.swift in Sources */, 2D42FF7E25C82218004A627A /* ActionToolBarContainer.swift in Sources */, DB221B16260C395900AEFE46 /* CustomEmojiPickerInputViewModel.swift in Sources */, - DB0140A125C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift in Sources */, DB789A1C25F9F76A0071ACA0 /* ComposeStatusContentCollectionViewCell.swift in Sources */, DB1FD43625F26899004CFCFC /* MastodonPickServerViewModel+LoadIndexedServerState.swift in Sources */, 2D939AE825EE1CF80076FA61 /* MastodonRegisterViewController+Avatar.swift in Sources */, @@ -3220,7 +3206,6 @@ 2D4AD89C263165B500613EFC /* SuggestionAccountCollectionViewCell.swift in Sources */, DB447691260B406600B66B82 /* CustomEmojiPickerItemCollectionViewCell.swift in Sources */, DB9282B225F3222800823B15 /* PickServerEmptyStateView.swift in Sources */, - DB0140A825C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift in Sources */, DB1FD45025F26FA1004CFCFC /* MastodonPickServerViewModel+Diffable.swift in Sources */, DB2B3AE925E38850007045F9 /* UIViewPreview.swift in Sources */, DB68046C2636DC9E00430867 /* MastodonNotification.swift in Sources */, @@ -3280,7 +3265,6 @@ DB8190C62601FF0400020C08 /* AttachmentContainerView.swift in Sources */, DB51D173262832380062B7A1 /* BlurHashEncode.swift in Sources */, DB5086AB25CC0BBB00C2C187 /* AvatarConfigurableView.swift in Sources */, - DB0140AE25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift in Sources */, 2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */, DB71FD2C25F86A5100512AE1 /* AvatarStackContainerButton.swift in Sources */, DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */, @@ -3630,16 +3614,16 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.5.0; - PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.Mastodon; + MARKETING_VERSION = 0.6.0; + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -3657,16 +3641,16 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 5; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.5.0; - PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.Mastodon; + MARKETING_VERSION = 0.6.0; + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; @@ -3680,7 +3664,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3701,7 +3685,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3721,7 +3705,7 @@ baseConfigurationReference = 459EA4F43058CAB47719E963 /* Pods-Mastodon-MastodonUITests.debug.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3741,7 +3725,7 @@ baseConfigurationReference = BB482D32A7B9825BF5327C4F /* Pods-Mastodon-MastodonUITests.release.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3765,7 +3749,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -3776,7 +3760,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.Mastodon.AppShared; + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.AppShared; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -3796,7 +3780,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -3807,7 +3791,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.Mastodon.AppShared; + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.AppShared; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; @@ -3824,7 +3808,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -3853,7 +3837,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -3879,7 +3863,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = CoreDataStackTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3899,7 +3883,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7LFDZ96332; + DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = CoreDataStackTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3920,16 +3904,16 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 5; - DEVELOPMENT_TEAM = 7LFDZ96332; + CURRENT_PROJECT_VERSION = 10; + DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.5.0; - PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.Mastodon.NotificationService; + MARKETING_VERSION = 0.6.0; + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; @@ -3943,16 +3927,16 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 5; - DEVELOPMENT_TEAM = 7LFDZ96332; + CURRENT_PROJECT_VERSION = 10; + DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.5.0; - PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.Mastodon.NotificationService; + MARKETING_VERSION = 0.6.0; + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 217fe199..6d27be6a 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ AppShared.xcscheme_^#shared#^_ orderHint - 18 + 14 CoreDataStack.xcscheme_^#shared#^_ @@ -27,12 +27,12 @@ Mastodon.xcscheme_^#shared#^_ orderHint - 1 + 13 NotificationService.xcscheme_^#shared#^_ orderHint - 16 + 12 SuppressBuildableAutocreation diff --git a/Mastodon/Activity/SafariActivity.swift b/Mastodon/Activity/SafariActivity.swift index e10a0b08..a43e34f9 100644 --- a/Mastodon/Activity/SafariActivity.swift +++ b/Mastodon/Activity/SafariActivity.swift @@ -18,7 +18,7 @@ final class SafariActivity: UIActivity { } override var activityType: UIActivity.ActivityType? { - return UIActivity.ActivityType("org.joinmastodon.Mastodon.safari-activity") + return UIActivity.ActivityType("org.joinmastodon.app.safari-activity") } override var activityTitle: String? { diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index f9da785a..11053e66 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -42,7 +42,6 @@ extension SceneCoordinator { // onboarding case welcome case mastodonPickServer(viewMode: MastodonPickServerViewModel) - case mastodonPinBasedAuthentication(viewModel: MastodonPinBasedAuthenticationViewModel) case mastodonRegister(viewModel: MastodonRegisterViewModel) case mastodonServerRules(viewModel: MastodonServerRulesViewModel) case mastodonConfirmEmail(viewModel: MastodonConfirmEmailViewModel) @@ -78,6 +77,7 @@ extension SceneCoordinator { case safari(url: URL) case alertController(alertController: UIAlertController) case activityViewController(activityViewController: UIActivityViewController, sourceView: UIView?, barButtonItem: UIBarButtonItem?) + #if DEBUG case publicTimeline #endif @@ -86,7 +86,6 @@ extension SceneCoordinator { switch self { case .welcome, .mastodonPickServer, - .mastodonPinBasedAuthentication, .mastodonRegister, .mastodonServerRules, .mastodonConfirmEmail, @@ -217,10 +216,6 @@ private extension SceneCoordinator { let _viewController = MastodonPickServerViewController() _viewController.viewModel = viewModel viewController = _viewController - case .mastodonPinBasedAuthentication(let viewModel): - let _viewController = MastodonPinBasedAuthenticationViewController() - _viewController.viewModel = viewModel - viewController = _viewController case .mastodonRegister(let viewModel): let _viewController = MastodonRegisterViewController() _viewController.viewModel = viewModel diff --git a/Mastodon/Diffiable/Section/ComposeStatusSection.swift b/Mastodon/Diffiable/Section/ComposeStatusSection.swift index 875a8284..836d91e7 100644 --- a/Mastodon/Diffiable/Section/ComposeStatusSection.swift +++ b/Mastodon/Diffiable/Section/ComposeStatusSection.swift @@ -141,8 +141,8 @@ extension ComposeStatusSection { attribute.contentWarningContent.value = text } .store(in: &cell.disposeBag) - ComposeStatusSection.configureCustomEmojiPicker(viewModel: customEmojiPickerInputViewModel, customEmojiReplacableTextInput: cell.textEditorView, disposeBag: &cell.disposeBag) - ComposeStatusSection.configureCustomEmojiPicker(viewModel: customEmojiPickerInputViewModel, customEmojiReplacableTextInput: cell.statusContentWarningEditorView.textView, disposeBag: &cell.disposeBag) + ComposeStatusSection.configureCustomEmojiPicker(viewModel: customEmojiPickerInputViewModel, customEmojiReplaceableTextInput: cell.textEditorView, disposeBag: &cell.disposeBag) + ComposeStatusSection.configureCustomEmojiPicker(viewModel: customEmojiPickerInputViewModel, customEmojiReplaceableTextInput: cell.statusContentWarningEditorView.textView, disposeBag: &cell.disposeBag) return cell case .attachment(let attachmentService): @@ -228,7 +228,7 @@ extension ComposeStatusSection { .assign(to: \.value, on: attribute.option) .store(in: &cell.disposeBag) cell.delegate = composeStatusPollOptionCollectionViewCellDelegate - ComposeStatusSection.configureCustomEmojiPicker(viewModel: customEmojiPickerInputViewModel, customEmojiReplacableTextInput: cell.pollOptionView.optionTextField, disposeBag: &cell.disposeBag) + ComposeStatusSection.configureCustomEmojiPicker(viewModel: customEmojiPickerInputViewModel, customEmojiReplaceableTextInput: cell.pollOptionView.optionTextField, disposeBag: &cell.disposeBag) return cell case .pollOptionAppendEntry: let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: ComposeStatusPollOptionAppendEntryCollectionViewCell.self), for: indexPath) as! ComposeStatusPollOptionAppendEntryCollectionViewCell @@ -295,7 +295,7 @@ protocol CustomEmojiReplaceableTextInput: AnyObject { var isFirstResponder: Bool { get } } -class CustomEmojiReplacableTextInputReference { +class CustomEmojiReplaceableTextInputReference { weak var value: CustomEmojiReplaceableTextInput? init(value: CustomEmojiReplaceableTextInput? = nil) { @@ -320,7 +320,7 @@ extension ComposeStatusSection { static func configureCustomEmojiPicker( viewModel: CustomEmojiPickerInputViewModel?, - customEmojiReplacableTextInput: CustomEmojiReplaceableTextInput, + customEmojiReplaceableTextInput: CustomEmojiReplaceableTextInput, disposeBag: inout Set ) { guard let viewModel = viewModel else { return } @@ -328,9 +328,9 @@ extension ComposeStatusSection { .receive(on: DispatchQueue.main) .sink { [weak viewModel] isCustomEmojiComposing in guard let viewModel = viewModel else { return } - customEmojiReplacableTextInput.inputView = isCustomEmojiComposing ? viewModel.customEmojiPickerInputView : nil - customEmojiReplacableTextInput.reloadInputViews() - viewModel.append(customEmojiReplacableTextInput: customEmojiReplacableTextInput) + customEmojiReplaceableTextInput.inputView = isCustomEmojiComposing ? viewModel.customEmojiPickerInputView : nil + customEmojiReplaceableTextInput.reloadInputViews() + viewModel.append(customEmojiReplaceableTextInput: customEmojiReplaceableTextInput) } .store(in: &disposeBag) } diff --git a/Mastodon/Mastodon.entitlements b/Mastodon/Mastodon.entitlements index 8917adbf..0135ecdd 100644 --- a/Mastodon/Mastodon.entitlements +++ b/Mastodon/Mastodon.entitlements @@ -6,7 +6,7 @@ development com.apple.security.application-groups - group.org.joinmastodon.mastodon-temp + group.org.joinmastodon.app diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index 69fef0a5..90f3e448 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -61,7 +61,8 @@ final class ComposeViewController: UIViewController, NeedsDependency { var systemKeyboardHeight: CGFloat = .zero { didSet { // note: some system AutoLayout warning here - customEmojiPickerInputView.frame.size.height = systemKeyboardHeight != .zero ? systemKeyboardHeight : 300 + let height = max(300, systemKeyboardHeight) + customEmojiPickerInputView.frame.size.height = height } } @@ -730,7 +731,7 @@ extension ComposeViewController: TextEditorViewTextAttributesDelegate { guard let emoji = customEmojiViewModel.emoji(shortcode: name) else { continue } os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: handle emoji: %s", ((#file as NSString).lastPathComponent), #line, #function, name) - // set emoji token invisiable (without upper bounce space) + // set emoji token invisible (without upper bounce space) var attributes = [NSAttributedString.Key: Any]() attributes[.font] = UIFont.systemFont(ofSize: 0.01) attributedString.addAttributes(attributes, range: match.range) @@ -812,15 +813,15 @@ extension ComposeViewController: TextEditorViewTextAttributesDelegate { extension ComposeViewController: TextEditorViewChangeObserver { func textEditorView(_ textEditorView: TextEditorView, didChangeWithChangeResult changeResult: TextEditorViewChangeResult) { - guard var autoCompeletion = ComposeViewController.scanAutoCompleteInfo(textEditorView: textEditorView) else { + guard var autoCompletion = ComposeViewController.scanAutoCompleteInfo(textEditorView: textEditorView) else { viewModel.autoCompleteInfo.value = nil return } - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: auto complete %s (%s)", ((#file as NSString).lastPathComponent), #line, #function, String(autoCompeletion.toHighlightEndString), String(autoCompeletion.toCursorString)) + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: auto complete %s (%s)", ((#file as NSString).lastPathComponent), #line, #function, String(autoCompletion.toHighlightEndString), String(autoCompletion.toCursorString)) // get layout text bounding rect var glyphRange = NSRange() - textEditorView.layoutManager.characterRange(forGlyphRange: NSRange(autoCompeletion.toCursorRange, in: textEditorView.text), actualGlyphRange: &glyphRange) + textEditorView.layoutManager.characterRange(forGlyphRange: NSRange(autoCompletion.toCursorRange, in: textEditorView.text), actualGlyphRange: &glyphRange) let textContainer = textEditorView.layoutManager.textContainers[0] let textBoundingRect = textEditorView.layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) @@ -838,13 +839,13 @@ extension ComposeViewController: TextEditorViewChangeObserver { viewModel.autoCompleteRetryLayoutTimes.value = 0 // get symbol bounding rect - textEditorView.layoutManager.characterRange(forGlyphRange: NSRange(autoCompeletion.symbolRange, in: textEditorView.text), actualGlyphRange: &glyphRange) + textEditorView.layoutManager.characterRange(forGlyphRange: NSRange(autoCompletion.symbolRange, in: textEditorView.text), actualGlyphRange: &glyphRange) let symbolBoundingRect = textEditorView.layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) // set bounding rect and trigger layout - autoCompeletion.textBoundingRect = textBoundingRect - autoCompeletion.symbolBoundingRect = symbolBoundingRect - viewModel.autoCompleteInfo.value = autoCompeletion + autoCompletion.textBoundingRect = textBoundingRect + autoCompletion.symbolBoundingRect = symbolBoundingRect + viewModel.autoCompleteInfo.value = autoCompletion } struct AutoCompleteInfo { @@ -864,12 +865,14 @@ extension ComposeViewController: TextEditorViewChangeObserver { private static func scanAutoCompleteInfo(textEditorView: TextEditorView) -> AutoCompleteInfo? { let text = textEditorView.text - let cursorLocation = textEditorView.selectedRange.location - let cursorIndex = text.index(text.startIndex, offsetBy: cursorLocation) - guard cursorLocation > 0, !text.isEmpty else { return nil } - - let _highlighStartIndex: String.Index? = { - var index = text.index(text.startIndex, offsetBy: cursorLocation - 1) + + guard textEditorView.selectedRange.location > 0, !text.isEmpty, + let selectedRange = Range(textEditorView.selectedRange, in: text) else { + return nil + } + let cursorIndex = selectedRange.upperBound + let _highlightStartIndex: String.Index? = { + var index = text.index(before: cursorIndex) while index > text.startIndex { let char = text[index] if char == "@" || char == "#" || char == ":" { @@ -886,18 +889,18 @@ extension ComposeViewController: TextEditorViewChangeObserver { } }() - guard let highlighStartIndex = _highlighStartIndex else { return nil } - let scanRange = NSRange(highlighStartIndex..= cursorIndex else { return nil } - let symbolRange = highlighStartIndex..= cursorIndex else { return nil } + let symbolRange = highlightStartIndex..() - private var customEmojiReplacableTextInputReferences: [CustomEmojiReplacableTextInputReference] = [] + private var customEmojiReplaceableTextInputReferences: [CustomEmojiReplaceableTextInputReference] = [] // input weak var customEmojiPickerInputView: CustomEmojiPickerInputView? @@ -25,27 +25,27 @@ final class CustomEmojiPickerInputViewModel { extension CustomEmojiPickerInputViewModel { private func removeEmptyReferences() { - customEmojiReplacableTextInputReferences.removeAll(where: { element in + customEmojiReplaceableTextInputReferences.removeAll(where: { element in element.value == nil }) } - func append(customEmojiReplacableTextInput textInput: CustomEmojiReplaceableTextInput) { + func append(customEmojiReplaceableTextInput textInput: CustomEmojiReplaceableTextInput) { removeEmptyReferences() - let isContains = customEmojiReplacableTextInputReferences.contains(where: { element in + let isContains = customEmojiReplaceableTextInputReferences.contains(where: { element in element.value === textInput }) guard !isContains else { return } - customEmojiReplacableTextInputReferences.append(CustomEmojiReplacableTextInputReference(value: textInput)) + customEmojiReplaceableTextInputReferences.append(CustomEmojiReplaceableTextInputReference(value: textInput)) } - func insertText(_ text: String) -> CustomEmojiReplacableTextInputReference? { + func insertText(_ text: String) -> CustomEmojiReplaceableTextInputReference? { removeEmptyReferences() - for reference in customEmojiReplacableTextInputReferences { + for reference in customEmojiReplaceableTextInputReferences { guard reference.value?.isFirstResponder == true else { continue } reference.value?.insertText(text) return reference diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift index 7c7e7b0e..2a978c69 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift @@ -9,6 +9,7 @@ import os.log import UIKit import Combine import GameController +import AuthenticationServices final class MastodonPickServerViewController: UIViewController, NeedsDependency { @@ -19,6 +20,11 @@ final class MastodonPickServerViewController: UIViewController, NeedsDependency weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } var viewModel: MastodonPickServerViewModel! + private(set) lazy var authenticationViewModel = AuthenticationViewModel( + context: context, + coordinator: coordinator, + isAuthenticationExist: false + ) private var expandServerDomainSet = Set() @@ -50,6 +56,8 @@ final class MastodonPickServerViewController: UIViewController, NeedsDependency }() var nextStepButtonBottomLayoutConstraint: NSLayoutConstraint! + var mastodonAuthenticationController: MastodonAuthenticationController? + deinit { tableViewObservation = nil os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) @@ -182,23 +190,26 @@ extension MastodonPickServerViewController { .assign(to: \.isEnabled, on: nextStepButton) .store(in: &disposeBag) - viewModel.error - .compactMap { $0 } - .receive(on: DispatchQueue.main) - .sink { [weak self] error in - guard let self = self else { return } - let alertController = UIAlertController(for: error, title: "Error", preferredStyle: .alert) - let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil) - alertController.addAction(okAction) - self.coordinator.present( - scene: .alertController(alertController: alertController), - from: nil, - transition: .alertController(animated: true, completion: nil) - ) - } - .store(in: &disposeBag) + Publishers.Merge( + viewModel.error, + authenticationViewModel.error + ) + .compactMap { $0 } + .receive(on: DispatchQueue.main) + .sink { [weak self] error in + guard let self = self else { return } + let alertController = UIAlertController(for: error, title: "Error", preferredStyle: .alert) + let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil) + alertController.addAction(okAction) + self.coordinator.present( + scene: .alertController(alertController: alertController), + from: nil, + transition: .alertController(animated: true, completion: nil) + ) + } + .store(in: &disposeBag) - viewModel + authenticationViewModel .authenticated .flatMap { [weak self] (domain, user) -> AnyPublisher, Never> in guard let self = self else { return Just(.success(false)).eraseToAnyPublisher() } @@ -217,7 +228,7 @@ extension MastodonPickServerViewController { } .store(in: &disposeBag) - viewModel.isAuthenticating + authenticationViewModel.isAuthenticating .receive(on: DispatchQueue.main) .sink { [weak self] isAuthenticating in guard let self = self else { return } @@ -273,11 +284,15 @@ extension MastodonPickServerViewController { private func doSignIn() { guard let server = viewModel.selectedServer.value else { return } - viewModel.isAuthenticating.send(true) + authenticationViewModel.isAuthenticating.send(true) context.apiService.createApplication(domain: server.domain) - .tryMap { response -> MastodonPickServerViewModel.AuthenticateInfo in + .tryMap { response -> AuthenticationViewModel.AuthenticateInfo in let application = response.value - guard let info = MastodonPickServerViewModel.AuthenticateInfo(domain: server.domain, application: application) else { + guard let info = AuthenticationViewModel.AuthenticateInfo( + domain: server.domain, + application: application, + redirectURI: response.value.redirectURI ?? MastodonAuthenticationController.callbackURL + ) else { throw APIService.APIError.explicit(.badResponse) } return info @@ -285,7 +300,7 @@ extension MastodonPickServerViewController { .receive(on: DispatchQueue.main) .sink { [weak self] completion in guard let self = self else { return } - self.viewModel.isAuthenticating.send(false) + self.authenticationViewModel.isAuthenticating.send(false) switch completion { case .failure(let error): @@ -296,15 +311,19 @@ extension MastodonPickServerViewController { } } receiveValue: { [weak self] info in guard let self = self else { return } - let mastodonPinBasedAuthenticationViewModel = MastodonPinBasedAuthenticationViewModel(authenticateURL: info.authorizeURL) - self.viewModel.authenticate( - info: info, - pinCodePublisher: mastodonPinBasedAuthenticationViewModel.pinCodePublisher + let authenticationController = MastodonAuthenticationController( + context: self.context, + authenticateURL: info.authorizeURL ) - self.viewModel.mastodonPinBasedAuthenticationViewController = self.coordinator.present( - scene: .mastodonPinBasedAuthentication(viewModel: mastodonPinBasedAuthenticationViewModel), - from: nil, - transition: .modal(animated: true, completion: nil) + + self.mastodonAuthenticationController = authenticationController + authenticationController.authenticationSession?.prefersEphemeralWebBrowserSession = true + authenticationController.authenticationSession?.presentationContextProvider = self + authenticationController.authenticationSession?.start() + + self.authenticationViewModel.authenticate( + info: info, + pinCodePublisher: authenticationController.pinCodePublisher ) } .store(in: &disposeBag) @@ -313,7 +332,7 @@ extension MastodonPickServerViewController { private func doSignUp() { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) guard let server = viewModel.selectedServer.value else { return } - viewModel.isAuthenticating.send(true) + authenticationViewModel.isAuthenticating.send(true) context.apiService.instance(domain: server.domain) .compactMap { [weak self] response -> AnyPublisher? in @@ -328,7 +347,10 @@ extension MastodonPickServerViewController { .switchToLatest() .tryMap { response -> MastodonPickServerViewModel.SignUpResponseSecond in let application = response.application.value - guard let authenticateInfo = AuthenticationViewModel.AuthenticateInfo(domain: server.domain, application: application) else { + guard let authenticateInfo = AuthenticationViewModel.AuthenticateInfo( + domain: server.domain, + application: application + ) else { throw APIService.APIError.explicit(.badResponse) } return MastodonPickServerViewModel.SignUpResponseSecond(instance: response.instance, authenticateInfo: authenticateInfo) @@ -340,7 +362,8 @@ extension MastodonPickServerViewController { return self.context.apiService.applicationAccessToken( domain: server.domain, clientID: authenticateInfo.clientID, - clientSecret: authenticateInfo.clientSecret + clientSecret: authenticateInfo.clientSecret, + redirectURI: authenticateInfo.redirectURI ) .map { MastodonPickServerViewModel.SignUpResponseThird(instance: instance, authenticateInfo: authenticateInfo, applicationToken: $0) } .eraseToAnyPublisher() @@ -349,7 +372,7 @@ extension MastodonPickServerViewController { .receive(on: DispatchQueue.main) .sink { [weak self] completion in guard let self = self else { return } - self.viewModel.isAuthenticating.send(false) + self.authenticationViewModel.isAuthenticating.send(false) switch completion { case .failure(let error): @@ -519,3 +542,10 @@ extension MastodonPickServerViewController: PickServerCellDelegate { // MARK: - OnboardingViewControllerAppearance extension MastodonPickServerViewController: OnboardingViewControllerAppearance { } + +// MARK: - ASWebAuthenticationPresentationContextProviding +extension MastodonPickServerViewController: ASWebAuthenticationPresentationContextProviding { + func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { + return view.window! + } +} diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift index a576632a..8348f884 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift @@ -58,15 +58,11 @@ class MastodonPickServerViewModel: NSObject { let filteredIndexedServers = CurrentValueSubject<[Mastodon.Entity.Server], Never>([]) let servers = CurrentValueSubject<[Mastodon.Entity.Server], Error>([]) let selectedServer = CurrentValueSubject(nil) - let error = PassthroughSubject() - let authenticated = PassthroughSubject<(domain: String, account: Mastodon.Entity.Account), Never>() - let isAuthenticating = CurrentValueSubject(false) + let error = CurrentValueSubject(nil) let isLoadingIndexedServers = CurrentValueSubject(false) let emptyStateViewState = CurrentValueSubject(.none) - - var mastodonPinBasedAuthenticationViewController: UIViewController? - + init(context: AppContext, mode: PickServerMode) { self.context = context self.mode = mode @@ -233,156 +229,6 @@ extension MastodonPickServerViewModel { } } } - - -// MARK: - SignIn methods & structs -extension MastodonPickServerViewModel { - enum AuthenticationError: Error, LocalizedError { - case badCredentials - case registrationClosed - - var errorDescription: String? { - switch self { - case .badCredentials: return "Bad Credentials" - case .registrationClosed: return "Registration Closed" - } - } - - var failureReason: String? { - switch self { - case .badCredentials: return "Credentials invalid." - case .registrationClosed: return "Server disallow registration." - } - } - - var helpAnchor: String? { - switch self { - case .badCredentials: return "Please try again." - case .registrationClosed: return "Please try another domain." - } - } - } - - struct AuthenticateInfo { - let domain: String - let clientID: String - let clientSecret: String - let authorizeURL: URL - - init?(domain: String, application: Mastodon.Entity.Application) { - self.domain = domain - guard let clientID = application.clientID, - let clientSecret = application.clientSecret else { return nil } - self.clientID = clientID - self.clientSecret = clientSecret - self.authorizeURL = { - let query = Mastodon.API.OAuth.AuthorizeQuery(clientID: clientID) - let url = Mastodon.API.OAuth.authorizeURL(domain: domain, query: query) - return url - }() - } - } - - func authenticate(info: AuthenticateInfo, pinCodePublisher: PassthroughSubject) { - pinCodePublisher - .handleEvents(receiveOutput: { [weak self] _ in - guard let self = self else { return } -// self.isAuthenticating.value = true - self.mastodonPinBasedAuthenticationViewController?.dismiss(animated: true, completion: nil) - self.mastodonPinBasedAuthenticationViewController = nil - }) - .compactMap { [weak self] code -> AnyPublisher, Error>? in - guard let self = self else { return nil } - return self.context.apiService - .userAccessToken( - domain: info.domain, - clientID: info.clientID, - clientSecret: info.clientSecret, - code: code - ) - .flatMap { response -> AnyPublisher, Error> in - let token = response.value - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: sign in success. Token: %s", ((#file as NSString).lastPathComponent), #line, #function, token.accessToken) - return Self.verifyAndSaveAuthentication( - context: self.context, - info: info, - userToken: token - ) - } - .eraseToAnyPublisher() - } - .switchToLatest() - .receive(on: DispatchQueue.main) - .sink { [weak self] completion in - guard let self = self else { return } - switch completion { - case .failure(let error): - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: swap user access token swap fail: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription) -// self.isAuthenticating.value = false - self.error.send(error) - case .finished: - break - } - } receiveValue: { [weak self] response in - guard let self = self else { return } - let account = response.value - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: user %s sign in success", ((#file as NSString).lastPathComponent), #line, #function, account.username) - - self.authenticated.send((domain: info.domain, account: account)) - } - .store(in: &self.disposeBag) - } - - static func verifyAndSaveAuthentication( - context: AppContext, - info: AuthenticateInfo, - userToken: Mastodon.Entity.Token - ) -> AnyPublisher, Error> { - let authorization = Mastodon.API.OAuth.Authorization(accessToken: userToken.accessToken) - let managedObjectContext = context.backgroundManagedObjectContext - - return context.apiService.accountVerifyCredentials( - domain: info.domain, - authorization: authorization - ) - .flatMap { response -> AnyPublisher, Error> in - let account = response.value - let mastodonUserRequest = MastodonUser.sortedFetchRequest - mastodonUserRequest.predicate = MastodonUser.predicate(domain: info.domain, id: account.id) - mastodonUserRequest.fetchLimit = 1 - guard let mastodonUser = try? managedObjectContext.fetch(mastodonUserRequest).first else { - return Fail(error: AuthenticationError.badCredentials).eraseToAnyPublisher() - } - - let property = MastodonAuthentication.Property( - domain: info.domain, - userID: mastodonUser.id, - username: mastodonUser.username, - appAccessToken: userToken.accessToken, // TODO: swap app token - userAccessToken: userToken.accessToken, - clientID: info.clientID, - clientSecret: info.clientSecret - ) - return managedObjectContext.performChanges { - _ = APIService.CoreData.createOrMergeMastodonAuthentication( - into: managedObjectContext, - for: mastodonUser, - in: info.domain, - property: property, - networkDate: response.networkDate - ) - } - .tryMap { result in - switch result { - case .failure(let error): throw error - case .success: return response - } - } - .eraseToAnyPublisher() - } - .eraseToAnyPublisher() - } -} // MARK: - SignUp methods & structs extension MastodonPickServerViewModel { diff --git a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerSearchCell.swift b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerSearchCell.swift index dc048f67..5d10a39b 100644 --- a/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerSearchCell.swift +++ b/Mastodon/Scene/Onboarding/PickServer/TableViewCell/PickServerSearchCell.swift @@ -52,6 +52,8 @@ class PickServerSearchCell: UITableViewCell { textField.clearButtonMode = .whileEditing textField.autocapitalizationType = .none textField.autocorrectionType = .no + textField.returnKeyType = .done + textField.keyboardType = .URL return textField }() @@ -78,6 +80,7 @@ extension PickServerSearchCell { backgroundColor = Asset.Colors.Background.systemGroupedBackground.color searchTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged) + searchTextField.delegate = self contentView.addSubview(bgView) contentView.addSubview(textFieldBgView) @@ -107,3 +110,12 @@ extension PickServerSearchCell { delegate?.pickServerSearchCell(self, searchTextDidChange: textField.text) } } + +// MARK: - UITextFieldDelegate +extension PickServerSearchCell: UITextFieldDelegate { + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + textField.resignFirstResponder() + return false + } +} diff --git a/Mastodon/Scene/Onboarding/PinBasedAuthentication/MastodonPinBasedAuthenticationViewController.swift b/Mastodon/Scene/Onboarding/PinBasedAuthentication/MastodonPinBasedAuthenticationViewController.swift deleted file mode 100644 index d566da4c..00000000 --- a/Mastodon/Scene/Onboarding/PinBasedAuthentication/MastodonPinBasedAuthenticationViewController.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// MastodonPinBasedAuthenticationViewController.swift -// Mastodon -// -// Created by MainasuK Cirno on 2021/1/29. -// - -import os.log -import UIKit -import Combine -import WebKit - -final class MastodonPinBasedAuthenticationViewController: UIViewController, NeedsDependency { - - weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } - weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } - - var disposeBag = Set() - var viewModel: MastodonPinBasedAuthenticationViewModel! - - let webView: WKWebView = { - let configuration = WKWebViewConfiguration() - configuration.processPool = WKProcessPool() - let webView = WKWebView(frame: .zero, configuration: configuration) - return webView - }() - - deinit { - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) - - // cleanup cookie - let httpCookieStore = webView.configuration.websiteDataStore.httpCookieStore - httpCookieStore.getAllCookies { cookies in - for cookie in cookies { - httpCookieStore.delete(cookie, completionHandler: nil) - } - } - } - -} - -extension MastodonPinBasedAuthenticationViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - title = "Authentication" - navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(MastodonPinBasedAuthenticationViewController.cancelBarButtonItemPressed(_:))) - - webView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(webView) - NSLayoutConstraint.activate([ - webView.topAnchor.constraint(equalTo: view.topAnchor), - webView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - webView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - webView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) - - let request = URLRequest(url: viewModel.authenticateURL) - webView.navigationDelegate = viewModel.navigationDelegate - webView.load(request) - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: authenticate via: %s", ((#file as NSString).lastPathComponent), #line, #function, viewModel.authenticateURL.debugDescription) - } - -} - -extension MastodonPinBasedAuthenticationViewController { - - @objc private func cancelBarButtonItemPressed(_ sender: UIBarButtonItem) { - dismiss(animated: true, completion: nil) - } - -} diff --git a/Mastodon/Scene/Onboarding/PinBasedAuthentication/MastodonPinBasedAuthenticationViewModel.swift b/Mastodon/Scene/Onboarding/PinBasedAuthentication/MastodonPinBasedAuthenticationViewModel.swift deleted file mode 100644 index 5eac359e..00000000 --- a/Mastodon/Scene/Onboarding/PinBasedAuthentication/MastodonPinBasedAuthenticationViewModel.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// MastodonPinBasedAuthenticationViewModel.swift -// Mastodon -// -// Created by MainasuK Cirno on 2021/1/29. -// - -import os.log -import Foundation -import Combine -import WebKit - -final class MastodonPinBasedAuthenticationViewModel { - - // input - let authenticateURL: URL - - // output - let pinCodePublisher = PassthroughSubject() - private var navigationDelegateShim: MastodonPinBasedAuthenticationViewModelNavigationDelegateShim? - - init(authenticateURL: URL) { - self.authenticateURL = authenticateURL - } - - deinit { - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) - } - -} - -extension MastodonPinBasedAuthenticationViewModel { - - var navigationDelegate: WKNavigationDelegate { - let navigationDelegateShim = MastodonPinBasedAuthenticationViewModelNavigationDelegateShim(viewModel: self) - self.navigationDelegateShim = navigationDelegateShim - return navigationDelegateShim - } - -} diff --git a/Mastodon/Scene/Onboarding/PinBasedAuthentication/MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift b/Mastodon/Scene/Onboarding/PinBasedAuthentication/MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift deleted file mode 100644 index dd890172..00000000 --- a/Mastodon/Scene/Onboarding/PinBasedAuthentication/MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift -// Mastodon -// -// Created by Cirno MainasuK on 2021/1/29. -// - -import os.log -import Foundation -import WebKit - -final class MastodonPinBasedAuthenticationViewModelNavigationDelegateShim: NSObject { - - weak var viewModel: MastodonPinBasedAuthenticationViewModel? - - init(viewModel: MastodonPinBasedAuthenticationViewModel) { - self.viewModel = viewModel - } - - deinit { - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) - } -} - - -// MARK: - WKNavigationDelegate -extension MastodonPinBasedAuthenticationViewModelNavigationDelegateShim: WKNavigationDelegate { - - func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - guard let url = webView.url, - let components = URLComponents(url: url, resolvingAgainstBaseURL: false), - let codeQueryItem = components.queryItems?.first(where: { $0.name == "code" }), - let code = codeQueryItem.value else { - return - } - - viewModel?.pinCodePublisher.send(code) - } - -} - diff --git a/Mastodon/Scene/Onboarding/Share/AuthenticationViewModel.swift b/Mastodon/Scene/Onboarding/Share/AuthenticationViewModel.swift index 0bd1bf09..eb3cf572 100644 --- a/Mastodon/Scene/Onboarding/Share/AuthenticationViewModel.swift +++ b/Mastodon/Scene/Onboarding/Share/AuthenticationViewModel.swift @@ -31,9 +31,7 @@ final class AuthenticationViewModel { let isIdle = CurrentValueSubject(true) let authenticated = PassthroughSubject<(domain: String, account: Mastodon.Entity.Account), Never>() let error = CurrentValueSubject(nil) - - var mastodonPinBasedAuthenticationViewController: UIViewController? - + init(context: AppContext, coordinator: SceneCoordinator, isAuthenticationExist: Bool) { self.context = context self.coordinator = coordinator @@ -118,18 +116,24 @@ extension AuthenticationViewModel { let clientID: String let clientSecret: String let authorizeURL: URL + let redirectURI: String - init?(domain: String, application: Mastodon.Entity.Application) { + init?( + domain: String, + application: Mastodon.Entity.Application, + redirectURI: String = MastodonAuthenticationController.callbackURL + ) { self.domain = domain guard let clientID = application.clientID, let clientSecret = application.clientSecret else { return nil } self.clientID = clientID self.clientSecret = clientSecret self.authorizeURL = { - let query = Mastodon.API.OAuth.AuthorizeQuery(clientID: clientID) + let query = Mastodon.API.OAuth.AuthorizeQuery(clientID: clientID, redirectURI: redirectURI) let url = Mastodon.API.OAuth.authorizeURL(domain: domain, query: query) return url }() + self.redirectURI = redirectURI } } @@ -138,8 +142,6 @@ extension AuthenticationViewModel { .handleEvents(receiveOutput: { [weak self] _ in guard let self = self else { return } self.isAuthenticating.value = true - self.mastodonPinBasedAuthenticationViewController?.dismiss(animated: true, completion: nil) - self.mastodonPinBasedAuthenticationViewController = nil }) .compactMap { [weak self] code -> AnyPublisher, Error>? in guard let self = self else { return nil } @@ -148,6 +150,7 @@ extension AuthenticationViewModel { domain: info.domain, clientID: info.clientID, clientSecret: info.clientSecret, + redirectURI: info.redirectURI, code: code ) .flatMap { response -> AnyPublisher, Error> in diff --git a/Mastodon/Scene/Onboarding/Share/MastodonAuthenticationController.swift b/Mastodon/Scene/Onboarding/Share/MastodonAuthenticationController.swift new file mode 100644 index 00000000..c97fc148 --- /dev/null +++ b/Mastodon/Scene/Onboarding/Share/MastodonAuthenticationController.swift @@ -0,0 +1,75 @@ +// +// MastodonAuthenticationController.swift +// Mastodon +// +// Created by MainasuK Cirno on 2021-6-4. +// + +import os.log +import UIKit +import Combine +import AuthenticationServices + +final class MastodonAuthenticationController { + + static let callbackURLScheme = "mastodon" + static let callbackURL = "mastodon://joinmastodon.org/oauth" + + var disposeBag = Set() + + // input + var context: AppContext! + let authenticateURL: URL + var authenticationSession: ASWebAuthenticationSession? + + // output + let isAuthenticating = CurrentValueSubject(false) + let error = CurrentValueSubject(nil) + let pinCodePublisher = PassthroughSubject() + + init( + context: AppContext, + authenticateURL: URL + ) { + self.context = context + self.authenticateURL = authenticateURL + + authentication() + } + +} + +extension MastodonAuthenticationController { + private func authentication() { + authenticationSession = ASWebAuthenticationSession( + url: authenticateURL, + callbackURLScheme: MastodonAuthenticationController.callbackURLScheme + ) { [weak self] callback, error in + guard let self = self else { return } + os_log("%{public}s[%{public}ld], %{public}s: callback: %s, error: %s", ((#file as NSString).lastPathComponent), #line, #function, callback?.debugDescription ?? "", error.debugDescription) + + if let error = error { + if let error = error as? ASWebAuthenticationSessionError { + if error.errorCode == ASWebAuthenticationSessionError.canceledLogin.rawValue { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: user cancel authentication", ((#file as NSString).lastPathComponent), #line, #function) + self.isAuthenticating.value = false + return + } + } + + self.isAuthenticating.value = false + self.error.value = error + return + } + + guard let url = callback, + let components = URLComponents(url: url, resolvingAgainstBaseURL: false), + let codeQueryItem = components.queryItems?.first(where: { $0.name == "code" }), + let code = codeQueryItem.value else { + return + } + + self.pinCodePublisher.send(code) + } + } +} diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift index ad85bee8..07705846 100644 --- a/Mastodon/Scene/Settings/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/SettingsViewController.swift @@ -94,7 +94,7 @@ class SettingsViewController: UIViewController, NeedsDependency { tableView.translatesAutoresizingMaskIntoConstraints = false tableView.delegate = self tableView.rowHeight = UITableView.automaticDimension - tableView.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color + tableView.backgroundColor = .clear tableView.register(SettingsAppearanceTableViewCell.self, forCellReuseIdentifier: String(describing: SettingsAppearanceTableViewCell.self)) tableView.register(SettingsToggleTableViewCell.self, forCellReuseIdentifier: String(describing: SettingsToggleTableViewCell.self)) @@ -185,7 +185,14 @@ class SettingsViewController: UIViewController, NeedsDependency { } private func setupView() { - view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color + view.backgroundColor = UIColor(dynamicProvider: { traitCollection in + switch traitCollection.userInterfaceLevel { + case .elevated where traitCollection.userInterfaceStyle == .dark: + return Asset.Colors.Background.systemElevatedBackground.color + default: + return Asset.Colors.Background.secondarySystemBackground.color + } + }) setupNavigation() view.addSubview(tableView) diff --git a/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift b/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift index a58bebf8..9a9ff745 100644 --- a/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift +++ b/Mastodon/Scene/Settings/View/Cell/SettingsAppearanceTableViewCell.swift @@ -176,7 +176,7 @@ class SettingsAppearanceTableViewCell: UITableViewCell { // MARK: Private methods private func setupUI() { - backgroundColor = Asset.Colors.Background.systemGroupedBackground.color + backgroundColor = .clear selectionStyle = .none contentView.addSubview(stackView) diff --git a/Mastodon/Scene/Settings/View/SettingsSectionHeader.swift b/Mastodon/Scene/Settings/View/SettingsSectionHeader.swift index ccd7fd87..0ce45101 100644 --- a/Mastodon/Scene/Settings/View/SettingsSectionHeader.swift +++ b/Mastodon/Scene/Settings/View/SettingsSectionHeader.swift @@ -39,7 +39,8 @@ class SettingsSectionHeader: UIView { init(frame: CGRect, customView: UIView? = nil) { super.init(frame: frame) - backgroundColor = Asset.Colors.Background.systemGroupedBackground.color + backgroundColor = .clear + stackView.addArrangedSubview(titleLabel) if let view = customView { stackView.addArrangedSubview(view) diff --git a/Mastodon/Scene/Share/ViewModel/MosaicImageViewModel.swift b/Mastodon/Scene/Share/ViewModel/MosaicImageViewModel.swift index 9563a19c..7d3dd275 100644 --- a/Mastodon/Scene/Share/ViewModel/MosaicImageViewModel.swift +++ b/Mastodon/Scene/Share/ViewModel/MosaicImageViewModel.swift @@ -46,7 +46,7 @@ struct MosaicMeta { let blurhash: String? let altText: String? - let workingQueue = DispatchQueue(label: "org.joinmastodon.Mastodon.MosaicMeta.working-queue", qos: .userInitiated, attributes: .concurrent) + let workingQueue = DispatchQueue(label: "org.joinmastodon.app.MosaicMeta.working-queue", qos: .userInitiated, attributes: .concurrent) func blurhashImagePublisher() -> AnyPublisher { return Future { promise in diff --git a/Mastodon/Scene/Share/ViewModel/VideoPlayerViewModel.swift b/Mastodon/Scene/Share/ViewModel/VideoPlayerViewModel.swift index d34e73eb..6da59aef 100644 --- a/Mastodon/Scene/Share/ViewModel/VideoPlayerViewModel.swift +++ b/Mastodon/Scene/Share/ViewModel/VideoPlayerViewModel.swift @@ -14,7 +14,7 @@ import UIKit final class VideoPlayerViewModel { var disposeBag = Set() - static let appWillPlayVideoNotification = NSNotification.Name(rawValue: "org.joinmastodon.Mastodon.video-playback-service.appWillPlayVideo") + static let appWillPlayVideoNotification = NSNotification.Name(rawValue: "org.joinmastodon.app.video-playback-service.appWillPlayVideo") // input let previewImageURL: URL? let videoURL: URL diff --git a/Mastodon/Service/APIService/APIService+App.swift b/Mastodon/Service/APIService/APIService+App.swift index 9726a6ee..b5b1d868 100644 --- a/Mastodon/Service/APIService/APIService+App.swift +++ b/Mastodon/Service/APIService/APIService+App.swift @@ -20,7 +20,11 @@ extension APIService { #endif func createApplication(domain: String) -> AnyPublisher, Error> { - let query = Mastodon.API.App.CreateQuery(clientName: APIService.clientName, website: nil) + let query = Mastodon.API.App.CreateQuery( + clientName: APIService.clientName, + redirectURIs: MastodonAuthenticationController.callbackURL, + website: nil + ) return Mastodon.API.App.create( session: session, domain: domain, diff --git a/Mastodon/Service/APIService/APIService+Authentication.swift b/Mastodon/Service/APIService/APIService+Authentication.swift index 55a188a5..ffd9afd7 100644 --- a/Mastodon/Service/APIService/APIService+Authentication.swift +++ b/Mastodon/Service/APIService/APIService+Authentication.swift @@ -17,11 +17,13 @@ extension APIService { domain: String, clientID: String, clientSecret: String, + redirectURI: String, code: String ) -> AnyPublisher, Error> { let query = Mastodon.API.OAuth.AccessTokenQuery( clientID: clientID, clientSecret: clientSecret, + redirectURI: redirectURI, code: code, grantType: "authorization_code" ) @@ -35,11 +37,13 @@ extension APIService { func applicationAccessToken( domain: String, clientID: String, - clientSecret: String + clientSecret: String, + redirectURI: String ) -> AnyPublisher, Error> { let query = Mastodon.API.OAuth.AccessTokenQuery( clientID: clientID, clientSecret: clientSecret, + redirectURI: redirectURI, code: nil, grantType: "client_credentials" ) diff --git a/Mastodon/Service/AudioPlaybackService.swift b/Mastodon/Service/AudioPlaybackService.swift index 34ceb3bb..274cd559 100644 --- a/Mastodon/Service/AudioPlaybackService.swift +++ b/Mastodon/Service/AudioPlaybackService.swift @@ -14,7 +14,7 @@ import os.log final class AudioPlaybackService: NSObject { - static let appWillPlayAudioNotification = NSNotification.Name(rawValue: "org.joinmastodon.Mastodon.audio-playback-service.appWillPlayAudio") + static let appWillPlayAudioNotification = NSNotification.Name(rawValue: "org.joinmastodon.app.audio-playback-service.appWillPlayAudio") var disposeBag = Set() diff --git a/Mastodon/Service/EmojiService/EmojiService.swift b/Mastodon/Service/EmojiService/EmojiService.swift index 3883d4ba..a11ebb8b 100644 --- a/Mastodon/Service/EmojiService/EmojiService.swift +++ b/Mastodon/Service/EmojiService/EmojiService.swift @@ -15,7 +15,7 @@ final class EmojiService { weak var apiService: APIService? - let workingQueue = DispatchQueue(label: "org.joinmastodon.Mastodon.EmojiService.working-queue") + let workingQueue = DispatchQueue(label: "org.joinmastodon.app.EmojiService.working-queue") private(set) var customEmojiViewModelDict: [String: CustomEmojiViewModel] = [:] init(apiService: APIService) { diff --git a/Mastodon/Service/MastodonAttachmentService/MastodonAttachmentService.swift b/Mastodon/Service/MastodonAttachmentService/MastodonAttachmentService.swift index 4c541a8d..ede5c64b 100644 --- a/Mastodon/Service/MastodonAttachmentService/MastodonAttachmentService.swift +++ b/Mastodon/Service/MastodonAttachmentService/MastodonAttachmentService.swift @@ -52,10 +52,10 @@ final class MastodonAttachmentService { init( context: AppContext, pickerResult: PHPickerResult, - initalAuthenticationBox: AuthenticationService.MastodonAuthenticationBox? + initialAuthenticationBox: AuthenticationService.MastodonAuthenticationBox? ) { self.context = context - self.authenticationBox = initalAuthenticationBox + self.authenticationBox = initialAuthenticationBox // end init setupServiceObserver() @@ -90,10 +90,10 @@ final class MastodonAttachmentService { init( context: AppContext, image: UIImage, - initalAuthenticationBox: AuthenticationService.MastodonAuthenticationBox? + initialAuthenticationBox: AuthenticationService.MastodonAuthenticationBox? ) { self.context = context - self.authenticationBox = initalAuthenticationBox + self.authenticationBox = initialAuthenticationBox // end init setupServiceObserver() @@ -105,10 +105,10 @@ final class MastodonAttachmentService { init( context: AppContext, documentURL: URL, - initalAuthenticationBox: AuthenticationService.MastodonAuthenticationBox? + initialAuthenticationBox: AuthenticationService.MastodonAuthenticationBox? ) { self.context = context - self.authenticationBox = initalAuthenticationBox + self.authenticationBox = initialAuthenticationBox // end init setupServiceObserver() @@ -213,7 +213,7 @@ extension MastodonAttachmentService: Equatable, Hashable { extension MastodonAttachmentService { private static func createWorkingQueue() -> DispatchQueue { - return DispatchQueue(label: "org.joinmastodon.Mastodon.MastodonAttachmentService.\(UUID().uuidString)") + return DispatchQueue(label: "org.joinmastodon.app.MastodonAttachmentService.\(UUID().uuidString)") } static func loadAttachment(url: URL) -> AnyPublisher { diff --git a/Mastodon/Service/NotificationService.swift b/Mastodon/Service/NotificationService.swift index e21a3cff..f1a5bb49 100644 --- a/Mastodon/Service/NotificationService.swift +++ b/Mastodon/Service/NotificationService.swift @@ -17,7 +17,7 @@ final class NotificationService { var disposeBag = Set() - let workingQueue = DispatchQueue(label: "org.joinmastodon.Mastodon.NotificationService.working-queue") + let workingQueue = DispatchQueue(label: "org.joinmastodon.app.NotificationService.working-queue") // input weak var apiService: APIService? diff --git a/Mastodon/Service/StatusPrefetchingService.swift b/Mastodon/Service/StatusPrefetchingService.swift index e1337204..7828c5cf 100644 --- a/Mastodon/Service/StatusPrefetchingService.swift +++ b/Mastodon/Service/StatusPrefetchingService.swift @@ -16,7 +16,7 @@ final class StatusPrefetchingService { typealias TaskID = String - let workingQueue = DispatchQueue(label: "org.joinmastodon.Mastodon.StatusPrefetchingService.working-queue") + let workingQueue = DispatchQueue(label: "org.joinmastodon.app.StatusPrefetchingService.working-queue") var disposeBag = Set() private(set) var statusPrefetchingDisposeBagDict: [TaskID: AnyCancellable] = [:] diff --git a/Mastodon/Service/StatusPublishService.swift b/Mastodon/Service/StatusPublishService.swift index 4728af8c..f797d9f6 100644 --- a/Mastodon/Service/StatusPublishService.swift +++ b/Mastodon/Service/StatusPublishService.swift @@ -16,7 +16,7 @@ final class StatusPublishService { var disposeBag = Set() - let workingQueue = DispatchQueue(label: "org.joinmastodon.Mastodon.StatusPublishService.working-queue") + let workingQueue = DispatchQueue(label: "org.joinmastodon.app.StatusPublishService.working-queue") // input var viewModels = CurrentValueSubject<[ComposeViewModel], Never>([]) // use strong reference to retain the view models diff --git a/Mastodon/Service/ViedeoPlaybackService.swift b/Mastodon/Service/ViedeoPlaybackService.swift index 523af310..a15431f0 100644 --- a/Mastodon/Service/ViedeoPlaybackService.swift +++ b/Mastodon/Service/ViedeoPlaybackService.swift @@ -14,7 +14,7 @@ import os.log final class VideoPlaybackService { var disposeBag = Set() - let workingQueue = DispatchQueue(label: "org.joinmastodon.Mastodon.VideoPlaybackService.working-queue") + let workingQueue = DispatchQueue(label: "org.joinmastodon.app.VideoPlaybackService.working-queue") private(set) var viewPlayerViewModelDict: [URL: VideoPlayerViewModel] = [:] // only for video kind diff --git a/Mastodon/State/AppContext.swift b/Mastodon/State/AppContext.swift index 8c0fa364..89771dfb 100644 --- a/Mastodon/State/AppContext.swift +++ b/Mastodon/State/AppContext.swift @@ -111,7 +111,7 @@ extension AppContext { return formatter }() - private static let purgeCacheWorkingQueue = DispatchQueue(label: "org.joinmastodon.Mastodon.AppContext.purgeCacheWorkingQueue") + private static let purgeCacheWorkingQueue = DispatchQueue(label: "org.joinmastodon.app.AppContext.purgeCacheWorkingQueue") func purgeCache() -> AnyPublisher { Publishers.MergeMany([ diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+App.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+App.swift index 3993afa6..48d78d68 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+App.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+App.swift @@ -103,7 +103,7 @@ extension Mastodon.API.App { public init( clientName: String, - redirectURIs: String = "urn:ietf:wg:oauth:2.0:oob", + redirectURIs: String, scopes: String? = "read write follow push", website: String? ) { diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+OAuth.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+OAuth.swift index 332d78a3..b5451e8f 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+OAuth.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+OAuth.swift @@ -139,7 +139,7 @@ extension Mastodon.API.OAuth { forceLogin: String? = nil, responseType: String = "code", clientID: String, - redirectURI: String = "urn:ietf:wg:oauth:2.0:oob", + redirectURI: String, scope: String? = "read write follow push" ) { self.forceLogin = forceLogin @@ -166,7 +166,7 @@ extension Mastodon.API.OAuth { public init( clientID: String, clientSecret: String, - redirectURI: String = "urn:ietf:wg:oauth:2.0:oob", + redirectURI: String, scope: String? = "read write follow push", code: String?, grantType: String diff --git a/MastodonSDK/Sources/MastodonSDK/Query/SerialStream.swift b/MastodonSDK/Sources/MastodonSDK/Query/SerialStream.swift index ad86033e..cde09b71 100644 --- a/MastodonSDK/Sources/MastodonSDK/Query/SerialStream.swift +++ b/MastodonSDK/Sources/MastodonSDK/Query/SerialStream.swift @@ -26,7 +26,7 @@ final class SerialStream: NSObject { private var buffer: UnsafeMutablePointer private var canWrite = false - private let workingQueue = DispatchQueue(label: "org.joinmastodon.Mastodon.SerialStream.\(UUID().uuidString)") + private let workingQueue = DispatchQueue(label: "org.joinmastodon.app.SerialStream.\(UUID().uuidString)") // bound pair stream private(set) lazy var boundStreams: Streams = { diff --git a/NotificationService/NotificationService.entitlements b/NotificationService/NotificationService.entitlements index d334a5e6..c3bc3f81 100644 --- a/NotificationService/NotificationService.entitlements +++ b/NotificationService/NotificationService.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.org.joinmastodon.mastodon-temp + group.org.joinmastodon.app