@@ -9,6 +9,8 @@ import class AutomatticTracks.CrashLogging
99///
1010final class ProductsViewController : UIViewController , GhostableViewController {
1111
12+ let viewModel : ProductListViewModel = . init( )
13+
1214 /// Main TableView
1315 ///
1416 @IBOutlet weak var tableView : UITableView !
@@ -264,7 +266,24 @@ private extension ProductsViewController {
264266 }
265267
266268 @objc func startBulkEditing( ) {
267- // TODO-8517: implement selection state
269+ tableView. setEditing ( true , animated: true )
270+
271+ // Disable pull-to-refresh while editing
272+ refreshControl. removeFromSuperview ( )
273+
274+ configureNavigationBarForEditing ( )
275+ showOrHideToolbar ( )
276+ }
277+
278+ @objc func finishBulkEditing( ) {
279+ viewModel. deselectAll ( )
280+ tableView. setEditing ( false , animated: true )
281+
282+ // Enable pull-to-refresh
283+ tableView. addSubview ( refreshControl)
284+
285+ configureNavigationBar ( )
286+ showOrHideToolbar ( )
268287 }
269288}
270289
@@ -330,12 +349,8 @@ private extension ProductsViewController {
330349 target: self ,
331350 action: #selector( startBulkEditing) )
332351 button. accessibilityTraits = . button
333- button. accessibilityLabel = NSLocalizedString ( " Edit products " ,
334- comment: " Action to start bulk editing of products " )
335- button. accessibilityHint = NSLocalizedString (
336- " Edit status or price for multiple products at once " ,
337- comment: " VoiceOver accessibility hint, informing the user the button can be used to bulk edit products "
338- )
352+ button. accessibilityLabel = Localization . bulkEditingNavBarButtonTitle
353+ button. accessibilityHint = Localization . bulkEditingNavBarButtonHint
339354
340355 return button
341356 } ( )
@@ -345,6 +360,26 @@ private extension ProductsViewController {
345360 navigationItem. rightBarButtonItems = rightBarButtonItems
346361 }
347362
363+ func configureNavigationBarForEditing( ) {
364+ configureNavigationBarTitleForEditing ( )
365+ configureNavigationBarRightButtonItemsForEditing ( )
366+ }
367+
368+ func configureNavigationBarTitleForEditing( ) {
369+ let selectedProducts = viewModel. selectedProductsCount
370+ if selectedProducts == 0 {
371+ navigationItem. title = Localization . bulkEditingTitle
372+ } else {
373+ navigationItem. title = String . localizedStringWithFormat ( Localization . bulkEditingItemsTitle, String ( selectedProducts) )
374+ }
375+ }
376+
377+ func configureNavigationBarRightButtonItemsForEditing( ) {
378+ navigationItem. rightBarButtonItems = [ UIBarButtonItem ( barButtonSystemItem: . cancel,
379+ target: self ,
380+ action: #selector( finishBulkEditing) ) ]
381+ }
382+
348383 /// Apply Woo styles.
349384 ///
350385 func configureMainView( ) {
@@ -371,6 +406,8 @@ private extension ProductsViewController {
371406 tableView. tableFooterView = footerSpinnerView
372407 tableView. separatorStyle = . none
373408
409+ tableView. allowsMultipleSelectionDuringEditing = true
410+
374411 // Adds the refresh control to table view manually so that the refresh control always appears below the navigation bar title in
375412 // large or normal size to be consistent with Dashboard and Orders tab with large titles workaround.
376413 // If we do `tableView.refreshControl = refreshControl`, the refresh control appears in the navigation bar when large title is shown.
@@ -447,6 +484,11 @@ private extension ProductsViewController {
447484 /// if there is 1 or more products, toolbar will be visible
448485 ///
449486 func showOrHideToolbar( ) {
487+ guard !tableView. isEditing else {
488+ toolbar. isHidden = true
489+ return
490+ }
491+
450492 toolbar. isHidden = filters. numberOfActiveFilters == 0 ? isEmpty : false
451493 }
452494}
@@ -627,13 +669,28 @@ extension ProductsViewController: UITableViewDelegate {
627669 }
628670
629671 func tableView( _ tableView: UITableView , didSelectRowAt indexPath: IndexPath ) {
630- tableView . deselectRow ( at: indexPath, animated : true )
672+ let product = resultsController . object ( at: indexPath)
631673
632- ServiceLocator . analytics. track ( . productListProductTapped)
674+ if tableView. isEditing {
675+ viewModel. selectProduct ( product)
676+ configureNavigationBarTitleForEditing ( )
677+ } else {
678+ tableView. deselectRow ( at: indexPath, animated: true )
633679
634- let product = resultsController. object ( at: indexPath)
680+ ServiceLocator . analytics. track ( . productListProductTapped)
681+
682+ didSelectProduct ( product: product)
683+ }
684+ }
685+
686+ func tableView( _ tableView: UITableView , didDeselectRowAt indexPath: IndexPath ) {
687+ guard tableView. isEditing else {
688+ return
689+ }
635690
636- didSelectProduct ( product: product)
691+ let product = resultsController. object ( at: indexPath)
692+ viewModel. deselectProduct ( product)
693+ configureNavigationBarTitleForEditing ( )
637694 }
638695
639696 func tableView( _ tableView: UITableView , willDisplay cell: UITableViewCell , forRowAt indexPath: IndexPath ) {
@@ -646,6 +703,14 @@ extension ProductsViewController: UITableViewDelegate {
646703 // the actual value. AKA no flicker!
647704 //
648705 estimatedRowHeights [ indexPath] = cell. frame. height
706+
707+ // Restore cell selection state
708+ let product = resultsController. object ( at: indexPath)
709+ if self . viewModel. productIsSelected ( product) {
710+ tableView. selectRow ( at: indexPath, animated: false , scrollPosition: . none)
711+ } else {
712+ tableView. deselectRow ( at: indexPath, animated: false )
713+ }
649714 }
650715
651716 func scrollViewDidScroll( _ scrollView: UIScrollView ) {
@@ -1046,4 +1111,22 @@ private extension ProductsViewController {
10461111 static let headerContainerInsets = UIEdgeInsets ( top: 0 , left: 0 , bottom: 0 , right: 0 )
10471112 static let toolbarButtonInsets = UIEdgeInsets ( top: 12 , left: 16 , bottom: 12 , right: 16 )
10481113 }
1114+
1115+ enum Localization {
1116+
1117+ static let bulkEditingNavBarButtonTitle = NSLocalizedString ( " Edit products " , comment: " Action to start bulk editing of products " )
1118+ static let bulkEditingNavBarButtonHint = NSLocalizedString (
1119+ " Edit status or price for multiple products at once " ,
1120+ comment: " VoiceOver accessibility hint, informing the user the button can be used to bulk edit products "
1121+ )
1122+
1123+ static let bulkEditingTitle = NSLocalizedString (
1124+ " Select items " ,
1125+ comment: " Title that appears on top of the Product List screen when bulk editing starts. "
1126+ )
1127+ static let bulkEditingItemsTitle = NSLocalizedString (
1128+ " %1$@ selected " ,
1129+ comment: " Title that appears on top of the Product List screen during bulk editing. Reads like: 2 selected "
1130+ )
1131+ }
10491132}
0 commit comments