Skip to content

Commit 33e8e47

Browse files
authored
Merge pull request #8698 from woocommerce/issue/8524-select-all
Bulk Editing: Add select all action
2 parents b880467 + 7008f8a commit 33e8e47

File tree

3 files changed

+50
-5
lines changed

3 files changed

+50
-5
lines changed

WooCommerce/Classes/ViewRelated/Products/ProductsListViewModel.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,16 @@ class ProductListViewModel {
3131
return selectedProducts.contains(productToCheck)
3232
}
3333

34-
func selectProduct(_ selectedProduct: Product) {
35-
selectedProducts.insert(selectedProduct)
34+
func selectProduct(_ product: Product) {
35+
selectedProducts.insert(product)
3636
}
3737

38-
func deselectProduct(_ selectedProduct: Product) {
39-
selectedProducts.remove(selectedProduct)
38+
func selectProducts(_ products: [Product]) {
39+
selectedProducts.formUnion(products)
40+
}
41+
42+
func deselectProduct(_ product: Product) {
43+
selectedProducts.remove(product)
4044
}
4145

4246
func deselectAll() {

WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ final class ProductsViewController: UIViewController, GhostableViewController {
7373
didSet {
7474
bottomToolbar.isHidden = true
7575
bottomToolbar.backgroundColor = .systemColor(.secondarySystemGroupedBackground)
76-
bottomToolbar.setSubviews(leftViews: [], rightViews: [bulkEditButton])
76+
bottomToolbar.setSubviews(leftViews: [selectAllButton], rightViews: [bulkEditButton])
7777
bottomToolbar.addDividerOnTop()
7878
}
7979
}
@@ -105,6 +105,18 @@ final class ProductsViewController: UIViewController, GhostableViewController {
105105
return button
106106
}()
107107

108+
/// The select all CTA in the bottom toolbar.
109+
private lazy var selectAllButton: UIButton = {
110+
let button = UIButton(frame: .zero)
111+
button.setTitle(Localization.selectAllToolbarButtonTitle, for: .normal)
112+
button.addTarget(self, action: #selector(selectAllProducts), for: .touchUpInside)
113+
button.applyLinkButtonStyle()
114+
var configuration = UIButton.Configuration.plain()
115+
configuration.contentInsets = Constants.toolbarButtonInsets
116+
button.configuration = configuration
117+
return button
118+
}()
119+
108120
/// Container of the top banner that shows that the Products feature is still work in progress.
109121
///
110122
private lazy var topBannerContainerView: SwappableSubviewContainerView = SwappableSubviewContainerView()
@@ -333,6 +345,12 @@ private extension ProductsViewController {
333345
bulkEditButton.isEnabled = viewModel.bulkEditActionIsEnabled
334346
}
335347

348+
@objc func selectAllProducts() {
349+
viewModel.selectProducts(resultsController.fetchedObjects)
350+
updatedSelectedItems()
351+
tableView.reloadRows(at: tableView.indexPathsForVisibleRows ?? [], with: .none)
352+
}
353+
336354
@objc func openBulkEditingOptions(sender: UIButton) {
337355
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
338356

@@ -1305,6 +1323,10 @@ private extension ProductsViewController {
13051323
comment: "VoiceOver accessibility hint, informing the user the button can be used to bulk edit products"
13061324
)
13071325

1326+
static let selectAllToolbarButtonTitle = NSLocalizedString(
1327+
"Select all",
1328+
comment: "Title of a button that selects all products for bulk update"
1329+
)
13081330
static let bulkEditingToolbarButtonTitle = NSLocalizedString(
13091331
"Bulk update",
13101332
comment: "Title of a button that presents a menu with possible products bulk update options"

WooCommerce/WooCommerceTests/ViewRelated/Products/ProductListViewModelTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,25 @@ final class ProductListViewModelTests: XCTestCase {
3838
XCTAssertFalse(viewModel.productIsSelected(sampleProduct1))
3939
}
4040

41+
func test_selecting_multiple_products_works() {
42+
// Given
43+
let viewModel = ProductListViewModel(siteID: sampleSiteID, stores: storesManager)
44+
let sampleProduct1 = Product.fake().copy(productID: 1)
45+
let sampleProduct2 = Product.fake().copy(productID: 2)
46+
let sampleProduct3 = Product.fake().copy(productID: 3)
47+
XCTAssertEqual(viewModel.selectedProductsCount, 0)
48+
49+
// When
50+
viewModel.selectProduct(sampleProduct1)
51+
viewModel.selectProducts([sampleProduct2, sampleProduct3])
52+
53+
// Then
54+
XCTAssertEqual(viewModel.selectedProductsCount, 3)
55+
XCTAssertTrue(viewModel.productIsSelected(sampleProduct1))
56+
XCTAssertTrue(viewModel.productIsSelected(sampleProduct2))
57+
XCTAssertTrue(viewModel.productIsSelected(sampleProduct3))
58+
}
59+
4160
func test_deselecting_not_selected_product_does_nothing() {
4261
// Given
4362
let viewModel = ProductListViewModel(siteID: sampleSiteID, stores: storesManager)

0 commit comments

Comments
 (0)