@@ -4,18 +4,21 @@ import Yosemite
44
55/// Displays a paginated list of products where the user can select.
66final class ProductListSelectorViewController : UIViewController {
7+ /// Whether the view is for selecting or excluding products
8+ private let isExclusion : Bool
9+
710 private let excludedProductIDs : [ Int64 ]
811 private var productIDs : [ Int64 ] = [ ] {
912 didSet {
1013 if productIDs != oldValue {
11- updateNavigationTitle ( productIDs: productIDs)
12- updateNavigationRightBarButtonItem ( productIDs: productIDs)
14+ updateDoneButton ( productIDs: productIDs)
1315 }
1416 }
1517 }
1618
1719 private let siteID : Int64
1820 private var selectedProductIDsSubscription : AnyCancellable ?
21+ private var filters : FilterProductListViewModel . Filters = FilterProductListViewModel . Filters ( )
1922
2023 private lazy var dataSource = ProductListMultiSelectorDataSource ( siteID: siteID, excludedProductIDs: excludedProductIDs)
2124
@@ -30,14 +33,69 @@ final class ProductListSelectorViewController: UIViewController {
3033 return PaginatedListSelectorViewController( viewProperties: viewProperties , dataSource : dataSource , onDismiss : { _ in } )
3134 } ( )
3235
36+ private lazy var contentStackView : UIStackView = {
37+ let stackView = UIStackView ( arrangedSubviews: [ ] )
38+ stackView. axis = . vertical
39+ stackView. translatesAutoresizingMaskIntoConstraints = false
40+ return stackView
41+ } ( )
42+
43+ private lazy var doneButton : UIButton = {
44+ let button = UIButton ( )
45+ button. translatesAutoresizingMaskIntoConstraints = false
46+ button. addTarget ( self , action: #selector( doneButtonTapped) , for: . touchUpInside)
47+ button. applyPrimaryButtonStyle ( )
48+ return button
49+ } ( )
50+
51+ private lazy var doneButtonContainer : UIView = {
52+ let buttonContainer = UIView ( frame: . zero)
53+ buttonContainer. translatesAutoresizingMaskIntoConstraints = false
54+ buttonContainer. addSubview ( doneButton)
55+ buttonContainer. pinSubviewToSafeArea ( doneButton, insets: Constants . doneButtonInsets)
56+ return buttonContainer
57+ } ( )
58+
59+ private lazy var topBarContainer : UIView = {
60+ let container = UIView ( frame: . zero)
61+ container. translatesAutoresizingMaskIntoConstraints = false
62+
63+ let selectAllButton = UIButton ( )
64+ selectAllButton. setTitle ( Localization . selectAll, for: . normal)
65+ selectAllButton. translatesAutoresizingMaskIntoConstraints = false
66+ selectAllButton. addTarget ( self , action: #selector( selectAllProducts) , for: . touchUpInside)
67+ selectAllButton. applyLinkButtonStyle ( )
68+ selectAllButton. contentEdgeInsets = . zero
69+ container. addSubview ( selectAllButton)
70+
71+ let filterButton = UIButton ( )
72+ filterButton. setTitle ( Localization . filter, for: . normal)
73+ filterButton. translatesAutoresizingMaskIntoConstraints = false
74+ filterButton. addTarget ( self , action: #selector( showFilter) , for: . touchUpInside)
75+ filterButton. applyLinkButtonStyle ( )
76+ filterButton. contentEdgeInsets = . zero
77+ container. addSubview ( filterButton)
78+
79+ NSLayoutConstraint . activate ( [
80+ container. heightAnchor. constraint ( equalToConstant: Constants . topBarHeight) ,
81+ selectAllButton. leadingAnchor. constraint ( equalTo: container. safeLeadingAnchor, constant: Constants . topBarMargin) ,
82+ selectAllButton. centerYAnchor. constraint ( equalTo: container. centerYAnchor) ,
83+ container. safeTrailingAnchor. constraint ( equalTo: filterButton. trailingAnchor, constant: Constants . topBarMargin) ,
84+ filterButton. centerYAnchor. constraint ( equalTo: container. centerYAnchor) ,
85+ ] )
86+
87+ return container
88+ } ( )
89+
3390 // Completion callback
3491 //
3592 typealias Completion = ( _ selectedProductIDs: [ Int64 ] ) -> Void
3693 private let onCompletion : Completion
3794
38- init ( excludedProductIDs: [ Int64 ] , siteID: Int64 , onCompletion: @escaping Completion ) {
95+ init ( excludedProductIDs: [ Int64 ] , siteID: Int64 , isExclusion : Bool = false , onCompletion: @escaping Completion ) {
3996 self . excludedProductIDs = excludedProductIDs
4097 self . siteID = siteID
98+ self . isExclusion = isExclusion
4199 self . onCompletion = onCompletion
42100 super. init ( nibName: nil , bundle: nil )
43101 }
@@ -51,12 +109,29 @@ final class ProductListSelectorViewController: UIViewController {
51109
52110 configureMainView ( )
53111 configureNavigation ( )
54- configurePaginatedProductListSelectorChildViewController ( )
112+ configureContentStackView ( )
55113 }
56114}
57115
58116// MARK: - Actions
59117private extension ProductListSelectorViewController {
118+ @objc func selectAllProducts( ) {
119+ // TODO
120+ }
121+
122+ @objc func showFilter( ) {
123+ let viewModel = FilterProductListViewModel ( filters: filters, siteID: siteID)
124+ let filterProductListViewController = FilterListViewController ( viewModel: viewModel, onFilterAction: { [ weak self] filters in
125+ ServiceLocator . analytics. track ( . productFilterListShowProductsButtonTapped, withProperties: [ " filters " : filters. analyticsDescription] )
126+ self ? . filters = filters
127+ } , onClearAction: {
128+ ServiceLocator . analytics. track ( . productFilterListClearMenuButtonTapped)
129+ } , onDismissAction: {
130+ ServiceLocator . analytics. track ( . productFilterListDismissButtonTapped)
131+ } )
132+ present ( filterProductListViewController, animated: true , completion: nil )
133+ }
134+
60135 @objc func doneButtonTapped( ) {
61136 completeUpdating ( )
62137 }
@@ -114,25 +189,13 @@ extension ProductListSelectorViewController {
114189
115190// MARK: - UI updates
116191private extension ProductListSelectorViewController {
117- func updateNavigationRightBarButtonItem( productIDs: [ Int64 ] ) {
118- if productIDs. isEmpty {
119- navigationItem. rightBarButtonItem = UIBarButtonItem ( barButtonSystemItem: . search, target: self , action: #selector( searchButtonTapped) )
120- } else {
121- navigationItem. rightBarButtonItem = UIBarButtonItem ( barButtonSystemItem: . done, target: self , action: #selector( doneButtonTapped) )
122- }
123- }
124192
125- func updateNavigationTitle( productIDs: [ Int64 ] ) {
126- let title : String
127- switch productIDs. count {
128- case 0 :
129- title = Localization . titleWithoutSelectedProducts
130- case 1 :
131- title = Localization . titleWithOneSelectedProduct
132- default :
133- title = String . localizedStringWithFormat ( Localization . titleWithMultipleSelectedProductsFormat, productIDs. count)
134- }
135- navigationItem. title = title
193+ func updateDoneButton( productIDs: [ Int64 ] ) {
194+ let itemCount = String . pluralize ( productIDs. count, singular: Localization . singleProduct, plural: Localization . multipleProducts)
195+ let format = isExclusion ? Localization . exclusionActionTitle : Localization . selectionActionTitle
196+ let title = String . localizedStringWithFormat ( format, itemCount)
197+ doneButton. setTitle ( title, for: . normal)
198+ doneButtonContainer. isHidden = productIDs. isEmpty
136199 }
137200}
138201
@@ -144,19 +207,29 @@ private extension ProductListSelectorViewController {
144207 }
145208
146209 func configureNavigation( ) {
147- updateNavigationTitle ( productIDs : productIDs )
148- updateNavigationRightBarButtonItem ( productIDs : productIDs )
210+ navigationItem . title = isExclusion ? Localization . exclusionTitle : Localization . selectionTitle
211+ navigationItem . rightBarButtonItem = UIBarButtonItem ( barButtonSystemItem : . search , target : self , action : #selector ( searchButtonTapped ) )
149212 }
150213
151- func configurePaginatedProductListSelectorChildViewController ( ) {
152- observeSelectedProductIDs ( observableProductIDs : dataSource . productIDs )
214+ func configureContentStackView ( ) {
215+ contentStackView . addArrangedSubview ( topBarContainer )
153216
217+ observeSelectedProductIDs ( observableProductIDs: dataSource. productIDs)
154218 addChild ( paginatedListSelector)
155219 paginatedListSelector. view. translatesAutoresizingMaskIntoConstraints = false
156- view . addSubview ( paginatedListSelector. view)
220+ contentStackView . addArrangedSubview ( paginatedListSelector. view)
157221 paginatedListSelector. didMove ( toParent: self )
158222
159- view. pinSubviewToAllEdges ( paginatedListSelector. view)
223+ contentStackView. addArrangedSubview ( doneButtonContainer)
224+ doneButtonContainer. isHidden = true // Hide the button initially since no product is selected yet.
225+
226+ view. addSubview ( contentStackView)
227+ NSLayoutConstraint . activate ( [
228+ view. leadingAnchor. constraint ( equalTo: contentStackView. leadingAnchor) ,
229+ view. trailingAnchor. constraint ( equalTo: contentStackView. trailingAnchor) ,
230+ view. safeTopAnchor. constraint ( equalTo: contentStackView. safeTopAnchor) ,
231+ view. safeBottomAnchor. constraint ( equalTo: contentStackView. safeBottomAnchor)
232+ ] )
160233 }
161234
162235 func observeSelectedProductIDs( observableProductIDs: AnyPublisher < [ Int64 ] , Never > ) {
@@ -169,15 +242,30 @@ private extension ProductListSelectorViewController {
169242// MARK: - Constants
170243//
171244private extension ProductListSelectorViewController {
245+ enum Constants {
246+ static let doneButtonInsets = UIEdgeInsets ( top: 16 , left: 16 , bottom: 0 , right: 16 )
247+ static let topBarMargin : CGFloat = 16
248+ static let topBarHeight : CGFloat = 46
249+ }
250+
172251 enum Localization {
173252 static let noResultsPlaceholder = NSLocalizedString ( " No products yet " ,
174253 comment: " Placeholder text when there are no products on the product list selector " )
175- static let titleWithoutSelectedProducts = NSLocalizedString ( " Add Products " , comment: " Navigation bar title for selecting multiple products. " )
176- static let titleWithOneSelectedProduct =
177- NSLocalizedString ( " 1 Product Selected " ,
178- comment: " Navigation bar title for selecting multiple products when one product has been selected. " )
179- static let titleWithMultipleSelectedProductsFormat =
180- NSLocalizedString ( " %ld Products Selected " ,
181- comment: " Navigation bar title for selecting multiple products when more multiple products have been selected. " )
254+ static let selectionTitle = NSLocalizedString ( " Select products " , comment: " Title for the Select Products screen " )
255+ static let exclusionTitle = NSLocalizedString ( " Exclude products " , comment: " Title of the Exclude Products screen " )
256+ static let selectionActionTitle = NSLocalizedString (
257+ " Select %1$@ " ,
258+ comment: " Title of the action button on the Select Products screen " +
259+ " Reads like: Select 1 Product "
260+ )
261+ static let exclusionActionTitle = NSLocalizedString (
262+ " Exclude %1$@ " ,
263+ comment: " Title of the action button on the Exclude Products screen " +
264+ " Reads like: Exclude 1 Product "
265+ )
266+ static let singleProduct = NSLocalizedString ( " %1$d Product " , comment: " Count of one product " )
267+ static let multipleProducts = NSLocalizedString ( " %1$d Products " , comment: " Count of several products, reads like: 2 Products " )
268+ static let selectAll = NSLocalizedString ( " Select All " , comment: " Button to select all products on the product list selector " )
269+ static let filter = NSLocalizedString ( " Filter " , comment: " Button to filter products on the product list selector " )
182270 }
183271}
0 commit comments