Skip to content

Commit bb8f875

Browse files
committed
Move navigation actions that don't change the data from view model to view controller.
1 parent bef0794 commit bb8f875

File tree

3 files changed

+42
-49
lines changed

3 files changed

+42
-49
lines changed

WooCommerce/Classes/ViewRelated/Filters/FilterListViewController.swift

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import UIKit
33
/// The view model protocol for filtering a list of models with generic filters.
44
///
55
protocol FilterListViewModel {
6+
/// The type of the final value returned to the caller of `FilterListViewController`.
7+
associatedtype Criteria
8+
69
// Filter Action UI configuration
710

811
/// The title of the Filter CTA at the bottom.
@@ -14,13 +17,10 @@ protocol FilterListViewModel {
1417
/// Tapping on each filter type row navigates to another list selector for the filter value.
1518
var filterTypeViewModels: [FilterTypeViewModel] { get }
1619

17-
// Navigation & Actions
18-
19-
/// Called when the user taps on the CTA to filter the list with the latest filters.
20-
func onFilterActionTapped()
20+
/// The final value returned to the caller of `FilterListViewController`.
21+
var criteria: Criteria { get }
2122

22-
/// Called when the user dismisses the filter list screen.
23-
func onDismissActionTapped()
23+
// Navigation & Actions
2424

2525
/// Called when the user taps on the CTA to clear all filters.
2626
func onClearAllActionTapped()
@@ -76,12 +76,12 @@ protocol FilterType {
7676
/// The UI consists of a list of filters at the top and a Filter CTA at the bottom that is always visible to apply the filters.
7777
/// Tapping on a filter in the list navigates to a list of options for the filter.
7878
///
79-
final class FilterListViewController: UIViewController {
79+
final class FilterListViewController<ViewModel: FilterListViewModel>: UIViewController {
8080

8181
@IBOutlet private weak var navigationControllerContainerView: UIView!
8282
@IBOutlet private weak var filterActionContainerView: UIView!
8383

84-
private let viewModel: FilterListViewModel
84+
private let viewModel: ViewModel
8585
private let listSelectorCommand: FilterListSelectorCommand
8686

8787
private lazy var listSelector: ListSelectorViewController
@@ -94,8 +94,21 @@ final class FilterListViewController: UIViewController {
9494
private var cancellableSelectedFilterType: ObservationToken?
9595
private var cancellableSelectedFilterValue: ObservationToken?
9696

97-
init(viewModel: FilterListViewModel) {
97+
private let onFilterAction: (ViewModel.Criteria) -> Void
98+
99+
// Strings.
100+
101+
private let navigationBarTitleWithoutActiveFilters =
102+
NSLocalizedString("Filters", comment: "Navigation bar title format for filtering a list of products without filters applied.")
103+
private let navigationBarTitleFormatWithActiveFilters =
104+
NSLocalizedString("Filters (%ld)", comment: "Navigation bar title format for filtering a list of products with filters applied.")
105+
106+
/// - Parameters:
107+
/// - viewModel: Used to render the filter list selector and the selected filter value list selector.
108+
/// - onFilterAction: Called when the user taps on the Filter CTA.
109+
init(viewModel: ViewModel, onFilterAction: @escaping (ViewModel.Criteria) -> Void) {
98110
self.viewModel = viewModel
111+
self.onFilterAction = onFilterAction
99112
self.listSelectorCommand = FilterListSelectorCommand(data: viewModel.filterTypeViewModels)
100113
super.init(nibName: "FilterListViewController", bundle: nil)
101114
}
@@ -123,11 +136,17 @@ final class FilterListViewController: UIViewController {
123136
// MARK: - Navigation
124137
//
125138
@objc func filterActionButtonTapped() {
126-
viewModel.onFilterActionTapped()
139+
dismiss(animated: true) { [weak self] in
140+
guard let self = self else {
141+
return
142+
}
143+
let criteria = self.viewModel.criteria
144+
self.onFilterAction(criteria)
145+
}
127146
}
128147

129148
@objc func dismissButtonTapped() {
130-
viewModel.onDismissActionTapped()
149+
dismiss(animated: true) {}
131150
}
132151

133152
@objc func clearAllButtonTapped() {
@@ -224,20 +243,13 @@ private extension FilterListViewController {
224243

225244
func updateListSelectorNavigationTitle(numberOfActiveFilters: Int) {
226245
listSelectorCommand.navigationBarTitle = numberOfActiveFilters > 0 ?
227-
String.localizedStringWithFormat(Strings.navigationBarTitleFormatWithActiveFilters, numberOfActiveFilters):
228-
Strings.navigationBarTitleWithoutActiveFilters
246+
String.localizedStringWithFormat(navigationBarTitleFormatWithActiveFilters, numberOfActiveFilters):
247+
navigationBarTitleWithoutActiveFilters
229248
}
230249

231250
func updateClearAllActionVisibility(numberOfActiveFilters: Int) {
232251
listSelector.navigationItem.rightBarButtonItem = numberOfActiveFilters > 0 ? clearAllBarButtonItem: nil
233252
}
234-
235-
enum Strings {
236-
static let navigationBarTitleWithoutActiveFilters =
237-
NSLocalizedString("Filters", comment: "Navigation bar title format for filtering a list of products without filters applied.")
238-
static let navigationBarTitleFormatWithActiveFilters =
239-
NSLocalizedString("Filters (%ld)", comment: "Navigation bar title format for filtering a list of products with filters applied.")
240-
}
241253
}
242254

243255
private extension FilterListViewController {

WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import Yosemite
33

44
/// `FilterListViewModel` for filtering a list of products.
55
final class FilterProductListViewModel: FilterListViewModel {
6+
typealias Criteria = Filters
7+
68
/// Aggregates the filter values that can be updated in the Filter Products UI.
79
struct Filters {
810
let stockStatus: ProductStockStatus?
@@ -18,20 +20,9 @@ final class FilterProductListViewModel: FilterListViewModel {
1820
private let productStatusFilterViewModel: FilterTypeViewModel
1921
private let productTypeFilterViewModel: FilterTypeViewModel
2022

21-
/// Used to dismiss the Filter Products UI.
22-
private let sourceViewController: UIViewController
23-
24-
typealias FilterCompletion = (_ filters: Filters) -> Void
25-
private let onFilterCompletion: FilterCompletion
26-
2723
/// - Parameters:
28-
/// - sourceViewController: the view controller that presents the Filter Products UI, used to dismiss the screen upon user actions.
2924
/// - filters: the filters to be applied initially.
30-
/// - onFilterCompletion: called when the user taps the Filter CTA to apply the latest filters to the product list.
31-
init(sourceViewController: UIViewController, filters: Filters, onFilterCompletion: @escaping FilterCompletion) {
32-
self.sourceViewController = sourceViewController
33-
self.onFilterCompletion = onFilterCompletion
34-
25+
init(filters: Filters) {
3526
self.stockStatusFilterViewModel = ProductListFilter.stockStatus.createViewModel(filters: filters)
3627
self.productStatusFilterViewModel = ProductListFilter.productStatus.createViewModel(filters: filters)
3728
self.productTypeFilterViewModel = ProductListFilter.productType.createViewModel(filters: filters)
@@ -43,21 +34,11 @@ final class FilterProductListViewModel: FilterListViewModel {
4334
]
4435
}
4536

46-
func onFilterActionTapped() {
47-
sourceViewController.dismiss(animated: true) { [weak self] in
48-
guard let self = self else {
49-
return
50-
}
51-
let stockStatus = self.stockStatusFilterViewModel.selectedValue as? ProductStockStatus ?? nil
52-
let productStatus = self.productStatusFilterViewModel.selectedValue as? ProductStatus ?? nil
53-
let productType = self.productTypeFilterViewModel.selectedValue as? ProductType ?? nil
54-
let filters = Filters(stockStatus: stockStatus, productStatus: productStatus, productType: productType)
55-
self.onFilterCompletion(filters)
56-
}
57-
}
58-
59-
func onDismissActionTapped() {
60-
sourceViewController.dismiss(animated: true, completion: nil)
37+
var criteria: Filters {
38+
let stockStatus = stockStatusFilterViewModel.selectedValue as? ProductStockStatus ?? nil
39+
let productStatus = productStatusFilterViewModel.selectedValue as? ProductStatus ?? nil
40+
let productType = productTypeFilterViewModel.selectedValue as? ProductType ?? nil
41+
return Filters(stockStatus: stockStatus, productStatus: productStatus, productType: productType)
6142
}
6243

6344
func onClearAllActionTapped() {

WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,11 +458,11 @@ private extension ProductsViewController {
458458
}
459459

460460
@objc func filterButtonTapped() {
461-
let viewModel = FilterProductListViewModel(sourceViewController: self, filters: filters) { [weak self] filters in
461+
let viewModel = FilterProductListViewModel(filters: filters)
462+
let filterProductListViewController = FilterListViewController(viewModel: viewModel) { [weak self] filters in
462463
self?.filters = filters
463464
// TODO-2037: filter products based on the filters
464465
}
465-
let filterProductListViewController = FilterListViewController(viewModel: viewModel)
466466
present(filterProductListViewController, animated: true, completion: nil)
467467
}
468468
}

0 commit comments

Comments
 (0)