@@ -22,7 +22,7 @@ class OrdersViewController: UIViewController {
2222
2323 weak var delegate : OrdersViewControllerDelegate ?
2424
25- private lazy var viewModel = OrdersViewModel ( )
25+ private let viewModel : OrdersViewModel
2626
2727 /// Main TableView.
2828 ///
@@ -46,15 +46,6 @@ class OrdersViewController: UIViewController {
4646 return FooterSpinnerView ( tableViewStyle: tableView. style)
4747 } ( )
4848
49- /// ResultsController: Surrounds us. Binds the galaxy together. And also, keeps the UITableView <> (Stored) Orders in sync.
50- ///
51- private lazy var resultsController : ResultsController < StorageOrder > = {
52- let storageManager = ServiceLocator . storageManager
53- let descriptor = NSSortDescriptor ( keyPath: \StorageOrder . dateCreated, ascending: false )
54-
55- return ResultsController < StorageOrder > ( storageManager: storageManager, sectionNameKeyPath: " normalizedAgeAsString " , sortedBy: [ descriptor] )
56- } ( )
57-
5849 /// Used for looking up the `OrderStatus` to show in the `OrderTableViewCell`.
5950 ///
6051 /// The `OrderStatus` data is fetched from the API by `OrdersMasterViewModel`.
@@ -70,28 +61,12 @@ class OrdersViewController: UIViewController {
7061 ///
7162 private let syncingCoordinator = SyncingCoordinator ( )
7263
73- /// OrderStatus that must be matched by retrieved orders.
74- ///
75- private let statusFilter : OrderStatus ?
76-
7764 /// The current list of order statuses for the default site
7865 ///
7966 private var currentSiteStatuses : [ OrderStatus ] {
8067 return statusResultsController. fetchedObjects
8168 }
8269
83- /// Indicates if there are no results onscreen.
84- ///
85- private var isEmpty : Bool {
86- return resultsController. isEmpty
87- }
88-
89- /// Indicates if there's a filter being applied.
90- ///
91- private var isFiltered : Bool {
92- return statusFilter != nil
93- }
94-
9570 /// UI Active State
9671 ///
9772 private var state : State = . results {
@@ -112,7 +87,7 @@ class OrdersViewController: UIViewController {
11287 /// - Parameter statusFilter The filter to use.
11388 ///
11489 init ( title: String , statusFilter: OrderStatus ? = nil ) {
115- self . statusFilter = statusFilter
90+ viewModel = OrdersViewModel ( statusFilter: statusFilter )
11691
11792 super. init ( nibName: Self . nibName, bundle: nil )
11893
@@ -126,7 +101,6 @@ class OrdersViewController: UIViewController {
126101 override func viewDidLoad( ) {
127102 super. viewDidLoad ( )
128103
129- refreshResultsPredicate ( )
130104 refreshStatusPredicate ( )
131105 registerTableViewHeadersAndCells ( )
132106
@@ -135,6 +109,8 @@ class OrdersViewController: UIViewController {
135109 configureGhostableTableView ( )
136110 configureResultsControllers ( )
137111
112+ configureViewModel ( )
113+
138114 startListeningToNotifications ( )
139115 }
140116
@@ -153,24 +129,10 @@ class OrdersViewController: UIViewController {
153129// MARK: - User Interface Initialization
154130//
155131private extension OrdersViewController {
156- /// Setup: Order filtering
132+ /// Initialize ViewModel operations
157133 ///
158- func refreshResultsPredicate( ) {
159- resultsController. predicate = {
160- let excludeSearchCache = NSPredicate ( format: " exclusiveForSearch = false " )
161- let excludeNonMatchingStatus = statusFilter. map { NSPredicate ( format: " statusKey = %@ " , $0. slug) }
162-
163- var predicates = [ excludeSearchCache, excludeNonMatchingStatus ] . compactMap { $0 }
164- if let tomorrow = Date . tomorrow ( ) {
165- let dateSubPredicate = NSPredicate ( format: " dateCreated < %@ " , tomorrow as NSDate )
166- predicates. append ( dateSubPredicate)
167- }
168-
169- return NSCompoundPredicate ( andPredicateWithSubpredicates: predicates)
170- } ( )
171-
172- tableView. setContentOffset ( . zero, animated: false )
173- tableView. reloadData ( )
134+ func configureViewModel( ) {
135+ viewModel. activateAndForwardUpdates ( to: tableView)
174136 }
175137
176138 /// Setup: Order status predicate
@@ -192,10 +154,6 @@ private extension OrdersViewController {
192154 /// Setup: Results Controller
193155 ///
194156 func configureResultsControllers( ) {
195- // Orders FRC
196- resultsController. startForwardingEvents ( to: tableView)
197- try ? resultsController. performFetch ( )
198-
199157 // Order status FRC
200158 try ? statusResultsController. performFetch ( )
201159 }
@@ -302,7 +260,6 @@ extension OrdersViewController: SyncingCoordinatorDelegate {
302260
303261 let action = viewModel. synchronizationAction (
304262 siteID: siteID,
305- statusKey: statusFilter? . slug,
306263 pageNumber: pageNumber,
307264 pageSize: pageSize,
308265 reason: SyncReason ( rawValue: reason ?? " " ) ) { [ weak self] error in
@@ -314,7 +271,8 @@ extension OrdersViewController: SyncingCoordinatorDelegate {
314271 DDLogError ( " ⛔️ Error synchronizing orders: \( error) " )
315272 self . displaySyncingErrorNotice ( pageNumber: pageNumber, pageSize: pageSize, reason: reason)
316273 } else {
317- ServiceLocator . analytics. track ( . ordersListLoaded, withProperties: [ " status " : self . statusFilter? . slug ?? String ( ) ] )
274+ let status = self . viewModel. statusFilter? . slug ?? String ( )
275+ ServiceLocator . analytics. track ( . ordersListLoaded, withProperties: [ " status " : status] )
318276 }
319277
320278 self . transitionToResultsUpdatedState ( )
@@ -347,7 +305,7 @@ extension OrdersViewController {
347305 return false
348306 }
349307
350- return highestPageBeingSynced * SyncingCoordinator. Defaults. pageSize > resultsController . numberOfObjects
308+ return highestPageBeingSynced * SyncingCoordinator. Defaults. pageSize > viewModel . numberOfObjects
351309 }
352310
353311 /// Stops animating the Footer Spinner.
@@ -452,12 +410,6 @@ private extension OrdersViewController {
452410//
453411private extension OrdersViewController {
454412
455- func detailsViewModel( at indexPath: IndexPath ) -> OrderDetailsViewModel {
456- let order = resultsController. object ( at: indexPath)
457-
458- return OrderDetailsViewModel ( order: order)
459- }
460-
461413 func lookUpOrderStatus( for order: Order ) -> OrderStatus ? {
462414 for orderStatus in currentSiteStatuses where orderStatus. slug == order. statusKey {
463415 return orderStatus
@@ -473,21 +425,21 @@ private extension OrdersViewController {
473425extension OrdersViewController : UITableViewDataSource {
474426
475427 func numberOfSections( in tableView: UITableView ) -> Int {
476- return resultsController . sections . count
428+ viewModel . numberOfSections
477429 }
478430
479431 func tableView( _ tableView: UITableView , numberOfRowsInSection section: Int ) -> Int {
480- return resultsController . sections [ section] . numberOfObjects
432+ viewModel . numberOfRows ( in : section)
481433 }
482434
483435 func tableView( _ tableView: UITableView , cellForRowAt indexPath: IndexPath ) -> UITableViewCell {
484436 guard let cell = tableView. dequeueReusableCell ( withIdentifier: OrderTableViewCell . reuseIdentifier, for: indexPath) as? OrderTableViewCell else {
485437 fatalError ( )
486438 }
487439
488- let viewModel = detailsViewModel ( at: indexPath)
489- let orderStatus = lookUpOrderStatus ( for: viewModel . order)
490- cell. configureCell ( viewModel: viewModel , orderStatus: orderStatus)
440+ let detailsViewModel = viewModel . detailsViewModel ( at: indexPath)
441+ let orderStatus = lookUpOrderStatus ( for: detailsViewModel . order)
442+ cell. configureCell ( viewModel: detailsViewModel , orderStatus: orderStatus)
491443 cell. layoutIfNeeded ( )
492444 return cell
493445 }
@@ -499,7 +451,7 @@ extension OrdersViewController: UITableViewDataSource {
499451 }
500452
501453 header. leftText = {
502- let rawAge = resultsController . sections [ section] . name
454+ let rawAge = viewModel . sectionInfo ( at : section) . name
503455 return Age ( rawValue: rawAge) ? . description
504456 } ( )
505457 header. rightText = nil
@@ -524,13 +476,13 @@ extension OrdersViewController: UITableViewDelegate {
524476 assertionFailure ( " Expected OrderDetailsViewController to be instantiated " )
525477 return
526478 }
527- orderDetailsVC. viewModel = detailsViewModel ( at: indexPath)
479+ orderDetailsVC. viewModel = viewModel . detailsViewModel ( at: indexPath)
528480
529481 navigationController? . pushViewController ( orderDetailsVC, animated: true )
530482 }
531483
532484 func tableView( _ tableView: UITableView , willDisplay cell: UITableViewCell , forRowAt indexPath: IndexPath ) {
533- let orderIndex = resultsController . objectIndex ( from: indexPath)
485+ let orderIndex = viewModel . objectIndex ( from: indexPath)
534486 syncingCoordinator. ensureNextPageIsSynchronized ( lastVisibleIndex: orderIndex)
535487 }
536488}
@@ -590,19 +542,19 @@ private extension OrdersViewController {
590542 /// we've got cached results, or not.
591543 ///
592544 func transitionToSyncingState( ) {
593- state = isEmpty ? . placeholder : . syncing
545+ state = viewModel . isEmpty ? . placeholder : . syncing
594546 }
595547
596548 /// Should be called whenever the results are updated: after Sync'ing (or after applying a filter).
597549 /// Transitions to `.results` / `.emptyFiltered` / `.emptyUnfiltered` accordingly.
598550 ///
599551 func transitionToResultsUpdatedState( ) {
600- if isEmpty == false {
552+ if viewModel . isEmpty == false {
601553 state = . results
602554 return
603555 }
604556
605- if isFiltered {
557+ if viewModel . isFiltered {
606558 state = . emptyFiltered
607559 return
608560 }
0 commit comments