Compare commits

..

No commits in common. "2891f47cb34167e715d92b2c917a85bf03919c86" and "7f4ab57a1d9e2532fc707321e534f1484e59d5d0" have entirely different histories.

6 changed files with 50 additions and 63 deletions

View File

@ -354,7 +354,6 @@ class ConversationTableViewController: EnhancedTableViewController {
case let .status(id: id, state: state) = dataSource.itemIdentifier(for: IndexPath(row: indexPath.row - 1, section: indexPath.section)) { case let .status(id: id, state: state) = dataSource.itemIdentifier(for: IndexPath(row: indexPath.row - 1, section: indexPath.section)) {
let conv = ConversationTableViewController(for: id, state: state, mastodonController: mastodonController) let conv = ConversationTableViewController(for: id, state: state, mastodonController: mastodonController)
conv.statusIDToScrollToOnLoad = childThreads.first!.status.id conv.statusIDToScrollToOnLoad = childThreads.first!.status.id
conv.showStatusesAutomatically = showStatusesAutomatically
show(conv) show(conv)
} else { } else {
super.tableView(tableView, didSelectRowAt: indexPath) super.tableView(tableView, didSelectRowAt: indexPath)

View File

@ -84,7 +84,7 @@ class AddSavedHashtagViewController: UIViewController {
navigationItem.searchController = searchController navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false navigationItem.hidesSearchBarWhenScrolling = false
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonPressed)) navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelButtonPressed))
} }
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
@ -107,12 +107,15 @@ class AddSavedHashtagViewController: UIViewController {
} }
private func selectHashtag(_ hashtag: Hashtag) { private func selectHashtag(_ hashtag: Hashtag) {
show(HashtagTimelineViewController(for: hashtag, mastodonController: mastodonController), sender: nil) let context = mastodonController.persistentContainer.viewContext
_ = SavedHashtag(hashtag: hashtag, context: context)
try! context.save()
presentingViewController!.dismiss(animated: true)
} }
// MARK: - Interaction // MARK: - Interaction
@objc func doneButtonPressed() { @objc func cancelButtonPressed() {
dismiss(animated: true) dismiss(animated: true)
} }
@ -125,6 +128,11 @@ extension AddSavedHashtagViewController {
enum Item: Hashable { enum Item: Hashable {
case tag(Hashtag) case tag(Hashtag)
} }
// class DataSource: UITableViewDiffableDataSource<Section, Item> {
// override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
// return
// }
// }
} }
extension AddSavedHashtagViewController: UICollectionViewDelegate { extension AddSavedHashtagViewController: UICollectionViewDelegate {

View File

@ -24,7 +24,7 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate {
var searchControllerStatusOnAppearance: Bool? = nil var searchControllerStatusOnAppearance: Bool? = nil
private var cancellables = Set<AnyCancellable>() private var listsCancellable: AnyCancellable?
init(mastodonController: MastodonController) { init(mastodonController: MastodonController) {
self.mastodonController = mastodonController self.mastodonController = mastodonController
@ -70,26 +70,12 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate {
navigationItem.searchController = searchController navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false navigationItem.hidesSearchBarWhenScrolling = false
NotificationCenter.default.addObserver(self, selector: #selector(savedHashtagsChanged), name: .savedHashtagsChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(savedInstancesChanged), name: .savedInstancesChanged, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(savedInstancesChanged), name: .savedInstancesChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil)
mastodonController.$lists listsCancellable = mastodonController.$lists
.sink { [unowned self] in self.reloadLists($0) } .sink { [unowned self] in self.reloadLists($0) }
.store(in: &cancellables)
mastodonController.$followedHashtags
.merge(with:
NotificationCenter.default.publisher(for: .savedHashtagsChanged)
.map { [unowned self] _ in self.mastodonController.followedHashtags }
)
.sink { [unowned self] in self.updateHashtagsSection(followed: $0) }
.store(in: &cancellables)
let a = PassthroughSubject<Int, Never>()
let b = PassthroughSubject<Int, Never>()
a.merge(with: b)
.sink(receiveValue: { print($0) })
.store(in: &cancellables)
} }
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
@ -163,7 +149,9 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate {
addDiscoverSection(to: &snapshot) addDiscoverSection(to: &snapshot)
} }
snapshot.appendItems([.addList], toSection: .lists) snapshot.appendItems([.addList], toSection: .lists)
let hashtags = fetchHashtagItems(followed: mastodonController.followedHashtags) let hashtags = fetchSavedHashtags().map {
Item.savedHashtag(Hashtag(name: $0.name, url: $0.url))
}
snapshot.appendItems(hashtags, toSection: .savedHashtags) snapshot.appendItems(hashtags, toSection: .savedHashtags)
snapshot.appendItems([.addSavedHashtag], toSection: .savedHashtags) snapshot.appendItems([.addSavedHashtag], toSection: .savedHashtags)
let instances = fetchSavedInstances().map { let instances = fetchSavedInstances().map {
@ -205,16 +193,14 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate {
} }
@MainActor @MainActor
private func fetchHashtagItems(followed: [FollowedHashtag]) -> [Item] { private func fetchSavedHashtags() -> [SavedHashtag] {
let saved = (try? mastodonController.persistentContainer.viewContext.fetch(SavedHashtag.fetchRequest())) ?? [] let req = SavedHashtag.fetchRequest()
var items = saved.map { req.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true, selector: #selector(NSString.localizedCompare(_:)))]
Item.savedHashtag(Hashtag(name: $0.name, url: $0.url)) do {
return try mastodonController.persistentContainer.viewContext.fetch(req)
} catch {
return []
} }
for followed in followed where !saved.contains(where: { $0.name == followed.name }) {
items.append(.savedHashtag(Hashtag(name: followed.name, url: followed.url)))
}
items.sort(using: SemiCaseSensitiveComparator.keyPath(\.label))
return items
} }
@MainActor @MainActor
@ -228,10 +214,12 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate {
} }
} }
private func updateHashtagsSection(followed: [FollowedHashtag]) { @objc private func savedHashtagsChanged() {
var snapshot = dataSource.snapshot() var snapshot = dataSource.snapshot()
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .savedHashtags)) snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .savedHashtags))
let hashtags = fetchHashtagItems(followed: followed) let hashtags = fetchSavedHashtags().map {
Item.savedHashtag(Hashtag(name: $0.name, url: $0.url))
}
snapshot.appendItems(hashtags, toSection: .savedHashtags) snapshot.appendItems(hashtags, toSection: .savedHashtags)
snapshot.appendItems([.addSavedHashtag], toSection: .savedHashtags) snapshot.appendItems([.addSavedHashtag], toSection: .savedHashtags)
dataSource.apply(snapshot) dataSource.apply(snapshot)
@ -398,7 +386,7 @@ extension ExploreViewController {
case .lists: case .lists:
return NSLocalizedString("Lists", comment: "explore lists section title") return NSLocalizedString("Lists", comment: "explore lists section title")
case .savedHashtags: case .savedHashtags:
return NSLocalizedString("Hashtags", comment: "explore saved hashtags section title") return NSLocalizedString("Saved Hashtags", comment: "explore saved hashtags section title")
case .savedInstances: case .savedInstances:
return NSLocalizedString("Instance Timelines", comment: "explore instance timelines section title") return NSLocalizedString("Instance Timelines", comment: "explore instance timelines section title")
} }
@ -437,7 +425,7 @@ extension ExploreViewController {
case let .savedHashtag(hashtag): case let .savedHashtag(hashtag):
return hashtag.name return hashtag.name
case .addSavedHashtag: case .addSavedHashtag:
return NSLocalizedString("Add Hashtag...", comment: "save hashtag nav item title") return NSLocalizedString("Save Hashtag...", comment: "save hashtag nav item title")
case let .savedInstance(url): case let .savedInstance(url):
return url.host! return url.host!
case .findInstance: case .findInstance:

View File

@ -30,7 +30,7 @@ class MainSidebarViewController: UIViewController {
private var collectionView: UICollectionView! private var collectionView: UICollectionView!
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>! private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
private var cancellables = Set<AnyCancellable>() private var listsCancellable: AnyCancellable?
var allItems: [Item] { var allItems: [Item] {
[ [
@ -101,19 +101,12 @@ class MainSidebarViewController: UIViewController {
select(item: .tab(.timelines), animated: false) select(item: .tab(.timelines), animated: false)
NotificationCenter.default.addObserver(self, selector: #selector(reloadSavedHashtags), name: .savedHashtagsChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(reloadSavedInstances), name: .savedInstancesChanged, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(reloadSavedInstances), name: .savedInstancesChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil)
mastodonController.$lists listsCancellable = mastodonController.$lists
.sink { [unowned self] in self.reloadLists($0) } .sink { [unowned self] in self.reloadLists($0) }
.store(in: &cancellables)
mastodonController.$followedHashtags
.merge(with:
NotificationCenter.default.publisher(for: .savedHashtagsChanged)
.map { [unowned self] _ in self.mastodonController.followedHashtags }
)
.sink { [unowned self] in self.updateHashtagsSection(followed: $0) }
.store(in: &cancellables)
onViewDidLoad?() onViewDidLoad?()
} }
@ -183,7 +176,7 @@ class MainSidebarViewController: UIViewController {
applyDiscoverSectionSnapshot() applyDiscoverSectionSnapshot()
reloadLists(mastodonController.lists) reloadLists(mastodonController.lists)
updateHashtagsSection(followed: mastodonController.followedHashtags) reloadSavedHashtags()
reloadSavedInstances() reloadSavedInstances()
} }
@ -231,16 +224,14 @@ class MainSidebarViewController: UIViewController {
} }
@MainActor @MainActor
private func fetchHashtagItems(followed: [FollowedHashtag]) -> [Item] { private func fetchSavedHashtags() -> [SavedHashtag] {
let saved = (try? mastodonController.persistentContainer.viewContext.fetch(SavedHashtag.fetchRequest())) ?? [] let req = SavedHashtag.fetchRequest()
var items = saved.map { req.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true, selector: #selector(NSString.localizedCompare(_:)))]
Item.savedHashtag(Hashtag(name: $0.name, url: $0.url)) do {
return try mastodonController.persistentContainer.viewContext.fetch(req)
} catch {
return []
} }
for followed in followed where !saved.contains(where: { $0.name == followed.name }) {
items.append(.savedHashtag(Hashtag(name: followed.name, url: followed.url)))
}
items.sort(using: SemiCaseSensitiveComparator.keyPath(\.title))
return items
} }
@MainActor @MainActor
@ -254,8 +245,10 @@ class MainSidebarViewController: UIViewController {
} }
} }
private func updateHashtagsSection(followed: [FollowedHashtag]) { @objc private func reloadSavedHashtags() {
let hashtags = fetchHashtagItems(followed: followed) let hashtags = fetchSavedHashtags().map {
Item.savedHashtag(Hashtag(name: $0.name, url: $0.url))
}
if let selectedItem, if let selectedItem,
case .savedHashtag(_) = selectedItem, case .savedHashtag(_) = selectedItem,
!hashtags.contains(selectedItem) { !hashtags.contains(selectedItem) {
@ -410,13 +403,13 @@ extension MainSidebarViewController {
case .addList: case .addList:
return "New List..." return "New List..."
case .savedHashtagsHeader: case .savedHashtagsHeader:
return "Hashtags" return "Saved Hashtags"
case let .savedHashtag(hashtag): case let .savedHashtag(hashtag):
return hashtag.name return hashtag.name
case .addSavedHashtag: case .addSavedHashtag:
return "Add Hashtag..." return "Save Hashtag..."
case .savedInstancesHeader: case .savedInstancesHeader:
return "Instance Timelines" return "Saved Instances"
case let .savedInstance(url): case let .savedInstance(url):
return url.host! return url.host!
case .addSavedInstance: case .addSavedInstance:

View File

@ -83,8 +83,7 @@ class TimelinesPageViewController: SegmentedPageViewController<TimelinesPageView
return return
} }
selectPage(page, animated: false) selectPage(page, animated: false)
// can't use currentIndex here because the view isn't loaded yet, and so the page wasn't actually updated by the selectPage call let timelineVC = pageControllers[currentIndex] as! TimelineViewController
let timelineVC = pageControllers[pages.firstIndex(of: page)!] as! TimelineViewController
timelineVC.restoreActivity(activity) timelineVC.restoreActivity(activity)
} }

View File

@ -42,7 +42,7 @@ class SegmentedPageViewController<Page: Hashable>: UIPageViewController, UIPageV
self.selectPage(option, animated: true) self.selectPage(option, animated: true)
} }
} }
// TODO: the custom segmented control isn't treated as a group and I have no idea how to change that // TODO: double check this with the custom segmented control
// the segemented control itself is only focusable when VoiceOver is in Group navigation mode, // the segemented control itself is only focusable when VoiceOver is in Group navigation mode,
// so make it clear that to switch tabs the user needs to enter the group // so make it clear that to switch tabs the user needs to enter the group
segmentedControl.accessibilityHint = "Enter group to select timeline" segmentedControl.accessibilityHint = "Enter group to select timeline"