diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index cdc0c3f58..f85a7c96f 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -569,7 +569,10 @@ public extension SceneCoordinator { @MainActor func showLoading(on viewController: UIViewController?) { guard let viewController else { return } - + + /// Don't add HUD twice + guard MBProgressHUD.forView(viewController.view) == nil else { return } + MBProgressHUD.showAdded(to: viewController.view, animated: true) } diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift index 5140639fd..3fdf08e4e 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift @@ -50,7 +50,6 @@ extension DataSourceFacade { await responseToURLAction( provider: provider, - status: status, url: url ) case .hashtag(_, let hashtag, _): diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift index 3f2c6fe2d..82ec945fb 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift @@ -12,19 +12,21 @@ import MastodonSDK extension DataSourceFacade { + @MainActor static func coordinateToProfileScene( provider: DataSourceProvider & AuthContextProvider, target: StatusTarget, status: MastodonStatus ) async { - let acct: String = { - switch target { - case .status: - return status.reblog?.entity.account.acct ?? status.entity.account.acct - case .reblog: - return status.entity.account.acct - } - }() + let acct: String + switch target { + case .status: + acct = status.reblog?.entity.account.acct ?? status.entity.account.acct + case .reblog: + acct = status.entity.account.acct + } + + provider.coordinator.showLoading() let _redirectRecord = try? await Mastodon.API.Account.lookupAccount( session: .shared, @@ -35,6 +37,7 @@ extension DataSourceFacade { guard let redirectRecord = _redirectRecord else { assertionFailure() + provider.coordinator.hideLoading() return } await coordinateToProfileScene( @@ -110,12 +113,9 @@ extension DataSourceFacade { return } - let managedObjectContext = provider.context.managedObjectContext - let mentions = try? await managedObjectContext.perform { - return status.entity.mentions ?? [] - } + let mentions = status.entity.mentions ?? [] - guard let mention = mentions?.first(where: { $0.url == href }) else { + guard let mention = mentions.first(where: { $0.url == href }) else { _ = provider.coordinator.present( scene: .safari(url: url), from: provider, diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+URL.swift b/Mastodon/Protocol/Provider/DataSourceFacade+URL.swift index 286618a2c..ff1578af9 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+URL.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+URL.swift @@ -14,7 +14,6 @@ import MastodonSDK extension DataSourceFacade { static func responseToURLAction( provider: DataSourceProvider & AuthContextProvider, - status: MastodonStatus, url: URL ) async { let domain = provider.authContext.mastodonAuthenticationBox.domain diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift index 546b5e974..5ed4fc8b1 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift @@ -182,9 +182,15 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Med let _mediaTransitionContext: NotificationMediaTransitionContext? = { guard let status = record.status?.reblog ?? record.status else { return nil } + let needsToBeToggled: Bool = { + guard let sensitive = status.entity.sensitive else { + return false + } + return status.isSensitiveToggled ? !sensitive : sensitive + }() return NotificationMediaTransitionContext( status: status, - needsToggleMediaSensitive: status.isSensitiveToggled ? !(status.entity.sensitive == true) : (status.entity.sensitive == true) + needsToggleMediaSensitive: needsToBeToggled ) }() diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift index d380c4f36..57360f0c6 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift @@ -148,7 +148,6 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte await DataSourceFacade.responseToURLAction( provider: self, - status: status, url: url ) } @@ -173,7 +172,6 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte await DataSourceFacade.responseToURLAction( provider: self, - status: status, url: url ) } diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift index 97081cc6f..cfc3e07f3 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift @@ -65,10 +65,7 @@ extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvid case .status(let record): return record case .notification(let record): - guard let statusRecord = record.status else { - return nil - } - return statusRecord + return record.status default: return nil } diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift index 41838b0e6..276500c03 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift @@ -40,9 +40,7 @@ extension UITableViewDelegate where Self: DataSourceProvider & AuthContextProvid provider: self, tag: tag ) - case .notification(let notification): - let managedObjectContext = context.managedObjectContext - + case .notification(let notification): let _status: MastodonStatus? = notification.status if let status = _status { await DataSourceFacade.coordinateToStatusThreadScene( diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift index 28b6a4984..aa4252b46 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift @@ -22,15 +22,12 @@ extension HomeTimelineViewController: DataSourceProvider { switch item { case .feed(let feed): - let item: DataSourceItem? = { - guard feed.kind == .home else { return nil } - if let status = feed.status { - return .status(record: status) - } else { - return nil - } - }() - return item + guard feed.kind == .home else { return nil } + if let status = feed.status { + return .status(record: status) + } else { + return nil + } default: return nil } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadOldestState.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadOldestState.swift index a2bf3e224..5f306ea20 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadOldestState.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadOldestState.swift @@ -52,10 +52,7 @@ extension HomeTimelineViewModel.LoadOldestState { } Task { - let _maxID: Mastodon.Entity.Status.ID? = { - guard let status = lastFeedRecord.status else { return nil } - return status.id - }() + let _maxID = lastFeedRecord.status?.id guard let maxID = _maxID else { await self.enter(state: Fail.self) diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift index 4a7d22229..e7a8de3b6 100644 --- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController+DataSourceProvider.swift @@ -42,7 +42,7 @@ extension NotificationTimelineViewController: DataSourceProvider { } func delete(status: MastodonStatus) { - viewModel.feedFetchedResultsController + viewModel.feedFetchedResultsController.delete(status: status) } @MainActor diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift index cdc1840fe..9b552857c 100644 --- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift +++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel.swift @@ -111,18 +111,6 @@ extension NotificationTimelineViewModel { // load timeline gap func loadMore(item: NotificationItem) async { -// guard case let .feedLoader(record) = item else { return } - -// guard let maxID = record.notification?.id else { return } - -// // fetch data -// if let notifications = try? await context.apiService.notifications( -// maxID: maxID, -// scope: scope, -// authenticationBox: authContext.mastodonAuthenticationBox -// ) { -// self.feedFetchedResultsController.records += notifications.value.map { MastodonFeed.fromNotification($0, kind: record.kind) } -// } switch scope { case .everything: feedFetchedResultsController.loadNext(kind: .notificationAll) diff --git a/Mastodon/Scene/Report/Share/Cell/ReportStatusTableViewCell+ViewModel.swift b/Mastodon/Scene/Report/Share/Cell/ReportStatusTableViewCell+ViewModel.swift index a5ad90bc4..f5078847a 100644 --- a/Mastodon/Scene/Report/Share/Cell/ReportStatusTableViewCell+ViewModel.swift +++ b/Mastodon/Scene/Report/Share/Cell/ReportStatusTableViewCell+ViewModel.swift @@ -9,6 +9,7 @@ import UIKit import MastodonSDK extension ReportStatusTableViewCell { + // todo: refactor / remove this final class ViewModel { let value: MastodonStatus diff --git a/MastodonSDK/Sources/MastodonCore/Model/UserIdentifier.swift b/MastodonSDK/Sources/MastodonCore/Model/UserIdentifier.swift index 6db7499c6..a02593f66 100644 --- a/MastodonSDK/Sources/MastodonCore/Model/UserIdentifier.swift +++ b/MastodonSDK/Sources/MastodonCore/Model/UserIdentifier.swift @@ -13,6 +13,12 @@ public protocol UserIdentifier { var userID: Mastodon.Entity.Account.ID { get } } +public extension UserIdentifier { + var uniqueUserDomainIdentifier: String { + "\(userID)@\(domain)" + } +} + public struct MastodonUserIdentifier: UserIdentifier { public let domain: String public var userID: Mastodon.Entity.Account.ID diff --git a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift index 989c5c5db..f11ff61e1 100644 --- a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift +++ b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift @@ -14,20 +14,16 @@ public enum Persistence { case notificationsMentions(UserIdentifier) case notificationsAll(UserIdentifier) - private func uniqueUserDomainIdentifier(for userIdentifier: UserIdentifier) -> String { - "\(userIdentifier.userID)@\(userIdentifier.domain)" - } - private var filename: String { switch self { case .searchHistory: return "search_history" // todo: @zeitschlag should this be user-scoped as well? case let .homeTimeline(userIdentifier): - return "home_timeline_\(uniqueUserDomainIdentifier(for: userIdentifier))" + return "home_timeline_\(userIdentifier.uniqueUserDomainIdentifier)" case let .notificationsMentions(userIdentifier): - return "notifications_mentions_\(uniqueUserDomainIdentifier(for: userIdentifier))" + return "notifications_mentions_\(userIdentifier.uniqueUserDomainIdentifier)" case let .notificationsAll(userIdentifier): - return "notifications_all_\(uniqueUserDomainIdentifier(for: userIdentifier))" + return "notifications_all_\(userIdentifier.uniqueUserDomainIdentifier)" } } diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HashtagTimeline.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HashtagTimeline.swift index f1d7c0688..26ef9625f 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HashtagTimeline.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HashtagTimeline.swift @@ -50,8 +50,8 @@ extension APIService { for entity in response.value { guard let poll = entity.poll else { continue } _ = Persistence.Poll.createOrMerge( - in: managedObjectContext, - context: .init(domain: domain, entity: poll, me: me, networkDate: response.networkDate) + in: managedObjectContext, + context: .init(domain: domain, entity: poll, me: me, networkDate: response.networkDate) ) } } diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HomeTimeline.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HomeTimeline.swift index e6e3e9504..272d81fa2 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HomeTimeline.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HomeTimeline.swift @@ -49,8 +49,8 @@ extension APIService { for entity in response.value { guard let poll = entity.poll else { continue } _ = Persistence.Poll.createOrMerge( - in: managedObjectContext, - context: .init(domain: domain, entity: poll, me: me, networkDate: response.networkDate) + in: managedObjectContext, + context: .init(domain: domain, entity: poll, me: me, networkDate: response.networkDate) ) } } diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+PublicTimeline.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+PublicTimeline.swift index 6fa686bf9..ed36a57bc 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+PublicTimeline.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+PublicTimeline.swift @@ -35,8 +35,8 @@ extension APIService { for entity in response.value { guard let poll = entity.poll else { continue } _ = Persistence.Poll.createOrMerge( - in: managedObjectContext, - context: .init(domain: domain, entity: poll, me: me, networkDate: response.networkDate) + in: managedObjectContext, + context: .init(domain: domain, entity: poll, me: me, networkDate: response.networkDate) ) } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusCardControl.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusCardControl.swift index 14a87c6ea..c096428a5 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusCardControl.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusCardControl.swift @@ -344,9 +344,12 @@ private extension Mastodon.Entity.Card { if !aspectRatio.isFinite { aspectRatio = 1 } - return (abs(aspectRatio - 1) < 0.05 || image == nil) && html == nil - ? .compact - : .large(aspectRatio: aspectRatio) + + if (abs(aspectRatio - 1) < 0.05 || image == nil) && html == nil { + return .compact + } else { + return .large(aspectRatio: aspectRatio) + } } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift index 24cf83f70..1818becaf 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift @@ -193,7 +193,6 @@ extension StatusView { } .store(in: &disposeBag) } // end if let -// } // end else B2. } // end else B. } else { @@ -389,14 +388,17 @@ extension StatusView { private func configurePoll(status: MastodonStatus) { let status = status.reblog ?? status - - let predicate = Poll.predicate(domain: viewModel.authContext?.mastodonAuthenticationBox.domain ?? "", id: status.entity.poll?.id ?? "") - + guard let context = viewModel.context?.managedObjectContext, - let poll = Poll.findOrFetch(in: context, matching: predicate) - else { return } - + let domain = viewModel.authContext?.mastodonAuthenticationBox.domain, + let pollId = status.entity.poll?.id + else { + return + } + + let predicate = Poll.predicate(domain: domain, id: pollId) + guard let poll = Poll.findOrFetch(in: context, matching: predicate) else { return } viewModel.managedObjects.insert(poll)