From 672db8f3c207c59fd0e75f156e253364dea851a8 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 8 Apr 2021 17:05:10 +0800 Subject: [PATCH] chore: use fake aspect protocol to group extension default implementations --- .../StatusTableViewControllerAspect.swift | 45 ++++++++++++++---- ...ableViewCellHeightCacheableContainer.swift | 2 +- .../HashtagTimelineViewController.swift | 46 ++++++++++--------- .../Favorite/FavoriteViewController.swift | 17 +++++-- .../ProfileRelationshipActionButton.swift | 2 +- .../Timeline/UserTimelineViewController.swift | 16 +++++-- 6 files changed, 89 insertions(+), 39 deletions(-) diff --git a/Mastodon/Protocol/StatusTableViewControllerAspect.swift b/Mastodon/Protocol/StatusTableViewControllerAspect.swift index dfc1a89eb..ecd8291ff 100644 --- a/Mastodon/Protocol/StatusTableViewControllerAspect.swift +++ b/Mastodon/Protocol/StatusTableViewControllerAspect.swift @@ -8,6 +8,15 @@ import UIKit import AVKit +// Check List Last Updated +// - FavoriteViewController: 2021/4/8 +// - HashtagTimelineViewController: 2021/4/8 +// - UserTimelineViewController: 2021/4/8 +// * StatusTableViewControllerAspect: 2021/4/7 + +// (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 @@ -17,9 +26,9 @@ protocol StatusTableViewControllerAspect: UIViewController { var tableView: UITableView { get } } -// MARK: - UIViewController +// MARK: - UIViewController [A] -// aspectViewWillAppear(_:) +// [A1] aspectViewWillAppear(_:) extension StatusTableViewControllerAspect { /// [UI] hook to deselect row in the transitioning for the table view func aspectViewWillAppear(_ animated: Bool) { @@ -31,12 +40,13 @@ 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 +// MARK: - UITableViewDelegate [B] -// aspectTableView(_:estimatedHeightForRowAt:) +// [B1] aspectTableView(_:estimatedHeightForRowAt:) extension StatusTableViewControllerAspect where Self: LoadMoreConfigurableTableViewContainer { /// [Data Source] hook to notify table view bottom loader func aspectScrollViewDidScroll(_ scrollView: UIScrollView) { @@ -44,7 +54,7 @@ extension StatusTableViewControllerAspect where Self: LoadMoreConfigurableTableV } } -// aspectTableView(_:estimatedHeightForRowAt:) +// [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 { @@ -52,7 +62,14 @@ extension StatusTableViewControllerAspect where Self: TableViewCellHeightCacheab } } -// StatusTableViewControllerAspect.aspectTableView(_:didEndDisplaying:forRowAt:) +// [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] StatusTableViewControllerAspect.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) { @@ -76,9 +93,19 @@ extension StatusTableViewControllerAspect where Self: StatusTableViewCellDelegat } } -// MARK: - AVPlayerViewControllerDelegate & NeedsDependency +// MARK: - UITableViewDataSourcePrefetching [C] -// aspectPlayerViewController(_:willBeginFullScreenPresentationWithAnimationCoordinator:) +// [C1] aspectTableView(:prefetchRowsAt) +extension StatusTableViewControllerAspect where Self: UITableViewDataSourcePrefetching & StatusTableViewCellDelegate & StatusProvider { + /// [Data Source] hook to prefetch reply to info for status + func aspectTableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { + handleTableView(tableView, prefetchRowsAt: 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) { @@ -86,7 +113,7 @@ extension StatusTableViewControllerAspect where Self: AVPlayerViewControllerDele } } -// aspectPlayerViewController(_:willEndFullScreenPresentationWithAnimationCoordinator:) +// [D2] aspectPlayerViewController(_:willEndFullScreenPresentationWithAnimationCoordinator:) extension StatusTableViewControllerAspect where Self: AVPlayerViewControllerDelegate & NeedsDependency { /// [Media] hook to mark transitioning to video service func aspectPlayerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { diff --git a/Mastodon/Protocol/TableViewCellHeightCacheableContainer.swift b/Mastodon/Protocol/TableViewCellHeightCacheableContainer.swift index 7c851cadc..0907db56f 100644 --- a/Mastodon/Protocol/TableViewCellHeightCacheableContainer.swift +++ b/Mastodon/Protocol/TableViewCellHeightCacheableContainer.swift @@ -27,7 +27,7 @@ extension TableViewCellHeightCacheableContainer { if case .bottomLoader = item { return TimelineLoaderTableViewCell.cellHeight } else { - return 200 + return UITableView.automaticDimension } } diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift index 6dab0f180..c9bf87410 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift @@ -111,6 +111,9 @@ extension HashtagTimelineViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + + aspectViewWillAppear(animated) + viewModel.fetchTag() guard viewModel.loadLatestStateMachine.currentState is HashtagTimelineViewModel.LoadLatestState.Initial else { return } @@ -120,8 +123,8 @@ extension HashtagTimelineViewController { override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) - context.videoPlaybackService.viewDidDisappear(from: self) - context.audioPlaybackService.viewDidDisappear(from: self) + + aspectViewDidDisappear(animated) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { @@ -158,6 +161,7 @@ extension HashtagTimelineViewController { subtitle = L10n.Scene.Hashtag.prompt("\(peopleTalkingNumber)") } } + } extension HashtagTimelineViewController { @@ -176,11 +180,20 @@ extension HashtagTimelineViewController { } } +// MARK: - StatusTableViewControllerAspect +extension HashtagTimelineViewController: StatusTableViewControllerAspect { } + +// MARK: - TableViewCellHeightCacheableContainer +extension HashtagTimelineViewController: TableViewCellHeightCacheableContainer { + var cellFrameCache: NSCache { + return viewModel.cellFrameCache + } +} + // MARK: - UIScrollViewDelegate extension HashtagTimelineViewController { func scrollViewDidScroll(_ scrollView: UIScrollView) { - handleScrollViewDidScroll(scrollView) -// self.viewModel.homeTimelineNavigationBarState.handleScrollViewDidScroll(scrollView) + aspectScrollViewDidScroll(scrollView) } } @@ -194,25 +207,16 @@ extension HashtagTimelineViewController: LoadMoreConfigurableTableViewContainer // MARK: - UITableViewDelegate extension HashtagTimelineViewController: UITableViewDelegate { - // TODO: - // func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { - // guard let diffableDataSource = viewModel.diffableDataSource else { return 100 } - // guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return 100 } - // - // guard let frame = viewModel.cellFrameCache.object(forKey: NSNumber(value: item.hashValue))?.cgRectValue else { - // return 200 - // } - // // os_log("%{public}s[%{public}ld], %{public}s: cache cell frame %s", ((#file as NSString).lastPathComponent), #line, #function, frame.debugDescription) - // - // return ceil(frame.height) - // } + func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { + return aspectTableView(tableView, estimatedHeightForRowAt: indexPath) + } func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { - handleTableView(tableView, willDisplay: cell, forRowAt: indexPath) + aspectTableView(tableView, willDisplay: cell, forRowAt: indexPath) } func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { - handleTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath) + aspectTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath) } } @@ -227,7 +231,7 @@ extension HashtagTimelineViewController: ContentOffsetAdjustableTimelineViewCont // MARK: - UITableViewDataSourcePrefetching extension HashtagTimelineViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { - handleTableView(tableView, prefetchRowsAt: indexPaths) + aspectTableView(tableView, prefetchRowsAt: indexPaths) } } @@ -298,11 +302,11 @@ extension HashtagTimelineViewController: TimelineMiddleLoaderTableViewCellDelega extension HashtagTimelineViewController: AVPlayerViewControllerDelegate { func playerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { - handlePlayerViewController(playerViewController, willBeginFullScreenPresentationWithAnimationCoordinator: coordinator) + aspectPlayerViewController(playerViewController, willBeginFullScreenPresentationWithAnimationCoordinator: coordinator) } func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { - handlePlayerViewController(playerViewController, willEndFullScreenPresentationWithAnimationCoordinator: coordinator) + aspectPlayerViewController(playerViewController, willEndFullScreenPresentationWithAnimationCoordinator: coordinator) } } diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift index 0b4a01a40..a175ae348 100644 --- a/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift +++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift @@ -59,6 +59,7 @@ extension FavoriteViewController { ]) tableView.delegate = self + tableView.prefetchDataSource = self viewModel.setupDiffableDataSource( for: tableView, dependency: self, @@ -105,26 +106,36 @@ extension FavoriteViewController: UITableViewDelegate { aspectTableView(tableView, estimatedHeightForRowAt: indexPath) } + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + aspectTableView(tableView, willDisplay: cell, forRowAt: indexPath) + } + func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { aspectTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath) } } +// MARK: - UITableViewDataSourcePrefetching +extension FavoriteViewController: UITableViewDataSourcePrefetching { + func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { + aspectTableView(tableView, prefetchRowsAt: indexPaths) + } +} + // MARK: - AVPlayerViewControllerDelegate extension FavoriteViewController: AVPlayerViewControllerDelegate { func playerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { - handlePlayerViewController(playerViewController, willBeginFullScreenPresentationWithAnimationCoordinator: coordinator) + aspectPlayerViewController(playerViewController, willBeginFullScreenPresentationWithAnimationCoordinator: coordinator) } func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { - handlePlayerViewController(playerViewController, willEndFullScreenPresentationWithAnimationCoordinator: coordinator) + aspectPlayerViewController(playerViewController, willEndFullScreenPresentationWithAnimationCoordinator: coordinator) } } - // MARK: - TimelinePostTableViewCellDelegate extension FavoriteViewController: StatusTableViewCellDelegate { weak var playerViewControllerDelegate: AVPlayerViewControllerDelegate? { return self } diff --git a/Mastodon/Scene/Profile/Header/View/ProfileRelationshipActionButton.swift b/Mastodon/Scene/Profile/Header/View/ProfileRelationshipActionButton.swift index 64dc9f00e..70e6e1647 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileRelationshipActionButton.swift +++ b/Mastodon/Scene/Profile/Header/View/ProfileRelationshipActionButton.swift @@ -36,7 +36,7 @@ extension ProfileRelationshipActionButton { setBackgroundImage(.placeholder(color: actionOptionSet.backgroundColor.withAlphaComponent(0.5)), for: .highlighted) setBackgroundImage(.placeholder(color: actionOptionSet.backgroundColor.withAlphaComponent(0.5)), for: .disabled) - if let option = actionOptionSet.highPriorityAction(except: .editOptions), option == .blocked { + if let option = actionOptionSet.highPriorityAction(except: .editOptions), option == .blocked || option == .suspended { isEnabled = false } else { isEnabled = true diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift index 4219f5117..e8e71ccf4 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift @@ -57,6 +57,7 @@ extension UserTimelineViewController { ]) tableView.delegate = self + tableView.prefetchDataSource = self viewModel.setupDiffableDataSource( for: tableView, dependency: self, @@ -115,12 +116,23 @@ extension UserTimelineViewController: UITableViewDelegate { aspectTableView(tableView, estimatedHeightForRowAt: indexPath) } + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + aspectTableView(tableView, willDisplay: cell, forRowAt: indexPath) + } + func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { aspectTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath) } } +// MARK: - UITableViewDataSourcePrefetching +extension UserTimelineViewController: UITableViewDataSourcePrefetching { + func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { + aspectTableView(tableView, prefetchRowsAt: indexPaths) + } +} + // MARK: - AVPlayerViewControllerDelegate extension UserTimelineViewController: AVPlayerViewControllerDelegate { @@ -140,10 +152,6 @@ extension UserTimelineViewController: StatusTableViewCellDelegate { func parent() -> UIViewController { return self } } -//// MARK: - TimelineHeaderTableViewCellDelegate -//extension UserTimelineViewController: TimelineHeaderTableViewCellDelegate { } - - // MARK: - CustomScrollViewContainerController extension UserTimelineViewController: ScrollViewContainer { var scrollView: UIScrollView { return tableView }