Convert Explore screen to use list-style collection view
This commit is contained in:
parent
669d55500a
commit
73aceda97f
|
@ -97,7 +97,6 @@
|
|||
D627943723A552C200D38C68 /* BookmarkStatusActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627943623A552C200D38C68 /* BookmarkStatusActivity.swift */; };
|
||||
D627943923A553B600D38C68 /* UnbookmarkStatusActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627943823A553B600D38C68 /* UnbookmarkStatusActivity.swift */; };
|
||||
D627943B23A55BA600D38C68 /* NavigableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627943A23A55BA600D38C68 /* NavigableTableViewCell.swift */; };
|
||||
D627943E23A564D400D38C68 /* ExploreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627943D23A564D400D38C68 /* ExploreViewController.swift */; };
|
||||
D627944723A6AC9300D38C68 /* BasicTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D627944623A6AC9300D38C68 /* BasicTableViewCell.xib */; };
|
||||
D627944A23A6AD6100D38C68 /* BookmarksTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627944923A6AD6100D38C68 /* BookmarksTableViewController.swift */; };
|
||||
D627944D23A9A03D00D38C68 /* ListTimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627944C23A9A03D00D38C68 /* ListTimelineViewController.swift */; };
|
||||
|
@ -272,6 +271,7 @@
|
|||
D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693FB2162FE6F007D6A6D /* LoadingViewController.swift */; };
|
||||
D6C693FE2162FEEA007D6A6D /* UIViewController+Children.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */; };
|
||||
D6C7D27D22B6EBF800071952 /* AttachmentsContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C7D27C22B6EBF800071952 /* AttachmentsContainerView.swift */; };
|
||||
D6C82B4125C5BB7E0017F1E6 /* ExploreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C82B4025C5BB7E0017F1E6 /* ExploreViewController.swift */; };
|
||||
D6C82B5625C5F3F20017F1E6 /* ExpandThreadTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C82B5425C5F3F20017F1E6 /* ExpandThreadTableViewCell.swift */; };
|
||||
D6C82B5725C5F3F20017F1E6 /* ExpandThreadTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6C82B5525C5F3F20017F1E6 /* ExpandThreadTableViewCell.xib */; };
|
||||
D6C94D872139E62700CB5196 /* LargeImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C94D862139E62700CB5196 /* LargeImageViewController.swift */; };
|
||||
|
@ -460,7 +460,6 @@
|
|||
D627943623A552C200D38C68 /* BookmarkStatusActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkStatusActivity.swift; sourceTree = "<group>"; };
|
||||
D627943823A553B600D38C68 /* UnbookmarkStatusActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnbookmarkStatusActivity.swift; sourceTree = "<group>"; };
|
||||
D627943A23A55BA600D38C68 /* NavigableTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigableTableViewCell.swift; sourceTree = "<group>"; };
|
||||
D627943D23A564D400D38C68 /* ExploreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreViewController.swift; sourceTree = "<group>"; };
|
||||
D627944623A6AC9300D38C68 /* BasicTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BasicTableViewCell.xib; sourceTree = "<group>"; };
|
||||
D627944923A6AD6100D38C68 /* BookmarksTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksTableViewController.swift; sourceTree = "<group>"; };
|
||||
D627944C23A9A03D00D38C68 /* ListTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTimelineViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -633,6 +632,7 @@
|
|||
D6C693FB2162FE6F007D6A6D /* LoadingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingViewController.swift; sourceTree = "<group>"; };
|
||||
D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Children.swift"; sourceTree = "<group>"; };
|
||||
D6C7D27C22B6EBF800071952 /* AttachmentsContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentsContainerView.swift; sourceTree = "<group>"; };
|
||||
D6C82B4025C5BB7E0017F1E6 /* ExploreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreViewController.swift; sourceTree = "<group>"; };
|
||||
D6C82B5425C5F3F20017F1E6 /* ExpandThreadTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandThreadTableViewCell.swift; sourceTree = "<group>"; };
|
||||
D6C82B5525C5F3F20017F1E6 /* ExpandThreadTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExpandThreadTableViewCell.xib; sourceTree = "<group>"; };
|
||||
D6C94D862139E62700CB5196 /* LargeImageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeImageViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -910,7 +910,7 @@
|
|||
D627943C23A5635D00D38C68 /* Explore */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D627943D23A564D400D38C68 /* ExploreViewController.swift */,
|
||||
D6C82B4025C5BB7E0017F1E6 /* ExploreViewController.swift */,
|
||||
D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */,
|
||||
D6093F9A25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift */,
|
||||
D6945C3923AC75E2005C403C /* FindInstanceViewController.swift */,
|
||||
|
@ -1996,7 +1996,6 @@
|
|||
D6B053AE23BD322B00A066FA /* AssetPickerSheetContainerViewController.swift in Sources */,
|
||||
D6C693EF216192C2007D6A6D /* TuskerNavigationDelegate.swift in Sources */,
|
||||
D6C94D872139E62700CB5196 /* LargeImageViewController.swift in Sources */,
|
||||
D627943E23A564D400D38C68 /* ExploreViewController.swift in Sources */,
|
||||
D6B053AB23BD2F1400A066FA /* AssetCollectionViewCell.swift in Sources */,
|
||||
D622757A24EE21D900B82A16 /* ComposeAttachmentRow.swift in Sources */,
|
||||
D6434EB3215B1856001A919A /* XCBRequest.swift in Sources */,
|
||||
|
@ -2080,6 +2079,7 @@
|
|||
D6D4DDD0212518A000E1C4BB /* AppDelegate.swift in Sources */,
|
||||
D6412B0924B0291E00F5412E /* MyProfileViewController.swift in Sources */,
|
||||
D6A6C10525B6138A00298D0F /* StatusTablePrefetching.swift in Sources */,
|
||||
D6C82B4125C5BB7E0017F1E6 /* ExploreViewController.swift in Sources */,
|
||||
D6B053A423BD2C8100A066FA /* AssetCollectionsListViewController.swift in Sources */,
|
||||
D690797324A4EF9700023A34 /* UIBezierPath+Helpers.swift in Sources */,
|
||||
D693DE5723FE1A6A0061E07D /* EnhancedNavigationViewController.swift in Sources */,
|
||||
|
|
|
@ -10,23 +10,22 @@ import UIKit
|
|||
import Combine
|
||||
import Pachyderm
|
||||
|
||||
class ExploreViewController: EnhancedTableViewController {
|
||||
class ExploreViewController: UIViewController, UICollectionViewDelegate {
|
||||
|
||||
weak var mastodonController: MastodonController!
|
||||
|
||||
var dataSource: DataSource!
|
||||
private var collectionView: UICollectionView!
|
||||
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
||||
|
||||
var resultsController: SearchResultsViewController!
|
||||
var searchController: UISearchController!
|
||||
private(set) var resultsController: SearchResultsViewController!
|
||||
private(set) var searchController: UISearchController!
|
||||
|
||||
var searchControllerStatusOnAppearance: Bool? = nil
|
||||
|
||||
init(mastodonController: MastodonController) {
|
||||
self.mastodonController = mastodonController
|
||||
|
||||
super.init(style: .insetGrouped)
|
||||
|
||||
dragEnabled = true
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
title = NSLocalizedString("Explore", comment: "explore tab title")
|
||||
tabBarItem.image = UIImage(systemName: "magnifyingglass")
|
||||
|
@ -38,64 +37,20 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
|
||||
configuration.trailingSwipeActionsConfigurationProvider = self.trailingSwipeActionsForCell(at:)
|
||||
configuration.headerMode = .supplementary
|
||||
let layout = UICollectionViewCompositionalLayout.list(using: configuration)
|
||||
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
||||
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
collectionView.delegate = self
|
||||
collectionView.dragDelegate = self
|
||||
view.addSubview(collectionView)
|
||||
|
||||
tableView.register(UINib(nibName: "BasicTableViewCell", bundle: .main), forCellReuseIdentifier: "basicCell")
|
||||
|
||||
dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "basicCell", for: indexPath)
|
||||
|
||||
switch item {
|
||||
case .bookmarks:
|
||||
cell.imageView!.image = UIImage(systemName: "bookmark.fill")
|
||||
cell.textLabel!.text = NSLocalizedString("Bookmarks", comment: "bookmarks nav item title")
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
case let .list(list):
|
||||
cell.imageView!.image = UIImage(systemName: "list.bullet")
|
||||
cell.textLabel!.text = list.title
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
case .addList:
|
||||
cell.imageView!.image = UIImage(systemName: "plus")
|
||||
cell.textLabel!.text = NSLocalizedString("New List...", comment: "new list nav item title")
|
||||
cell.accessoryType = .none
|
||||
|
||||
case let .savedHashtag(hashtag):
|
||||
cell.imageView!.image = UIImage(systemName: "number")
|
||||
cell.textLabel!.text = hashtag.name
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
case .addSavedHashtag:
|
||||
cell.imageView!.image = UIImage(systemName: "plus")
|
||||
cell.textLabel!.text = NSLocalizedString("Save Hashtag...", comment: "save hashtag nav item title")
|
||||
cell.accessoryType = .none
|
||||
|
||||
case let .savedInstance(url):
|
||||
cell.imageView!.image = UIImage(systemName: "globe")
|
||||
cell.textLabel!.text = url.host!
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
case .findInstance:
|
||||
cell.imageView!.image = UIImage(systemName: "magnifyingglass")
|
||||
cell.textLabel!.text = NSLocalizedString("Find An Instance...", comment: "find instance nav item title")
|
||||
cell.accessoryType = .none
|
||||
}
|
||||
|
||||
return cell
|
||||
})
|
||||
dataSource.exploreController = self
|
||||
dataSource = createDataSource()
|
||||
applyInitialSnapshot()
|
||||
|
||||
let account = mastodonController.accountInfo!
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||
snapshot.appendSections([.bookmarks, .lists, .savedHashtags, .savedInstances])
|
||||
snapshot.appendItems([.bookmarks], toSection: .bookmarks)
|
||||
snapshot.appendItems([.addList], toSection: .lists)
|
||||
snapshot.appendItems(SavedDataManager.shared.sortedHashtags(for: account).map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
||||
snapshot.appendItems(SavedDataManager.shared.savedInstances(for: account).map { .savedInstance($0) } + [.findInstance], toSection: .savedInstances)
|
||||
// the initial, static items should not be displayed with an animation
|
||||
dataSource.apply(snapshot, animatingDifferences: false)
|
||||
|
||||
resultsController = SearchResultsViewController(mastodonController: mastodonController)
|
||||
resultsController.exploreNavigationController = self.navigationController!
|
||||
searchController = UISearchController(searchResultsController: resultsController)
|
||||
|
@ -109,8 +64,20 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(savedHashtagsChanged), name: .savedHashtagsChanged, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(savedInstancesChanged), name: .savedInstancesChanged, object: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
reloadLists()
|
||||
// Can't use UICollectionViewController's builtin version of this because it requires
|
||||
// the collection view layout be passed into the constructor. Swipe actions for list collection views
|
||||
// are created by passing a closure to the layout's configuration. This closure needs to capture
|
||||
// `self`, so it can't be passed into the super constructor.
|
||||
if let indexPaths = collectionView.indexPathsForSelectedItems {
|
||||
for indexPath in indexPaths {
|
||||
collectionView.deselectItem(at: indexPath, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
@ -125,43 +92,101 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
func reloadLists() {
|
||||
private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> {
|
||||
let sectionHeaderCell = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionHeader) { (headerView, collectionView, indexPath) in
|
||||
let section = self.dataSource.snapshot().sectionIdentifiers[indexPath.section]
|
||||
|
||||
var config = headerView.defaultContentConfiguration()
|
||||
config.text = section.label
|
||||
headerView.contentConfiguration = config
|
||||
}
|
||||
|
||||
let listCell = UICollectionView.CellRegistration<UICollectionViewListCell, Item> { (cell, indexPath, item) in
|
||||
var config = cell.defaultContentConfiguration()
|
||||
config.text = item.label
|
||||
config.image = item.image
|
||||
cell.contentConfiguration = config
|
||||
|
||||
switch item {
|
||||
case .addList, .addSavedHashtag, .findInstance:
|
||||
cell.accessories = []
|
||||
default:
|
||||
cell.accessories = [.disclosureIndicator()]
|
||||
}
|
||||
}
|
||||
|
||||
let dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { (collectionView, indexPath, item) in
|
||||
return collectionView.dequeueConfiguredReusableCell(using: listCell, for: indexPath, item: item)
|
||||
}
|
||||
dataSource.supplementaryViewProvider = { (collectionView, elementKind, indexPath) in
|
||||
if elementKind == UICollectionView.elementKindSectionHeader {
|
||||
return collectionView.dequeueConfiguredReusableSupplementary(using: sectionHeaderCell, for: indexPath)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return dataSource
|
||||
}
|
||||
|
||||
private func applyInitialSnapshot() {
|
||||
let account = mastodonController.accountInfo!
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||
snapshot.appendSections(Section.allCases)
|
||||
snapshot.appendItems([.bookmarks], toSection: .bookmarks)
|
||||
snapshot.appendItems([.addList], toSection: .lists)
|
||||
snapshot.appendItems(SavedDataManager.shared.sortedHashtags(for: account).map { .savedHashtag($0) }, toSection: .savedHashtags)
|
||||
snapshot.appendItems([.addSavedHashtag], toSection: .savedHashtags)
|
||||
snapshot.appendItems(SavedDataManager.shared.savedInstances(for: account).map { .savedInstance($0) }, toSection: .savedInstances)
|
||||
snapshot.appendItems([.findInstance], toSection: .savedInstances)
|
||||
dataSource.apply(snapshot, animatingDifferences: false)
|
||||
|
||||
reloadLists()
|
||||
}
|
||||
|
||||
private func reloadLists() {
|
||||
let request = Client.getLists()
|
||||
mastodonController.run(request) { (response) in
|
||||
guard case let .success(lists, _) = response else {
|
||||
fatalError()
|
||||
return
|
||||
}
|
||||
|
||||
var snapshot = self.dataSource.snapshot()
|
||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .lists))
|
||||
snapshot.appendItems(lists.map { .list($0) } + [.addList], toSection: .lists)
|
||||
|
||||
snapshot.appendItems(lists.map { .list($0) }, toSection: .lists)
|
||||
snapshot.appendItems([.addList], toSection: .lists)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.dataSource.apply(snapshot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func savedHashtagsChanged() {
|
||||
@objc private func savedHashtagsChanged() {
|
||||
let account = mastodonController.accountInfo!
|
||||
var snapshot = dataSource.snapshot()
|
||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .savedHashtags))
|
||||
snapshot.appendItems(SavedDataManager.shared.sortedHashtags(for: account).map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
||||
snapshot.appendItems(SavedDataManager.shared.sortedHashtags(for: account).map { .savedHashtag($0) }, toSection: .savedHashtags)
|
||||
snapshot.appendItems([.addSavedHashtag], toSection: .savedHashtags)
|
||||
dataSource.apply(snapshot)
|
||||
}
|
||||
|
||||
@objc func savedInstancesChanged() {
|
||||
@objc private func savedInstancesChanged() {
|
||||
let account = mastodonController.accountInfo!
|
||||
var snapshot = dataSource.snapshot()
|
||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .savedInstances))
|
||||
snapshot.appendItems(SavedDataManager.shared.savedInstances(for: account).map { .savedInstance($0) } + [.findInstance], toSection: .savedInstances)
|
||||
snapshot.appendItems(SavedDataManager.shared.savedInstances(for: account).map { .savedInstance($0) }, toSection: .savedInstances)
|
||||
snapshot.appendItems([.findInstance], toSection: .savedInstances)
|
||||
dataSource.apply(snapshot)
|
||||
}
|
||||
|
||||
func deleteList(_ list: List) {
|
||||
let title = String(format: NSLocalizedString("Are you sure want to delete the '%@' list?", comment: "delete list alert title"), list.title)
|
||||
private func deleteList(_ list: List, completion: @escaping (Bool) -> Void) {
|
||||
let titleFormat = NSLocalizedString("Are you sure you want to delete the '%@' list?", comment: "delete list alert title")
|
||||
let title = String(format: titleFormat, list.title)
|
||||
let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "delete list alert cancel button"), style: .cancel, handler: nil))
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "delete list alert cancel button"), style: .cancel, handler: { (_) in
|
||||
completion(false)
|
||||
}))
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Delete List", comment: "delete list alert confirm button"), style: .destructive, handler: { (_) in
|
||||
|
||||
let request = List.delete(list)
|
||||
|
@ -174,6 +199,7 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
snapshot.deleteItems([.list(list)])
|
||||
DispatchQueue.main.async {
|
||||
self.dataSource.apply(snapshot)
|
||||
completion(true)
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
@ -190,9 +216,38 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
SavedDataManager.shared.remove(instance: instanceURL, for: account)
|
||||
}
|
||||
|
||||
// MARK: - Table view delegate
|
||||
private func trailingSwipeActionsForCell(at indexPath: IndexPath) -> UISwipeActionsConfiguration? {
|
||||
let handler: UIContextualAction.Handler
|
||||
switch dataSource.itemIdentifier(for: indexPath) {
|
||||
case let .list(list):
|
||||
handler = { (_, _, completion) in
|
||||
self.deleteList(list, completion: completion)
|
||||
}
|
||||
|
||||
case let .savedHashtag(hashtag):
|
||||
handler = { (_, _, completion) in
|
||||
self.removeSavedHashtag(hashtag)
|
||||
completion(true)
|
||||
}
|
||||
|
||||
case let .savedInstance(url):
|
||||
handler = { (_, _, completion) in
|
||||
self.removeSavedInstance(url)
|
||||
completion(true)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
return UISwipeActionsConfiguration(actions: [
|
||||
UIContextualAction(style: .destructive, title: NSLocalizedString("Delete", comment: "delete swipe action title"), handler: handler)
|
||||
])
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
// MARK: - Collection View Delegate
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
switch dataSource.itemIdentifier(for: indexPath) {
|
||||
case nil:
|
||||
return
|
||||
|
@ -204,7 +259,7 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
show(ListTimelineViewController(for: list, mastodonController: mastodonController), sender: nil)
|
||||
|
||||
case .addList:
|
||||
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||
collectionView.deselectItem(at: indexPath, animated: true)
|
||||
let alert = UIAlertController(title: NSLocalizedString("New List", comment: "new list alert title"), message: NSLocalizedString("Choose a title for your new list", comment: "new list alert message"), preferredStyle: .alert)
|
||||
alert.addTextField(configurationHandler: nil)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "new list alert cancel button"), style: .cancel, handler: nil))
|
||||
|
@ -232,7 +287,7 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
show(HashtagTimelineViewController(for: hashtag, mastodonController: mastodonController), sender: nil)
|
||||
|
||||
case .addSavedHashtag:
|
||||
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||
collectionView.deselectItem(at: indexPath, animated: true)
|
||||
let navController = UINavigationController(rootViewController: AddSavedHashtagViewController(mastodonController: mastodonController))
|
||||
present(navController, animated: true)
|
||||
|
||||
|
@ -240,44 +295,13 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
show(InstanceTimelineViewController(for: url, parentMastodonController: mastodonController), sender: nil)
|
||||
|
||||
case .findInstance:
|
||||
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||
collectionView.deselectItem(at: indexPath, animated: true)
|
||||
let findController = FindInstanceViewController(parentMastodonController: mastodonController)
|
||||
findController.instanceTimelineDelegate = self
|
||||
let navController = UINavigationController(rootViewController: findController)
|
||||
present(navController, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
|
||||
return .delete
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
||||
switch dataSource.itemIdentifier(for: indexPath) {
|
||||
case .bookmarks:
|
||||
return UIContextMenuConfiguration(identifier: nil, previewProvider: {
|
||||
return BookmarksTableViewController(mastodonController: self.mastodonController)
|
||||
}, actionProvider: nil)
|
||||
|
||||
case let .list(list):
|
||||
return UIContextMenuConfiguration(identifier: nil, previewProvider: {
|
||||
return ListTimelineViewController(for: list, mastodonController: self.mastodonController)
|
||||
}, actionProvider: nil)
|
||||
|
||||
case let .savedHashtag(hashtag):
|
||||
return UIContextMenuConfiguration(identifier: nil, previewProvider: {
|
||||
return HashtagTimelineViewController(for: hashtag, mastodonController: self.mastodonController)
|
||||
}, actionProvider: nil)
|
||||
|
||||
case let .savedInstance(url):
|
||||
return UIContextMenuConfiguration(identifier: nil, previewProvider: {
|
||||
return InstanceTimelineViewController(for: url, parentMastodonController: self.mastodonController)
|
||||
}, actionProvider: nil)
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -287,7 +311,21 @@ extension ExploreViewController {
|
|||
case lists
|
||||
case savedHashtags
|
||||
case savedInstances
|
||||
|
||||
var label: String? {
|
||||
switch self {
|
||||
case .bookmarks:
|
||||
return nil
|
||||
case .lists:
|
||||
return NSLocalizedString("Lists", comment: "explore lists section title")
|
||||
case .savedHashtags:
|
||||
return NSLocalizedString("Saved Hashtags", comment: "explore saved hashtags section title")
|
||||
case .savedInstances:
|
||||
return NSLocalizedString("Instance Timelines", comment: "explore instance timelines section title")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Item: Hashable {
|
||||
case bookmarks
|
||||
case list(List)
|
||||
|
@ -296,8 +334,46 @@ extension ExploreViewController {
|
|||
case addSavedHashtag
|
||||
case savedInstance(URL)
|
||||
case findInstance
|
||||
|
||||
static func == (lhs: ExploreViewController.Item, rhs: ExploreViewController.Item) -> Bool {
|
||||
|
||||
var label: String {
|
||||
switch self {
|
||||
case .bookmarks:
|
||||
return NSLocalizedString("Bookmarks", comment: "bookmarks nav item title")
|
||||
case let .list(list):
|
||||
return list.title
|
||||
case .addList:
|
||||
return NSLocalizedString("New List...", comment: "new list nav item title")
|
||||
case let .savedHashtag(hashtag):
|
||||
return hashtag.name
|
||||
case .addSavedHashtag:
|
||||
return NSLocalizedString("Save Hashtag...", comment: "save hashtag nav item title")
|
||||
case let .savedInstance(url):
|
||||
return url.host!
|
||||
case .findInstance:
|
||||
return NSLocalizedString("Find An Instance...", comment: "find instance nav item title")
|
||||
}
|
||||
}
|
||||
|
||||
var image: UIImage {
|
||||
let name: String
|
||||
switch self {
|
||||
case .bookmarks:
|
||||
name = "bookmark.fill"
|
||||
case .list(_):
|
||||
name = "list.bullet"
|
||||
case .addList, .addSavedHashtag:
|
||||
name = "plus"
|
||||
case .savedHashtag(_):
|
||||
name = "number"
|
||||
case .savedInstance(_):
|
||||
name = "globe"
|
||||
case .findInstance:
|
||||
name = "magnifyingglass"
|
||||
}
|
||||
return UIImage(systemName: name)!
|
||||
}
|
||||
|
||||
static func == (lhs: Item, rhs: Item) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.bookmarks, .bookmarks):
|
||||
return true
|
||||
|
@ -317,6 +393,7 @@ extension ExploreViewController {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
switch self {
|
||||
case .bookmarks:
|
||||
|
@ -339,57 +416,6 @@ extension ExploreViewController {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DataSource: UITableViewDiffableDataSource<Section, Item> {
|
||||
|
||||
weak var exploreController: ExploreViewController?
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
switch section {
|
||||
case 1:
|
||||
return NSLocalizedString("Lists", comment: "explore lists section title")
|
||||
case 2:
|
||||
return NSLocalizedString("Saved Hashtags", comment: "explore saved hashtags section title")
|
||||
case 3:
|
||||
return NSLocalizedString("Instance Timelines", comment: "explore instance timelines section title")
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
||||
switch itemIdentifier(for: indexPath) {
|
||||
case .list(_):
|
||||
return true
|
||||
case .savedHashtag(_):
|
||||
return true
|
||||
case .savedInstance(_):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
guard editingStyle == .delete,
|
||||
let exploreController = exploreController else {
|
||||
return
|
||||
}
|
||||
|
||||
switch itemIdentifier(for: indexPath) {
|
||||
case let .list(list):
|
||||
exploreController.deleteList(list)
|
||||
case let .savedHashtag(hashtag):
|
||||
exploreController.removeSavedHashtag(hashtag)
|
||||
case let .savedInstance(url):
|
||||
exploreController.removeSavedInstance(url)
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
extension ExploreViewController: InstanceTimelineViewControllerDelegate {
|
||||
|
@ -404,12 +430,13 @@ extension ExploreViewController: InstanceTimelineViewControllerDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
extension ExploreViewController {
|
||||
override func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
|
||||
extension ExploreViewController: UICollectionViewDragDelegate {
|
||||
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
|
||||
guard let item = dataSource.itemIdentifier(for: indexPath),
|
||||
let accountID = mastodonController.accountInfo?.id else {
|
||||
return []
|
||||
}
|
||||
|
||||
let provider: NSItemProvider
|
||||
switch item {
|
||||
case .bookmarks:
|
||||
|
@ -425,11 +452,7 @@ extension ExploreViewController {
|
|||
case let .savedInstance(url):
|
||||
provider = NSItemProvider(object: url as NSURL)
|
||||
// todo: should dragging public timelines into new windows be supported?
|
||||
case .addList:
|
||||
return []
|
||||
case .addSavedHashtag:
|
||||
return []
|
||||
case .findInstance:
|
||||
case .addList, .addSavedHashtag, .findInstance:
|
||||
return []
|
||||
}
|
||||
return [UIDragItem(itemProvider: provider)]
|
||||
|
|
Loading…
Reference in New Issue