diff --git a/Localization/app.json b/Localization/app.json index 734169df0..9d8ce91b4 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -222,10 +222,11 @@ "pending": "Pending", "block": "Block", "block_user": "Block %s", - "block_domain": "Block %s", + "block_domain": "Block domain %s", "unblock": "Unblock", "unblock_user": "Unblock %s", "blocked": "Blocked", + "domain_blocked": "Domain Blocked", "mute": "Mute", "mute_user": "Mute %s", "unmute": "Unmute", @@ -603,6 +604,14 @@ "confirm_hide_reblogs": { "title": "Hide Reblogs", "message": "Confirm to hide reblogs" + }, + "confirm_block_domain": { + "title": "Block domain", + "message": "Confirm to block domain %s" + }, + "confirm_unblock_domain": { + "title": "Unblock domain", + "message": "Confirm to unblock domain %s" } }, "accessibility": { diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index b6a44d8fa..4ad25d216 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4623,7 +4623,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2023.17; + MARKETING_VERSION = 2024.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4654,7 +4654,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2023.17; + MARKETING_VERSION = 2024.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4844,7 +4844,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2023.17; + MARKETING_VERSION = 2024.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -5140,7 +5140,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2023.17; + MARKETING_VERSION = 2024.1; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift index 33dda8971..3473d6e80 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift @@ -34,4 +34,19 @@ extension DataSourceFacade { return response.value } + + static func responseToDomainBlockAction( + dependency: NeedsDependency & AuthContextProvider, + account: Mastodon.Entity.Account + ) async throws -> Mastodon.Entity.Empty { + let selectionFeedbackGenerator = await UISelectionFeedbackGenerator() + await selectionFeedbackGenerator.selectionChanged() + + let apiService = dependency.context.apiService + let authBox = dependency.authContext.mastodonAuthenticationBox + + let response = try await apiService.toggleDomainBlock(account: account, authenticationBox: authBox) + + return response.value + } } diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift index 2595da4dc..c13906f4a 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift @@ -367,8 +367,42 @@ extension DataSourceFacade { case .followUser(_): try await DataSourceFacade.responseToUserFollowAction(dependency: dependency, account: menuContext.author) + case .blockDomain(let context): + let title: String + let message: String + let actionTitle: String + + if context.isBlocking { + title = L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnblockDomain.title + message = L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnblockDomain.message(context.domain) + actionTitle = L10n.Common.Controls.Friendship.unblockDomain(context.domain) + } else { + title = L10n.Scene.Profile.RelationshipActionAlert.ConfirmBlockDomain.title + message = L10n.Common.Alerts.BlockDomain.title(context.domain) + actionTitle = L10n.Common.Alerts.BlockDomain.blockEntireDomain + } + + let alertController = UIAlertController( + title: title, + message: message, + preferredStyle: .alert + ) + + let confirmAction = UIAlertAction(title: actionTitle, style: .destructive ) { [weak dependency] _ in + guard let dependency else { return } + Task { + try await DataSourceFacade.responseToDomainBlockAction( + dependency: dependency, + account: menuContext.author + ) + } + } + alertController.addAction(confirmAction) + let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel) + alertController.addAction(cancelAction) + dependency.present(alertController, animated: true) } - } // end func + } } extension DataSourceFacade { diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift index 5ddb57dc4..0aa45ae14 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift +++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift @@ -133,7 +133,7 @@ extension ProfileHeaderView.ViewModel { .compactMap { relationship in guard let relationship else { return false } - return relationship.blocking || relationship.blockedBy + return relationship.blocking || relationship.blockedBy || relationship.domainBlocking } .sink { needsImageOverlayBlurred in UIView.animate(withDuration: 0.33) { @@ -203,9 +203,10 @@ extension ProfileHeaderView.ViewModel { guard let relationship else { return nil } - let isBlocking = relationship.blocking + let isBlocking = relationship.blocking || relationship.domainBlocking let isBlockedBy = relationship.blockedBy let isSuspended = account.suspended ?? false + let isNeedsHidden = isBlocking || isBlockedBy || isSuspended return isNeedsHidden diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index baff03943..d6c7b3d94 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -791,6 +791,33 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate { let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel) alertController.addAction(cancelAction) coordinator.present(scene: .alertController(alertController: alertController), transition: .alertController(animated: true)) + } else if relationship.domainBlocking { + guard let domain = account.domain else { return } + + let alertController = UIAlertController( + title: L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnblockDomain.title, + message: L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnblockDomain.message(domain), + preferredStyle: .alert + ) + + let unblockAction = UIAlertAction(title: L10n.Common.Controls.Friendship.unblockDomain(domain), style: .default) { [weak self] _ in + guard let self else { return } + Task { + _ = try await DataSourceFacade.responseToDomainBlockAction( + dependency: self, + account: account + ) + + guard let newRelationship = try await self.context.apiService.relationship(forAccounts: [account], authenticationBox: self.authContext.mastodonAuthenticationBox).value.first else { return } + + self.viewModel.relationship = newRelationship + } + } + alertController.addAction(unblockAction) + let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel) + alertController.addAction(cancelAction) + coordinator.present(scene: .alertController(alertController: alertController), transition: .alertController(animated: true)) + } else if relationship.muting { let name = account.displayNameWithFallback @@ -877,6 +904,7 @@ extension ProfileViewController: MastodonMenuDelegate { switch action { case .muteUser(_), .blockUser(_), + .blockDomain(_), .hideReblogs(_): Task { try await DataSourceFacade.responseToMenuAction( diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift index 67f2b8035..422440020 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift @@ -41,11 +41,12 @@ extension UserTimelineViewModel { } .store(in: &disposeBag) - let needsTimelineHidden = Publishers.CombineLatest3( + let needsTimelineHidden = Publishers.CombineLatest4( $isBlocking, $isBlockedBy, - $isSuspended - ).map { $0 || $1 || $2 } + $isSuspended, + $isDomainBlocking + ).map { $0 || $1 || $2 || $3 } Publishers.CombineLatest( statusFetchedResultsController.$records, diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift index f2b67c3ee..c64378d57 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift @@ -27,6 +27,7 @@ final class UserTimelineViewModel { @Published var queryFilter: QueryFilter @Published var isBlocking = false + @Published var isDomainBlocking = false @Published var isBlockedBy = false @Published var isSuspended = false diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+DomainBlock.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+DomainBlock.swift index 3bfa519c7..33d1476b8 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+DomainBlock.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+DomainBlock.swift @@ -66,72 +66,64 @@ extension APIService { } .eraseToAnyPublisher() } - + + public func toggleDomainBlock( + account: Mastodon.Entity.Account, + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content { + guard let originalRelationship = try await relationship(forAccounts: [account], authenticationBox: authenticationBox).value.first else { + throw APIError.implicit(.badRequest) + } + + let response: Mastodon.Response.Content + let domainBlocking = originalRelationship.domainBlocking + + if domainBlocking { + response = try await unblockDomain(account: account, authorizationBox: authenticationBox) + } else { + response = try await blockDomain(account: account, authorizationBox: authenticationBox) + } + + return response + } + func blockDomain( - user: MastodonUser, + account: Mastodon.Entity.Account, authorizationBox: MastodonAuthenticationBox - ) -> AnyPublisher, Error> { + ) async throws -> Mastodon.Response.Content { let authorization = authorizationBox.userAuthorization - return Mastodon.API.DomainBlock.blockDomain( + guard let domain = account.domainFromAcct else { + throw APIError.implicit(.badRequest) + } + + let result = try await Mastodon.API.DomainBlock.blockDomain( domain: authorizationBox.domain, - blockDomain: user.domainFromAcct, + blockDomain: domain, session: session, authorization: authorization - ) - .flatMap { response -> AnyPublisher, Error> in - self.backgroundManagedObjectContext.performChanges { - let requestMastodonUserRequest = MastodonUser.sortedFetchRequest - requestMastodonUserRequest.predicate = MastodonUser.predicate(domain: authorizationBox.domain, id: authorizationBox.userID) - requestMastodonUserRequest.fetchLimit = 1 - guard let requestMastodonUser = self.backgroundManagedObjectContext.safeFetch(requestMastodonUserRequest).first else { return } - user.update(isDomainBlocking: true, by: requestMastodonUser) - } - .setFailureType(to: Error.self) - .tryMap { result -> Mastodon.Response.Content in - switch result { - case .success: - return response - case .failure(let error): - throw error - } - } - .eraseToAnyPublisher() - } - .eraseToAnyPublisher() + ).singleOutput() + + return result } func unblockDomain( - user: MastodonUser, + account: Mastodon.Entity.Account, authorizationBox: MastodonAuthenticationBox - ) -> AnyPublisher, Error> { + ) async throws -> Mastodon.Response.Content { let authorization = authorizationBox.userAuthorization - - return Mastodon.API.DomainBlock.unblockDomain( + + guard let domain = account.domainFromAcct else { + throw APIError.implicit(.badRequest) + } + + let result = try await Mastodon.API.DomainBlock.unblockDomain( domain: authorizationBox.domain, - blockDomain: user.domainFromAcct, + blockDomain: domain, session: session, authorization: authorization - ) - .flatMap { response -> AnyPublisher, Error> in - self.backgroundManagedObjectContext.performChanges { - let requestMastodonUserRequest = MastodonUser.sortedFetchRequest - requestMastodonUserRequest.predicate = MastodonUser.predicate(domain: authorizationBox.domain, id: authorizationBox.userID) - requestMastodonUserRequest.fetchLimit = 1 - guard let requestMastodonUser = self.backgroundManagedObjectContext.safeFetch(requestMastodonUserRequest).first else { return } - user.update(isDomainBlocking: false, by: requestMastodonUser) - } - .setFailureType(to: Error.self) - .tryMap { result -> Mastodon.Response.Content in - switch result { - case .success: - return response - case .failure(let error): - throw error - } - } - .eraseToAnyPublisher() - } - .eraseToAnyPublisher() + ).singleOutput() + + return result } } diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 99c061f91..fae0ddc50 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -216,6 +216,8 @@ public enum L10n { public static func blockUser(_ p1: Any) -> String { return L10n.tr("Localizable", "Common.Controls.Friendship.BlockUser", String(describing: p1), fallback: "Block %@") } + /// Domain Blocked + public static let domainBlocked = L10n.tr("Localizable", "Common.Controls.Friendship.DomainBlocked", fallback: "Domain Blocked") /// Edit Info public static let editInfo = L10n.tr("Localizable", "Common.Controls.Friendship.EditInfo", fallback: "Edit Info") /// Follow @@ -241,6 +243,10 @@ public enum L10n { /// Unblock public static let unblock = L10n.tr("Localizable", "Common.Controls.Friendship.Unblock", fallback: "Unblock") /// Unblock %@ + public static func unblockDomain(_ p1: Any) -> String { + return L10n.tr("Localizable", "Common.Controls.Friendship.UnblockDomain", String(describing: p1), fallback: "Unblock %@") + } + /// Unblock %@ public static func unblockUser(_ p1: Any) -> String { return L10n.tr("Localizable", "Common.Controls.Friendship.UnblockUser", String(describing: p1), fallback: "Unblock %@") } @@ -953,6 +959,10 @@ public enum L10n { public static let followsYou = L10n.tr("Localizable", "Scene.Profile.Header.FollowsYou", fallback: "Follows You") } public enum RelationshipActionAlert { + public enum ConfirmBlockDomain { + /// Block Domain + public static let title = L10n.tr("Localizable", "Scene.Profile.RelationshipActionAlert.ConfirmBlockDomain.Title", fallback: "Block Domain") + } public enum ConfirmBlockUser { /// Confirm to block %@ public static func message(_ p1: Any) -> String { @@ -981,6 +991,14 @@ public enum L10n { /// Show Reblogs public static let title = L10n.tr("Localizable", "Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title", fallback: "Show Reblogs") } + public enum ConfirmUnblockDomain { + /// Confirm to unblock domain %@ + public static func message(_ p1: Any) -> String { + return L10n.tr("Localizable", "Scene.Profile.RelationshipActionAlert.ConfirmUnblockDomain.Message", String(describing: p1), fallback: "Confirm to unblock domain %@") + } + /// Unblock Domain + public static let title = L10n.tr("Localizable", "Scene.Profile.RelationshipActionAlert.ConfirmUnblockDomain.Title", fallback: "Unblock Domain") + } public enum ConfirmUnblockUser { /// Confirm to unblock %@ public static func message(_ p1: Any) -> String { diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings index 2faf5ebb7..bd1bfc949 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings @@ -73,6 +73,7 @@ Please check your internet connection."; "Common.Controls.Friendship.BlockDomain" = "Block %@"; "Common.Controls.Friendship.BlockUser" = "Block %@"; "Common.Controls.Friendship.Blocked" = "Blocked"; +"Common.Controls.Friendship.DomainBlocked" = "Domain Blocked"; "Common.Controls.Friendship.EditInfo" = "Edit Info"; "Common.Controls.Friendship.Follow" = "Follow"; "Common.Controls.Friendship.Following" = "Following"; @@ -85,6 +86,7 @@ Please check your internet connection."; "Common.Controls.Friendship.ShowReblogs" = "Show Reblogs"; "Common.Controls.Friendship.Unblock" = "Unblock"; "Common.Controls.Friendship.UnblockUser" = "Unblock %@"; +"Common.Controls.Friendship.UnblockDomain" = "Unblock %@"; "Common.Controls.Friendship.Unmute" = "Unmute"; "Common.Controls.Friendship.UnmuteUser" = "Unmute %@"; "Common.Controls.Keyboard.Common.ComposeNewPost" = "Compose New Post"; @@ -336,6 +338,9 @@ uploaded to Mastodon."; "Scene.Profile.Header.FollowsYou" = "Follows You"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confirm to block %@"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Block Account"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockDomain.Title" = "Block Domain"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockDomain.Message" = "Confirm to unblock domain %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockDomain.Title" = "Unblock Domain"; "Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Confirm to hide reblogs"; "Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Hide Reblogs"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Confirm to mute %@"; @@ -563,4 +568,4 @@ uploaded to Mastodon."; "Widget.MultipleFollowers.ConfigurationDescription" = "Show number of followers for multiple accounts."; "Widget.MultipleFollowers.ConfigurationDisplayName" = "Multiple followers"; "Widget.MultipleFollowers.MockUser.AccountName" = "another@follower.social"; -"Widget.MultipleFollowers.MockUser.DisplayName" = "Another follower"; \ No newline at end of file +"Widget.MultipleFollowers.MockUser.DisplayName" = "Another follower"; diff --git a/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift b/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift index 65231c51d..72f2877a9 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift @@ -59,7 +59,8 @@ extension MastodonMenu { case deleteStatus case editStatus case followUser(FollowUserActionContext) - + case blockDomain(BlockDomainActionContext) + func build(delegate: MastodonMenuDelegate) -> LabeledAction { switch self { case .hideReblogs(let context): @@ -194,14 +195,29 @@ extension MastodonMenu { image = UIImage(systemName: "person.fill.badge.plus") } let action = LabeledAction(title: title, image: image) { [weak delegate] in - guard let delegate = delegate else { return } + guard let delegate else { return } delegate.menuAction(self) } return action + case .blockDomain(let context): + let title: String + let image: UIImage? + if context.isBlocking { + title = L10n.Common.Controls.Actions.unblockDomain(context.domain) + image = UIImage(systemName: "hand.raised.slash.fill") + } else { + title = L10n.Common.Controls.Actions.blockDomain(context.domain) + image = UIImage(systemName: "hand.raised.fill") + } + let action = LabeledAction(title: title, image: image) { [weak delegate] in + guard let delegate else { return } - } // end switch - } // end func build - } // end enum Action + delegate.menuAction(self) + } + return action + } + } + } } extension MastodonMenu { @@ -275,4 +291,14 @@ extension MastodonMenu { self.isFollowing = isFollowing } } + + public struct BlockDomainActionContext { + public let domain: String + public let isBlocking: Bool + + public init(domain: String, isBlocking: Bool) { + self.domain = domain + self.isBlocking = isBlocking + } + } } diff --git a/WidgetExtension/Variants/FollowersCount/FollowersCountWidget.swift b/WidgetExtension/Variants/FollowersCount/FollowersCountWidget.swift index 1f118aeeb..c50c58c9b 100644 --- a/WidgetExtension/Variants/FollowersCount/FollowersCountWidget.swift +++ b/WidgetExtension/Variants/FollowersCount/FollowersCountWidget.swift @@ -4,6 +4,7 @@ import WidgetKit import SwiftUI import Intents import MastodonSDK +import MastodonCore import MastodonLocalization struct FollowersCountWidgetProvider: IntentTimelineProvider { @@ -70,6 +71,9 @@ struct FollowersCountWidget: Widget { private extension FollowersCountWidgetProvider { func loadCurrentEntry(for configuration: FollowersCountIntent, in context: Context, completion: @escaping (FollowersCountEntry) -> Void) { Task { + + AuthenticationServiceProvider.shared.restore() + guard let authBox = WidgetExtension.appContext .authenticationService diff --git a/WidgetExtension/Variants/Hashtag/HashtagWidget.swift b/WidgetExtension/Variants/Hashtag/HashtagWidget.swift index 41e21da83..08ca4c77b 100644 --- a/WidgetExtension/Variants/Hashtag/HashtagWidget.swift +++ b/WidgetExtension/Variants/Hashtag/HashtagWidget.swift @@ -4,6 +4,7 @@ import WidgetKit import SwiftUI import MastodonSDK import MastodonLocalization +import MastodonCore struct HashtagWidgetProvider: IntentTimelineProvider { func placeholder(in context: Context) -> HashtagWidgetTimelineEntry { @@ -24,6 +25,8 @@ struct HashtagWidgetProvider: IntentTimelineProvider { extension HashtagWidgetProvider { func loadMostRecentHashtag(for configuration: HashtagIntent, in context: Context, completion: @escaping (HashtagWidgetTimelineEntry) -> Void ) { + AuthenticationServiceProvider.shared.restore() + guard let authBox = WidgetExtension.appContext .authenticationService diff --git a/WidgetExtension/Variants/LatestFollowers/LatestFollowersWidget.swift b/WidgetExtension/Variants/LatestFollowers/LatestFollowersWidget.swift index d2bf73b5a..456af2ebb 100644 --- a/WidgetExtension/Variants/LatestFollowers/LatestFollowersWidget.swift +++ b/WidgetExtension/Variants/LatestFollowers/LatestFollowersWidget.swift @@ -5,6 +5,7 @@ import SwiftUI import Intents import MastodonSDK import MastodonLocalization +import MastodonCore struct LatestFollowersWidgetProvider: IntentTimelineProvider { func placeholder(in context: Context) -> LatestFollowersEntry { @@ -77,6 +78,9 @@ struct LatestFollowersWidget: Widget { private extension LatestFollowersWidgetProvider { func loadCurrentEntry(for configuration: LatestFollowersIntent, in context: Context, completion: @escaping (LatestFollowersEntry) -> Void) { Task { @MainActor in + + AuthenticationServiceProvider.shared.restore() + guard let authBox = WidgetExtension.appContext .authenticationService diff --git a/WidgetExtension/Variants/MultiFollowersCount/MultiFollowersCountWidget.swift b/WidgetExtension/Variants/MultiFollowersCount/MultiFollowersCountWidget.swift index 15c1c4d14..38e3ddc8c 100644 --- a/WidgetExtension/Variants/MultiFollowersCount/MultiFollowersCountWidget.swift +++ b/WidgetExtension/Variants/MultiFollowersCount/MultiFollowersCountWidget.swift @@ -4,6 +4,7 @@ import WidgetKit import SwiftUI import Intents import MastodonSDK +import MastodonCore import MastodonLocalization struct MultiFollowersCountWidgetProvider: IntentTimelineProvider { @@ -70,6 +71,9 @@ struct MultiFollowersCountWidget: Widget { private extension MultiFollowersCountWidgetProvider { func loadCurrentEntry(for configuration: MultiFollowersCountIntent, in context: Context, completion: @escaping (MultiFollowersCountEntry) -> Void) { Task { + + AuthenticationServiceProvider.shared.restore() + guard let authBox = WidgetExtension.appContext .authenticationService