[App] Integrated the Feed List to the App with coordinators (#16)

This PR contains the work done to implement the integration of the `FeedListViewController` view controller in the `Feed` framework to the `App` target by using coordinators.

Reviewed-on: #16
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:
Javier Cicchelli 2024-03-21 18:52:52 +00:00 committed by Javier Cicchelli
parent 60cab50c1e
commit 9a5c385903
7 changed files with 143 additions and 14 deletions

View File

@ -6,6 +6,7 @@
// Copyright © 2020 ING. All rights reserved. // Copyright © 2020 ING. All rights reserved.
// //
import ReviewsCoordinationKit
import ReviewsFeed import ReviewsFeed
import UIKit import UIKit
@ -13,6 +14,7 @@ import UIKit
class AppDelegate: UIResponder { class AppDelegate: UIResponder {
// MARK: Properties // MARK: Properties
var coordinator: AppCoordinator?
var window: UIWindow? var window: UIWindow?
} }
@ -26,9 +28,19 @@ extension AppDelegate: UIApplicationDelegate {
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds) window = UIWindow(frame: UIScreen.main.bounds)
coordinator = .init(router: WindowRouter(window))
guard let coordinator else {
fatalError("AppCoordinator should have been instantiated")
}
window?.rootViewController = UINavigationController(rootViewController: FeedListViewController()) coordinator.present(animated: false)
window?.makeKeyAndVisible() coordinator.present(
child: FeedListCoordinator(
router: StackRouter(coordinator.navigationController)
),
animated: false
)
return true return true
} }

View File

@ -0,0 +1,40 @@
//
// AppCoordinator.swift
// App
//
// Created by Javier Cicchelli on 21/03/2024.
// Copyright © 2024 Röck+Cöde. All rights reserved.
//
import Foundation
import ReviewsCoordinationKit
import ReviewsFeed
import UIKit
final class AppCoordinator: Coordinator {
// MARK: Constants
let router: any Router
// MARK: Properties
var children: [any Coordinator] = []
lazy var navigationController = UINavigationController()
// MARK: Initialisers
init(router: any Router) {
self.router = router
}
// MARK: Functions
func present(
animated: Bool,
onDismiss: Router.OnDismissClosure? = nil
) {
router.present(
navigationController,
animated: false
)
}
}

View File

@ -0,0 +1,45 @@
//
// FeedListCoordinator.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 FeedListCoordinator: Coordinator {
// MARK: Constants
public let router: any Router
private let sessionConfiguration: URLSessionConfiguration
// MARK: Properties
public var children: [any Coordinator] = []
// MARK: Initialisers
public init(
router: any Router,
sessionConfiguration: URLSessionConfiguration = .ephemeral
) {
self.router = router
self.sessionConfiguration = sessionConfiguration
}
// MARK: Functions
public func present(
animated: Bool,
onDismiss: Router.OnDismissClosure? = nil
) {
router.present(
FeedListViewController(configuration: .init(
session: sessionConfiguration
)),
animated: animated,
onDismiss: onDismiss
)
}
}

View File

