mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00

A large amount of change primarily to the view model layer, to make reasoning about the content reveal/hide state easier. To prevent terrible scrolling jags while allowing the cells to be shorter when hiding content, the layout changes for content display state now happen before the cell is returned by the datasource provider and the tableview is reloaded when a status’s display mode changes.
102 lines
3.5 KiB
Swift
102 lines
3.5 KiB
Swift
//
|
|
// ThreadViewController+DataSourceProvider.swift
|
|
// Mastodon
|
|
//
|
|
// Created by MainasuK on 2022-1-17.
|
|
//
|
|
|
|
import UIKit
|
|
import MastodonSDK
|
|
|
|
// MARK: - DataSourceProvider
|
|
extension ThreadViewController: DataSourceProvider {
|
|
var filterContext: MastodonSDK.Mastodon.Entity.FilterContext? {
|
|
return .thread
|
|
}
|
|
|
|
func didToggleContentWarningDisplayStatus(status: MastodonSDK.MastodonStatus) {
|
|
tableView.reloadData()
|
|
}
|
|
|
|
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)
|
|
}
|
|
guard let indexPath = _indexPath else { return nil }
|
|
|
|
guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else {
|
|
return nil
|
|
}
|
|
|
|
switch item {
|
|
case .thread(let thread):
|
|
return .status(record: thread.record)
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func update(status _status: MastodonStatus, intent: MastodonStatus.UpdateIntent) {
|
|
let status = _status.reblog ?? _status
|
|
if case MastodonStatus.UpdateIntent.delete = intent {
|
|
return handleDelete(status)
|
|
}
|
|
|
|
switch viewModel.root {
|
|
case let .root(context):
|
|
if context.status.id == status.id {
|
|
viewModel.root = .root(context: .init(status: status))
|
|
} else {
|
|
handleUpdate(status: status, viewModel: viewModel.mastodonStatusThreadViewModel, intent: intent)
|
|
}
|
|
case let .reply(context):
|
|
if context.status.id == status.id {
|
|
viewModel.root = .reply(context: .init(status: status))
|
|
} else {
|
|
handleUpdate(status: status, viewModel: viewModel.mastodonStatusThreadViewModel, intent: intent)
|
|
}
|
|
case let .leaf(context):
|
|
if context.status.id == status.id {
|
|
viewModel.root = .leaf(context: .init(status: status))
|
|
} else {
|
|
handleUpdate(status: status, viewModel: viewModel.mastodonStatusThreadViewModel, intent: intent)
|
|
}
|
|
case .none:
|
|
assertionFailure("This should not have happened")
|
|
}
|
|
}
|
|
|
|
private func handleDelete(_ status: MastodonStatus) {
|
|
if viewModel.root?.record.id == status.id {
|
|
viewModel.root = nil
|
|
viewModel.onDismiss.send(status)
|
|
}
|
|
viewModel.mastodonStatusThreadViewModel.handleDelete(status)
|
|
}
|
|
|
|
@MainActor
|
|
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
|
return tableView.indexPath(for: cell)
|
|
}
|
|
|
|
private func handleUpdate(status: MastodonStatus, viewModel: MastodonStatusThreadViewModel, intent: MastodonStatus.UpdateIntent) {
|
|
switch intent {
|
|
case .bookmark:
|
|
viewModel.handleBookmark(status)
|
|
case let .reblog(isReblogged):
|
|
viewModel.handleReblog(status, isReblogged)
|
|
case .favorite:
|
|
viewModel.handleFavorite(status)
|
|
case let .toggleSensitive(isVisible):
|
|
viewModel.handleSensitive(status, isVisible)
|
|
case .edit:
|
|
viewModel.handleEdit(status)
|
|
case .delete:
|
|
break // this case has already been handled
|
|
case .pollVote:
|
|
viewModel.handleEdit(status) // technically the data changed so refresh it to reflect the new data
|
|
}
|
|
}
|
|
}
|