From 229a78936bffd798ad3c37e02bdb2aeebb918ad4 Mon Sep 17 00:00:00 2001 From: Evgeny Aleksandrov Date: Thu, 12 Jan 2023 17:53:36 +0300 Subject: [PATCH 1/9] Add bottom toolbar --- .../Products/ProductsViewController.swift | 59 ++++++++++++++++++- .../Products/ProductsViewController.xib | 27 +++++++-- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift index b60e1ed9fd4..fe27e48560b 100644 --- a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift @@ -66,12 +66,40 @@ final class ProductsViewController: UIViewController, GhostableViewController { /// @IBOutlet private weak var toolbar: ToolbarView! + /// Top toolbar that shows the bulk edit CTA. + /// + @IBOutlet private weak var bottomToolbar: ToolbarView! { + didSet { + bottomToolbar.isHidden = true + bottomToolbar.backgroundColor = .systemColor(.secondarySystemGroupedBackground) + bottomToolbar.setSubviews(leftViews: [], rightViews: [bulkEditButton]) + } + } + + /// Bottom placeholder inside StackView to cover the safe area gap below the bottom toolbar. + /// + @IBOutlet private weak var bottomPlaceholder: UIView! { + didSet { + bottomPlaceholder.backgroundColor = .systemColor(.secondarySystemGroupedBackground) + } + } + // Used to trick the navigation bar for large title (ref: issue 3 in p91TBi-45c-p2). private let hiddenScrollView = UIScrollView() /// The filter CTA in the top toolbar. private lazy var filterButton: UIButton = UIButton(frame: .zero) + /// The bulk edit CTA in the bottom toolbar. + private lazy var bulkEditButton: UIButton = { + let button = UIButton(frame: .zero) + button.setTitle(Localization.bulkEditingToolbarButtonTitle, for: .normal) + button.addTarget(self, action: #selector(filterButtonTapped), for: .touchUpInside) + button.applyLinkButtonStyle() + button.contentEdgeInsets = Constants.toolbarButtonInsets + return button + }() + /// Container of the top banner that shows that the Products feature is still work in progress. /// private lazy var topBannerContainerView: SwappableSubviewContainerView = SwappableSubviewContainerView() @@ -273,6 +301,7 @@ private extension ProductsViewController { configureNavigationBarForEditing() showOrHideToolbar() + showBottomToolbar() } @objc func finishBulkEditing() { @@ -284,6 +313,11 @@ private extension ProductsViewController { configureNavigationBar() showOrHideToolbar() + hideBottomToolbar() + } + + @objc func openBulkEditingOptions(sender: UIBarButtonItem) { + // TODO-8517: show menu with bulk editing options } } @@ -383,7 +417,7 @@ private extension ProductsViewController { /// Apply Woo styles. /// func configureMainView() { - view.backgroundColor = .listBackground + view.backgroundColor = .listBackground //.backgroundColor = .systemColor(.secondarySystemGroupedBackground) } func configureTabBarItem() { @@ -491,6 +525,24 @@ private extension ProductsViewController { toolbar.isHidden = filters.numberOfActiveFilters == 0 ? isEmpty : false } + + func showBottomToolbar() { + tabBarController?.tabBar.isHidden = true + + // trigger safe area update + if let tabBarController { + let currentFrame = tabBarController.view.frame + tabBarController.view.frame = currentFrame.insetBy(dx: 0, dy: 1) + tabBarController.view.frame = currentFrame + } + + bottomToolbar.isHidden = false + } + + func hideBottomToolbar() { + tabBarController?.tabBar.isHidden = false + bottomToolbar.isHidden = true + } } // MARK: - Updates @@ -1120,6 +1172,11 @@ private extension ProductsViewController { comment: "VoiceOver accessibility hint, informing the user the button can be used to bulk edit products" ) + static let bulkEditingToolbarButtonTitle = NSLocalizedString( + "Bulk update", + comment: "Title of a button that presents a menu with possible bulk update options" + ) + static let bulkEditingTitle = NSLocalizedString( "Select items", comment: "Title that appears on top of the Product List screen when bulk editing starts." diff --git a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.xib b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.xib index a0ce78608c1..9217ea8c1b4 100644 --- a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.xib +++ b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.xib @@ -1,9 +1,9 @@ - + - + @@ -11,6 +11,8 @@ + + @@ -22,7 +24,7 @@ - + @@ -32,11 +34,22 @@ - + + + + + + + + + + + + @@ -45,7 +58,7 @@ - + @@ -54,8 +67,10 @@ - + + + From b3642720e20bb5c6b6c1d37fee80634b7cda2ca7 Mon Sep 17 00:00:00 2001 From: Evgeny Aleksandrov Date: Thu, 12 Jan 2023 17:53:36 +0300 Subject: [PATCH 2/9] Fix autolayout warning --- .../Classes/ViewRelated/Products/ProductsViewController.xib | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.xib b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.xib index 9217ea8c1b4..18d36c4d60d 100644 --- a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.xib +++ b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.xib @@ -30,7 +30,7 @@ - + @@ -43,7 +43,7 @@ - + From c49b60505fa06290c66e5ac0ab516a5ef8456cfd Mon Sep 17 00:00:00 2001 From: Evgeny Aleksandrov Date: Thu, 12 Jan 2023 17:53:36 +0300 Subject: [PATCH 3/9] Add divider to toolbar --- .../Products/ProductsViewController.swift | 1 + .../Classes/ViewRelated/Toolbar/ToolbarView.swift | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift index fe27e48560b..e1de86bcdb2 100644 --- a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift @@ -73,6 +73,7 @@ final class ProductsViewController: UIViewController, GhostableViewController { bottomToolbar.isHidden = true bottomToolbar.backgroundColor = .systemColor(.secondarySystemGroupedBackground) bottomToolbar.setSubviews(leftViews: [], rightViews: [bulkEditButton]) + bottomToolbar.addDividerOnTop() } } diff --git a/WooCommerce/Classes/ViewRelated/Toolbar/ToolbarView.swift b/WooCommerce/Classes/ViewRelated/Toolbar/ToolbarView.swift index ce969ec2727..f370e6c6193 100644 --- a/WooCommerce/Classes/ViewRelated/Toolbar/ToolbarView.swift +++ b/WooCommerce/Classes/ViewRelated/Toolbar/ToolbarView.swift @@ -26,6 +26,20 @@ final class ToolbarView: UIView { pinSubviewToAllEdges(stackView) } + func addDividerOnTop() { + let divider = UIView() + divider.backgroundColor = .divider + divider.translatesAutoresizingMaskIntoConstraints = false + addSubview(divider) + + NSLayoutConstraint.activate([ + divider.heightAnchor.constraint(equalToConstant: 1/UIScreen.main.scale), + divider.topAnchor.constraint(equalTo: topAnchor), + divider.leadingAnchor.constraint(equalTo: leadingAnchor), + divider.trailingAnchor.constraint(equalTo: trailingAnchor) + ]) + } + func setSubviews(leftViews: [UIView], rightViews: [UIView]) { stackView.removeAllArrangedSubviews() From 6003873841e0e3fe054c667c5677288f714b6097 Mon Sep 17 00:00:00 2001 From: Evgeny Aleksandrov Date: Thu, 12 Jan 2023 17:53:36 +0300 Subject: [PATCH 4/9] Update toolbar button --- .../Classes/ViewRelated/Products/ProductsViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift index e1de86bcdb2..38e06d6115e 100644 --- a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift @@ -95,7 +95,7 @@ final class ProductsViewController: UIViewController, GhostableViewController { private lazy var bulkEditButton: UIButton = { let button = UIButton(frame: .zero) button.setTitle(Localization.bulkEditingToolbarButtonTitle, for: .normal) - button.addTarget(self, action: #selector(filterButtonTapped), for: .touchUpInside) + button.addTarget(self, action: #selector(openBulkEditingOptions(sender:)), for: .touchUpInside) button.applyLinkButtonStyle() button.contentEdgeInsets = Constants.toolbarButtonInsets return button @@ -317,7 +317,7 @@ private extension ProductsViewController { hideBottomToolbar() } - @objc func openBulkEditingOptions(sender: UIBarButtonItem) { + @objc func openBulkEditingOptions(sender: UIButton) { // TODO-8517: show menu with bulk editing options } } From 3ef1ad8f3ea885a8ea6f933679f286d2f8a3a8e1 Mon Sep 17 00:00:00 2001 From: Evgeny Aleksandrov Date: Thu, 12 Jan 2023 17:53:36 +0300 Subject: [PATCH 5/9] Enabled bulk edit button conditionally --- .../Products/ProductsListViewModel.swift | 4 ++++ .../Products/ProductsViewController.swift | 14 ++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Products/ProductsListViewModel.swift b/WooCommerce/Classes/ViewRelated/Products/ProductsListViewModel.swift index 9d773c74925..ebac8476401 100644 --- a/WooCommerce/Classes/ViewRelated/Products/ProductsListViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Products/ProductsListViewModel.swift @@ -10,6 +10,10 @@ class ProductListViewModel { selectedProducts.count } + var bulkEditActionIsEnabled: Bool { + !selectedProducts.isEmpty + } + func productIsSelected(_ productToCheck: Product) -> Bool { return selectedProducts.contains(productToCheck) } diff --git a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift index 38e06d6115e..e95b21e3397 100644 --- a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift @@ -98,6 +98,7 @@ final class ProductsViewController: UIViewController, GhostableViewController { button.addTarget(self, action: #selector(openBulkEditingOptions(sender:)), for: .touchUpInside) button.applyLinkButtonStyle() button.contentEdgeInsets = Constants.toolbarButtonInsets + button.isEnabled = false return button }() @@ -317,6 +318,11 @@ private extension ProductsViewController { hideBottomToolbar() } + func updatedSelectedItems() { + updateNavigationBarTitleForEditing() + bulkEditButton.isEnabled = viewModel.bulkEditActionIsEnabled + } + @objc func openBulkEditingOptions(sender: UIButton) { // TODO-8517: show menu with bulk editing options } @@ -396,11 +402,11 @@ private extension ProductsViewController { } func configureNavigationBarForEditing() { - configureNavigationBarTitleForEditing() + updateNavigationBarTitleForEditing() configureNavigationBarRightButtonItemsForEditing() } - func configureNavigationBarTitleForEditing() { + func updateNavigationBarTitleForEditing() { let selectedProducts = viewModel.selectedProductsCount if selectedProducts == 0 { navigationItem.title = Localization.bulkEditingTitle @@ -726,7 +732,7 @@ extension ProductsViewController: UITableViewDelegate { if tableView.isEditing { viewModel.selectProduct(product) - configureNavigationBarTitleForEditing() + updatedSelectedItems() } else { tableView.deselectRow(at: indexPath, animated: true) @@ -743,7 +749,7 @@ extension ProductsViewController: UITableViewDelegate { let product = resultsController.object(at: indexPath) viewModel.deselectProduct(product) - configureNavigationBarTitleForEditing() + updatedSelectedItems() } func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { From a69e1112bb8d3cbf77636ad0c49f7478a6d2c5f6 Mon Sep 17 00:00:00 2001 From: Evgeny Aleksandrov Date: Thu, 12 Jan 2023 17:53:36 +0300 Subject: [PATCH 6/9] Add disabled state for link button style --- WooCommerce/Classes/Extensions/UIButton+Helpers.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/Classes/Extensions/UIButton+Helpers.swift b/WooCommerce/Classes/Extensions/UIButton+Helpers.swift index eb26047fa83..723c46edb3c 100644 --- a/WooCommerce/Classes/Extensions/UIButton+Helpers.swift +++ b/WooCommerce/Classes/Extensions/UIButton+Helpers.swift @@ -101,6 +101,7 @@ extension UIButton { setTitleColor(.accent, for: .normal) setTitleColor(.accentDark, for: .highlighted) + setTitleColor(.buttonDisabledTitle, for: .disabled) } /// Applies the Modal Cancel Button Style From 64b6621270b34b21f44b2700cb0c6a480208aee0 Mon Sep 17 00:00:00 2001 From: Evgeny Aleksandrov Date: Thu, 12 Jan 2023 18:48:28 +0300 Subject: [PATCH 7/9] Show action sheet/popover with bulk edit options --- .../Products/ProductsViewController.swift | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift index e95b21e3397..94ad67e0e17 100644 --- a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift @@ -324,7 +324,26 @@ private extension ProductsViewController { } @objc func openBulkEditingOptions(sender: UIButton) { - // TODO-8517: show menu with bulk editing options + let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + + let updateStatus = UIAlertAction(title: Localization.bulkEditingStatusOption, style: .default) { _ in + // TODO-8519: show UI for status update + } + let updatePrice = UIAlertAction(title: Localization.bulkEditingPriceOption, style: .default) { _ in + // TODO-8520: show UI for price update + } + let cancelAction = UIAlertAction(title: Localization.cancel, style: .cancel) + + actionSheet.addAction(updateStatus) + actionSheet.addAction(updatePrice) + actionSheet.addAction(cancelAction) + + if let popoverController = actionSheet.popoverPresentationController { + popoverController.sourceView = sender + popoverController.sourceRect = sender.bounds + } + + present(actionSheet, animated: true) } } @@ -1181,8 +1200,11 @@ private extension ProductsViewController { static let bulkEditingToolbarButtonTitle = NSLocalizedString( "Bulk update", - comment: "Title of a button that presents a menu with possible bulk update options" + comment: "Title of a button that presents a menu with possible products bulk update options" ) + static let bulkEditingStatusOption = NSLocalizedString("Update status", comment: "Title of an option that opens bulk products status update flow") + static let bulkEditingPriceOption = NSLocalizedString("Update price", comment: "Title of an option that opens bulk products price update flow") + static let cancel = NSLocalizedString("Cancel", comment: "Title of an option to dismiss the bulk edit action sheet") static let bulkEditingTitle = NSLocalizedString( "Select items", From 1aa1b700b326ae39d1f634e89242d2b877f808cb Mon Sep 17 00:00:00 2001 From: Evgeny Aleksandrov Date: Thu, 12 Jan 2023 18:48:28 +0300 Subject: [PATCH 8/9] Fix contentEdgeInsets deprecation warnings --- .../ViewRelated/Products/ProductsViewController.swift | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift index 94ad67e0e17..a71e4dcb54a 100644 --- a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift @@ -97,7 +97,9 @@ final class ProductsViewController: UIViewController, GhostableViewController { button.setTitle(Localization.bulkEditingToolbarButtonTitle, for: .normal) button.addTarget(self, action: #selector(openBulkEditingOptions(sender:)), for: .touchUpInside) button.applyLinkButtonStyle() - button.contentEdgeInsets = Constants.toolbarButtonInsets + var configuration = UIButton.Configuration.plain() + configuration.contentInsets = Constants.toolbarButtonInsets + button.configuration = configuration button.isEnabled = false return button }() @@ -519,7 +521,9 @@ private extension ProductsViewController { [sortButton, filterButton].forEach { $0.applyLinkButtonStyle() - $0.contentEdgeInsets = Constants.toolbarButtonInsets + var configuration = UIButton.Configuration.plain() + configuration.contentInsets = Constants.toolbarButtonInsets + $0.configuration = configuration } toolbar.backgroundColor = .systemColor(.secondarySystemGroupedBackground) @@ -1187,7 +1191,7 @@ private extension ProductsViewController { static let placeholderRowsPerSection = [3] static let headerDefaultHeight = CGFloat(130) static let headerContainerInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) - static let toolbarButtonInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16) + static let toolbarButtonInsets = NSDirectionalEdgeInsets(top: 12, leading: 16, bottom: 12, trailing: 16) } enum Localization { From 3ea8bc280fca169e7d8a86b8ee7f3bf767c0a16a Mon Sep 17 00:00:00 2001 From: Evgeny Aleksandrov Date: Thu, 12 Jan 2023 20:28:07 +0300 Subject: [PATCH 9/9] Remove commented code --- .../Classes/ViewRelated/Products/ProductsViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift index a71e4dcb54a..2705b0af143 100644 --- a/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift @@ -445,7 +445,7 @@ private extension ProductsViewController { /// Apply Woo styles. /// func configureMainView() { - view.backgroundColor = .listBackground //.backgroundColor = .systemColor(.secondarySystemGroupedBackground) + view.backgroundColor = .listBackground } func configureTabBarItem() {