[Framework] Feed Item coordinator (#17)
This PR contains the work done to implement the `FeedItemCoordinator` coordinator in the `Feed` framework. Reviewed-on: #17 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
9a5c385903
commit
d19c1c15d1
@ -37,6 +37,7 @@ extension AppDelegate: UIApplicationDelegate {
|
|||||||
coordinator.present(animated: false)
|
coordinator.present(animated: false)
|
||||||
coordinator.present(
|
coordinator.present(
|
||||||
child: FeedListCoordinator(
|
child: FeedListCoordinator(
|
||||||
|
configuration: .init(session: .ephemeral),
|
||||||
router: StackRouter(coordinator.navigationController)
|
router: StackRouter(coordinator.navigationController)
|
||||||
),
|
),
|
||||||
animated: false
|
animated: false
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// FeedListCoordination.swift
|
||||||
|
// ReviewsFeed
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/03/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
protocol FeedListCoordination: AnyObject {
|
||||||
|
|
||||||
|
// MARK: Functions
|
||||||
|
func open(_ item: Review)
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// FeedItemCoordinator.swift
|
||||||
|
// ReviewsFeed
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/03/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import ReviewsCoordinationKit
|
||||||
|
|
||||||
|
public final class FeedItemCoordinator: Coordinator {
|
||||||
|
|
||||||
|
// MARK: Constants
|
||||||
|
public let router: any Router
|
||||||
|
|
||||||
|
private let item: Review
|
||||||
|
|
||||||
|
// MARK: Properties
|
||||||
|
public var children: [any Coordinator] = []
|
||||||
|
|
||||||
|
public init(
|
||||||
|
item: Review,
|
||||||
|
router: any Router
|
||||||
|
) {
|
||||||
|
self.item = item
|
||||||
|
self.router = router
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Functions
|
||||||
|
public func present(
|
||||||
|
animated: Bool,
|
||||||
|
onDismiss: Router.OnDismissClosure? = nil
|
||||||
|
) {
|
||||||
|
router.present(
|
||||||
|
FeedItemViewController(item),
|
||||||
|
animated: animated,
|
||||||
|
onDismiss: onDismiss
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -10,22 +10,29 @@ import Foundation
|
|||||||
import ReviewsCoordinationKit
|
import ReviewsCoordinationKit
|
||||||
|
|
||||||
public final class FeedListCoordinator: Coordinator {
|
public final class FeedListCoordinator: Coordinator {
|
||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
public let router: any Router
|
public let router: any Router
|
||||||
|
|
||||||
private let sessionConfiguration: URLSessionConfiguration
|
private let configuration: FeedListConfiguration
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
public var children: [any Coordinator] = []
|
public var children: [any Coordinator] = []
|
||||||
|
|
||||||
|
lazy var viewController = {
|
||||||
|
FeedListViewController(.init(
|
||||||
|
configuration: configuration,
|
||||||
|
coordination: self
|
||||||
|
))
|
||||||
|
}()
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initialisers
|
||||||
public init(
|
public init(
|
||||||
router: any Router,
|
configuration: FeedListConfiguration,
|
||||||
sessionConfiguration: URLSessionConfiguration = .ephemeral
|
router: any Router
|
||||||
) {
|
) {
|
||||||
|
self.configuration = configuration
|
||||||
self.router = router
|
self.router = router
|
||||||
self.sessionConfiguration = sessionConfiguration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
@ -34,12 +41,26 @@ public final class FeedListCoordinator: Coordinator {
|
|||||||
onDismiss: Router.OnDismissClosure? = nil
|
onDismiss: Router.OnDismissClosure? = nil
|
||||||
) {
|
) {
|
||||||
router.present(
|
router.present(
|
||||||
FeedListViewController(configuration: .init(
|
viewController,
|
||||||
session: sessionConfiguration
|
|
||||||
)),
|
|
||||||
animated: animated,
|
animated: animated,
|
||||||
onDismiss: onDismiss
|
onDismiss: onDismiss
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - FeedListCoordination
|
||||||
|
extension FeedListCoordinator: FeedListCoordination {
|
||||||
|
|
||||||
|
// MARK: Functions
|
||||||
|
func open(_ item: Review) {
|
||||||
|
present(
|
||||||
|
child: FeedItemCoordinator(
|
||||||
|
item: item,
|
||||||
|
router: SheetRouter(parentViewController: viewController)
|
||||||
|
),
|
||||||
|
animated: true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct Review {
|
public struct Review {
|
||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
let author: String
|
let author: String
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// FeedListConfiguration.swift
|
||||||
|
// ReviewsFeed
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/03/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public struct FeedListConfiguration {
|
||||||
|
|
||||||
|
// MARK: Constants
|
||||||
|
let appID: String
|
||||||
|
let countryCode: String
|
||||||
|
let session: URLSessionConfiguration
|
||||||
|
|
||||||
|
// MARK: Initialisers
|
||||||
|
public init(
|
||||||
|
appID: String = "474495017",
|
||||||
|
countryCode: String = "nl",
|
||||||
|
session: URLSessionConfiguration = .ephemeral
|
||||||
|
) {
|
||||||
|
self.appID = appID
|
||||||
|
self.countryCode = countryCode
|
||||||
|
self.session = session
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -13,11 +13,8 @@ import ReviewsiTunesKit
|
|||||||
extension FeedListViewController {
|
extension FeedListViewController {
|
||||||
final class ViewModel: ObservableObject {
|
final class ViewModel: ObservableObject {
|
||||||
|
|
||||||
// MARK: Type aliases
|
|
||||||
typealias Configuration = FeedListViewController.Configuration
|
|
||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
private let configuration: Configuration
|
private let configuration: FeedListConfiguration
|
||||||
|
|
||||||
private let filterWords: FilterWordsUseCase = .init()
|
private let filterWords: FilterWordsUseCase = .init()
|
||||||
private let topWords: TopWordsUseCase = .init()
|
private let topWords: TopWordsUseCase = .init()
|
||||||
@ -30,18 +27,24 @@ extension FeedListViewController {
|
|||||||
|
|
||||||
var items: [Review] = []
|
var items: [Review] = []
|
||||||
var words: [TopWord] = []
|
var words: [TopWord] = []
|
||||||
|
|
||||||
private var reviewsAll: [Review] = []
|
private var reviewsAll: [Review] = []
|
||||||
private var reviewsFiltered: FilteredReviews = [:]
|
private var reviewsFiltered: FilteredReviews = [:]
|
||||||
private var reviewsTopWords: TopWordsReviews = [:]
|
private var reviewsTopWords: TopWordsReviews = [:]
|
||||||
|
|
||||||
|
private weak var coordination: FeedListCoordination?
|
||||||
|
|
||||||
lazy private var iTunesService: iTunesService = {
|
lazy private var iTunesService: iTunesService = {
|
||||||
.init(configuration: .init(session: configuration.session))
|
.init(configuration: .init(session: configuration.session))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initialisers
|
||||||
init(configuration: Configuration = .init()) {
|
init(
|
||||||
|
configuration: FeedListConfiguration = .init(),
|
||||||
|
coordination: FeedListCoordination? = nil
|
||||||
|
) {
|
||||||
self.configuration = configuration
|
self.configuration = configuration
|
||||||
|
self.coordination = coordination
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Computed
|
// MARK: Computed
|
||||||
@ -114,6 +117,12 @@ extension FeedListViewController {
|
|||||||
? items[index - 1]
|
? items[index - 1]
|
||||||
: items[index]
|
: items[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func openItem(at index: Int) {
|
||||||
|
guard let item = item(for: index) else { return }
|
||||||
|
|
||||||
|
coordination?.open(item)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import ReviewsUIKit
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
public class FeedListViewController: UITableViewController {
|
final class FeedListViewController: UITableViewController {
|
||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
private let viewModel: ViewModel
|
private let viewModel: ViewModel
|
||||||
@ -79,8 +79,8 @@ public class FeedListViewController: UITableViewController {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initialisers
|
||||||
public init(configuration: Configuration = .init()) {
|
init(_ viewModel: ViewModel) {
|
||||||
self.viewModel = .init(configuration: configuration)
|
self.viewModel = viewModel
|
||||||
|
|
||||||
super.init(style: .plain)
|
super.init(style: .plain)
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ public class FeedListViewController: UITableViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: UIViewController
|
// MARK: UIViewController
|
||||||
public override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
setNavigationBar()
|
setNavigationBar()
|
||||||
@ -108,14 +108,14 @@ public class FeedListViewController: UITableViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: UITableViewDataSource
|
// MARK: UITableViewDataSource
|
||||||
public override func tableView(
|
override func tableView(
|
||||||
_ tableView: UITableView,
|
_ tableView: UITableView,
|
||||||
numberOfRowsInSection section: Int
|
numberOfRowsInSection section: Int
|
||||||
) -> Int {
|
) -> Int {
|
||||||
viewModel.itemsCount
|
viewModel.itemsCount
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func tableView(
|
override func tableView(
|
||||||
_ tableView: UITableView,
|
_ tableView: UITableView,
|
||||||
cellForRowAt indexPath: IndexPath
|
cellForRowAt indexPath: IndexPath
|
||||||
) -> UITableViewCell {
|
) -> UITableViewCell {
|
||||||
@ -127,21 +127,16 @@ public class FeedListViewController: UITableViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: UITableViewDelegate
|
// MARK: UITableViewDelegate
|
||||||
public override func tableView(
|
override func tableView(
|
||||||
_ tableView: UITableView,
|
_ tableView: UITableView,
|
||||||
didSelectRowAt indexPath: IndexPath
|
didSelectRowAt indexPath: IndexPath
|
||||||
) {
|
) {
|
||||||
guard let item = viewModel.item(for: indexPath.row) else { return }
|
viewModel.openItem(at: indexPath.row)
|
||||||
|
|
||||||
tableView.deselectRow(
|
tableView.deselectRow(
|
||||||
at: indexPath,
|
at: indexPath,
|
||||||
animated: true
|
animated: true
|
||||||
)
|
)
|
||||||
|
|
||||||
navigationController?.pushViewController(
|
|
||||||
FeedItemViewController(item),
|
|
||||||
animated: true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -292,29 +287,6 @@ private extension FeedListViewController {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Configuration
|
|
||||||
extension FeedListViewController {
|
|
||||||
public struct Configuration {
|
|
||||||
|
|
||||||
// MARK: Constants
|
|
||||||
let appID: String
|
|
||||||
let countryCode: String
|
|
||||||
let session: URLSessionConfiguration
|
|
||||||
|
|
||||||
// MARK: Initialisers
|
|
||||||
public init(
|
|
||||||
appID: String = "474495017",
|
|
||||||
countryCode: String = "nl",
|
|
||||||
session: URLSessionConfiguration = .ephemeral
|
|
||||||
) {
|
|
||||||
self.appID = appID
|
|
||||||
self.countryCode = countryCode
|
|
||||||
self.session = session
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - String+Constants
|
// MARK: - String+Constants
|
||||||
private extension String {
|
private extension String {
|
||||||
enum Cell {
|
enum Cell {
|
||||||
@ -363,9 +335,9 @@ import ReviewsiTunesKit
|
|||||||
#Preview("Feed List loading reviews") {
|
#Preview("Feed List loading reviews") {
|
||||||
MockURLProtocol.response = .init(statusCode: 200)
|
MockURLProtocol.response = .init(statusCode: 200)
|
||||||
|
|
||||||
return UINavigationController(
|
return UINavigationController(rootViewController: FeedListViewController(.init(
|
||||||
rootViewController: FeedListViewController(configuration: .init(session: .mock))
|
configuration: .init(session: .mock)
|
||||||
)
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 17.0, *)
|
@available(iOS 17.0, *)
|
||||||
@ -421,9 +393,9 @@ import ReviewsiTunesKit
|
|||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
|
||||||
return UINavigationController(
|
return UINavigationController(rootViewController: FeedListViewController(.init(
|
||||||
rootViewController: FeedListViewController(configuration: .init(session: .mock))
|
configuration: .init(session: .mock)
|
||||||
)
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 17.0, *)
|
@available(iOS 17.0, *)
|
||||||
@ -433,13 +405,13 @@ import ReviewsiTunesKit
|
|||||||
object: Feed(entries: [])
|
object: Feed(entries: [])
|
||||||
)
|
)
|
||||||
|
|
||||||
return UINavigationController(
|
return UINavigationController(rootViewController: FeedListViewController(.init(
|
||||||
rootViewController: FeedListViewController(configuration: .init(session: .mock))
|
configuration: .init(session: .mock)
|
||||||
)
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 17.0, *)
|
@available(iOS 17.0, *)
|
||||||
#Preview("Feed List with live reviews") {
|
#Preview("Feed List with live reviews") {
|
||||||
UINavigationController(rootViewController: FeedListViewController())
|
return UINavigationController(rootViewController: FeedListViewController(.init()))
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
103
Libraries/Coordination/Kit/Sources/Routers/SheetRouter.swift
Normal file
103
Libraries/Coordination/Kit/Sources/Routers/SheetRouter.swift
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
//
|
||||||
|
// SheetRouter.swift
|
||||||
|
// ReviewsCoordinationKit
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/03/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReviewsUIKit
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
public class SheetRouter: BaseNavigationRouter {
|
||||||
|
|
||||||
|
// MARK: Properties
|
||||||
|
public unowned let parentViewController: UIViewController
|
||||||
|
|
||||||
|
// MARK: Initialisers
|
||||||
|
public init(parentViewController: UIViewController) {
|
||||||
|
self.parentViewController = parentViewController
|
||||||
|
|
||||||
|
super.init(navigationController: .init())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Router
|
||||||
|
extension SheetRouter: Router {
|
||||||
|
|
||||||
|
// MARK: Functions
|
||||||
|
public func present(
|
||||||
|
_ viewController: UIViewController,
|
||||||
|
animated: Bool,
|
||||||
|
onDismiss: Router.OnDismissClosure?
|
||||||
|
) {
|
||||||
|
onDismissForViewController[viewController] = onDismiss
|
||||||
|
|
||||||
|
if navigationController.viewControllers.isEmpty {
|
||||||
|
presentModally(
|
||||||
|
viewController,
|
||||||
|
animated: animated
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
navigationController.pushViewController(
|
||||||
|
viewController,
|
||||||
|
animated: animated
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func dismiss(animated: Bool) {
|
||||||
|
guard let firstViewController = navigationController.viewControllers.first else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
performOnDismiss(for: firstViewController)
|
||||||
|
|
||||||
|
parentViewController.dismiss(animated: animated)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Helpers
|
||||||
|
private extension SheetRouter {
|
||||||
|
|
||||||
|
// MARK: Actions
|
||||||
|
@objc func onCancelPressed() {
|
||||||
|
guard let firstViewController = navigationController.viewControllers.first else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss(animated: true)
|
||||||
|
|
||||||
|
performOnDismiss(for: firstViewController)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Functions
|
||||||
|
func presentModally(
|
||||||
|
_ viewController: UIViewController,
|
||||||
|
animated: Bool
|
||||||
|
) {
|
||||||
|
viewController.navigationItem.rightBarButtonItem = UIBarButtonItem(
|
||||||
|
image: .Icon.close,
|
||||||
|
style: .plain,
|
||||||
|
target: self,
|
||||||
|
action: #selector(onCancelPressed)
|
||||||
|
)
|
||||||
|
|
||||||
|
if #available(iOS 15.0, *) {
|
||||||
|
navigationController.sheetPresentationController?.detents = [.medium(), .large()]
|
||||||
|
}
|
||||||
|
|
||||||
|
navigationController.setViewControllers(
|
||||||
|
[viewController],
|
||||||
|
animated: false
|
||||||
|
)
|
||||||
|
|
||||||
|
parentViewController.present(
|
||||||
|
navigationController,
|
||||||
|
animated: animated
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -25,6 +25,7 @@ let package = Package(
|
|||||||
name: .Target.coordination.kit,
|
name: .Target.coordination.kit,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.byName(name: .Target.foundation.kit),
|
.byName(name: .Target.foundation.kit),
|
||||||
|
.byName(name: .Target.ui.kit),
|
||||||
],
|
],
|
||||||
path: "Coordination/Kit"
|
path: "Coordination/Kit"
|
||||||
),
|
),
|
||||||
|
@ -19,6 +19,7 @@ public extension String {
|
|||||||
public static let star4 = "4.circle"
|
public static let star4 = "4.circle"
|
||||||
public static let star5 = "5.circle"
|
public static let star5 = "5.circle"
|
||||||
|
|
||||||
|
static let close = "xmark.circle.fill"
|
||||||
static let filter = "camera.filters"
|
static let filter = "camera.filters"
|
||||||
static let questionMark = "questionmark.circle.fill"
|
static let questionMark = "questionmark.circle.fill"
|
||||||
static let star = "star"
|
static let star = "star"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// UIImage+ICons.swift
|
// UIImage+Icons.swift
|
||||||
// ReviewsUIKit
|
// ReviewsUIKit
|
||||||
//
|
//
|
||||||
// Created by Javier Cicchelli on 20/03/2024.
|
// Created by Javier Cicchelli on 20/03/2024.
|
||||||
@ -12,6 +12,7 @@ public extension UIImage {
|
|||||||
enum Icon {
|
enum Icon {
|
||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
|
public static let close = UIImage(systemName: .Icon.close)
|
||||||
public static let filter = UIImage(systemName: .Icon.filter)
|
public static let filter = UIImage(systemName: .Icon.filter)
|
||||||
public static let star = UIImage(systemName: .Icon.star)
|
public static let star = UIImage(systemName: .Icon.star)
|
||||||
|
|
@ -10,6 +10,9 @@
|
|||||||
0220ADA32BA90646001E6A9F /* FeedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0220ADA22BA90646001E6A9F /* FeedItemView.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 */; };
|
||||||
|
028134712BACC8CC0074AB4B /* FeedListConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028134702BACC8CC0074AB4B /* FeedListConfiguration.swift */; };
|
||||||
|
028134822BACCC780074AB4B /* FeedListCoordination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028134812BACCC770074AB4B /* FeedListCoordination.swift */; };
|
||||||
|
028134842BACD0B20074AB4B /* FeedItemCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028134832BACD0B20074AB4B /* FeedItemCoordinator.swift */; };
|
||||||
02909E792BAB6B0200710E14 /* FilterOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02909E782BAB6B0200710E14 /* FilterOption.swift */; };
|
02909E792BAB6B0200710E14 /* FilterOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02909E782BAB6B0200710E14 /* FilterOption.swift */; };
|
||||||
02909E7B2BAB6D2E00710E14 /* Bundle+Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02909E7A2BAB6D2E00710E14 /* Bundle+Constants.swift */; };
|
02909E7B2BAB6D2E00710E14 /* Bundle+Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02909E7A2BAB6D2E00710E14 /* Bundle+Constants.swift */; };
|
||||||
02909E7D2BAB7FFE00710E14 /* Review+DTOs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02909E7C2BAB7FFE00710E14 /* Review+DTOs.swift */; };
|
02909E7D2BAB7FFE00710E14 /* Review+DTOs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02909E7C2BAB7FFE00710E14 /* Review+DTOs.swift */; };
|
||||||
@ -62,6 +65,9 @@
|
|||||||
0220ADA22BA90646001E6A9F /* FeedItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedItemView.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>"; };
|
||||||
|
028134702BACC8CC0074AB4B /* FeedListConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListConfiguration.swift; sourceTree = "<group>"; };
|
||||||
|
028134812BACCC770074AB4B /* FeedListCoordination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListCoordination.swift; sourceTree = "<group>"; };
|
||||||
|
028134832BACD0B20074AB4B /* FeedItemCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedItemCoordinator.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>"; };
|
||||||
02909E7A2BAB6D2E00710E14 /* Bundle+Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Constants.swift"; sourceTree = "<group>"; };
|
02909E7A2BAB6D2E00710E14 /* Bundle+Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Constants.swift"; sourceTree = "<group>"; };
|
||||||
02909E7C2BAB7FFE00710E14 /* Review+DTOs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Review+DTOs.swift"; sourceTree = "<group>"; };
|
02909E7C2BAB7FFE00710E14 /* Review+DTOs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Review+DTOs.swift"; sourceTree = "<group>"; };
|
||||||
@ -134,6 +140,7 @@
|
|||||||
02909E772BAB6AD500710E14 /* Enumerations */,
|
02909E772BAB6AD500710E14 /* Enumerations */,
|
||||||
023AC7FA2BAA3EB60027D064 /* Extensions */,
|
023AC7FA2BAA3EB60027D064 /* Extensions */,
|
||||||
02620B8A2BA89C3300DE7137 /* Models */,
|
02620B8A2BA89C3300DE7137 /* Models */,
|
||||||
|
0281346F2BACC8B00074AB4B /* Structs */,
|
||||||
02620B872BA89C0700DE7137 /* View Models */,
|
02620B872BA89C0700DE7137 /* View Models */,
|
||||||
);
|
);
|
||||||
path = Logic;
|
path = Logic;
|
||||||
@ -174,6 +181,22 @@
|
|||||||
path = Models;
|
path = Models;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
0281346F2BACC8B00074AB4B /* Structs */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
028134702BACC8CC0074AB4B /* FeedListConfiguration.swift */,
|
||||||
|
);
|
||||||
|
path = Structs;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
028134802BACCC630074AB4B /* Coordination */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
028134812BACCC770074AB4B /* FeedListCoordination.swift */,
|
||||||
|
);
|
||||||
|
path = Coordination;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
02909E772BAB6AD500710E14 /* Enumerations */ = {
|
02909E772BAB6AD500710E14 /* Enumerations */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -202,6 +225,8 @@
|
|||||||
02C1B1952BAC9BE7001781DE /* Coordinators */ = {
|
02C1B1952BAC9BE7001781DE /* Coordinators */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
028134802BACCC630074AB4B /* Coordination */,
|
||||||
|
028134832BACD0B20074AB4B /* FeedItemCoordinator.swift */,
|
||||||
02C1B1962BAC9BFE001781DE /* FeedListCoordinator.swift */,
|
02C1B1962BAC9BFE001781DE /* FeedListCoordinator.swift */,
|
||||||
);
|
);
|
||||||
path = Coordinators;
|
path = Coordinators;
|
||||||
@ -473,6 +498,7 @@
|
|||||||
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 */,
|
02EACF2E2BABA34600FF8ECD /* FeedItemCell.swift in Sources */,
|
||||||
|
028134842BACD0B20074AB4B /* FeedItemCoordinator.swift in Sources */,
|
||||||
02909E7D2BAB7FFE00710E14 /* Review+DTOs.swift in Sources */,
|
02909E7D2BAB7FFE00710E14 /* Review+DTOs.swift in Sources */,
|
||||||
0220ADA32BA90646001E6A9F /* FeedItemView.swift in Sources */,
|
0220ADA32BA90646001E6A9F /* FeedItemView.swift in Sources */,
|
||||||
02EACF362BABB2F200FF8ECD /* TopWord+DTOs.swift in Sources */,
|
02EACF362BABB2F200FF8ECD /* TopWord+DTOs.swift in Sources */,
|
||||||
@ -480,6 +506,8 @@
|
|||||||
02C1B1972BAC9BFE001781DE /* FeedListCoordinator.swift in Sources */,
|
02C1B1972BAC9BFE001781DE /* FeedListCoordinator.swift in Sources */,
|
||||||
02DC7FAE2BA51B4C000EEEBE /* FeedListViewController.swift in Sources */,
|
02DC7FAE2BA51B4C000EEEBE /* FeedListViewController.swift in Sources */,
|
||||||
02EACF322BABB23A00FF8ECD /* TopWordsView.swift in Sources */,
|
02EACF322BABB23A00FF8ECD /* TopWordsView.swift in Sources */,
|
||||||
|
028134712BACC8CC0074AB4B /* FeedListConfiguration.swift in Sources */,
|
||||||
|
028134822BACCC780074AB4B /* FeedListCoordination.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