183 lines
8.6 KiB
Swift
183 lines
8.6 KiB
Swift
//
|
|
// StatusTableViewControllerAspect.swift
|
|
// Mastodon
|
|
//
|
|
// Created by MainasuK Cirno on 2021-4-7.
|
|
//
|
|
|
|
import UIKit
|
|
import AVKit
|
|
import GameController
|
|
|
|
// Check List Last Updated
|
|
// - HomeViewController: 2021/7/15
|
|
// - FavoriteViewController: 2021/4/30
|
|
// - HashtagTimelineViewController: 2021/4/30
|
|
// - UserTimelineViewController: 2021/4/30
|
|
// - ThreadViewController: 2021/4/30
|
|
// - SearchResultViewController: 2021/7/15
|
|
// * StatusTableViewControllerAspect: 2021/7/15
|
|
|
|
// (Fake) Aspect protocol to group common protocol extension implementations
|
|
// Needs update related view controller when aspect interface changes
|
|
|
|
/// Status related operations aspect
|
|
/// Please check the aspect methods (Option+Click) and add hook to implement features
|
|
/// - UI
|
|
/// - Media
|
|
/// - Data Source
|
|
protocol StatusTableViewControllerAspect: UIViewController {
|
|
var tableView: UITableView { get }
|
|
}
|
|
|
|
// MARK: - UIViewController [A]
|
|
|
|
// [A1] aspectViewWillAppear(_:)
|
|
extension StatusTableViewControllerAspect {
|
|
/// [UI] hook to deselect row in the transitioning for the table view
|
|
func aspectViewWillAppear(_ animated: Bool) {
|
|
if GCKeyboard.coalesced != nil, let backKeyCommandPressDate = UserDefaults.shared.backKeyCommandPressDate {
|
|
guard backKeyCommandPressDate.timeIntervalSinceNow <= -0.5 else {
|
|
// break if interval greater than 0.5s
|
|
return
|
|
}
|
|
}
|
|
tableView.deselectRow(with: transitionCoordinator, animated: animated)
|
|
}
|
|
}
|
|
|
|
// [A2] aspectViewDidDisappear(_:)
|
|
extension StatusTableViewControllerAspect where Self: NeedsDependency {
|
|
/// [Media] hook to notify video service
|
|
func aspectViewDidDisappear(_ animated: Bool) {
|
|
context.videoPlaybackService.viewDidDisappear(from: self)
|
|
context.audioPlaybackService.viewDidDisappear(from: self)
|
|
}
|
|
}
|
|
|
|
// MARK: - UITableViewDelegate [B]
|
|
|
|
// [B1] aspectTableView(_:estimatedHeightForRowAt:)
|
|
extension StatusTableViewControllerAspect where Self: LoadMoreConfigurableTableViewContainer {
|
|
/// [Data Source] hook to notify table view bottom loader
|
|
func aspectScrollViewDidScroll(_ scrollView: UIScrollView) {
|
|
handleScrollViewDidScroll(scrollView)
|
|
}
|
|
}
|
|
|
|
// [B2] aspectTableView(_:estimatedHeightForRowAt:)
|
|
extension StatusTableViewControllerAspect where Self: TableViewCellHeightCacheableContainer {
|
|
/// [UI] hook to estimate table view cell height from cache
|
|
func aspectTableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
|
|
handleTableView(tableView, estimatedHeightForRowAt: indexPath)
|
|
}
|
|
}
|
|
|
|
// [B3] aspectTableView(_:willDisplay:forRowAt:)
|
|
extension StatusTableViewControllerAspect where Self: StatusTableViewCellDelegate & StatusProvider {
|
|
func aspectTableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
|
handleTableView(tableView, willDisplay: cell, forRowAt: indexPath)
|
|
}
|
|
}
|
|
|
|
// [B4] aspectTableView(_:didEndDisplaying:forRowAt:)
|
|
extension StatusTableViewControllerAspect where Self: StatusTableViewCellDelegate & StatusProvider {
|
|
/// [Media] hook to notify video service
|
|
func aspectTableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
|
handleTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath)
|
|
}
|
|
}
|
|
|
|
extension StatusTableViewControllerAspect where Self: TableViewCellHeightCacheableContainer {
|
|
/// [UI] hook to cache table view cell height
|
|
func aspectTableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
|
cacheTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath)
|
|
}
|
|
}
|
|
|
|
extension StatusTableViewControllerAspect where Self: StatusProvider & StatusTableViewCellDelegate & TableViewCellHeightCacheableContainer {
|
|
/// [Media] hook to notify video service
|
|
/// [UI] hook to cache table view cell height
|
|
func aspectTableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
|
handleTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath)
|
|
cacheTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath)
|
|
}
|
|
}
|
|
|
|
// [B5] aspectTableView(_:didSelectRowAt:)
|
|
extension StatusTableViewControllerAspect where Self: StatusTableViewCellDelegate & StatusProvider {
|
|
/// [UI] hook to coordinator to thread
|
|
func aspectTableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
handleTableView(tableView, didSelectRowAt: indexPath)
|
|
}
|
|
}
|
|
|
|
// [B6] aspectTableView(_:contextMenuConfigurationForRowAt:point:)
|
|
extension StatusTableViewControllerAspect where Self: StatusTableViewCellDelegate & StatusProvider {
|
|
// [UI] hook to display context menu for images
|
|
func aspectTableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
|
return handleTableView(tableView, contextMenuConfigurationForRowAt: indexPath, point: point)
|
|
}
|
|
}
|
|
|
|
// [B7] aspectTableView(_:contextMenuConfigurationForRowAt:point:)
|
|
extension StatusTableViewControllerAspect where Self: StatusTableViewCellDelegate & StatusProvider {
|
|
// [UI] hook to configure context menu for images
|
|
func aspectTableView(_ tableView: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
|
|
return handleTableView(tableView, previewForHighlightingContextMenuWithConfiguration: configuration)
|
|
}
|
|
}
|
|
|
|
// [B8] aspectTableView(_:previewForDismissingContextMenuWithConfiguration:)
|
|
extension StatusTableViewControllerAspect where Self: StatusTableViewCellDelegate & StatusProvider {
|
|
// [UI] hook to configure context menu for images
|
|
func aspectTableView(_ tableView: UITableView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
|
|
return handleTableView(tableView, previewForDismissingContextMenuWithConfiguration: configuration)
|
|
}
|
|
}
|
|
|
|
// [B9] aspectTableView(_:willPerformPreviewActionForMenuWith:animator:)
|
|
extension StatusTableViewControllerAspect where Self: StatusTableViewCellDelegate & StatusProvider {
|
|
// [UI] hook to configure context menu preview action
|
|
func aspectTableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
|
|
handleTableView(tableView, willPerformPreviewActionForMenuWith: configuration, animator: animator)
|
|
}
|
|
}
|
|
|
|
// MARK: - UITableViewDataSourcePrefetching [C]
|
|
|
|
// [C1] aspectTableView(:prefetchRowsAt)
|
|
extension StatusTableViewControllerAspect where Self: UITableViewDataSourcePrefetching & StatusTableViewCellDelegate & StatusProvider {
|
|
/// [Data Source] hook to prefetch status
|
|
func aspectTableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
|
|
handleTableView(tableView, prefetchRowsAt: indexPaths)
|
|
}
|
|
}
|
|
|
|
// [C2] aspectTableView(:prefetchRowsAt)
|
|
extension StatusTableViewControllerAspect where Self: UITableViewDataSourcePrefetching & StatusTableViewCellDelegate & StatusProvider {
|
|
/// [Data Source] hook to cancel prefetch status
|
|
func aspectTableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) {
|
|
handleTableView(tableView, cancelPrefetchingForRowsAt: indexPaths)
|
|
}
|
|
}
|
|
|
|
// MARK: - AVPlayerViewControllerDelegate & NeedsDependency [D]
|
|
|
|
// [D1] aspectPlayerViewController(_:willBeginFullScreenPresentationWithAnimationCoordinator:)
|
|
extension StatusTableViewControllerAspect where Self: AVPlayerViewControllerDelegate & NeedsDependency {
|
|
/// [Media] hook to mark transitioning to video service
|
|
func aspectPlayerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
|
|
handlePlayerViewController(playerViewController, willBeginFullScreenPresentationWithAnimationCoordinator: coordinator)
|
|
}
|
|
}
|
|
|
|
// [D2] aspectPlayerViewController(_:willEndFullScreenPresentationWithAnimationCoordinator:)
|
|
extension StatusTableViewControllerAspect where Self: AVPlayerViewControllerDelegate & NeedsDependency {
|
|
/// [Media] hook to mark transitioning to video service
|
|
func aspectPlayerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
|
|
handlePlayerViewController(playerViewController, willEndFullScreenPresentationWithAnimationCoordinator: coordinator)
|
|
}
|
|
}
|
|
|