[Framework] Feed List improvements (#19)

This PR contains the work done to improve the overall implementation of the `FeedListViewModel` view model in the `Feed` framework by utilising unit tests.

Reviewed-on: rock-n-code/app-reviews#19
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This commit was merged in pull request #19.
This commit is contained in:
2024-03-22 14:44:52 +00:00
committed by javier
parent 050e7e9620
commit c150b88ddc
6 changed files with 919 additions and 102 deletions
@@ -20,14 +20,14 @@ extension FeedListViewController {
private let topWords: TopWordsUseCase = .init()
// MARK: Properties
@Published var filter: FilterOption = .all
@Published var isFilterEnabled: Bool = false
@Published var isFiltering: Bool = false
@Published var isLoading: Bool = false
@Published var state: FeedListState = .initial
@Published private(set) var filter: FilterOption = .all
@Published private(set) var isFilterEnabled: Bool = false
@Published private(set) var isFiltering: Bool = false
@Published private(set) var isLoading: Bool = false
@Published private(set) var state: FeedListState = .initial
var items: [Review] = []
var words: [TopWord] = []
private(set) var items: [Review] = []
private(set) var words: [TopWord] = []
private var reviewsAll: [Review] = []
private var reviewsFiltered: FilteredReviews = [:]
@@ -57,50 +57,51 @@ extension FeedListViewController {
var isWordsShowing: Bool {
filter != .all
&& !words.isEmpty
&& !words.isEmpty
}
// MARK: Functions
func fetch() {
Task {
isFilterEnabled = false
isLoading = items.isEmpty
func fetch() async {
isFilterEnabled = false
isLoading = items.isEmpty
do {
let output = try await iTunesService.getReviews(.init(
appID: configuration.appID,
countryCode: configuration.countryCode
))
reviewsAll = output.reviews.map(Review.init)
reviewsFiltered = FilterOption.allCases
.reduce(into: FilteredReviews()) { partialResult, option in
partialResult[option] = reviewsAll.filter { $0.rating.stars == option.rawValue }
}
reviewsTopWords = reviewsFiltered
.mapValues { reviews in
reviews.map(\.comment)
.compactMap { try? filterWords($0) }
}
.mapValues {
topWords($0).map(TopWord.init)
}
do {
let output = try await iTunesService.getReviews(.init(
appID: configuration.appID,
countryCode: configuration.countryCode
))
reviewsAll = output.reviews.map(Review.init)
reviewsFiltered = FilterOption.allCases
.reduce(into: FilteredReviews()) { partialResult, option in
partialResult[option] = reviewsAll.filter { $0.rating.stars == option.rawValue }
}
reviewsTopWords = reviewsFiltered
.mapValues { reviews in
reviews.map(\.comment)
.compactMap { try? filterWords($0) }
}
.mapValues {
topWords($0).map(TopWord.init)
}
items = filter == .all
? reviewsAll
: reviewsFiltered[filter] ?? []
items = filter == .all
? reviewsAll
: reviewsFiltered[filter] ?? []
words = filter == .all
? []
: reviewsTopWords[filter] ?? []
isFilterEnabled = !items.isEmpty
state = items.isEmpty
? .empty
: .populated
} catch {
items = []
state = .error
}
isLoading = false
isFilterEnabled = !items.isEmpty
state = items.isEmpty
? .empty
: .populated
} catch {
items = []
state = .error
}
isLoading = false
}
func filter(by option: FilterOption) {
@@ -115,16 +116,19 @@ extension FeedListViewController {
}
func item(for index: Int) -> Review? {
guard
!items.isEmpty,
index < items.count
else {
guard !items.isEmpty else {
return nil
}
return isWordsShowing
? items[index - 1]
: items[index]
let indexToUse = isWordsShowing
? index - 1
: index
guard indexToUse < items.count else {
return nil
}
return items[indexToUse]
}
func openItem(at index: Int) {