Compare commits
18 Commits
main
...
setup/app-
Author | SHA1 | Date | |
---|---|---|---|
cb5b4743f2 | |||
83ed85b755 | |||
b73a8e1010 | |||
b9417244a4 | |||
9b14b79ea2 | |||
5e5653bbe2 | |||
c16b40652f | |||
0d824637ae | |||
8a0c7d95e0 | |||
8deadffe2a | |||
2d068de8ed | |||
0dfbe62603 | |||
b4b99dfa87 | |||
a55ba672da | |||
229bd1b878 | |||
0fe40095c7 | |||
30bb62e795 | |||
c3fc42d724 |
@ -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 }
|
||||
|
||||
}
|
@ -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 }
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
@ -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...
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
@ -1,23 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>Default Configuration</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict/>
|
||||
</plist>
|
||||
|
@ -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<UISceneSession>
|
||||
) {
|
||||
// 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.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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 {}
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -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()
|
||||
}
|
@ -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 {}
|
@ -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()
|
||||
|
||||
}
|
@ -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 }
|
||||
|
||||
}
|
@ -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()
|
||||
|
||||
}
|
@ -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.
|
||||
}
|
||||
|
||||
}
|
@ -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"
|
||||
}
|
||||
|
||||
}
|
@ -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 {}
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -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 = "<group>"; };
|
||||
02031EC529E5FEE4003C108C /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = "<group>"; };
|
||||
02031EC829E60B29003C108C /* DependencyService+Keys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DependencyService+Keys.swift"; sourceTree = "<group>"; };
|
||||
46C3B7C529E5BF1500F8F57C /* LocationsListCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsListCoordinator.swift; sourceTree = "<group>"; };
|
||||
46C3B7CA29E5CD3200F8F57C /* LocationsListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsListViewModel.swift; sourceTree = "<group>"; };
|
||||
46C3B7CE29E5D00E00F8F57C /* LocationsAddViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsAddViewModel.swift; sourceTree = "<group>"; };
|
||||
46C3B7D029E5D06D00F8F57C /* LocationsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsAddViewController.swift; sourceTree = "<group>"; };
|
||||
46C3B7D529E5E50500F8F57C /* LocationsListViewModeling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsListViewModeling.swift; sourceTree = "<group>"; };
|
||||
46C3B7D729E5E55000F8F57C /* LocationsListCoordination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsListCoordination.swift; sourceTree = "<group>"; };
|
||||
46C3B7DB29E5ED2300F8F57C /* LocationsAddCoordination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsAddCoordination.swift; sourceTree = "<group>"; };
|
||||
46C3B7DD29E5ED2E00F8F57C /* LocationsAddCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsAddCoordinator.swift; sourceTree = "<group>"; };
|
||||
46EB325829E1BD5C001D5EAF /* Wikipedia.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Wikipedia.xcodeproj; path = Wikipedia/Wikipedia.xcodeproj; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
46EB331C29E1CE04001D5EAF /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
46EB331E29E1CE04001D5EAF /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
46EB331E29E1CE04001D5EAF /* LocationsListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsListViewController.swift; sourceTree = "<group>"; };
|
||||
46EB332629E1CE05001D5EAF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
46EB332929E1CE05001D5EAF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
46EB332B29E1CE05001D5EAF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@ -138,6 +158,85 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
02031EC429E5FEB1003C108C /* View Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
02031EC529E5FEE4003C108C /* BaseViewController.swift */,
|
||||
);
|
||||
path = "View Controllers";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
02031EC729E60ADB003C108C /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
02031EC829E60B29003C108C /* DependencyService+Keys.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0276C96029E5F5DC000B62AF /* Protocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0276C96229E5F5ED000B62AF /* Coordination */,
|
||||
0276C96129E5F5E5000B62AF /* ViewModeling */,
|
||||
);
|
||||
path = Protocols;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0276C96129E5F5E5000B62AF /* ViewModeling */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
02031EBE29E5F949003C108C /* LocationsAddViewModeling.swift */,
|
||||
46C3B7D529E5E50500F8F57C /* LocationsListViewModeling.swift */,
|
||||
);
|
||||
path = ViewModeling;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0276C96229E5F5ED000B62AF /* Coordination */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46C3B7DB29E5ED2300F8F57C /* LocationsAddCoordination.swift */,
|
||||
46C3B7D729E5E55000F8F57C /* LocationsListCoordination.swift */,
|
||||
);
|
||||
path = Coordination;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
46C3B7C429E5BEE900F8F57C /* Coordinators */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46C3B7DD29E5ED2E00F8F57C /* LocationsAddCoordinator.swift */,
|
||||
46C3B7C529E5BF1500F8F57C /* LocationsListCoordinator.swift */,
|
||||
);
|
||||
path = Coordinators;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
46C3B7C929E5CB8F00F8F57C /* Screens */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46C3B7CD29E5CFCD00F8F57C /* LocationsAdd */,
|
||||
46C3B7CC29E5CFBB00F8F57C /* LocationsList */,
|
||||
);
|
||||
path = Screens;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
46C3B7CC29E5CFBB00F8F57C /* LocationsList */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46EB331E29E1CE04001D5EAF /* LocationsListViewController.swift */,
|
||||
46C3B7CA29E5CD3200F8F57C /* LocationsListViewModel.swift */,
|
||||
);
|
||||
path = LocationsList;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
46C3B7CD29E5CFCD00F8F57C /* LocationsAdd */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
46C3B7D029E5D06D00F8F57C /* LocationsAddViewController.swift */,
|
||||
46C3B7CE29E5D00E00F8F57C /* LocationsAddViewModel.swift */,
|
||||
);
|
||||
path = LocationsAdd;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
@ -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;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user