Move trending statuses to Explore on iPad

See #171
This commit is contained in:
Shadowfacts 2023-01-22 13:54:21 -05:00
parent a75862b5cc
commit a47b9c0c75
3 changed files with 81 additions and 38 deletions

View File

@ -41,7 +41,7 @@ class MainSidebarViewController: UIViewController {
}
var exploreTabItems: [Item] {
var items: [Item] = [.explore, .bookmarks, .trendingStatuses, .profileDirectory]
var items: [Item] = [.explore, .bookmarks, .profileDirectory]
let snapshot = dataSource.snapshot()
for case let .list(list) in snapshot.itemIdentifiers(inSection: .lists) {
items.append(.list(list))
@ -195,9 +195,6 @@ class MainSidebarViewController: UIViewController {
discoverSnapshot.append([
.profileDirectory,
], to: .discoverHeader)
if mastodonController.instanceFeatures.trendingStatusesAndLinks {
discoverSnapshot.insert([.trendingStatuses], before: .profileDirectory)
}
dataSource.apply(discoverSnapshot, to: .discover)
}
@ -388,7 +385,7 @@ extension MainSidebarViewController {
enum Item: Hashable {
case tab(MainTabBarViewController.Tab)
case explore, bookmarks
case discoverHeader, trendingStatuses, profileDirectory
case discoverHeader, profileDirectory
case listsHeader, list(List), addList
case savedHashtagsHeader, savedHashtag(Hashtag), addSavedHashtag
case savedInstancesHeader, savedInstance(URL), addSavedInstance
@ -403,8 +400,6 @@ extension MainSidebarViewController {
return "Bookmarks"
case .discoverHeader:
return "Discover"
case .trendingStatuses:
return "Trending Posts"
case .profileDirectory:
return "Profile Directory"
case .listsHeader:
@ -436,8 +431,6 @@ extension MainSidebarViewController {
return "magnifyingglass"
case .bookmarks:
return "bookmark"
case .trendingStatuses:
return "square.text.square"
case .profileDirectory:
return "person.2.fill"
case .list(_):

View File

@ -232,7 +232,7 @@ extension MainSplitViewController: UISplitViewControllerDelegate {
tabBarViewController.select(tab: .explore)
case .bookmarks, .trendingStatuses, .profileDirectory, .list(_), .savedHashtag(_), .savedInstance(_):
case .bookmarks, .profileDirectory, .list(_), .savedHashtag(_), .savedInstance(_):
tabBarViewController.select(tab: .explore)
// Make sure the Explore VC doesn't show it's search bar when it appears, in case the user was previously
// in compact mode and performing a search.
@ -309,7 +309,7 @@ extension MainSplitViewController: UISplitViewControllerDelegate {
case let instanceVC as InstanceTimelineViewController:
exploreItem = .savedInstance(instanceVC.instanceURL)
case is TrendingStatusesViewController:
exploreItem = .trendingStatuses
exploreItem = .explore
case is TrendingHashtagsViewController:
exploreItem = .explore
case is TrendingLinksViewController:
@ -376,8 +376,6 @@ fileprivate extension MainSidebarViewController.Item {
return SearchViewController(mastodonController: mastodonController)
case .bookmarks:
return BookmarksTableViewController(mastodonController: mastodonController)
case .trendingStatuses:
return TrendingStatusesViewController(mastodonController: mastodonController)
case .profileDirectory:
return ProfileDirectoryViewController(mastodonController: mastodonController)
case let .list(list):

View File

@ -11,11 +11,11 @@ import Pachyderm
import SafariServices
import WebURLFoundationExtras
class SearchViewController: UIViewController {
class SearchViewController: UIViewController, CollectionViewController {
weak var mastodonController: MastodonController!
private var collectionView: UICollectionView!
var collectionView: UICollectionView!
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
var resultsController: SearchResultsViewController!
@ -23,6 +23,8 @@ class SearchViewController: UIViewController {
var searchControllerStatusOnAppearance: Bool? = nil
private var loadTask: Task<Void, Never>?
init(mastodonController: MastodonController) {
self.mastodonController = mastodonController
@ -59,7 +61,13 @@ class SearchViewController: UIViewController {
section.boundarySupplementaryItems = [
NSCollectionLayoutBoundarySupplementaryItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(12)), elementKind: UICollectionView.elementKindSectionHeader, alignment: .topLeading)
]
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 16, trailing: 0)
return section
case .trendingStatuses:
var listConfig = UICollectionLayoutListConfiguration(appearance: .grouped)
listConfig.headerMode = .supplementary
return NSCollectionLayoutSection.list(using: listConfig, layoutEnvironment: environment)
default:
fatalError("unimplemented")
@ -100,7 +108,10 @@ class SearchViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
Task(priority: .userInitiated) {
clearSelectionOnAppear(animated: animated)
loadTask?.cancel()
loadTask = Task(priority: .userInitiated) {
if (try? await mastodonController.getOwnInstance()) != nil {
await applySnapshot()
}
@ -133,6 +144,11 @@ class SearchViewController: UIViewController {
let trendingLinkCell = UICollectionView.CellRegistration<TrendingLinkCardCollectionViewCell, Card>(cellNib: UINib(nibName: "TrendingLinkCardCollectionViewCell", bundle: .main)) { (cell, indexPath, card) in
cell.updateUI(card: card)
}
let statusCell = UICollectionView.CellRegistration<TimelineStatusCollectionViewCell, (String, CollapseState)> { [unowned self] cell, indexPath, item in
cell.delegate = self
// TODO: filter trends
cell.updateUI(statusID: item.0, state: item.1, filterResult: .allow, precomputedContent: nil)
}
let dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { collectionView, indexPath, item in
switch item {
@ -142,8 +158,8 @@ class SearchViewController: UIViewController {
case let .link(card):
return collectionView.dequeueConfiguredReusableCell(using: trendingLinkCell, for: indexPath, item: card)
default:
fatalError("todo")
case let .status(id, state):
return collectionView.dequeueConfiguredReusableCell(using: statusCell, for: indexPath, item: (id, state))
}
}
dataSource.supplementaryViewProvider = { (collectionView, elementKind, indexPath) in
@ -165,27 +181,41 @@ class SearchViewController: UIViewController {
}
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
let hashtagsReq = Client.getTrendingHashtags(limit: 5)
async let hashtags = try? mastodonController.run(hashtagsReq).0
let linksReq = Client.getTrendingLinks(limit: 10)
async let links = try? mastodonController.run(linksReq).0
if let hashtags = await hashtags {
snapshot.appendSections([.trendingHashtags])
snapshot.appendItems(hashtags.map { .tag($0) }, toSection: .trendingHashtags)
}
if let links = await links {
snapshot.appendSections([.trendingLinks])
snapshot.appendItems(links.map { .link($0) }, toSection: .trendingLinks)
if mastodonController.instanceFeatures.trendingStatusesAndLinks {
let linksReq = Client.getTrendingLinks(limit: 10)
async let links = try? mastodonController.run(linksReq).0
let statusesReq = Client.getTrendingStatuses(limit: 10)
async let statuses = try? mastodonController.run(statusesReq).0
if let links = await links {
snapshot.appendSections([.trendingLinks])
snapshot.appendItems(links.map { .link($0) }, toSection: .trendingLinks)
}
if let statuses = await statuses {
await mastodonController.persistentContainer.addAll(statuses: statuses)
snapshot.appendSections([.trendingStatuses])
snapshot.appendItems(statuses.map { .status($0.id, .unknown) }, toSection: .trendingStatuses)
}
}
if !Task.isCancelled {
await dataSource.apply(snapshot)
}
await dataSource.apply(snapshot)
}
@objc private func preferencesChanged() {
Task {
loadTask?.cancel()
loadTask = Task {
await applySnapshot()
}
}
@ -196,8 +226,8 @@ extension SearchViewController {
enum Section {
case trendingHashtags
case trendingLinks
case trendingStatuses
case profileSuggestions
case trendingStatuses
var title: String {
switch self {
@ -206,20 +236,20 @@ extension SearchViewController {
case .trendingLinks:
return "Trending Links"
case .trendingStatuses:
return "Trending Statuses"
return "Trending Posts"
case .profileSuggestions:
return "Suggested Accounts"
}
}
}
enum Item: Equatable, Hashable {
case status(String)
case status(String, CollapseState)
case tag(Hashtag)
case link(Card)
static func == (lhs: SearchViewController.Item, rhs: SearchViewController.Item) -> Bool {
switch (lhs, rhs) {
case let (.status(a), .status(b)):
case let (.status(a, _), .status(b, _)):
return a == b
case let (.tag(a), .tag(b)):
return a == b
@ -232,7 +262,7 @@ extension SearchViewController {
func hash(into hasher: inout Hasher) {
switch self {
case let .status(id):
case let .status(id, _):
hasher.combine("status")
hasher.combine(id)
case let .tag(tag):
@ -260,8 +290,8 @@ extension SearchViewController: UICollectionViewDelegate {
selected(url: url)
}
default:
fatalError("todo")
case let .status(id, state):
selected(status: id, state: state.copy())
}
}
@ -348,8 +378,16 @@ extension SearchViewController: UICollectionViewDragDelegate {
}
return [UIDragItem(itemProvider: NSItemProvider(object: url as NSURL))]
default:
fatalError("todo")
case let .status(id, _):
guard let status = mastodonController.persistentContainer.status(for: id),
let url = status.url else {
return []
}
let provider = NSItemProvider(object: url as NSURL)
let activity = UserActivityManager.showConversationActivity(mainStatusID: id, accountID: mastodonController.accountInfo!.id)
activity.displaysAuxiliaryScene = true
provider.registerObject(activity, visibility: .all)
return [UIDragItem(itemProvider: provider)]
}
}
}
@ -363,3 +401,17 @@ extension SearchViewController: ToastableViewController {
extension SearchViewController: MenuActionProvider {
}
extension SearchViewController: StatusCollectionViewCellDelegate {
func statusCellNeedsReconfigure(_ cell: StatusCollectionViewCell, animated: Bool, completion: (() -> Void)?) {
if let indexPath = collectionView.indexPath(for: cell) {
var snapshot = dataSource.snapshot()
snapshot.reconfigureItems([dataSource.itemIdentifier(for: indexPath)!])
dataSource.apply(snapshot, animatingDifferences: animated, completion: completion)
}
}
func statusCellShowFiltered(_ cell: StatusCollectionViewCell) {
// TODO: filtering
}
}