diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift index 3a0457983..45ae33487 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DataSourceProvider.swift @@ -12,7 +12,7 @@ extension HomeTimelineViewController: DataSourceProvider { func item(from source: DataSourceItem.Source) async -> DataSourceItem? { var _indexPath = source.indexPath if _indexPath == nil, let cell = source.tableViewCell { - _indexPath = await self.indexPath(for: cell) + _indexPath = self.indexPath(for: cell) } guard let indexPath = _indexPath else { return nil } @@ -37,8 +37,7 @@ extension HomeTimelineViewController: DataSourceProvider { viewModel?.dataController.update(status: status, intent: intent) } - @MainActor - private func indexPath(for cell: UITableViewCell) async -> IndexPath? { + private func indexPath(for cell: UITableViewCell) -> IndexPath? { return tableView.indexPath(for: cell) } } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 37fde8e5c..1da17601b 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -109,7 +109,7 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media viewModel.timelineContext = .following viewModel.dataController.records = [] - viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadLatestState.LoadingManually.self) + viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadLatestState.ContextSwitch.self) timelineSelectorButton.setAttributedTitle( .init(string: "Following", attributes: [ .font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold)) @@ -124,9 +124,7 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media guard let self, let viewModel = self.viewModel else { return } viewModel.timelineContext = .localCommunity - viewModel.dataController.records = [] - - viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadLatestState.LoadingManually.self) + viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadLatestState.ContextSwitch.self) timelineSelectorButton.setAttributedTitle( .init(string: "Local", attributes: [ .font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold)) @@ -591,8 +589,12 @@ extension HomeTimelineViewController: UITableViewDelegate, AutoGenerateTableView // sourcery:end func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + guard let viewModel, + let currentState = viewModel.loadLatestStateMachine.currentState as? HomeTimelineViewModel.LoadLatestState, + (currentState.self is HomeTimelineViewModel.LoadLatestState.ContextSwitch) == false else { return } + if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 { - viewModel?.timelineDidReachEnd() + viewModel.timelineDidReachEnd() } } } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift index c9e81737f..9d2ae90fc 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift @@ -40,6 +40,9 @@ extension HomeTimelineViewModel { guard let self = self else { return } guard let diffableDataSource = self.diffableDataSource else { return } + guard let currentState = loadLatestStateMachine.currentState as? HomeTimelineViewModel.LoadLatestState, + (currentState.self is HomeTimelineViewModel.LoadLatestState.ContextSwitch) == false else { return } + Task { @MainActor in let oldSnapshot = diffableDataSource.snapshot() var newSnapshot: NSDiffableDataSourceSnapshot = { diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift index f9cf6a89e..ed2793c74 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift @@ -70,7 +70,33 @@ extension HomeTimelineViewModel.LoadLatestState { class Idle: HomeTimelineViewModel.LoadLatestState { override func isValidNextState(_ stateClass: AnyClass) -> Bool { - return stateClass == Loading.self || stateClass == LoadingManually.self + return stateClass == Loading.self || stateClass == LoadingManually.self || stateClass == ContextSwitch.self + } + } + + class ContextSwitch: HomeTimelineViewModel.LoadLatestState { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + return stateClass == Loading.self || stateClass == LoadingManually.self || stateClass == ContextSwitch.self + } + + override func didEnter(from previousState: GKState?) { + guard let viewModel else { return } + guard let diffableDataSource = viewModel.diffableDataSource else { + assertionFailure() + return + } + + OperationQueue.main.addOperation { + viewModel.dataController.records = [] + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + snapshot.appendItems([.topLoader], toSection: .main) + diffableDataSource.apply(snapshot) { [weak self] in + guard let self else { return } + + self.stateMachine?.enter(Loading.self) + } + } } } @@ -78,7 +104,7 @@ extension HomeTimelineViewModel.LoadLatestState { super.didEnter(from: previousState) guard let viewModel else { return } - + let latestFeedRecords = viewModel.dataController.records.prefix(APIService.onceRequestStatusMaxCount) Task { diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift index e2c9fed2b..c87920e78 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift @@ -55,6 +55,7 @@ final class HomeTimelineViewModel: NSObject { LoadLatestState.LoadingManually(viewModel: self), LoadLatestState.Fail(viewModel: self), LoadLatestState.Idle(viewModel: self), + LoadLatestState.ContextSwitch(viewModel: self), ]) stateMachine.enter(LoadLatestState.Initial.self) return stateMachine