diff --git a/Mastodon/Scene/Discovery/ForYou/ProfileCardView+ViewModel.swift b/Mastodon/Scene/Discovery/ForYou/ProfileCardView+ViewModel.swift index b67ac9b5d..05bd54fca 100644 --- a/Mastodon/Scene/Discovery/ForYou/ProfileCardView+ViewModel.swift +++ b/Mastodon/Scene/Discovery/ForYou/ProfileCardView+ViewModel.swift @@ -57,7 +57,7 @@ extension ProfileCardView.ViewModel { private func bindHeader(view: ProfileCardView) { $authorBannerImageURL .sink { url in - guard let url = url, !url.absoluteString.hasSuffix(Mastodon.Entity.Account.missingImageName) else { + guard let url, !url.absoluteString.hasSuffix(Mastodon.Entity.Account.missingImageName) else { view.bannerImageView.image = .placeholder(color: .systemGray3) return } diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift index 15b5064b0..47f695987 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift @@ -46,7 +46,6 @@ final class DiscoveryPostsViewModel { self.context = context self.authContext = authContext self.dataController = StatusDataController() - // end init Task { await checkServerEndpoint() diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift index c6de4b6ad..e4bcc8a12 100644 --- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift @@ -25,7 +25,6 @@ extension NotificationTimelineViewController: DataSourceProvider { let item: DataSourceItem? = { guard feed.kind == .notificationAll || feed.kind == .notificationMentions else { return nil } - //TODO: Get relationship if let notification = feed.notification { let mastodonNotification = MastodonNotification.fromEntity(notification, relationship: nil) return .notification(record: mastodonNotification) diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift index e6a48d092..c2ac144f8 100644 --- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift +++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift @@ -56,7 +56,6 @@ final class NotificationTimelineViewModel { switch scope { case .everything: - //TODO: I need the relationship here, too self.dataController.records = (try? FileManager.default.cachedNotificationsAll(for: authContext.mastodonAuthenticationBox))?.map({ notification in MastodonFeed.fromNotification(notification, relationship: nil, kind: .notificationAll) }) ?? [] diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index ddd28307e..35702c0d8 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -409,7 +409,6 @@ extension ProfileViewController { guard let relationship else { return } - // they don't run as there's not a change, probably? self.viewModel.relationship = relationship self.viewModel.account = account } diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index b32f96000..5cd0d9d7c 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -127,17 +127,17 @@ extension MainTabBarController { .sink { [weak self] error in guard let self, let coordinator = self.coordinator else { return } switch error { - case .implicit: - break - case .explicit: - let alertController = UIAlertController(for: error, title: nil, preferredStyle: .alert) - let okAction = UIAlertAction(title: "OK", style: .default, handler: nil) - alertController.addAction(okAction) - _ = coordinator.present( - scene: .alertController(alertController: alertController), - from: nil, - transition: .alertController(animated: true, completion: nil) - ) + case .implicit: + break + case .explicit: + let alertController = UIAlertController(for: error, title: nil, preferredStyle: .alert) + let okAction = UIAlertAction(title: "OK", style: .default, handler: nil) + alertController.addAction(okAction) + _ = coordinator.present( + scene: .alertController(alertController: alertController), + from: nil, + transition: .alertController(animated: true, completion: nil) + ) } } .store(in: &disposeBag) diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index 85c47fc42..c3aa06892 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -74,12 +74,12 @@ extension SidebarViewModel { let imageURL: URL? switch item { - case .me: - let account = self.authContext?.mastodonAuthenticationBox.authentication.account() - imageURL = account?.avatarImageURL() - case .home, .search, .compose, .notifications: - // no custom avatar for other tabs - imageURL = nil + case .me: + let account = self.authContext?.mastodonAuthenticationBox.authentication.account() + imageURL = account?.avatarImageURL() + case .home, .search, .compose, .notifications: + // no custom avatar for other tabs + imageURL = nil } cell.item = SidebarListContentView.Item( diff --git a/Mastodon/Supporting Files/SceneDelegate.swift b/Mastodon/Supporting Files/SceneDelegate.swift index 014c0cedb..75aa27c6e 100644 --- a/Mastodon/Supporting Files/SceneDelegate.swift +++ b/Mastodon/Supporting Files/SceneDelegate.swift @@ -267,77 +267,77 @@ extension SceneDelegate { print("source application = \(sendingAppID ?? "Unknown")") print("url = \(url)") #endif - + switch url.host { - case "post": - showComposeViewController() - case "profile": - let components = url.pathComponents - guard - components.count == 2, - components[0] == "/", - let authContext = coordinator?.authContext - else { return } - - Task { - do { - let authenticationBox = authContext.mastodonAuthenticationBox - - guard let me = authContext.mastodonAuthenticationBox.authentication.account() else { return } - - guard let account = try await AppContext.shared.apiService.search( - query: .init(q: components[1], type: .accounts, resolve: true), - authenticationBox: authenticationBox - ).value.accounts.first else { return } - - guard let relationship = try await AppContext.shared.apiService.relationship( - forAccounts: [account], - authenticationBox: authenticationBox - ).value.first else { return } - - let profileViewModel = ProfileViewModel( - context: AppContext.shared, - authContext: authContext, - account: account, - relationship: relationship, - me: me - ) - - self.coordinator?.present( - scene: .profile(viewModel: profileViewModel), - from: nil, - transition: .show - ) - } catch { - // fail silently - } + case "post": + showComposeViewController() + case "profile": + let components = url.pathComponents + guard + components.count == 2, + components[0] == "/", + let authContext = coordinator?.authContext + else { return } + + Task { + do { + let authenticationBox = authContext.mastodonAuthenticationBox + + guard let me = authContext.mastodonAuthenticationBox.authentication.account() else { return } + + guard let account = try await AppContext.shared.apiService.search( + query: .init(q: components[1], type: .accounts, resolve: true), + authenticationBox: authenticationBox + ).value.accounts.first else { return } + + guard let relationship = try await AppContext.shared.apiService.relationship( + forAccounts: [account], + authenticationBox: authenticationBox + ).value.first else { return } + + let profileViewModel = ProfileViewModel( + context: AppContext.shared, + authContext: authContext, + account: account, + relationship: relationship, + me: me + ) + + self.coordinator?.present( + scene: .profile(viewModel: profileViewModel), + from: nil, + transition: .show + ) + } catch { + // fail silently } - case "status": - let components = url.pathComponents - guard - components.count == 2, - components[0] == "/", - let authContext = coordinator?.authContext - else { return } - let statusId = components[1] - // View post from user - let threadViewModel = RemoteThreadViewModel( - context: AppContext.shared, - authContext: authContext, - statusID: statusId - ) - coordinator?.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show) - case "search": - let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems - guard - let authContext = coordinator?.authContext, - let searchQuery = queryItems?.first(where: { $0.name == "query" })?.value - else { return } - - let viewModel = SearchDetailViewModel(authContext: authContext, initialSearchText: searchQuery) - coordinator?.present(scene: .searchDetail(viewModel: viewModel), from: nil, transition: .show) - default: - return + } + case "status": + let components = url.pathComponents + guard + components.count == 2, + components[0] == "/", + let authContext = coordinator?.authContext + else { return } + let statusId = components[1] + // View post from user + let threadViewModel = RemoteThreadViewModel( + context: AppContext.shared, + authContext: authContext, + statusID: statusId + ) + coordinator?.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show) + case "search": + let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems + guard + let authContext = coordinator?.authContext, + let searchQuery = queryItems?.first(where: { $0.name == "query" })?.value + else { return } + + let viewModel = SearchDetailViewModel(authContext: authContext, initialSearchText: searchQuery) + coordinator?.present(scene: .searchDetail(viewModel: viewModel), from: nil, transition: .show) + default: + return } } } diff --git a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift index b933ca2ae..48ce11f07 100644 --- a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift +++ b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift @@ -22,7 +22,7 @@ public enum Persistence { private var filename: String { switch self { case .searchHistory(let userIdentifier): - return "search_history_\(uniqueUserDomainIdentifier(for: userIdentifier))" // todo: @zeitschlag should this be user-scoped as well? + return "search_history_\(uniqueUserDomainIdentifier(for: userIdentifier))" case let .homeTimeline(userIdentifier): return "home_timeline_\(uniqueUserDomainIdentifier(for: userIdentifier))" case let .notificationsMentions(userIdentifier): diff --git a/MastodonSDK/Sources/MastodonCore/Service/Notification/NotificationService.swift b/MastodonSDK/Sources/MastodonCore/Service/Notification/NotificationService.swift index b69b57ded..727cb7d18 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/Notification/NotificationService.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/Notification/NotificationService.swift @@ -97,33 +97,30 @@ extension NotificationService { extension NotificationService { public func unreadApplicationShortcutItems() async throws -> [UIApplicationShortcutItem] { guard let authenticationService = self.authenticationService else { return [] } - let managedObjectContext = authenticationService.managedObjectContext - return try await managedObjectContext.perform { - var items: [UIApplicationShortcutItem] = [] - for authentication in AuthenticationServiceProvider.shared.authentications { - guard let account = authentication.account() else { continue } - let accessToken = authentication.userAccessToken - let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: accessToken) - guard count > 0 else { continue } - - let title = "@\(account.acctWithDomain)" - let subtitle = L10n.A11y.Plural.Count.Unread.notification(count) - - let item = UIApplicationShortcutItem( - type: NotificationService.unreadShortcutItemIdentifier, - localizedTitle: title, - localizedSubtitle: subtitle, - icon: nil, - userInfo: [ - "accessToken": accessToken as NSSecureCoding - ] - ) - items.append(item) - } - return items + + var items: [UIApplicationShortcutItem] = [] + for authentication in AuthenticationServiceProvider.shared.authentications { + guard let account = authentication.account() else { continue } + let accessToken = authentication.userAccessToken + let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: accessToken) + guard count > 0 else { continue } + + let title = "@\(account.acctWithDomain)" + let subtitle = L10n.A11y.Plural.Count.Unread.notification(count) + + let item = UIApplicationShortcutItem( + type: NotificationService.unreadShortcutItemIdentifier, + localizedTitle: title, + localizedSubtitle: subtitle, + icon: nil, + userInfo: [ + "accessToken": accessToken as NSSecureCoding + ] + ) + items.append(item) } - } -} + return items + }} extension NotificationService {