@ -1,5 +1,5 @@
// //
// NavigationRouter.swift // BaseNavigationRouter.swift
// ReviewsCoordinationKit // ReviewsCoordinationKit
// //
// Created by Javier Cicchelli on 21/03/2024. // Created by Javier Cicchelli on 21/03/2024.
@ -8,14 +8,14 @@
import UIKit import UIKit
public class NavigationRouter: NSObject { open class BaseNavigationRouter: NSObject {
// MARK: Properties // MARK: Properties
var navigationController: UINavigationController var navigationController: UINavigationController
var onDismissForViewController: [UIViewController: Router.OnDismissClosure] = [:] var onDismissForViewController: [UIViewController: Router.OnDismissClosure] = [:]
// MARK: Initialisers // MARK: Initialisers
init(navigationController: UINavigationController) { public init(navigationController: UINavigationController) {
self.navigationController = navigationController self.navigationController = navigationController
super.init() super.init()
@ -37,7 +37,7 @@ public class NavigationRouter: NSObject {
} }
// MARK: - UINavigationControllerDelegate // MARK: - UINavigationControllerDelegate
extension NavigationRouter: UINavigationControllerDelegate { extension BaseNavigationRouter: UINavigationControllerDelegate {
// MARK: Functions // MARK: Functions
public func navigationController( public func navigationController(

View File

@ -1,5 +1,5 @@
// //
// File.swift // StackRouter.swift
// ReviewsCoordinationKit // ReviewsCoordinationKit
// //
// Created by Javier Cicchelli on 21/03/2024. // Created by Javier Cicchelli on 21/03/2024.
@ -8,14 +8,14 @@
import UIKit import UIKit
public class PushRouter: NavigationRouter { public class StackRouter: BaseNavigationRouter {
// MARK: Constants // MARK: Constants
private let rootViewController: UIViewController? private let rootViewController: UIViewController?
// MARK: Initialisers // MARK: Initialisers
public init( public init(
navigationController: UINavigationController, _ navigationController: UINavigationController,
rootViewController: UIViewController? = nil rootViewController: UIViewController? = nil
) { ) {
self.rootViewController = navigationController.viewControllers.first ?? rootViewController self.rootViewController = navigationController.viewControllers.first ?? rootViewController
@ -26,13 +26,13 @@ public class PushRouter: NavigationRouter {
} }
// MARK: - Router // MARK: - Router
extension PushRouter: Router { extension StackRouter: Router {
// MARK: Functions // MARK: Functions
public func present( public func present(
_ viewController: UIViewController, _ viewController: UIViewController,
animated: Bool, animated: Bool,
onDismiss: OnDismissClosure? onDismiss: OnDismissClosure? = nil
) { ) {
onDismissForViewController[viewController] = onDismiss onDismissForViewController[viewController] = onDismiss

View File

@ -14,7 +14,7 @@ public class WindowRouter: Router {
private let window: UIWindow? private let window: UIWindow?
// MARK: Initialisers // MARK: Initialisers
public init(window: UIWindow?) { public init(_ window: UIWindow?) {
self.window = window self.window = window
} }
@ -22,7 +22,7 @@ public class WindowRouter: Router {
public func present( public func present(
_ viewController: UIViewController, _ viewController: UIViewController,
animated: Bool, animated: Bool,
onDismiss: OnDismissClosure? onDismiss: OnDismissClosure? = nil
) { ) {
window?.rootViewController = viewController window?.rootViewController = viewController
window?.makeKeyAndVisible() window?.makeKeyAndVisible()

View File

@ -13,6 +13,8 @@
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 */; };
02C1B1972BAC9BFE001781DE /* FeedListCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C1B1962BAC9BFE001781DE /* FeedListCoordinator.swift */; };
02C1B1A92BACA722001781DE /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C1B1A82BACA722001781DE /* AppCoordinator.swift */; };
02DA924E2BAAE3FD00C47985 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 02DA924D2BAAE3FD00C47985 /* Localizable.xcstrings */; }; 02DA924E2BAAE3FD00C47985 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 02DA924D2BAAE3FD00C47985 /* Localizable.xcstrings */; };
02DC7F9F2BA51793000EEEBE /* ReviewsFeed.h in Headers */ = {isa = PBXBuildFile; fileRef = 02DC7F912BA51793000EEEBE /* ReviewsFeed.h */; settings = {ATTRIBUTES = (Public, ); }; }; 02DC7F9F2BA51793000EEEBE /* ReviewsFeed.h in Headers */ = {isa = PBXBuildFile; fileRef = 02DC7F912BA51793000EEEBE /* ReviewsFeed.h */; settings = {ATTRIBUTES = (Public, ); }; };
02DC7FA22BA51793000EEEBE /* ReviewsFeed.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02DC7F8F2BA51793000EEEBE /* ReviewsFeed.framework */; }; 02DC7FA22BA51793000EEEBE /* ReviewsFeed.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02DC7F8F2BA51793000EEEBE /* ReviewsFeed.framework */; };
@ -63,6 +65,8 @@
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>"; };
02C1B1962BAC9BFE001781DE /* FeedListCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListCoordinator.swift; sourceTree = "<group>"; };
02C1B1A82BACA722001781DE /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = "<group>"; };
02DA924D2BAAE3FD00C47985 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; }; 02DA924D2BAAE3FD00C47985 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
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>"; };
@ -195,6 +199,30 @@
path = Test; path = Test;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
02C1B1952BAC9BE7001781DE /* Coordinators */ = {
isa = PBXGroup;
children = (
02C1B1962BAC9BFE001781DE /* FeedListCoordinator.swift */,
);
path = Coordinators;
sourceTree = "<group>";
};
02C1B1A62BACA6FC001781DE /* App */ = {
isa = PBXGroup;
children = (
345AD11B24C6EDD9004E2EE1 /* AppDelegate.swift */,
);
path = App;
sourceTree = "<group>";
};
02C1B1A72BACA70B001781DE /* Coordinators */ = {
isa = PBXGroup;
children = (
02C1B1A82BACA722001781DE /* AppCoordinator.swift */,
);
path = Coordinators;
sourceTree = "<group>";
};
02DA924B2BAAE3E500C47985 /* Resources */ = { 02DA924B2BAAE3E500C47985 /* Resources */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -232,7 +260,8 @@
02DC7F742BA4F93B000EEEBE /* Sources */ = { 02DC7F742BA4F93B000EEEBE /* Sources */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
345AD11B24C6EDD9004E2EE1 /* AppDelegate.swift */, 02C1B1A62BACA6FC001781DE /* App */,
02C1B1A72BACA70B001781DE /* Coordinators */,
); );
path = Sources; path = Sources;
sourceTree = "<group>"; sourceTree = "<group>";
@ -273,6 +302,7 @@
02DC7FB02BA51B4F000EEEBE /* Sources */ = { 02DC7FB02BA51B4F000EEEBE /* Sources */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
02C1B1952BAC9BE7001781DE /* Coordinators */,
02620B862BA89C0000DE7137 /* Logic */, 02620B862BA89C0000DE7137 /* Logic */,
02620B852BA89BF900DE7137 /* UI */, 02620B852BA89BF900DE7137 /* UI */,
); );
@ -447,6 +477,7 @@
0220ADA32BA90646001E6A9F /* FeedItemView.swift in Sources */, 0220ADA32BA90646001E6A9F /* FeedItemView.swift in Sources */,
02EACF362BABB2F200FF8ECD /* TopWord+DTOs.swift in Sources */, 02EACF362BABB2F200FF8ECD /* TopWord+DTOs.swift in Sources */,
02DC7FAF2BA51B4C000EEEBE /* Review.swift in Sources */, 02DC7FAF2BA51B4C000EEEBE /* Review.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 */,
02909E792BAB6B0200710E14 /* FilterOption.swift in Sources */, 02909E792BAB6B0200710E14 /* FilterOption.swift in Sources */,
@ -457,6 +488,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
02C1B1A92BACA722001781DE /* AppCoordinator.swift in Sources */,
345AD11C24C6EDD9004E2EE1 /* AppDelegate.swift in Sources */, 345AD11C24C6EDD9004E2EE1 /* AppDelegate.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;