Implemented the items filtering by star rating for the FeedListViewController view controller and its view model in the Feed framework.
This commit is contained in:
parent
8d84f15b40
commit
e9590990ea
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ReviewsFilterKit
|
||||
import ReviewsiTunesKit
|
||||
|
||||
extension FeedListViewController {
|
||||
@ -21,10 +22,14 @@ extension FeedListViewController {
|
||||
// MARK: Properties
|
||||
@Published var filter: FilterOption = .all
|
||||
@Published var isFilterEnabled: Bool = false
|
||||
@Published var isFiltering: Bool = false
|
||||
@Published var isLoading: Bool = false
|
||||
|
||||
var items: [Review] = []
|
||||
|
||||
private var reviewsAll: [Review] = []
|
||||
private var reviewsFiltered: FilteredReviews = [:]
|
||||
|
||||
lazy private var iTunesService: iTunesService = {
|
||||
.init(configuration: .init(session: configuration.session))
|
||||
}()
|
||||
@ -46,19 +51,13 @@ extension FeedListViewController {
|
||||
countryCode: configuration.countryCode
|
||||
))
|
||||
|
||||
items = output.reviews
|
||||
.map { review -> Review in
|
||||
.init(
|
||||
author: review.author,
|
||||
comment: review.content,
|
||||
id: review.id,
|
||||
rating: .init(
|
||||
stars: review.rating,
|
||||
appVersion: review.version
|
||||
),
|
||||
title: review.title
|
||||
)
|
||||
reviewsAll = output.reviews.map(Review.init)
|
||||
reviewsFiltered = FilterOption.allCases
|
||||
.reduce(into: FilteredReviews()) { partialResult, option in
|
||||
partialResult[option] = reviewsAll.filter { $0.rating.stars == option.rawValue }
|
||||
}
|
||||
|
||||
items = reviewsAll
|
||||
isFilterEnabled = !items.isEmpty
|
||||
} catch {
|
||||
// TODO: handle this error gracefully.
|
||||
@ -68,6 +67,24 @@ extension FeedListViewController {
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
func filter(by option: FilterOption) {
|
||||
guard option != filter else { return }
|
||||
|
||||
items = option == .all
|
||||
? reviewsAll
|
||||
: reviewsFiltered[option] ?? []
|
||||
|
||||
filter = option
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
private extension FeedListViewController.ViewModel {
|
||||
|
||||
// MARK: Type aliases
|
||||
typealias FilteredReviews = [FilterOption: [Review]]
|
||||
|
||||
}
|
||||
|
@ -23,14 +23,7 @@ public class FeedListViewController: UITableViewController {
|
||||
|
||||
// MARK: Outlets
|
||||
private lazy var filterButton = {
|
||||
let allStars = UIAction(
|
||||
title: FilterOption.all.text,
|
||||
image: .init(systemName: FilterOption.all.icon)
|
||||
) { [weak self] _ in
|
||||
self?.viewModel.filter = .all
|
||||
}
|
||||
|
||||
return UIBarButtonItem(
|
||||
UIBarButtonItem(
|
||||
title: NSLocalizedString(
|
||||
.Key.Navigation.Button.filter,
|
||||
bundle: .module,
|
||||
@ -45,26 +38,19 @@ public class FeedListViewController: UITableViewController {
|
||||
comment: .empty
|
||||
),
|
||||
image: UIImage.Icon.star,
|
||||
children: [allStars, filterStarMenu]
|
||||
children: {
|
||||
FilterOption.allCases.map { option -> UIAction in
|
||||
.init(title: option.text,
|
||||
image: .init(systemName: option.icon)
|
||||
) { [weak self] _ in
|
||||
self?.viewModel.filter(by: option)
|
||||
}
|
||||
}
|
||||
}()
|
||||
)
|
||||
)
|
||||
}()
|
||||
|
||||
private lazy var filterStarMenu = {
|
||||
UIMenu(
|
||||
options: .displayInline,
|
||||
children: {
|
||||
FilterOption.allCases.map { option -> UIAction in
|
||||
.init(title: option.text,
|
||||
image: .init(systemName: option.icon)
|
||||
) { [weak self] _ in
|
||||
self?.viewModel.filter = option
|
||||
}
|
||||
}
|
||||
}()
|
||||
)
|
||||
}()
|
||||
|
||||
|
||||
// MARK: Initialisers
|
||||
public init(configuration: Configuration = .init()) {
|
||||
self.viewModel = .init(configuration: configuration)
|
||||
@ -145,6 +131,14 @@ private extension FeedListViewController {
|
||||
|
||||
// MARK: Functions
|
||||
func bindViewModel() {
|
||||
viewModel.$filter
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] option in
|
||||
self?.updateFilterMenu(option)
|
||||
self?.tableView.reloadData()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
viewModel.$isFilterEnabled
|
||||
.removeDuplicates()
|
||||
.receive(on: RunLoop.main)
|
||||
@ -180,6 +174,18 @@ private extension FeedListViewController {
|
||||
)
|
||||
}
|
||||
|
||||
func updateFilterMenu(_ option: FilterOption) {
|
||||
filterButton
|
||||
.menu?
|
||||
.children
|
||||
.compactMap { $0 as? UIAction }
|
||||
.forEach { action in
|
||||
action.state = action.title == option.text
|
||||
? .on
|
||||
: .off
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Configuration
|
||||
|
Loading…
x
Reference in New Issue
Block a user