2019-12-18 03:56:53 +00:00
//
// E d i t L i s t A c c o u n t s V i e w C o n t r o l l e r . s w i f t
// T u s k e r
//
// C r e a t e d b y S h a d o w f a c t s o n 1 2 / 1 7 / 1 9 .
// C o p y r i g h t © 2 0 1 9 S h a d o w f a c t s . A l l r i g h t s r e s e r v e d .
//
import UIKit
import Pachyderm
2022-11-19 19:08:39 +00:00
import Combine
2019-12-18 03:56:53 +00:00
class EditListAccountsViewController : EnhancedTableViewController {
2022-12-15 02:00:36 +00:00
private var list : List
2020-01-05 20:25:07 +00:00
let mastodonController : MastodonController
2022-12-15 02:00:36 +00:00
var changedAccounts = false
2019-12-18 03:56:53 +00:00
var dataSource : DataSource !
var nextRange : RequestRange ?
2022-11-28 02:44:17 +00:00
var searchResultsController : SearchResultsViewController !
2019-12-18 03:56:53 +00:00
var searchController : UISearchController !
2022-11-19 19:08:39 +00:00
private var listRenamedCancellable : AnyCancellable ?
2020-01-05 20:25:07 +00:00
init ( list : List , mastodonController : MastodonController ) {
2019-12-18 03:56:53 +00:00
self . list = list
2020-01-05 20:25:07 +00:00
self . mastodonController = mastodonController
2019-12-18 03:56:53 +00:00
super . init ( style : . plain )
2022-11-11 23:08:44 +00:00
listChanged ( )
2022-11-19 19:08:39 +00:00
listRenamedCancellable = mastodonController . $ lists
. compactMap { $0 . first { $0 . id = = list . id } }
. removeDuplicates ( by : { $0 . title = = $1 . title } )
. sink { [ unowned self ] in
self . list = $0
self . listChanged ( )
}
2019-12-18 03:56:53 +00:00
}
required init ? ( coder : NSCoder ) {
fatalError ( " init(coder:) has not been implemeneted " )
}
override func viewDidLoad ( ) {
super . viewDidLoad ( )
tableView . register ( UINib ( nibName : " AccountTableViewCell " , bundle : . main ) , forCellReuseIdentifier : " accountCell " )
tableView . rowHeight = UITableView . automaticDimension
tableView . estimatedRowHeight = 66
2023-01-16 22:47:56 +00:00
tableView . allowsSelection = false
2023-02-03 04:02:11 +00:00
tableView . backgroundColor = . appGroupedBackground
2019-12-18 03:56:53 +00:00
dataSource = DataSource ( tableView : tableView , cellProvider : { ( tableView , indexPath , item ) -> UITableViewCell ? in
guard case let . account ( id ) = item else { fatalError ( ) }
let cell = tableView . dequeueReusableCell ( withIdentifier : " accountCell " , for : indexPath ) as ! AccountTableViewCell
2021-02-06 19:35:34 +00:00
cell . delegate = self
2019-12-18 03:56:53 +00:00
cell . updateUI ( accountID : id )
2023-02-03 04:02:11 +00:00
cell . configurationUpdateHandler = { cell , state in
var config = UIBackgroundConfiguration . listGroupedCell ( ) . updated ( for : state )
if state . isHighlighted || state . isSelected {
config . backgroundColor = . appSelectedCellBackground
} else {
config . backgroundColor = . appGroupedCellBackground
}
cell . backgroundConfiguration = config
}
2019-12-18 03:56:53 +00:00
return cell
} )
dataSource . editListAccountsController = self
2023-01-22 16:41:38 +00:00
searchResultsController = SearchResultsViewController ( mastodonController : mastodonController , scope : . people )
2022-11-28 02:44:17 +00:00
searchResultsController . following = true
searchResultsController . delegate = self
2019-12-18 03:56:53 +00:00
searchController = UISearchController ( searchResultsController : searchResultsController )
searchController . hidesNavigationBarDuringPresentation = false
searchController . searchResultsUpdater = searchResultsController
searchController . searchBar . autocapitalizationType = . none
2022-11-28 02:44:17 +00:00
searchController . searchBar . placeholder = NSLocalizedString ( " Search accounts you follow " , comment : " edit list search field placeholder " )
2019-12-18 03:56:53 +00:00
searchController . searchBar . delegate = searchResultsController
definesPresentationContext = true
navigationItem . searchController = searchController
navigationItem . hidesSearchBarWhenScrolling = false
2022-11-30 21:53:11 +00:00
if #available ( iOS 16.0 , * ) {
navigationItem . preferredSearchBarPlacement = . stacked
}
2019-12-18 03:56:53 +00:00
navigationItem . rightBarButtonItem = UIBarButtonItem ( title : NSLocalizedString ( " Rename " , comment : " rename list button title " ) , style : . plain , target : self , action : #selector ( renameButtonPressed ) )
2022-11-11 22:28:19 +00:00
Task {
await loadAccounts ( )
}
2019-12-18 03:56:53 +00:00
}
2022-11-11 23:08:44 +00:00
private func listChanged ( ) {
title = String ( format : NSLocalizedString ( " Edit %@ " , comment : " edit list screen title " ) , list . title )
}
2022-11-11 22:28:19 +00:00
func loadAccounts ( ) async {
do {
2023-02-25 18:55:46 +00:00
let request = List . getAccounts ( list . id )
2022-11-11 22:28:19 +00:00
let ( accounts , pagination ) = try await mastodonController . run ( request )
2019-12-18 03:56:53 +00:00
self . nextRange = pagination ? . older
2022-11-11 22:28:19 +00:00
await withCheckedContinuation { continuation in
mastodonController . persistentContainer . addAll ( accounts : accounts ) {
continuation . resume ( )
2021-06-26 22:52:19 +00:00
}
2019-12-18 03:56:53 +00:00
}
2022-11-11 22:28:19 +00:00
var snapshot = self . dataSource . snapshot ( )
if snapshot . indexOfSection ( . accounts ) = = nil {
snapshot . appendSections ( [ . accounts ] )
} else {
snapshot . deleteItems ( snapshot . itemIdentifiers ( inSection : . accounts ) )
}
snapshot . appendItems ( accounts . map { . account ( id : $0 . id ) } )
await dataSource . apply ( snapshot )
} catch {
let config = ToastConfiguration ( from : error , with : " Error Loading Accounts " , in : self ) { [ unowned self ] toast in
toast . dismissToast ( animated : true )
await self . loadAccounts ( )
}
self . showToast ( configuration : config , animated : true )
}
}
private func addAccount ( id : String ) async {
2022-12-15 02:00:36 +00:00
changedAccounts = true
2022-11-11 22:28:19 +00:00
do {
2023-02-25 18:55:46 +00:00
let req = List . add ( list . id , accounts : [ id ] )
2022-11-11 22:28:19 +00:00
_ = try await mastodonController . run ( req )
self . searchController . isActive = false
await self . loadAccounts ( )
} catch {
let config = ToastConfiguration ( from : error , with : " Error Adding Account " , in : self ) { [ unowned self ] toast in
toast . dismissToast ( animated : true )
await self . addAccount ( id : id )
}
self . showToast ( configuration : config , animated : true )
}
}
private func removeAccount ( id : String ) async {
2022-12-15 02:00:36 +00:00
changedAccounts = true
2022-11-11 22:28:19 +00:00
do {
2023-02-25 18:55:46 +00:00
let request = List . remove ( list . id , accounts : [ id ] )
2022-11-11 22:28:19 +00:00
_ = try await mastodonController . run ( request )
await self . loadAccounts ( )
} catch {
let config = ToastConfiguration ( from : error , with : " Error Removing Account " , in : self ) { [ unowned self ] toast in
toast . dismissToast ( animated : true )
await self . removeAccount ( id : id )
}
self . showToast ( configuration : config , animated : true )
2019-12-18 03:56:53 +00:00
}
}
// MARK: - T a b l e v i e w d e l e g a t e
override func tableView ( _ tableView : UITableView , editingStyleForRowAt indexPath : IndexPath ) -> UITableViewCell . EditingStyle {
return . delete
}
// MARK: - I n t e r a c t i o n
@objc func renameButtonPressed ( ) {
2022-11-11 23:08:44 +00:00
RenameListService ( list : list , mastodonController : mastodonController , present : { self . present ( $0 , animated : true ) } ) . run ( )
2019-12-18 03:56:53 +00:00
}
}
extension EditListAccountsViewController {
enum Section : Hashable {
case accounts
}
enum Item : Hashable {
case account ( id : String )
}
class DataSource : UITableViewDiffableDataSource < Section , Item > {
weak var editListAccountsController : EditListAccountsViewController ?
override func tableView ( _ tableView : UITableView , canEditRowAt indexPath : IndexPath ) -> Bool {
return true
}
override func tableView ( _ tableView : UITableView , commit editingStyle : UITableViewCell . EditingStyle , forRowAt indexPath : IndexPath ) {
guard editingStyle = = . delete ,
case let . account ( id ) = itemIdentifier ( for : indexPath ) else {
return
}
2022-11-11 22:28:19 +00:00
Task {
await self . editListAccountsController ? . removeAccount ( id : id )
2019-12-18 03:56:53 +00:00
}
}
}
}
2021-02-06 19:35:34 +00:00
extension EditListAccountsViewController : TuskerNavigationDelegate {
2022-10-31 20:27:13 +00:00
var apiController : MastodonController ! { mastodonController }
2021-02-06 19:35:34 +00:00
}
2022-05-02 03:04:56 +00:00
extension EditListAccountsViewController : ToastableViewController {
}
extension EditListAccountsViewController : MenuActionProvider {
}
2022-11-28 02:44:17 +00:00
extension EditListAccountsViewController : SearchResultsViewControllerDelegate {
func selectedSearchResult ( account accountID : String ) {
Task {
await addAccount ( id : accountID )
}
}
}