diff --git a/Apps/Locations/Libraries/Sources/Core/Protocols/View.swift b/Apps/Locations/Libraries/Sources/Core/Protocols/View.swift
deleted file mode 100644
index 43c0b70..0000000
--- a/Apps/Locations/Libraries/Sources/Core/Protocols/View.swift
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-// View.swift
-// Core
-//
-// Created by Javier Cicchelli on 11/04/2023.
-// Copyright © 2023 Röck+Cöde. All rights reserved.
-//
-
-/// This protocol defines the view of the **MVVM** architecture.
-public protocol View {
-
- // MARK: Properties
-
- /// The view model related to the view.
- var viewModel: ViewModel { get set }
-
-}
diff --git a/Apps/Locations/Libraries/Sources/Core/Protocols/ViewModel.swift b/Apps/Locations/Libraries/Sources/Core/Protocols/ViewModel.swift
deleted file mode 100644
index a550329..0000000
--- a/Apps/Locations/Libraries/Sources/Core/Protocols/ViewModel.swift
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-// ViewModel.swift
-// Core
-//
-// Created by Javier Cicchelli on 11/04/2023.
-// Copyright © 2023 Röck+Cöde. All rights reserved.
-//
-
-/// This protocol defines the view model of the **MVVM** architecture.
-public protocol ViewModel: AnyObject {
-
- // MARK: Properties
-
- /// The reference to the coordinator that initialised the view model.
- var coordinator: Coordinator { get set }
-
-}
diff --git a/Apps/Locations/Libraries/Sources/Core/Routers/BaseNavigationRouter.swift b/Apps/Locations/Libraries/Sources/Core/Routers/BaseNavigationRouter.swift
new file mode 100644
index 0000000..411b13a
--- /dev/null
+++ b/Apps/Locations/Libraries/Sources/Core/Routers/BaseNavigationRouter.swift
@@ -0,0 +1,68 @@
+//
+// BaseNavigationRouter.swift
+// Core
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import UIKit
+
+/// This is a base class for the `NavigationRouter` concrete router implementations.
+public class BaseNavigationRouter: NSObject {
+
+ // MARK: Properties
+
+ /// A navigation controller to use within this concrete router.
+ var navigationController: UINavigationController
+
+ /// Dictionary that persist `onDismiss` closure for its respective view controllers until one of the later is dismissed.
+ var onDismissForViewController: [UIViewController: Router.OnDismissedClosure] = [:]
+
+ // MARK: Initialisers
+
+ /// Initialise this router.
+ /// - Parameter navigationController: A `UINavigationController` navigation controller instance to use in this router.
+ init(navigationController: UINavigationController) {
+ self.navigationController = navigationController
+
+ super.init()
+
+ self.navigationController.delegate = self
+ }
+
+ // MARK: Functions
+
+ /// Executes the `onDismiss` closure for a given view controller.
+ /// - Parameter viewController: A `UIViewController` view controller instance for which the on dismiss closure will be executed.
+ func performOnDismissed(for viewController: UIViewController) {
+ guard let onDismiss = onDismissForViewController[viewController] else {
+ return
+ }
+
+ onDismiss()
+
+ onDismissForViewController[viewController] = nil
+ }
+
+}
+
+// MARK: - UINavigationControllerDelegate
+
+extension BaseNavigationRouter: UINavigationControllerDelegate {
+
+ // MARK: Functions
+
+ public func navigationController(
+ _ navigationController: UINavigationController,
+ didShow viewController: UIViewController,
+ animated: Bool
+ ) {
+ guard let dismissedViewController = navigationController.transitionCoordinator?.viewController(forKey: .from) else {
+ return
+ }
+
+ performOnDismissed(for: dismissedViewController)
+ }
+
+}
diff --git a/Apps/Locations/Libraries/Sources/Core/Routers/ModalNavigationRouter.swift b/Apps/Locations/Libraries/Sources/Core/Routers/ModalNavigationRouter.swift
new file mode 100644
index 0000000..b80f2df
--- /dev/null
+++ b/Apps/Locations/Libraries/Sources/Core/Routers/ModalNavigationRouter.swift
@@ -0,0 +1,85 @@
+//
+// ModalNavigationRouter.swift
+// Core
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import UIKit
+
+public class ModalNavigationRouter: BaseNavigationRouter {
+
+ // MARK: Properties
+
+ /// The parent view controller from where this router is being called from.
+ public unowned let parentViewController: UIViewController
+
+ // MARK: Initialisers
+
+ /// Initialise this router.
+ /// - Parameter parentViewController: A `UIViewController` view controller instance from where this router is originated.
+ public init(parentViewController: UIViewController) {
+ self.parentViewController = parentViewController
+
+ super.init(navigationController: .init())
+ }
+
+}
+
+extension ModalNavigationRouter: Router {
+ public func present(
+ _ viewController: UIViewController,
+ animated: Bool,
+ onDismiss: OnDismissedClosure?
+ ) {
+ 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
+ }
+
+ performOnDismissed(for: firstViewController)
+
+ parentViewController.dismiss(animated: animated)
+ }
+
+}
+
+// MARK: - Helpers
+
+private extension ModalNavigationRouter {
+
+ // MARK: Functions
+
+ func presentModally(_ viewController: UIViewController, animated: Bool) {
+ viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(
+ title: "Cancel",
+ style: .plain,
+ target: self,
+ action: #selector(onCancelPressed)
+ )
+
+ navigationController.setViewControllers([viewController], animated: false)
+
+ parentViewController.present(navigationController, animated: animated)
+ }
+
+ @objc func onCancelPressed() {
+ guard let firstViewController = navigationController.viewControllers.first else {
+ return
+ }
+
+ performOnDismissed(for: firstViewController)
+ dismiss(animated: true)
+ }
+
+}
diff --git a/Apps/Locations/Libraries/Sources/Core/Routers/NavigationRouter.swift b/Apps/Locations/Libraries/Sources/Core/Routers/NavigationRouter.swift
deleted file mode 100644
index 688c8ce..0000000
--- a/Apps/Locations/Libraries/Sources/Core/Routers/NavigationRouter.swift
+++ /dev/null
@@ -1,105 +0,0 @@
-//
-// NavigationRouter.swift
-// Core
-//
-// Created by Javier Cicchelli on 11/04/2023.
-// Copyright © 2023 Röck+Cöde. All rights reserved.
-//
-
-import UIKit
-
-/// This class is responsible for presenting view controllers, as it is a concrete implementation of the `Router` protocol, but it won't know what view controller or which view controller is next.
-public class NavigationRouter: NSObject {
-
- // MARK: Properties
-
- /// A navigation controller to use within this concrete router.
- private let navigationController: UINavigationController
-
- /// A root view controller coming in from the navigation controller, if any.
- private let rootViewController: UIViewController?
-
- /// Dictionary that persist `onDismiss` closure for its respective view controllers until one of the later is dismissed.
- private var onDismissForViewController: [UIViewController: Router.OnDismissedClosure] = [:]
-
- // MARK: Initialisers
-
- /// Initialise this router.
- /// - Parameter navigationController: A `UINavigationController` navigation controller instance to use in this router.
- public init(navigationController: UINavigationController) {
- self.navigationController = navigationController
- self.rootViewController = navigationController.viewControllers.first
-
- super.init()
-
- self.navigationController.delegate = self
- }
-
-}
-
-// MARK: - Router
-
-extension NavigationRouter: Router {
-
- // MARK: Functions
-
- public func present(
- _ viewController: UIViewController,
- animated: Bool,
- onDismiss: OnDismissedClosure?
- ) {
- onDismissForViewController[viewController] = onDismiss
-
- navigationController.pushViewController(viewController, animated: animated)
- }
-
- public func dismiss(animated: Bool) {
- guard let rootViewController else {
- navigationController.popViewController(animated: animated)
- return
- }
-
- performOnDismissed(for: rootViewController)
-
- navigationController.popToViewController(rootViewController, animated: animated)
- }
-
-}
-
-// MARK: - UINavigationControllerDelegate
-
-extension NavigationRouter: UINavigationControllerDelegate {
-
- // MARK: Functions
-
- public func navigationController(
- _ navigationController: UINavigationController,
- didShow viewController: UIViewController,
- animated: Bool
- ) {
- guard let dismissedViewController = navigationController.transitionCoordinator?.viewController(forKey: .from) else {
- return
- }
-
- performOnDismissed(for: dismissedViewController)
- }
-
-}
-
-// MARK: - Helpers
-
-private extension NavigationRouter {
-
- // MARK: Functions
-
- func performOnDismissed(for viewController: UIViewController) {
- guard let onDismiss = onDismissForViewController[viewController] else {
- return
- }
-
- onDismiss()
-
- onDismissForViewController[viewController] = nil
- }
-
-}
diff --git a/Apps/Locations/Libraries/Sources/Core/Routers/PushNavigationRouter.swift b/Apps/Locations/Libraries/Sources/Core/Routers/PushNavigationRouter.swift
new file mode 100644
index 0000000..4d9b77b
--- /dev/null
+++ b/Apps/Locations/Libraries/Sources/Core/Routers/PushNavigationRouter.swift
@@ -0,0 +1,64 @@
+//
+// PushNavigationRouter.swift
+// Core
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import UIKit
+
+/// This class is responsible for presenting view controllers, as it is a concrete implementation of the `Router` protocol, but it won't know what view controller or which view controller is next.
+public class PushNavigationRouter: BaseNavigationRouter {
+
+ // MARK: Properties
+
+ /// A root view controller coming in from the navigation controller, if any.
+ private let rootViewController: UIViewController?
+
+ // MARK: Initialisers
+
+ /// Initialise this router.
+ /// - Parameters:
+ /// - navigationController: A `UINavigationController` navigation controller instance to use in this router.
+ /// - rootViewController: A `UIViewController` view controller instance to define as a root view controller of the navigation controller.
+ /// - Note This initialiser added the `rootViewController` parameter although it is not really needed to differentiate itself from the `.init(navigationController:)` implemented for the `BaseNavigationRouter` base class.
+ public init(
+ navigationController: UINavigationController,
+ rootViewController: UIViewController? = nil
+ ) {
+ self.rootViewController = navigationController.viewControllers.first ?? rootViewController
+
+ super.init(navigationController: navigationController)
+ }
+
+}
+
+// MARK: - Router
+
+extension PushNavigationRouter: Router {
+
+ // MARK: Functions
+
+ public func present(
+ _ viewController: UIViewController,
+ animated: Bool,
+ onDismiss: OnDismissedClosure?
+ ) {
+ onDismissForViewController[viewController] = onDismiss
+
+ navigationController.pushViewController(viewController, animated: animated)
+ }
+
+ public func dismiss(animated: Bool) {
+ guard let rootViewController else {
+ navigationController.popViewController(animated: animated)
+ return
+ }
+
+ performOnDismissed(for: rootViewController)
+
+ navigationController.popToViewController(rootViewController, animated: animated)
+ }
+
+}
diff --git a/Apps/Locations/Libraries/Sources/Core/Routers/WindowRouter.swift b/Apps/Locations/Libraries/Sources/Core/Routers/WindowRouter.swift
new file mode 100644
index 0000000..332ffac
--- /dev/null
+++ b/Apps/Locations/Libraries/Sources/Core/Routers/WindowRouter.swift
@@ -0,0 +1,43 @@
+//
+// WindowRouter.swift
+// Core
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import UIKit
+
+/// This class is responsible for populating the window of an application.
+public class WindowRouter: Router {
+
+ // MARK: Properties
+
+ /// The window to set manually with a `UIViewController` view controller instance.
+ private let window: UIWindow?
+
+ // MARK: Initialisers
+
+ /// Initialise this router.
+ /// - Parameter window: A `UIWindow` window instance to be set manually.
+ public init(window: UIWindow?) {
+ self.window = window
+ }
+
+ // MARK: Functions
+
+ public func present(
+ _ viewController: UIViewController,
+ animated: Bool,
+ onDismiss: OnDismissedClosure?
+ ) {
+ window?.rootViewController = viewController
+
+ window?.makeKeyAndVisible()
+ }
+
+ public func dismiss(animated: Bool) {
+ // Nothing to do here...
+ }
+
+}
diff --git a/Apps/Locations/Libraries/Sources/Remote/Clients/LocationsClient.swift b/Apps/Locations/Libraries/Sources/Remote/Clients/RemoteClient.swift
similarity index 93%
rename from Apps/Locations/Libraries/Sources/Remote/Clients/LocationsClient.swift
rename to Apps/Locations/Libraries/Sources/Remote/Clients/RemoteClient.swift
index 9ed37f2..cdb996c 100644
--- a/Apps/Locations/Libraries/Sources/Remote/Clients/LocationsClient.swift
+++ b/Apps/Locations/Libraries/Sources/Remote/Clients/RemoteClient.swift
@@ -1,6 +1,6 @@
//
-// LocationsClient.swift
-// Locations
+// RemoteClient.swift
+// Remote
//
// Created by Javier Cicchelli on 10/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
@@ -9,7 +9,7 @@
import APICore
import Foundation
-struct LocationsClient {
+struct RemoteClient {
// MARK: Properties
@@ -27,7 +27,7 @@ struct LocationsClient {
// MARK: - Client
-extension LocationsClient: Client {
+extension RemoteClient: Client {
// MARK: Functions
diff --git a/Apps/Locations/Libraries/Sources/Remote/Endpoints/GetLocationsEndpoint.swift b/Apps/Locations/Libraries/Sources/Remote/Endpoints/GetLocationsEndpoint.swift
index 1755734..3d58fa8 100644
--- a/Apps/Locations/Libraries/Sources/Remote/Endpoints/GetLocationsEndpoint.swift
+++ b/Apps/Locations/Libraries/Sources/Remote/Endpoints/GetLocationsEndpoint.swift
@@ -1,6 +1,6 @@
//
// GetLocationsEndpoint.swift
-// Locations
+// Remote
//
// Created by Javier Cicchelli on 10/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
diff --git a/Apps/Locations/Libraries/Sources/Remote/Extensions/String+Constants.swift b/Apps/Locations/Libraries/Sources/Remote/Extensions/String+Constants.swift
index 3eff3f9..a839fa5 100644
--- a/Apps/Locations/Libraries/Sources/Remote/Extensions/String+Constants.swift
+++ b/Apps/Locations/Libraries/Sources/Remote/Extensions/String+Constants.swift
@@ -1,6 +1,6 @@
//
// String+Constants.swift
-// Locations
+// Remote
//
// Created by Javier Cicchelli on 10/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
diff --git a/Apps/Locations/Libraries/Sources/Remote/Models/Location.swift b/Apps/Locations/Libraries/Sources/Remote/Models/Location.swift
index 52567a0..0342f96 100644
--- a/Apps/Locations/Libraries/Sources/Remote/Models/Location.swift
+++ b/Apps/Locations/Libraries/Sources/Remote/Models/Location.swift
@@ -1,6 +1,6 @@
//
// Location.swift
-// Locations (Library)
+// Remote
//
// Created by Javier Cicchelli on 10/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
diff --git a/Apps/Locations/Libraries/Sources/Remote/Services/LocationsService.swift b/Apps/Locations/Libraries/Sources/Remote/Services/RemoteService.swift
similarity index 82%
rename from Apps/Locations/Libraries/Sources/Remote/Services/LocationsService.swift
rename to Apps/Locations/Libraries/Sources/Remote/Services/RemoteService.swift
index 2e102ab..b9bca95 100644
--- a/Apps/Locations/Libraries/Sources/Remote/Services/LocationsService.swift
+++ b/Apps/Locations/Libraries/Sources/Remote/Services/RemoteService.swift
@@ -1,6 +1,6 @@
//
-// LocationsService.swift
-// Locations
+// RemoteService.swift
+// Remote
//
// Created by Javier Cicchelli on 10/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
@@ -9,7 +9,7 @@
import APICore
import Foundation
-public struct LocationsService {
+public struct RemoteService {
// MARK: Properties
@@ -18,7 +18,7 @@ public struct LocationsService {
// MARK: Initialisers
public init(configuration: URLSessionConfiguration = .default) {
- self.client = LocationsClient(configuration: configuration)
+ self.client = RemoteClient(configuration: configuration)
}
// MARK: Functions
diff --git a/Apps/Locations/Resources/Info.plist b/Apps/Locations/Resources/Info.plist
index 0eb786d..0c67376 100644
--- a/Apps/Locations/Resources/Info.plist
+++ b/Apps/Locations/Resources/Info.plist
@@ -1,23 +1,5 @@
-
- UIApplicationSceneManifest
-
- UIApplicationSupportsMultipleScenes
-
- UISceneConfigurations
-
- UIWindowSceneSessionRoleApplication
-
-
- UISceneConfigurationName
- Default Configuration
- UISceneDelegateClassName
- $(PRODUCT_MODULE_NAME).SceneDelegate
-
-
-
-
-
+
diff --git a/Apps/Locations/Sources/AppDelegate.swift b/Apps/Locations/Sources/AppDelegate.swift
index b40c8ba..55a61df 100644
--- a/Apps/Locations/Sources/AppDelegate.swift
+++ b/Apps/Locations/Sources/AppDelegate.swift
@@ -6,40 +6,31 @@
// Copyright © 2023 Röck+Cöde. All rights reserved.
//
+import Core
import UIKit
-import CoreData
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ // MARK: Properties
+
+ lazy var coordinator: LocationsListCoordinator = .init(router: router)
+ lazy var router: WindowRouter = .init(window: window)
+ lazy var window: UIWindow? = .init(frame: UIScreen.main.bounds)
+
+ // MARK: UIApplicationDelegate
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
- // Override point for customization after application launch.
+ coordinator.present(animated: false, onDismiss: nil)
+
return true
}
-
- // MARK: UISceneSession Lifecycle
-
- func application(
- _ application: UIApplication,
- configurationForConnecting connectingSceneSession: UISceneSession,
- options: UIScene.ConnectionOptions
- ) -> UISceneConfiguration {
- // Called when a new scene session is being created.
- // Use this method to select a configuration to create the new scene with.
- return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
- }
-
- func application(
- _ application: UIApplication,
- didDiscardSceneSessions sceneSessions: Set
- ) {
- // Called when the user discards a scene session.
- // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
- // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
+
+ func applicationDidEnterBackground(_ application: UIApplication) {
+ // Save changes in the application's managed object context when the application transitions to the background.
}
}
-
diff --git a/Apps/Locations/Sources/Coordinators/LocationsAddCoordinator.swift b/Apps/Locations/Sources/Coordinators/LocationsAddCoordinator.swift
new file mode 100644
index 0000000..61dd9c0
--- /dev/null
+++ b/Apps/Locations/Sources/Coordinators/LocationsAddCoordinator.swift
@@ -0,0 +1,41 @@
+//
+// LocationsAddCoordinator.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import Core
+import UIKit
+
+class LocationsAddCoordinator: Coordinator {
+
+ // MARK: Properties
+
+ var children: [Coordinator] = []
+ var router: Router
+
+ // MARK: Initialisers
+
+ init(router: Router) {
+ self.router = router
+ }
+
+ // MARK: Coordinator
+
+ func present(animated: Bool, onDismiss: (() -> Void)?) {
+ router.present(
+ LocationsAddViewController(
+ viewModel: LocationsAddViewModel(coordinator: self)
+ ),
+ animated: animated,
+ onDismiss: onDismiss
+ )
+ }
+
+}
+
+// MARK: - LocationsAddCoordination
+
+extension LocationsAddCoordinator: LocationsAddCoordination {}
diff --git a/Apps/Locations/Sources/Coordinators/LocationsListCoordinator.swift b/Apps/Locations/Sources/Coordinators/LocationsListCoordinator.swift
new file mode 100644
index 0000000..a7d2592
--- /dev/null
+++ b/Apps/Locations/Sources/Coordinators/LocationsListCoordinator.swift
@@ -0,0 +1,64 @@
+//
+// LocationsListCoordinator.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import Core
+import UIKit
+
+class LocationsListCoordinator: Coordinator {
+
+ // MARK: Properties
+
+ var children: [Coordinator] = []
+ var router: Router
+
+ private var viewController: UIViewController?
+
+ // MARK: Initialisers
+
+ init(router: Router) {
+ self.router = router
+ }
+
+ // MARK: Coordinator
+
+ func present(animated: Bool, onDismiss: (() -> Void)?) {
+ let navigationController = UINavigationController(rootViewController: LocationsListViewController(
+ viewModel: LocationsListViewModel(coordinator: self)
+ ))
+
+ viewController = navigationController
+
+ router.present(
+ navigationController,
+ animated: animated,
+ onDismiss: onDismiss
+ )
+ }
+
+}
+
+// MARK: - LocationsListCoordination
+
+extension LocationsListCoordinator: LocationsListCoordination {
+
+ // MARK: Functions
+
+ func openAddLocation() {
+ guard let viewController else {
+ return
+ }
+
+ present(
+ child: LocationsAddCoordinator(
+ router: ModalNavigationRouter(parentViewController: viewController)
+ ),
+ animated: true
+ )
+ }
+
+}
diff --git a/Apps/Locations/Sources/Extensions/DependencyService+Keys.swift b/Apps/Locations/Sources/Extensions/DependencyService+Keys.swift
new file mode 100644
index 0000000..b1286d0
--- /dev/null
+++ b/Apps/Locations/Sources/Extensions/DependencyService+Keys.swift
@@ -0,0 +1,35 @@
+//
+// DependencyService+Keys.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import Dependency
+import Persistence
+import Remote
+
+// MARK: - DependencyService+Keys
+
+extension DependencyService {
+ var persistence: PersistenceService {
+ get { Self[PersistenceKey.self] }
+ set { Self[PersistenceKey.self] = newValue }
+ }
+
+ var remote: RemoteService {
+ get { Self[RemoteKey.self] }
+ set { Self[RemoteKey.self] = newValue }
+ }
+}
+
+// MARK: - Dependency keys
+
+struct PersistenceKey: DependencyKey {
+ static var currentValue: PersistenceService = .shared
+}
+
+struct RemoteKey: DependencyKey {
+ static var currentValue: RemoteService = .init()
+}
diff --git a/Apps/Locations/Sources/Protocols/Coordination/LocationsAddCoordination.swift b/Apps/Locations/Sources/Protocols/Coordination/LocationsAddCoordination.swift
new file mode 100644
index 0000000..6dd5bee
--- /dev/null
+++ b/Apps/Locations/Sources/Protocols/Coordination/LocationsAddCoordination.swift
@@ -0,0 +1,9 @@
+//
+// LocationsAddCoordination.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+protocol LocationsAddCoordination: AnyObject {}
diff --git a/Apps/Locations/Sources/Protocols/Coordination/LocationsListCoordination.swift b/Apps/Locations/Sources/Protocols/Coordination/LocationsListCoordination.swift
new file mode 100644
index 0000000..bafe329
--- /dev/null
+++ b/Apps/Locations/Sources/Protocols/Coordination/LocationsListCoordination.swift
@@ -0,0 +1,15 @@
+//
+// LocationsListCoordination.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+protocol LocationsListCoordination: AnyObject {
+
+ // MARK: Functions
+
+ func openAddLocation()
+
+}
diff --git a/Apps/Locations/Sources/Protocols/ViewModeling/LocationsAddViewModeling.swift b/Apps/Locations/Sources/Protocols/ViewModeling/LocationsAddViewModeling.swift
new file mode 100644
index 0000000..b4e707c
--- /dev/null
+++ b/Apps/Locations/Sources/Protocols/ViewModeling/LocationsAddViewModeling.swift
@@ -0,0 +1,15 @@
+//
+// LocationsAddViewModeling.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+protocol LocationsAddViewModeling: AnyObject {
+
+ // MARK: Properties
+
+ var coordinator: LocationsAddCoordination? { get set }
+
+}
diff --git a/Apps/Locations/Sources/Protocols/ViewModeling/LocationsListViewModeling.swift b/Apps/Locations/Sources/Protocols/ViewModeling/LocationsListViewModeling.swift
new file mode 100644
index 0000000..90deeab
--- /dev/null
+++ b/Apps/Locations/Sources/Protocols/ViewModeling/LocationsListViewModeling.swift
@@ -0,0 +1,19 @@
+//
+// LocationsListViewModeling.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+protocol LocationsListViewModeling: AnyObject {
+
+ // MARK: Properties
+
+ var coordinator: LocationsListCoordination? { get set }
+
+ // MARK: Functions
+
+ func openAddLocation()
+
+}
diff --git a/Apps/Locations/Sources/SceneDelegate.swift b/Apps/Locations/Sources/SceneDelegate.swift
deleted file mode 100644
index c95cee8..0000000
--- a/Apps/Locations/Sources/SceneDelegate.swift
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-// SceneDelegate.swift
-// Locations
-//
-// Created by Javier Cicchelli on 08/04/2023.
-// Copyright © 2023 Röck+Cöde. All rights reserved.
-//
-
-import UIKit
-
-class SceneDelegate: UIResponder, UIWindowSceneDelegate {
-
- var window: UIWindow?
-
- func scene(
- _ scene: UIScene,
- willConnectTo session: UISceneSession,
- options connectionOptions: UIScene.ConnectionOptions
- ) {
- // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
- // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
- // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
- guard let windowScene = scene as? UIWindowScene else {
- return
- }
-
- window = {
- let window = UIWindow(windowScene: windowScene)
-
- window.rootViewController = ViewController()
- window.makeKeyAndVisible()
-
- return window
- }()
- }
-
- func sceneDidDisconnect(_ scene: UIScene) {
- // Called as the scene is being released by the system.
- // This occurs shortly after the scene enters the background, or when its session is discarded.
- // Release any resources associated with this scene that can be re-created the next time the scene connects.
- // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
- }
-
- func sceneDidBecomeActive(_ scene: UIScene) {
- // Called when the scene has moved from an inactive state to an active state.
- // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
- }
-
- func sceneWillResignActive(_ scene: UIScene) {
- // Called when the scene will move from an active state to an inactive state.
- // This may occur due to temporary interruptions (ex. an incoming phone call).
- }
-
- func sceneWillEnterForeground(_ scene: UIScene) {
- // Called as the scene transitions from the background to the foreground.
- // Use this method to undo the changes made on entering the background.
- }
-
- func sceneDidEnterBackground(_ scene: UIScene) {
- // Called as the scene transitions from the foreground to the background.
- // Use this method to save data, release shared resources, and store enough scene-specific state information
- // to restore the scene back to its current state.
-
- // Save changes in the application's managed object context when the application transitions to the background.
- }
-
-}
diff --git a/Apps/Locations/Sources/Screens/LocationsAdd/LocationsAddViewController.swift b/Apps/Locations/Sources/Screens/LocationsAdd/LocationsAddViewController.swift
new file mode 100644
index 0000000..86f4421
--- /dev/null
+++ b/Apps/Locations/Sources/Screens/LocationsAdd/LocationsAddViewController.swift
@@ -0,0 +1,38 @@
+//
+// LocationsAddViewController.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import Core
+import UIKit
+
+class LocationsAddViewController: BaseViewController {
+
+ // MARK: Properties
+
+ var viewModel: LocationsAddViewModeling
+
+ // MARK: Initialisers
+
+ init(viewModel: LocationsAddViewModeling) {
+ self.viewModel = viewModel
+
+ super.init()
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ // MARK: UIViewController
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ title = "Location Add"
+ }
+
+}
diff --git a/Apps/Locations/Sources/Screens/LocationsAdd/LocationsAddViewModel.swift b/Apps/Locations/Sources/Screens/LocationsAdd/LocationsAddViewModel.swift
new file mode 100644
index 0000000..84e9678
--- /dev/null
+++ b/Apps/Locations/Sources/Screens/LocationsAdd/LocationsAddViewModel.swift
@@ -0,0 +1,28 @@
+//
+// LocationsAddViewModel.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import Combine
+import Core
+
+class LocationsAddViewModel: ObservableObject {
+
+ // MARK: Properties
+
+ weak var coordinator: LocationsAddCoordination?
+
+ // MARK: Initialisers
+
+ init(coordinator: LocationsAddCoordination) {
+ self.coordinator = coordinator
+ }
+
+}
+
+// MARK: - LocationsAddViewModeling
+
+extension LocationsAddViewModel: LocationsAddViewModeling {}
diff --git a/Apps/Locations/Sources/Screens/LocationsList/LocationsListViewController.swift b/Apps/Locations/Sources/Screens/LocationsList/LocationsListViewController.swift
new file mode 100644
index 0000000..cc35c26
--- /dev/null
+++ b/Apps/Locations/Sources/Screens/LocationsList/LocationsListViewController.swift
@@ -0,0 +1,56 @@
+//
+// LocationsListViewController.swift
+// Locations
+//
+// Created by Javier Cicchelli on 08/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import Core
+import UIKit
+
+class LocationsListViewController: BaseViewController {
+
+ // MARK: Properties
+
+ var viewModel: LocationsListViewModeling
+
+ // MARK: Initialisers
+
+ init(viewModel: LocationsListViewModeling) {
+ self.viewModel = viewModel
+
+ super.init()
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ // MARK: UIViewController
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ navigationItem.rightBarButtonItem = UIBarButtonItem(
+ title: "Add",
+ style: .plain,
+ target: self,
+ action: #selector(addLocationPressed)
+ )
+ title = "Locations"
+ }
+
+}
+
+// MARK: - Helpers
+
+private extension LocationsListViewController {
+
+ // MARK: Functions
+
+ @objc func addLocationPressed() {
+ viewModel.openAddLocation()
+ }
+
+}
diff --git a/Apps/Locations/Sources/Screens/LocationsList/LocationsListViewModel.swift b/Apps/Locations/Sources/Screens/LocationsList/LocationsListViewModel.swift
new file mode 100644
index 0000000..c3644fa
--- /dev/null
+++ b/Apps/Locations/Sources/Screens/LocationsList/LocationsListViewModel.swift
@@ -0,0 +1,36 @@
+//
+// LocationsListViewModel.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import Combine
+import Core
+
+class LocationsListViewModel: ObservableObject {
+
+ // MARK: Properties
+
+ weak var coordinator: LocationsListCoordination?
+
+ // MARK: Initialisers
+
+ init(coordinator: LocationsListCoordination) {
+ self.coordinator = coordinator
+ }
+
+}
+
+// MARK: - LocationsListViewModeling
+
+extension LocationsListViewModel: LocationsListViewModeling {
+
+ // MARK: Functions
+
+ func openAddLocation() {
+ coordinator?.openAddLocation()
+ }
+
+}
diff --git a/Apps/Locations/Sources/View Controllers/BaseViewController.swift b/Apps/Locations/Sources/View Controllers/BaseViewController.swift
new file mode 100644
index 0000000..ea3fec4
--- /dev/null
+++ b/Apps/Locations/Sources/View Controllers/BaseViewController.swift
@@ -0,0 +1,31 @@
+//
+// BaseViewController.swift
+// Locations
+//
+// Created by Javier Cicchelli on 11/04/2023.
+// Copyright © 2023 Röck+Cöde. All rights reserved.
+//
+
+import UIKit
+
+class BaseViewController: UIViewController {
+
+ // MARK: Initialisers
+
+ init() {
+ super.init(nibName: nil, bundle: nil)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ // MARK: UIViewController
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ view.backgroundColor = .systemBackground
+ }
+
+}
diff --git a/Apps/Locations/Sources/ViewController.swift b/Apps/Locations/Sources/ViewController.swift
deleted file mode 100644
index 8c3be97..0000000
--- a/Apps/Locations/Sources/ViewController.swift
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-// ViewController.swift
-// Locations
-//
-// Created by Javier Cicchelli on 08/04/2023.
-// Copyright © 2023 Röck+Cöde. All rights reserved.
-//
-
-import UIKit
-
-class ViewController: UIViewController {
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- view.backgroundColor = .red
- }
-
-}
diff --git a/DeepLinking.xcodeproj/project.pbxproj b/DeepLinking.xcodeproj/project.pbxproj
index 6181e6f..33b73ae 100644
--- a/DeepLinking.xcodeproj/project.pbxproj
+++ b/DeepLinking.xcodeproj/project.pbxproj
@@ -7,9 +7,19 @@
objects = {
/* Begin PBXBuildFile section */
+ 02031EBF29E5F949003C108C /* LocationsAddViewModeling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02031EBE29E5F949003C108C /* LocationsAddViewModeling.swift */; };
+ 02031EC629E5FEE4003C108C /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02031EC529E5FEE4003C108C /* BaseViewController.swift */; };
+ 02031EC929E60B29003C108C /* DependencyService+Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02031EC829E60B29003C108C /* DependencyService+Keys.swift */; };
+ 46C3B7C629E5BF1500F8F57C /* LocationsListCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C3B7C529E5BF1500F8F57C /* LocationsListCoordinator.swift */; };
+ 46C3B7CB29E5CD3200F8F57C /* LocationsListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C3B7CA29E5CD3200F8F57C /* LocationsListViewModel.swift */; };
+ 46C3B7CF29E5D00E00F8F57C /* LocationsAddViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C3B7CE29E5D00E00F8F57C /* LocationsAddViewModel.swift */; };
+ 46C3B7D129E5D06D00F8F57C /* LocationsAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C3B7D029E5D06D00F8F57C /* LocationsAddViewController.swift */; };
+ 46C3B7D629E5E50500F8F57C /* LocationsListViewModeling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C3B7D529E5E50500F8F57C /* LocationsListViewModeling.swift */; };
+ 46C3B7D829E5E55000F8F57C /* LocationsListCoordination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C3B7D729E5E55000F8F57C /* LocationsListCoordination.swift */; };
+ 46C3B7DC29E5ED2300F8F57C /* LocationsAddCoordination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C3B7DB29E5ED2300F8F57C /* LocationsAddCoordination.swift */; };
+ 46C3B7DE29E5ED2E00F8F57C /* LocationsAddCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C3B7DD29E5ED2E00F8F57C /* LocationsAddCoordinator.swift */; };
46EB331B29E1CE04001D5EAF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46EB331A29E1CE04001D5EAF /* AppDelegate.swift */; };
- 46EB331D29E1CE04001D5EAF /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46EB331C29E1CE04001D5EAF /* SceneDelegate.swift */; };
- 46EB331F29E1CE04001D5EAF /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46EB331E29E1CE04001D5EAF /* ViewController.swift */; };
+ 46EB331F29E1CE04001D5EAF /* LocationsListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46EB331E29E1CE04001D5EAF /* LocationsListViewController.swift */; };
46EB332729E1CE05001D5EAF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 46EB332629E1CE05001D5EAF /* Assets.xcassets */; };
46EB332A29E1CE05001D5EAF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46EB332829E1CE05001D5EAF /* LaunchScreen.storyboard */; };
46EB334429E1D1EC001D5EAF /* Libraries in Frameworks */ = {isa = PBXBuildFile; productRef = 46EB334329E1D1EC001D5EAF /* Libraries */; };
@@ -111,11 +121,21 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
+ 02031EBE29E5F949003C108C /* LocationsAddViewModeling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsAddViewModeling.swift; sourceTree = ""; };
+ 02031EC529E5FEE4003C108C /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; };
+ 02031EC829E60B29003C108C /* DependencyService+Keys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DependencyService+Keys.swift"; sourceTree = ""; };
+ 46C3B7C529E5BF1500F8F57C /* LocationsListCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsListCoordinator.swift; sourceTree = ""; };
+ 46C3B7CA29E5CD3200F8F57C /* LocationsListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsListViewModel.swift; sourceTree = ""; };
+ 46C3B7CE29E5D00E00F8F57C /* LocationsAddViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsAddViewModel.swift; sourceTree = ""; };
+ 46C3B7D029E5D06D00F8F57C /* LocationsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsAddViewController.swift; sourceTree = ""; };
+ 46C3B7D529E5E50500F8F57C /* LocationsListViewModeling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsListViewModeling.swift; sourceTree = ""; };
+ 46C3B7D729E5E55000F8F57C /* LocationsListCoordination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsListCoordination.swift; sourceTree = ""; };
+ 46C3B7DB29E5ED2300F8F57C /* LocationsAddCoordination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsAddCoordination.swift; sourceTree = ""; };
+ 46C3B7DD29E5ED2E00F8F57C /* LocationsAddCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsAddCoordinator.swift; sourceTree = ""; };
46EB325829E1BD5C001D5EAF /* Wikipedia.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Wikipedia.xcodeproj; path = Wikipedia/Wikipedia.xcodeproj; sourceTree = ""; };
46EB331829E1CE04001D5EAF /* Locations.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Locations.app; sourceTree = BUILT_PRODUCTS_DIR; };
46EB331A29E1CE04001D5EAF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
- 46EB331C29E1CE04001D5EAF /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
- 46EB331E29E1CE04001D5EAF /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
+ 46EB331E29E1CE04001D5EAF /* LocationsListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsListViewController.swift; sourceTree = ""; };
46EB332629E1CE05001D5EAF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
46EB332929E1CE05001D5EAF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
46EB332B29E1CE05001D5EAF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
@@ -138,6 +158,85 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 02031EC429E5FEB1003C108C /* View Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ 02031EC529E5FEE4003C108C /* BaseViewController.swift */,
+ );
+ path = "View Controllers";
+ sourceTree = "";
+ };
+ 02031EC729E60ADB003C108C /* Extensions */ = {
+ isa = PBXGroup;
+ children = (
+ 02031EC829E60B29003C108C /* DependencyService+Keys.swift */,
+ );
+ path = Extensions;
+ sourceTree = "";
+ };
+ 0276C96029E5F5DC000B62AF /* Protocols */ = {
+ isa = PBXGroup;
+ children = (
+ 0276C96229E5F5ED000B62AF /* Coordination */,
+ 0276C96129E5F5E5000B62AF /* ViewModeling */,
+ );
+ path = Protocols;
+ sourceTree = "";
+ };
+ 0276C96129E5F5E5000B62AF /* ViewModeling */ = {
+ isa = PBXGroup;
+ children = (
+ 02031EBE29E5F949003C108C /* LocationsAddViewModeling.swift */,
+ 46C3B7D529E5E50500F8F57C /* LocationsListViewModeling.swift */,
+ );
+ path = ViewModeling;
+ sourceTree = "";
+ };
+ 0276C96229E5F5ED000B62AF /* Coordination */ = {
+ isa = PBXGroup;
+ children = (
+ 46C3B7DB29E5ED2300F8F57C /* LocationsAddCoordination.swift */,
+ 46C3B7D729E5E55000F8F57C /* LocationsListCoordination.swift */,
+ );
+ path = Coordination;
+ sourceTree = "";
+ };
+ 46C3B7C429E5BEE900F8F57C /* Coordinators */ = {
+ isa = PBXGroup;
+ children = (
+ 46C3B7DD29E5ED2E00F8F57C /* LocationsAddCoordinator.swift */,
+ 46C3B7C529E5BF1500F8F57C /* LocationsListCoordinator.swift */,
+ );
+ path = Coordinators;
+ sourceTree = "";
+ };
+ 46C3B7C929E5CB8F00F8F57C /* Screens */ = {
+ isa = PBXGroup;
+ children = (
+ 46C3B7CD29E5CFCD00F8F57C /* LocationsAdd */,
+ 46C3B7CC29E5CFBB00F8F57C /* LocationsList */,
+ );
+ path = Screens;
+ sourceTree = "";
+ };
+ 46C3B7CC29E5CFBB00F8F57C /* LocationsList */ = {
+ isa = PBXGroup;
+ children = (
+ 46EB331E29E1CE04001D5EAF /* LocationsListViewController.swift */,
+ 46C3B7CA29E5CD3200F8F57C /* LocationsListViewModel.swift */,
+ );
+ path = LocationsList;
+ sourceTree = "";
+ };
+ 46C3B7CD29E5CFCD00F8F57C /* LocationsAdd */ = {
+ isa = PBXGroup;
+ children = (
+ 46C3B7D029E5D06D00F8F57C /* LocationsAddViewController.swift */,
+ 46C3B7CE29E5D00E00F8F57C /* LocationsAddViewModel.swift */,
+ );
+ path = LocationsAdd;
+ sourceTree = "";
+ };
46EB325029E1BBD1001D5EAF = {
isa = PBXGroup;
children = (
@@ -200,8 +299,11 @@
isa = PBXGroup;
children = (
46EB331A29E1CE04001D5EAF /* AppDelegate.swift */,
- 46EB331C29E1CE04001D5EAF /* SceneDelegate.swift */,
- 46EB331E29E1CE04001D5EAF /* ViewController.swift */,
+ 0276C96029E5F5DC000B62AF /* Protocols */,
+ 02031EC729E60ADB003C108C /* Extensions */,
+ 46C3B7C429E5BEE900F8F57C /* Coordinators */,
+ 46C3B7C929E5CB8F00F8F57C /* Screens */,
+ 02031EC429E5FEB1003C108C /* View Controllers */,
);
path = Sources;
sourceTree = "";
@@ -407,9 +509,19 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 46EB331F29E1CE04001D5EAF /* ViewController.swift in Sources */,
+ 46C3B7C629E5BF1500F8F57C /* LocationsListCoordinator.swift in Sources */,
+ 46EB331F29E1CE04001D5EAF /* LocationsListViewController.swift in Sources */,
+ 02031EC629E5FEE4003C108C /* BaseViewController.swift in Sources */,
46EB331B29E1CE04001D5EAF /* AppDelegate.swift in Sources */,
- 46EB331D29E1CE04001D5EAF /* SceneDelegate.swift in Sources */,
+ 02031EBF29E5F949003C108C /* LocationsAddViewModeling.swift in Sources */,
+ 46C3B7DE29E5ED2E00F8F57C /* LocationsAddCoordinator.swift in Sources */,
+ 46C3B7DC29E5ED2300F8F57C /* LocationsAddCoordination.swift in Sources */,
+ 46C3B7D829E5E55000F8F57C /* LocationsListCoordination.swift in Sources */,
+ 46C3B7D629E5E50500F8F57C /* LocationsListViewModeling.swift in Sources */,
+ 46C3B7CF29E5D00E00F8F57C /* LocationsAddViewModel.swift in Sources */,
+ 02031EC929E60B29003C108C /* DependencyService+Keys.swift in Sources */,
+ 46C3B7D129E5D06D00F8F57C /* LocationsAddViewController.swift in Sources */,
+ 46C3B7CB29E5CD3200F8F57C /* LocationsListViewModel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};