[Framework] Show top words for filtered items in the Feed List (#12)
This PR contains the work done to show the top 3 words belonging to the filtered reviews in the `FeedListViewController` view controller. Reviewed-on: #12 Co-authored-by: Javier Cicchelli <javier@rock-n-code.com> Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This commit is contained in:
parent
eac34c61c1
commit
d00cfceb32
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// TopWord+DTOs.swift
|
||||||
|
// ReviewsFeed
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/03/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import ReviewsFilterKit
|
||||||
|
|
||||||
|
extension TopWord {
|
||||||
|
|
||||||
|
// MARK: Initialisers
|
||||||
|
init(_ dto: WordCount) {
|
||||||
|
self = .init(
|
||||||
|
id: UUID().uuidString,
|
||||||
|
term: dto.word.term,
|
||||||
|
count: dto.count
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
Frameworks/Feed/Bundle/Sources/Logic/Models/TopWord.swift
Normal file
16
Frameworks/Feed/Bundle/Sources/Logic/Models/TopWord.swift
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// TopWord.swift
|
||||||
|
// ReviewsFeed
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/03/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
struct TopWord: Identifiable {
|
||||||
|
|
||||||
|
// MARK: Constants
|
||||||
|
let id: String
|
||||||
|
let term: String
|
||||||
|
let count: Int
|
||||||
|
|
||||||
|
}
|
@ -18,6 +18,9 @@ extension FeedListViewController {
|
|||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
private let configuration: Configuration
|
private let configuration: Configuration
|
||||||
|
|
||||||
|
private let filterWords: FilterWordsUseCase = .init()
|
||||||
|
private let topWords: TopWordsUseCase = .init()
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
@Published var filter: FilterOption = .all
|
@Published var filter: FilterOption = .all
|
||||||
@ -26,9 +29,11 @@ extension FeedListViewController {
|
|||||||
@Published var isLoading: Bool = false
|
@Published var isLoading: Bool = false
|
||||||
|
|
||||||
var items: [Review] = []
|
var items: [Review] = []
|
||||||
|
var words: [TopWord] = []
|
||||||
|
|
||||||
private var reviewsAll: [Review] = []
|
private var reviewsAll: [Review] = []
|
||||||
private var reviewsFiltered: FilteredReviews = [:]
|
private var reviewsFiltered: FilteredReviews = [:]
|
||||||
|
private var reviewsTopWords: TopWordsReviews = [:]
|
||||||
|
|
||||||
lazy private var iTunesService: iTunesService = {
|
lazy private var iTunesService: iTunesService = {
|
||||||
.init(configuration: .init(session: configuration.session))
|
.init(configuration: .init(session: configuration.session))
|
||||||
@ -38,6 +43,18 @@ extension FeedListViewController {
|
|||||||
init(configuration: Configuration = .init()) {
|
init(configuration: Configuration = .init()) {
|
||||||
self.configuration = configuration
|
self.configuration = configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Computed
|
||||||
|
var itemsCount: Int {
|
||||||
|
isWordsShowing
|
||||||
|
? items.count
|
||||||
|
: items.count + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var isWordsShowing: Bool {
|
||||||
|
filter != .all
|
||||||
|
&& !words.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
func fetch() {
|
func fetch() {
|
||||||
@ -56,6 +73,14 @@ extension FeedListViewController {
|
|||||||
.reduce(into: FilteredReviews()) { partialResult, option in
|
.reduce(into: FilteredReviews()) { partialResult, option in
|
||||||
partialResult[option] = reviewsAll.filter { $0.rating.stars == option.rawValue }
|
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 = reviewsAll
|
items = reviewsAll
|
||||||
isFilterEnabled = !items.isEmpty
|
isFilterEnabled = !items.isEmpty
|
||||||
@ -74,9 +99,18 @@ extension FeedListViewController {
|
|||||||
items = option == .all
|
items = option == .all
|
||||||
? reviewsAll
|
? reviewsAll
|
||||||
: reviewsFiltered[option] ?? []
|
: reviewsFiltered[option] ?? []
|
||||||
|
words = reviewsTopWords[option] ?? []
|
||||||
|
|
||||||
filter = option
|
filter = option
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func item(for index: Int) -> Review? {
|
||||||
|
guard index < items.count else { return nil }
|
||||||
|
|
||||||
|
return isWordsShowing
|
||||||
|
? items[index - 1]
|
||||||
|
: items[index]
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,5 +120,6 @@ private extension FeedListViewController.ViewModel {
|
|||||||
|
|
||||||
// MARK: Type aliases
|
// MARK: Type aliases
|
||||||
typealias FilteredReviews = [FilterOption: [Review]]
|
typealias FilteredReviews = [FilterOption: [Review]]
|
||||||
|
typealias TopWordsReviews = [FilterOption: [TopWord]]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
17
Frameworks/Feed/Bundle/Sources/UI/Cells/FeedItemCell.swift
Normal file
17
Frameworks/Feed/Bundle/Sources/UI/Cells/FeedItemCell.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// FeedItemCell.swift
|
||||||
|
// ReviewsFeed
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/03/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReviewsUIKit
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
final class FeedItemCell: UITableViewCell, TableCell {
|
||||||
|
|
||||||
|
// MARK: Constants
|
||||||
|
static let cellID = "FeedItemCell"
|
||||||
|
|
||||||
|
}
|
17
Frameworks/Feed/Bundle/Sources/UI/Cells/TopWordsCell.swift
Normal file
17
Frameworks/Feed/Bundle/Sources/UI/Cells/TopWordsCell.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// TopWordsCell.swift
|
||||||
|
// ReviewsFeed
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/03/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReviewsUIKit
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
final class TopWordsCell: UITableViewCell, TableCell {
|
||||||
|
|
||||||
|
// MARK: Constants
|
||||||
|
static let cellID = "TopWordsCell"
|
||||||
|
|
||||||
|
}
|
@ -40,11 +40,12 @@ public class FeedListViewController: UITableViewController {
|
|||||||
image: UIImage.Icon.star,
|
image: UIImage.Icon.star,
|
||||||
children: {
|
children: {
|
||||||
FilterOption.allCases.map { option -> UIAction in
|
FilterOption.allCases.map { option -> UIAction in
|
||||||
.init(title: option.text,
|
.init(
|
||||||
image: .init(systemName: option.icon)
|
title: option.text,
|
||||||
) { [weak self] _ in
|
image: .init(systemName: option.icon)
|
||||||
self?.viewModel.filter(by: option)
|
) { [weak self] _ in
|
||||||
}
|
self?.viewModel.filter(by: option)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
)
|
)
|
||||||
@ -83,30 +84,18 @@ public class FeedListViewController: UITableViewController {
|
|||||||
_ tableView: UITableView,
|
_ tableView: UITableView,
|
||||||
numberOfRowsInSection section: Int
|
numberOfRowsInSection section: Int
|
||||||
) -> Int {
|
) -> Int {
|
||||||
viewModel.items.count
|
viewModel.itemsCount
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func tableView(
|
public override func tableView(
|
||||||
_ tableView: UITableView,
|
_ tableView: UITableView,
|
||||||
cellForRowAt indexPath: IndexPath
|
cellForRowAt indexPath: IndexPath
|
||||||
) -> UITableViewCell {
|
) -> UITableViewCell {
|
||||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: .Cell.feedItem) else {
|
if viewModel.isWordsShowing && indexPath.row == 0 {
|
||||||
return .init()
|
makeTopWordsCell(tableView)
|
||||||
|
} else {
|
||||||
|
makeFeedItemCell(tableView, at: indexPath.row)
|
||||||
}
|
}
|
||||||
|
|
||||||
cell.contentConfiguration = {
|
|
||||||
if #available(iOS 16.0, *) {
|
|
||||||
UIHostingConfiguration {
|
|
||||||
FeedItemCell(items[indexPath.row])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
HostingConfiguration {
|
|
||||||
FeedItemCell(items[indexPath.row])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return cell
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: UITableViewDelegate
|
// MARK: UITableViewDelegate
|
||||||
@ -158,8 +147,57 @@ private extension FeedListViewController {
|
|||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeFeedItemCell(
|
||||||
|
_ tableView: UITableView,
|
||||||
|
at row: Int
|
||||||
|
) -> UITableViewCell {
|
||||||
|
guard
|
||||||
|
let cell = FeedItemCell.dequeue(from: tableView),
|
||||||
|
let item = viewModel.item(for: row)
|
||||||
|
else {
|
||||||
|
return .init()
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.separatorInset = .init(width: tableView.bounds.size.width)
|
||||||
|
cell.contentConfiguration = {
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
UIHostingConfiguration {
|
||||||
|
FeedItemView(item)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HostingConfiguration {
|
||||||
|
FeedItemView(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeTopWordsCell(_ tableView: UITableView) -> UITableViewCell {
|
||||||
|
guard let cell = TopWordsCell.dequeue(from: tableView) else {
|
||||||
|
return .init()
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.separatorInset = .init(width: tableView.bounds.size.width)
|
||||||
|
cell.contentConfiguration = {
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
UIHostingConfiguration {
|
||||||
|
TopWordsView(viewModel.words)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HostingConfiguration {
|
||||||
|
TopWordsView(viewModel.words)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
func registerTableCells() {
|
func registerTableCells() {
|
||||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: .Cell.feedItem)
|
FeedItemCell.register(in: tableView)
|
||||||
|
TopWordsCell.register(in: tableView)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setNavigationBar() {
|
func setNavigationBar() {
|
||||||
@ -232,6 +270,21 @@ private extension String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - UIEdgeInsets+Inits
|
||||||
|
private extension UIEdgeInsets {
|
||||||
|
|
||||||
|
// MARK: Initialisers
|
||||||
|
init(width: CGFloat) {
|
||||||
|
self = .init(
|
||||||
|
top: 0,
|
||||||
|
left: width,
|
||||||
|
bottom: 0,
|
||||||
|
right: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Previews
|
// MARK: - Previews
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
import ReviewsiTunesKit
|
import ReviewsiTunesKit
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// FeedItemCell.swift
|
// FeedItemView.swift
|
||||||
// ReviewsFeed
|
// ReviewsFeed
|
||||||
//
|
//
|
||||||
// Created by Javier Cicchelli on 19/03/2024.
|
// Created by Javier Cicchelli on 19/03/2024.
|
||||||
@ -9,7 +9,7 @@
|
|||||||
import ReviewsUIKit
|
import ReviewsUIKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct FeedItemCell: View {
|
struct FeedItemView: View {
|
||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
private let item: Review
|
private let item: Review
|
||||||
@ -66,8 +66,8 @@ struct FeedItemCell: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Previews
|
// MARK: - Previews
|
||||||
#Preview("Feed Item Cell") {
|
#Preview("Feed Item") {
|
||||||
FeedItemCell(.init(
|
FeedItemView(.init(
|
||||||
author: "Some author name here...",
|
author: "Some author name here...",
|
||||||
comment: "Some review comment here...",
|
comment: "Some review comment here...",
|
||||||
id: 0,
|
id: 0,
|
82
Frameworks/Feed/Bundle/Sources/UI/Views/TopWordsView.swift
Normal file
82
Frameworks/Feed/Bundle/Sources/UI/Views/TopWordsView.swift
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
//
|
||||||
|
// TopWordsView.swift
|
||||||
|
// ReviewsFeed
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/03/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct TopWordsView: View {
|
||||||
|
|
||||||
|
// MARK: Constants
|
||||||
|
private let topWords: [TopWord]
|
||||||
|
|
||||||
|
// MARK: Initialisers
|
||||||
|
init(_ topWords: [TopWord]) {
|
||||||
|
self.topWords = topWords
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Body
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
HStack(spacing: 12) {
|
||||||
|
ForEach(topWords) { topWord in
|
||||||
|
Item(
|
||||||
|
term: topWord.term,
|
||||||
|
count: String(topWord.count)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Structs
|
||||||
|
private extension TopWordsView {
|
||||||
|
struct Item: View {
|
||||||
|
|
||||||
|
// MARK: Constants
|
||||||
|
let term: String
|
||||||
|
let count: String
|
||||||
|
|
||||||
|
// MARK: Body
|
||||||
|
var body: some View {
|
||||||
|
HStack(
|
||||||
|
alignment: .center,
|
||||||
|
spacing: 6
|
||||||
|
) {
|
||||||
|
Text(count)
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundColor(.primary.opacity(0.75))
|
||||||
|
|
||||||
|
Text(term)
|
||||||
|
.lineLimit(1)
|
||||||
|
.font(.body.bold())
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
.padding(.vertical, 6)
|
||||||
|
.background(Color.secondary.opacity(0.75))
|
||||||
|
.cornerRadius(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
#Preview {
|
||||||
|
TopWordsView([
|
||||||
|
.init(id: "1", term: "Something", count: 3),
|
||||||
|
.init(id: "2", term: "Something", count: 2),
|
||||||
|
.init(id: "3", term: "Something", count: 1),
|
||||||
|
])
|
||||||
|
.padding(.horizontal)
|
||||||
|
}
|
33
Libraries/UI/Kit/Sources/Protocols/TableCell.swift
Normal file
33
Libraries/UI/Kit/Sources/Protocols/TableCell.swift
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// TableCell.swift
|
||||||
|
// ReviewsUIKit
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/03/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde VoF. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
public protocol TableCell: UITableViewCell {
|
||||||
|
|
||||||
|
// MARK: Properties
|
||||||
|
static var cellID: String { get }
|
||||||
|
|
||||||
|
// MARK: Functions
|
||||||
|
static func dequeue(from tableView: UITableView) -> UITableViewCell?
|
||||||
|
static func register(in tableView: UITableView)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Implementations
|
||||||
|
extension TableCell {
|
||||||
|
|
||||||
|
public static func dequeue(from tableView: UITableView) -> UITableViewCell? {
|
||||||
|
tableView.dequeueReusableCell(withIdentifier: cellID)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func register(in tableView: UITableView) {
|
||||||
|
tableView.register(Self.self, forCellReuseIdentifier: cellID)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,7 +7,7 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
0220ADA32BA90646001E6A9F /* FeedItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0220ADA22BA90646001E6A9F /* FeedItemCell.swift */; };
|
0220ADA32BA90646001E6A9F /* FeedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0220ADA22BA90646001E6A9F /* FeedItemView.swift */; };
|
||||||
023AC7FC2BAA3EC10027D064 /* Int+Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023AC7FB2BAA3EC10027D064 /* Int+Constants.swift */; };
|
023AC7FC2BAA3EC10027D064 /* Int+Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023AC7FB2BAA3EC10027D064 /* Int+Constants.swift */; };
|
||||||
02620B8C2BA89C9A00DE7137 /* FeedListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02620B8B2BA89C9A00DE7137 /* FeedListViewModel.swift */; };
|
02620B8C2BA89C9A00DE7137 /* FeedListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02620B8B2BA89C9A00DE7137 /* FeedListViewModel.swift */; };
|
||||||
02909E792BAB6B0200710E14 /* FilterOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02909E782BAB6B0200710E14 /* FilterOption.swift */; };
|
02909E792BAB6B0200710E14 /* FilterOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02909E782BAB6B0200710E14 /* FilterOption.swift */; };
|
||||||
@ -22,6 +22,11 @@
|
|||||||
02DC7FAF2BA51B4C000EEEBE /* Review.swift in Sources */ = {isa = PBXBuildFile; fileRef = 345AD13124C6EE64004E2EE1 /* Review.swift */; };
|
02DC7FAF2BA51B4C000EEEBE /* Review.swift in Sources */ = {isa = PBXBuildFile; fileRef = 345AD13124C6EE64004E2EE1 /* Review.swift */; };
|
||||||
02DC7FB32BA52518000EEEBE /* ReviewsKit in Frameworks */ = {isa = PBXBuildFile; productRef = 02DC7FB22BA52518000EEEBE /* ReviewsKit */; };
|
02DC7FB32BA52518000EEEBE /* ReviewsKit in Frameworks */ = {isa = PBXBuildFile; productRef = 02DC7FB22BA52518000EEEBE /* ReviewsKit */; };
|
||||||
02DC7FB52BA52520000EEEBE /* ReviewsKit in Frameworks */ = {isa = PBXBuildFile; productRef = 02DC7FB42BA52520000EEEBE /* ReviewsKit */; };
|
02DC7FB52BA52520000EEEBE /* ReviewsKit in Frameworks */ = {isa = PBXBuildFile; productRef = 02DC7FB42BA52520000EEEBE /* ReviewsKit */; };
|
||||||
|
02EACF2E2BABA34600FF8ECD /* FeedItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02EACF2D2BABA34600FF8ECD /* FeedItemCell.swift */; };
|
||||||
|
02EACF302BABA50D00FF8ECD /* TopWordsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02EACF2F2BABA50D00FF8ECD /* TopWordsCell.swift */; };
|
||||||
|
02EACF322BABB23A00FF8ECD /* TopWordsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02EACF312BABB23A00FF8ECD /* TopWordsView.swift */; };
|
||||||
|
02EACF342BABB28900FF8ECD /* TopWord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02EACF332BABB28900FF8ECD /* TopWord.swift */; };
|
||||||
|
02EACF362BABB2F200FF8ECD /* TopWord+DTOs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02EACF352BABB2F200FF8ECD /* TopWord+DTOs.swift */; };
|
||||||
345AD11C24C6EDD9004E2EE1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 345AD11B24C6EDD9004E2EE1 /* AppDelegate.swift */; };
|
345AD11C24C6EDD9004E2EE1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 345AD11B24C6EDD9004E2EE1 /* AppDelegate.swift */; };
|
||||||
345AD12524C6EDDC004E2EE1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 345AD12424C6EDDC004E2EE1 /* Assets.xcassets */; };
|
345AD12524C6EDDC004E2EE1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 345AD12424C6EDDC004E2EE1 /* Assets.xcassets */; };
|
||||||
345AD12824C6EDDC004E2EE1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 345AD12624C6EDDC004E2EE1 /* LaunchScreen.storyboard */; };
|
345AD12824C6EDDC004E2EE1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 345AD12624C6EDDC004E2EE1 /* LaunchScreen.storyboard */; };
|
||||||
@ -52,7 +57,7 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
0220ADA22BA90646001E6A9F /* FeedItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedItemCell.swift; sourceTree = "<group>"; };
|
0220ADA22BA90646001E6A9F /* FeedItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedItemView.swift; sourceTree = "<group>"; };
|
||||||
023AC7FB2BAA3EC10027D064 /* Int+Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Int+Constants.swift"; sourceTree = "<group>"; };
|
023AC7FB2BAA3EC10027D064 /* Int+Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Int+Constants.swift"; sourceTree = "<group>"; };
|
||||||
02620B8B2BA89C9A00DE7137 /* FeedListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListViewModel.swift; sourceTree = "<group>"; };
|
02620B8B2BA89C9A00DE7137 /* FeedListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListViewModel.swift; sourceTree = "<group>"; };
|
||||||
02909E782BAB6B0200710E14 /* FilterOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterOption.swift; sourceTree = "<group>"; };
|
02909E782BAB6B0200710E14 /* FilterOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterOption.swift; sourceTree = "<group>"; };
|
||||||
@ -62,6 +67,11 @@
|
|||||||
02DC7F8F2BA51793000EEEBE /* ReviewsFeed.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReviewsFeed.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
02DC7F8F2BA51793000EEEBE /* ReviewsFeed.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReviewsFeed.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
02DC7F912BA51793000EEEBE /* ReviewsFeed.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReviewsFeed.h; sourceTree = "<group>"; };
|
02DC7F912BA51793000EEEBE /* ReviewsFeed.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReviewsFeed.h; sourceTree = "<group>"; };
|
||||||
02DC7FB12BA52084000EEEBE /* Libraries */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Libraries; sourceTree = "<group>"; };
|
02DC7FB12BA52084000EEEBE /* Libraries */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Libraries; sourceTree = "<group>"; };
|
||||||
|
02EACF2D2BABA34600FF8ECD /* FeedItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedItemCell.swift; sourceTree = "<group>"; };
|
||||||
|
02EACF2F2BABA50D00FF8ECD /* TopWordsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopWordsCell.swift; sourceTree = "<group>"; };
|
||||||
|
02EACF312BABB23A00FF8ECD /* TopWordsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopWordsView.swift; sourceTree = "<group>"; };
|
||||||
|
02EACF332BABB28900FF8ECD /* TopWord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopWord.swift; sourceTree = "<group>"; };
|
||||||
|
02EACF352BABB2F200FF8ECD /* TopWord+DTOs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TopWord+DTOs.swift"; sourceTree = "<group>"; };
|
||||||
345AD11824C6EDD9004E2EE1 /* Reviews.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Reviews.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
345AD11824C6EDD9004E2EE1 /* Reviews.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Reviews.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
345AD11B24C6EDD9004E2EE1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
345AD11B24C6EDD9004E2EE1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
345AD12424C6EDDC004E2EE1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
345AD12424C6EDDC004E2EE1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
@ -93,20 +103,13 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
0220ADA72BA98F8B001E6A9F /* Cells */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
0220ADA22BA90646001E6A9F /* FeedItemCell.swift */,
|
|
||||||
);
|
|
||||||
path = Cells;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
023AC7FA2BAA3EB60027D064 /* Extensions */ = {
|
023AC7FA2BAA3EB60027D064 /* Extensions */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
02909E7A2BAB6D2E00710E14 /* Bundle+Constants.swift */,
|
02909E7A2BAB6D2E00710E14 /* Bundle+Constants.swift */,
|
||||||
023AC7FB2BAA3EC10027D064 /* Int+Constants.swift */,
|
023AC7FB2BAA3EC10027D064 /* Int+Constants.swift */,
|
||||||
02909E7C2BAB7FFE00710E14 /* Review+DTOs.swift */,
|
02909E7C2BAB7FFE00710E14 /* Review+DTOs.swift */,
|
||||||
|
02EACF352BABB2F200FF8ECD /* TopWord+DTOs.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -114,7 +117,8 @@
|
|||||||
02620B852BA89BF900DE7137 /* UI */ = {
|
02620B852BA89BF900DE7137 /* UI */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
02620B892BA89C2400DE7137 /* Components */,
|
02EACF2C2BABA32A00FF8ECD /* Cells */,
|
||||||
|
02620B892BA89C2400DE7137 /* Views */,
|
||||||
02620B882BA89C1000DE7137 /* View Controllers */,
|
02620B882BA89C1000DE7137 /* View Controllers */,
|
||||||
);
|
);
|
||||||
path = UI;
|
path = UI;
|
||||||
@ -148,18 +152,20 @@
|
|||||||
path = "View Controllers";
|
path = "View Controllers";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
02620B892BA89C2400DE7137 /* Components */ = {
|
02620B892BA89C2400DE7137 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
0220ADA72BA98F8B001E6A9F /* Cells */,
|
0220ADA22BA90646001E6A9F /* FeedItemView.swift */,
|
||||||
|
02EACF312BABB23A00FF8ECD /* TopWordsView.swift */,
|
||||||
);
|
);
|
||||||
path = Components;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
02620B8A2BA89C3300DE7137 /* Models */ = {
|
02620B8A2BA89C3300DE7137 /* Models */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
345AD13124C6EE64004E2EE1 /* Review.swift */,
|
345AD13124C6EE64004E2EE1 /* Review.swift */,
|
||||||
|
02EACF332BABB28900FF8ECD /* TopWord.swift */,
|
||||||
);
|
);
|
||||||
path = Models;
|
path = Models;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -273,6 +279,15 @@
|
|||||||
path = Sources;
|
path = Sources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
02EACF2C2BABA32A00FF8ECD /* Cells */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
02EACF2D2BABA34600FF8ECD /* FeedItemCell.swift */,
|
||||||
|
02EACF2F2BABA50D00FF8ECD /* TopWordsCell.swift */,
|
||||||
|
);
|
||||||
|
path = Cells;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
345AD10F24C6EDD9004E2EE1 = {
|
345AD10F24C6EDD9004E2EE1 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -421,14 +436,19 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
02EACF302BABA50D00FF8ECD /* TopWordsCell.swift in Sources */,
|
||||||
02620B8C2BA89C9A00DE7137 /* FeedListViewModel.swift in Sources */,
|
02620B8C2BA89C9A00DE7137 /* FeedListViewModel.swift in Sources */,
|
||||||
|
02EACF342BABB28900FF8ECD /* TopWord.swift in Sources */,
|
||||||
023AC7FC2BAA3EC10027D064 /* Int+Constants.swift in Sources */,
|
023AC7FC2BAA3EC10027D064 /* Int+Constants.swift in Sources */,
|
||||||
02DC7FAC2BA51B4C000EEEBE /* FeedItemViewController.swift in Sources */,
|
02DC7FAC2BA51B4C000EEEBE /* FeedItemViewController.swift in Sources */,
|
||||||
02909E7B2BAB6D2E00710E14 /* Bundle+Constants.swift in Sources */,
|
02909E7B2BAB6D2E00710E14 /* Bundle+Constants.swift in Sources */,
|
||||||
|
02EACF2E2BABA34600FF8ECD /* FeedItemCell.swift in Sources */,
|
||||||
02909E7D2BAB7FFE00710E14 /* Review+DTOs.swift in Sources */,
|
02909E7D2BAB7FFE00710E14 /* Review+DTOs.swift in Sources */,
|
||||||
0220ADA32BA90646001E6A9F /* FeedItemCell.swift in Sources */,
|
0220ADA32BA90646001E6A9F /* FeedItemView.swift in Sources */,
|
||||||
|
02EACF362BABB2F200FF8ECD /* TopWord+DTOs.swift in Sources */,
|
||||||
02DC7FAF2BA51B4C000EEEBE /* Review.swift in Sources */,
|
02DC7FAF2BA51B4C000EEEBE /* Review.swift in Sources */,
|
||||||
02DC7FAE2BA51B4C000EEEBE /* FeedListViewController.swift in Sources */,
|
02DC7FAE2BA51B4C000EEEBE /* FeedListViewController.swift in Sources */,
|
||||||
|
02EACF322BABB23A00FF8ECD /* TopWordsView.swift in Sources */,
|
||||||
02909E792BAB6B0200710E14 /* FilterOption.swift in Sources */,
|
02909E792BAB6B0200710E14 /* FilterOption.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user