Compare commits
4 Commits
f5704e561b
...
bcae60316b
Author | SHA1 | Date |
---|---|---|
Shadowfacts | bcae60316b | |
Shadowfacts | 1a2fa10708 | |
Shadowfacts | f79c2feea6 | |
Shadowfacts | 7ec87d7853 |
|
@ -17,7 +17,7 @@ class EditListAccountsViewController: UIViewController, CollectionViewController
|
||||||
|
|
||||||
private var state = State.unloaded
|
private var state = State.unloaded
|
||||||
|
|
||||||
private(set) var changedAccounts = false
|
private(set) var shouldReloadListTimeline = false
|
||||||
|
|
||||||
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
||||||
var collectionView: UICollectionView! { view as? UICollectionView }
|
var collectionView: UICollectionView! { view as? UICollectionView }
|
||||||
|
@ -186,7 +186,7 @@ class EditListAccountsViewController: UIViewController, CollectionViewController
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
private func loadAccounts() async {
|
private func loadAccounts() async {
|
||||||
guard state == .unloaded else { return }
|
guard state == .unloaded || state == .loaded else { return }
|
||||||
|
|
||||||
state = .loading
|
state = .loading
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ class EditListAccountsViewController: UIViewController, CollectionViewController
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addAccount(id: String) async {
|
private func addAccount(id: String) async {
|
||||||
changedAccounts = true
|
shouldReloadListTimeline = true
|
||||||
do {
|
do {
|
||||||
let req = List.add(list.id, accounts: [id])
|
let req = List.add(list.id, accounts: [id])
|
||||||
_ = try await mastodonController.run(req)
|
_ = try await mastodonController.run(req)
|
||||||
|
@ -294,11 +294,19 @@ class EditListAccountsViewController: UIViewController, CollectionViewController
|
||||||
}
|
}
|
||||||
|
|
||||||
private func removeAccount(id: String) async {
|
private func removeAccount(id: String) async {
|
||||||
changedAccounts = true
|
shouldReloadListTimeline = true
|
||||||
do {
|
do {
|
||||||
let request = List.remove(list.id, accounts: [id])
|
let request = List.remove(list.id, accounts: [id])
|
||||||
_ = try await mastodonController.run(request)
|
_ = try await mastodonController.run(request)
|
||||||
await self.loadAccounts()
|
|
||||||
|
var snapshot = dataSource.snapshot()
|
||||||
|
if snapshot.itemIdentifiers.contains(.account(id: id)) {
|
||||||
|
snapshot.deleteItems([.account(id: id)])
|
||||||
|
await MainActor.run {
|
||||||
|
dataSource.apply(snapshot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
let config = ToastConfiguration(from: error, with: "Error Removing Account", in: self) { [unowned self] toast in
|
let config = ToastConfiguration(from: error, with: "Error Removing Account", in: self) { [unowned self] toast in
|
||||||
toast.dismissToast(animated: true)
|
toast.dismissToast(animated: true)
|
||||||
|
@ -309,6 +317,7 @@ class EditListAccountsViewController: UIViewController, CollectionViewController
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setReplyPolicy(_ replyPolicy: List.ReplyPolicy) {
|
private func setReplyPolicy(_ replyPolicy: List.ReplyPolicy) {
|
||||||
|
shouldReloadListTimeline = true
|
||||||
Task {
|
Task {
|
||||||
let service = EditListSettingsService(list: list, mastodonController: mastodonController, present: { self.present($0, animated: true) })
|
let service = EditListSettingsService(list: list, mastodonController: mastodonController, present: { self.present($0, animated: true) })
|
||||||
await service.run(replyPolicy: replyPolicy)
|
await service.run(replyPolicy: replyPolicy)
|
||||||
|
|
|
@ -16,6 +16,8 @@ class ListTimelineViewController: TimelineViewController {
|
||||||
|
|
||||||
var presentEditOnAppear = false
|
var presentEditOnAppear = false
|
||||||
|
|
||||||
|
private var noContentView: UIStackView!
|
||||||
|
|
||||||
private var listRenamedCancellable: AnyCancellable?
|
private var listRenamedCancellable: AnyCancellable?
|
||||||
|
|
||||||
init(for list: List, mastodonController: MastodonController) {
|
init(for list: List, mastodonController: MastodonController) {
|
||||||
|
@ -53,6 +55,39 @@ class ListTimelineViewController: TimelineViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func createNoContentView() {
|
||||||
|
let title = UILabel()
|
||||||
|
title.textColor = .secondaryLabel
|
||||||
|
title.font = .preferredFont(forTextStyle: .title1).withTraits(.traitBold)!
|
||||||
|
title.adjustsFontForContentSizeCategory = true
|
||||||
|
title.text = "No Posts"
|
||||||
|
|
||||||
|
let subtitle = UILabel()
|
||||||
|
subtitle.textColor = .secondaryLabel
|
||||||
|
subtitle.font = .preferredFont(forTextStyle: .body)
|
||||||
|
subtitle.adjustsFontForContentSizeCategory = true
|
||||||
|
subtitle.numberOfLines = 0
|
||||||
|
subtitle.textAlignment = .center
|
||||||
|
subtitle.text = "This list doesn't currently have any posts. Edit it to add accounts if necessary."
|
||||||
|
|
||||||
|
noContentView = UIStackView(arrangedSubviews: [
|
||||||
|
title,
|
||||||
|
subtitle,
|
||||||
|
])
|
||||||
|
noContentView.axis = .vertical
|
||||||
|
noContentView.spacing = 8
|
||||||
|
noContentView.alignment = .center
|
||||||
|
noContentView.isAccessibilityElement = true
|
||||||
|
noContentView.accessibilityLabel = subtitle.text
|
||||||
|
noContentView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
view.addSubview(noContentView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
noContentView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
||||||
|
noContentView.leadingAnchor.constraint(equalToSystemSpacingAfter: view.safeAreaLayoutGuide.leadingAnchor, multiplier: 1),
|
||||||
|
view.safeAreaLayoutGuide.trailingAnchor.constraint(equalToSystemSpacingAfter: noContentView.trailingAnchor, multiplier: 1),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
private func listChanged() {
|
private func listChanged() {
|
||||||
title = list.title
|
title = list.title
|
||||||
}
|
}
|
||||||
|
@ -61,10 +96,23 @@ class ListTimelineViewController: TimelineViewController {
|
||||||
let editListAccountsController = EditListAccountsViewController(list: list, mastodonController: mastodonController)
|
let editListAccountsController = EditListAccountsViewController(list: list, mastodonController: mastodonController)
|
||||||
editListAccountsController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(editListDoneButtonPressed))
|
editListAccountsController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(editListDoneButtonPressed))
|
||||||
let navController = UINavigationController(rootViewController: editListAccountsController)
|
let navController = UINavigationController(rootViewController: editListAccountsController)
|
||||||
|
navController.sheetPresentationController?.delegate = self
|
||||||
present(navController, animated: animated)
|
present(navController, animated: animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Interaction
|
private func reloadIfNecessary(editViewController: EditListAccountsViewController) {
|
||||||
|
guard editViewController.shouldReloadListTimeline else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
noContentView?.removeFromSuperview()
|
||||||
|
noContentView = nil
|
||||||
|
Task {
|
||||||
|
applyInitialSnapshot()
|
||||||
|
await controller.loadInitial()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Interaction
|
||||||
|
|
||||||
@objc func editListButtonPressed() {
|
@objc func editListButtonPressed() {
|
||||||
presentEdit(animated: true)
|
presentEdit(animated: true)
|
||||||
|
@ -75,12 +123,28 @@ class ListTimelineViewController: TimelineViewController {
|
||||||
|
|
||||||
dismiss(animated: true)
|
dismiss(animated: true)
|
||||||
|
|
||||||
if presented?.changedAccounts == true {
|
if let presented {
|
||||||
Task {
|
self.reloadIfNecessary(editViewController: presented)
|
||||||
applyInitialSnapshot()
|
|
||||||
await controller.loadInitial()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: TimelineLikeControllerDelegate
|
||||||
|
|
||||||
|
override func handleReplaceAllItems(_ timelineItems: [String]) async {
|
||||||
|
if timelineItems.isEmpty {
|
||||||
|
createNoContentView()
|
||||||
|
}
|
||||||
|
await super.handleReplaceAllItems(timelineItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ListTimelineViewController: UISheetPresentationControllerDelegate {
|
||||||
|
func presentationControllerWillDismiss(_ presentationController: UIPresentationController) {
|
||||||
|
guard let nav = presentationController.presentedViewController as? UINavigationController,
|
||||||
|
let edit = nav.viewControllers.first as? EditListAccountsViewController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reloadIfNecessary(editViewController: edit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1016,6 +1016,18 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
}
|
}
|
||||||
self.showToast(configuration: config, animated: true)
|
self.showToast(configuration: config, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is copied from the TimelineLikeCollectionViewController implementation because it needs to be overridable by ListTimelineViewController
|
||||||
|
func handleReplaceAllItems(_ timelineItems: [String]) async {
|
||||||
|
var snapshot = dataSource.snapshot()
|
||||||
|
if snapshot.sectionIdentifiers.contains(.entries) {
|
||||||
|
snapshot.deleteSections([.entries])
|
||||||
|
}
|
||||||
|
snapshot.appendSections([.entries])
|
||||||
|
snapshot.appendItems(timelineItems.map { .fromTimelineItem($0) }, toSection: .entries)
|
||||||
|
await apply(snapshot, animatingDifferences: false)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TimelineViewController {
|
extension TimelineViewController {
|
||||||
|
|
Loading…
Reference in New Issue