diff --git a/.github/workflows/pr_status.yml b/.github/workflows/pr_status.yml index 20bcb29..4827269 100644 --- a/.github/workflows/pr_status.yml +++ b/.github/workflows/pr_status.yml @@ -26,6 +26,8 @@ jobs: - 'Projects/DesignSystem/**' home: - 'Projects/Home/**' + detail: + - 'Projects/Detail/**' - name: Generate matrix id: matrix run: | @@ -45,6 +47,10 @@ jobs: if [ "${{ steps.filter.outputs.home }}" == "true" ]; then targets+=("Home") fi + + if [ "${{ steps.filter.outputs.detail }}" == "true" ]; then + targets+=("Detail") + fi if [ ${#targets[@]} -gt 0 ]; then matrix="{\"target\": [$(printf '"%s",' "${targets[@]}" | sed 's/,$//')]}" diff --git a/Projects/App/Project.swift b/Projects/App/Project.swift index bde3044..3d4769a 100644 --- a/Projects/App/Project.swift +++ b/Projects/App/Project.swift @@ -12,6 +12,10 @@ let dependecies: [TargetDependency] = [ path: "../Home"), .project(target: "HomeInterfaces", path: "../Home"), + .project(target: "Detail", + path: "../Detail"), + .project(target: "DetailInterfaces", + path: "../Detail"), .project(target: "NavigationInterfaces", path: "../Navigation"), .external(name: "Networking"), diff --git a/Projects/App/Sources/Assemblies/CoordinatorAssembly.swift b/Projects/App/Sources/Assemblies/CoordinatorAssembly.swift index 6294188..04071b4 100644 --- a/Projects/App/Sources/Assemblies/CoordinatorAssembly.swift +++ b/Projects/App/Sources/Assemblies/CoordinatorAssembly.swift @@ -6,6 +6,8 @@ // // import DependencyInjectionInterfaces +import Detail +import DetailInterfaces import HomeInterfaces import Home import NavigationInterfaces @@ -31,5 +33,21 @@ public struct CoordinatorAssembly { return HomeCoordinator(parentCoordinator: parentCoordinator, navigationController: navigationController) } + + injector.register(DetailCoordinating.self) { (_, arg: (UINavigationController, Coordinator?, Exchange)) in + let (navigationController, parentCoordinator, exchange) = arg + + return DetailCoordinator(parentCoordinator: parentCoordinator, + navigationController: navigationController, + exchange: exchange) + } + + injector.register(DetailCoordinating.self) { (_, arg: (UINavigationController, Coordinator?, Int)) in + let (navigationController, parentCoordinator, exchangeId) = arg + + return DetailCoordinator(parentCoordinator: parentCoordinator, + navigationController: navigationController, + exchangeId: exchangeId) + } } } diff --git a/Projects/App/Sources/Coordinator/AppCoordinator.swift b/Projects/App/Sources/Coordinator/AppCoordinator.swift index 124ee30..a364e14 100644 --- a/Projects/App/Sources/Coordinator/AppCoordinator.swift +++ b/Projects/App/Sources/Coordinator/AppCoordinator.swift @@ -29,7 +29,7 @@ final class AppCoordinator: AppCoordinating { let homeCoordinator = resolver.resolve(HomeCoordinating.self, argument: arg) - + children.append(homeCoordinator) homeCoordinator.start() } } diff --git a/Projects/App/Tests/Application/AppDelegateTests.swift b/Projects/App/Tests/Application/AppDelegateTests.swift index 9f7cd17..85c87ef 100644 --- a/Projects/App/Tests/Application/AppDelegateTests.swift +++ b/Projects/App/Tests/Application/AppDelegateTests.swift @@ -8,9 +8,11 @@ import Testing import DependencyInjectionInterfaces -import NetworkingInterfaces +import DetailInterfaces import HomeInterfaces import NavigationInterfaces +import NavigationTesting +import NetworkingInterfaces import UIKit @testable import App @@ -62,15 +64,45 @@ struct AppDelegateTests { func homeCoordinatorRegister() async throws { #expect(throws: Never.self) { let navigation = UINavigationController() - let parentCoordinator: Coordinator? = SharedContainer + let parentCoordinator: Coordinator? = CoordinatorSpy(children: [], + navigationController: navigation) + + _ = SharedContainer .shared .resolver() - .resolve(AppCoordinating.self, argument: navigation) - + .resolve(HomeCoordinating.self, argument: (navigation, parentCoordinator)) + } + } + + @Test("GIVEN AppDelegate initialize THEN it SHOULD register DI DetailCoordinating with Exchange") + func detailCoordinatorRegister() async throws { + #expect(throws: Never.self) { + let navigation = UINavigationController() + let exchange = Exchange(summary: .init(id: 0, name: "exchange")) + + let parentCoordinator: Coordinator? = CoordinatorSpy(children: [], + navigationController: navigation) + _ = SharedContainer .shared .resolver() - .resolve(HomeCoordinating.self, argument: (navigation, parentCoordinator)) + .resolve(DetailCoordinating.self, argument: (navigation, parentCoordinator, exchange)) + } + } + + @Test("GIVEN AppDelegate initialize THEN it SHOULD register DI DetailCoordinating with Exchange identifier") + func detailWithIdentifierCoordinatorRegister() async throws { + #expect(throws: Never.self) { + let navigation = UINavigationController() + let exchangeId: Int = 21 + + let parentCoordinator: Coordinator? = CoordinatorSpy(children: [], + navigationController: navigation) + + _ = SharedContainer + .shared + .resolver() + .resolve(DetailCoordinating.self, argument: (navigation, parentCoordinator, exchangeId)) } } } diff --git a/Projects/Detail/Interfaces/DetailCoordinating.swift b/Projects/Detail/Interfaces/DetailCoordinating.swift new file mode 100644 index 0000000..0360436 --- /dev/null +++ b/Projects/Detail/Interfaces/DetailCoordinating.swift @@ -0,0 +1,12 @@ +// +// +// Created by Vitor Conceicao. +// +// github.com/vitor-rc1 +// +// + +import NavigationInterfaces +import UIKit + +public protocol DetailCoordinating: Coordinator {} diff --git a/Projects/Detail/Project.swift b/Projects/Detail/Project.swift new file mode 100644 index 0000000..9214e15 --- /dev/null +++ b/Projects/Detail/Project.swift @@ -0,0 +1,24 @@ +import ProjectDescription +import ProjectDescriptionHelpers + +let moduleName = "Detail" + +let dependecies: [TargetDependency] = [ + .project(target: "DependencyInjectionInterfaces", + path: "../DependencyInjection"), + .project(target: "DesignSystem", + path: "../DesignSystem"), + .project(target: "HomeInterfaces", + path: "../Home"), + .external(name: "NetworkingInterfaces"), +] + +let interfaceDependecies: [TargetDependency] = [ + .project(target: "NavigationInterfaces", + path: "../Navigation"), +] + +let project = Project.templateModule(named: moduleName, + targets: [.source, .interfaces, .test], + dependencies: dependecies, + interfaceDependecies: interfaceDependecies) diff --git a/Projects/Detail/Sources/Coordinator/DetailCoordinator.swift b/Projects/Detail/Sources/Coordinator/DetailCoordinator.swift new file mode 100644 index 0000000..e3525b5 --- /dev/null +++ b/Projects/Detail/Sources/Coordinator/DetailCoordinator.swift @@ -0,0 +1,42 @@ +import UIKit +import DetailInterfaces +import DependencyInjectionInterfaces +import HomeInterfaces +import NavigationInterfaces +import NetworkingInterfaces + +@MainActor +public final class DetailCoordinator: DetailCoordinating { + // MARK: - Properties + + public weak var parentCoordinator: Coordinator? + public var children: [Coordinator] = [] + public var navigationController: UINavigationController + + private var exchange: Exchange? + private var exchangeId: Int? + + // MARK: - Initialization + + public init(parentCoordinator: Coordinator?, + navigationController: UINavigationController, + exchange: Exchange) { + self.parentCoordinator = parentCoordinator + self.navigationController = navigationController + self.exchange = exchange + } + + public init(parentCoordinator: Coordinator?, + navigationController: UINavigationController, + exchangeId: Int) { + self.parentCoordinator = parentCoordinator + self.navigationController = navigationController + self.exchangeId = exchangeId + } + + // MARK: - DetailCoordinating + + public func start() { + + } +} diff --git a/Projects/Detail/Tests/PlaceHolder.swift b/Projects/Detail/Tests/PlaceHolder.swift new file mode 100644 index 0000000..e69de29 diff --git a/Projects/Home/Interfaces/HomeCoordinating.swift b/Projects/Home/Interfaces/Coordinator/HomeCoordinating.swift similarity index 100% rename from Projects/Home/Interfaces/HomeCoordinating.swift rename to Projects/Home/Interfaces/Coordinator/HomeCoordinating.swift diff --git a/Projects/Home/Interfaces/Model/Exchange.swift b/Projects/Home/Interfaces/Model/Exchange.swift new file mode 100644 index 0000000..bf63b73 --- /dev/null +++ b/Projects/Home/Interfaces/Model/Exchange.swift @@ -0,0 +1,61 @@ +// +// +// Created by Vitor Conceicao. +// +// github.com/vitor-rc1 +// +// + +import Foundation + +public struct Exchange: Equatable, Identifiable { + public let id: Int + public let name: String + public let description: String? + public let logo: String + public let spotVolumeUsd: Double? + public let makerFee: Double + public let takerFee: Double + public let dateLaunched: String + public let websiteUrl: String? + public let twitterUrl: String? + + public let isLoadingDetails: Bool + + public init(id: Int, + name: String, + description: String? = nil, + logo: String, + spotVolumeUsd: Double? = nil, + makerFee: Double, + takerFee: Double, + dateLaunched: String, + websiteUrl: String? = nil, + twitterUrl: String? = nil) { + self.id = id + self.name = name + self.description = description + self.logo = logo + self.spotVolumeUsd = spotVolumeUsd + self.makerFee = makerFee + self.takerFee = takerFee + self.dateLaunched = dateLaunched + self.websiteUrl = websiteUrl + self.twitterUrl = twitterUrl + self.isLoadingDetails = false + } + + public init(summary: ExchangeSummary) { + self.id = summary.id + self.name = summary.name + self.description = nil + self.logo = "" + self.spotVolumeUsd = nil + self.makerFee = 0.0 + self.takerFee = 0.0 + self.dateLaunched = "" + self.websiteUrl = nil + self.twitterUrl = nil + self.isLoadingDetails = true + } +} diff --git a/Projects/Home/Interfaces/Model/ExchangeSummary.swift b/Projects/Home/Interfaces/Model/ExchangeSummary.swift new file mode 100644 index 0000000..c38c402 --- /dev/null +++ b/Projects/Home/Interfaces/Model/ExchangeSummary.swift @@ -0,0 +1,19 @@ +// +// +// Created by Vitor Conceicao. +// +// github.com/vitor-rc1 +// +// + +import Foundation + +public struct ExchangeSummary: Sendable, Equatable, Codable { + public let id: Int + public let name: String + + public init(id: Int, name: String) { + self.id = id + self.name = name + } +} diff --git a/Projects/Home/Interfaces/Model/Status.swift b/Projects/Home/Interfaces/Model/Status.swift new file mode 100644 index 0000000..7de661a --- /dev/null +++ b/Projects/Home/Interfaces/Model/Status.swift @@ -0,0 +1,39 @@ +// +// +// Created by Vitor Conceicao. +// +// github.com/vitor-rc1 +// +// + +import Foundation + +public struct Status: Equatable { + let timestamp: String + let errorCode: Int? + let errorMessage: String? + let elapsed: Int + let creditCount: Int + + public init(timestamp: String, + errorCode: Int? = nil, + errorMessage: String? = nil, + elapsed: Int, + creditCount: Int) { + self.timestamp = timestamp + self.errorCode = errorCode + self.errorMessage = errorMessage + self.elapsed = elapsed + self.creditCount = creditCount + } +} + +extension Status: Codable { + public enum CodingKeys: String, CodingKey { + case timestamp + case errorCode = "error_code" + case errorMessage = "error_message" + case elapsed + case creditCount = "credit_count" + } +} diff --git a/Projects/Home/Project.swift b/Projects/Home/Project.swift index b1e2751..42584f7 100644 --- a/Projects/Home/Project.swift +++ b/Projects/Home/Project.swift @@ -7,7 +7,9 @@ let dependecies: [TargetDependency] = [ .project(target: "DependencyInjectionInterfaces", path: "../DependencyInjection"), .project(target: "DesignSystem", - path: "../DesignSystem"), + path: "../DesignSystem"), + .project(target: "DetailInterfaces", + path: "../Detail"), .external(name: "NetworkingInterfaces"), ] diff --git a/Projects/Home/Sources/Coordinator/HomeCoordinator.swift b/Projects/Home/Sources/Coordinator/HomeCoordinator.swift index 2206557..5c3e911 100644 --- a/Projects/Home/Sources/Coordinator/HomeCoordinator.swift +++ b/Projects/Home/Sources/Coordinator/HomeCoordinator.swift @@ -7,6 +7,7 @@ // import DependencyInjectionInterfaces +import DetailInterfaces import HomeInterfaces import NavigationInterfaces import NetworkingInterfaces @@ -35,5 +36,14 @@ public final class HomeCoordinator: HomeCoordinating { } extension HomeCoordinator: HomeViewModelCoordinatorDelegate { - func navigateToDetails(of exchange: Exchange) {} + func navigateToDetails(of exchange: Exchange) { + let resolver = SharedContainer.shared.resolver() + let arg: (UINavigationController, Coordinator?, Exchange) = (navigationController, self, exchange) + + let detailCoordinator = resolver.resolve(DetailCoordinating.self, + argument: arg) + + children.append(detailCoordinator) + detailCoordinator.start() + } } diff --git a/Projects/Home/Sources/Model/Exchange.swift b/Projects/Home/Sources/Model/Exchange.swift deleted file mode 100644 index bb5e0c9..0000000 --- a/Projects/Home/Sources/Model/Exchange.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// -// Created by Vitor Conceicao. -// -// github.com/vitor-rc1 -// -// - -import Foundation - -struct Exchange: Equatable, Identifiable { - let id: Int - let name: String - let description: String? - let logo: String - let spotVolumeUsd: Double? - let makerFee: Double - let takerFee: Double - let dateLaunched: String - let websiteUrl: String? - let twitterUrl: String? - - let isLoadingDetails: Bool - - init(id: Int, - name: String, - description: String? = nil, - logo: String, - spotVolumeUsd: Double? = nil, - makerFee: Double, - takerFee: Double, - dateLaunched: String, - websiteUrl: String? = nil, - twitterUrl: String? = nil) { - self.id = id - self.name = name - self.description = description - self.logo = logo - self.spotVolumeUsd = spotVolumeUsd - self.makerFee = makerFee - self.takerFee = takerFee - self.dateLaunched = dateLaunched - self.websiteUrl = websiteUrl - self.twitterUrl = twitterUrl - self.isLoadingDetails = false - } - - init(summary: ExchangeSummary) { - self.id = summary.id - self.name = summary.name - self.description = nil - self.logo = "" - self.spotVolumeUsd = nil - self.makerFee = 0.0 - self.takerFee = 0.0 - self.dateLaunched = "" - self.websiteUrl = nil - self.twitterUrl = nil - self.isLoadingDetails = true - } -} diff --git a/Projects/Home/Sources/Model/ExchangeDetailResponse.swift b/Projects/Home/Sources/Model/ExchangeDetailResponse.swift index dd4bd38..08d809e 100644 --- a/Projects/Home/Sources/Model/ExchangeDetailResponse.swift +++ b/Projects/Home/Sources/Model/ExchangeDetailResponse.swift @@ -7,6 +7,7 @@ // import Foundation +import HomeInterfaces struct ExchangeDetailResponse: Codable { let status: Status diff --git a/Projects/Home/Sources/Model/ExchangeResponse.swift b/Projects/Home/Sources/Model/ExchangeResponse.swift index 318aa80..8bdc7a5 100644 --- a/Projects/Home/Sources/Model/ExchangeResponse.swift +++ b/Projects/Home/Sources/Model/ExchangeResponse.swift @@ -7,6 +7,7 @@ // import Foundation +import HomeInterfaces struct ExchangeResponse: Codable { let status: Status diff --git a/Projects/Home/Sources/Model/ExchangeSummary.swift b/Projects/Home/Sources/Model/ExchangeSummary.swift deleted file mode 100644 index 57f83e1..0000000 --- a/Projects/Home/Sources/Model/ExchangeSummary.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// -// Created by Vitor Conceicao. -// -// github.com/vitor-rc1 -// -// - -import Foundation - -struct ExchangeSummary: Equatable, Codable { - let id: Int - let name: String -} diff --git a/Projects/Home/Sources/Model/Status.swift b/Projects/Home/Sources/Model/Status.swift deleted file mode 100644 index f848afa..0000000 --- a/Projects/Home/Sources/Model/Status.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// -// Created by Vitor Conceicao. -// -// github.com/vitor-rc1 -// -// - -import Foundation - -struct Status: Equatable { - let timestamp: String - let errorCode: Int? - let errorMessage: String? - let elapsed: Int - let creditCount: Int -} - -extension Status: Codable { - enum CodingKeys: String, CodingKey { - case timestamp - case errorCode = "error_code" - case errorMessage = "error_message" - case elapsed - case creditCount = "credit_count" - } -} diff --git a/Projects/Home/Sources/Protocols/HomeServiceProtocol.swift b/Projects/Home/Sources/Protocols/HomeServiceProtocol.swift index 00fbce6..d541887 100644 --- a/Projects/Home/Sources/Protocols/HomeServiceProtocol.swift +++ b/Projects/Home/Sources/Protocols/HomeServiceProtocol.swift @@ -6,6 +6,7 @@ // // +import HomeInterfaces import Foundation protocol HomeServiceProtocol: AnyObject, Sendable { diff --git a/Projects/Home/Sources/Protocols/HomeViewModelCoordinatorDelegate.swift b/Projects/Home/Sources/Protocols/HomeViewModelCoordinatorDelegate.swift index 53df5d6..a5ef733 100644 --- a/Projects/Home/Sources/Protocols/HomeViewModelCoordinatorDelegate.swift +++ b/Projects/Home/Sources/Protocols/HomeViewModelCoordinatorDelegate.swift @@ -5,8 +5,9 @@ // github.com/vitor-rc1 // // - + import Foundation +import HomeInterfaces @MainActor protocol HomeViewModelCoordinatorDelegate: AnyObject { diff --git a/Projects/Home/Sources/Protocols/HomeViewModelProtocol.swift b/Projects/Home/Sources/Protocols/HomeViewModelProtocol.swift index 5d6fe8a..d8cb8c3 100644 --- a/Projects/Home/Sources/Protocols/HomeViewModelProtocol.swift +++ b/Projects/Home/Sources/Protocols/HomeViewModelProtocol.swift @@ -6,6 +6,7 @@ // // +import HomeInterfaces import Foundation @MainActor diff --git a/Projects/Home/Sources/Service/HomeService.swift b/Projects/Home/Sources/Service/HomeService.swift index b07ed9c..69b70a6 100644 --- a/Projects/Home/Sources/Service/HomeService.swift +++ b/Projects/Home/Sources/Service/HomeService.swift @@ -7,6 +7,7 @@ // import Foundation +import HomeInterfaces import NetworkingInterfaces enum ServiceError: Error, Equatable { diff --git a/Projects/Home/Sources/ViewModel/HomeViewModel.swift b/Projects/Home/Sources/ViewModel/HomeViewModel.swift index c237f41..5385a63 100644 --- a/Projects/Home/Sources/ViewModel/HomeViewModel.swift +++ b/Projects/Home/Sources/ViewModel/HomeViewModel.swift @@ -1,3 +1,12 @@ +// +// +// Created by Vitor Conceicao. +// +// github.com/vitor-rc1 +// +// + +import HomeInterfaces import Foundation @MainActor diff --git a/Projects/Home/Tests/Doubles/HomeServiceProtocolSpy.swift b/Projects/Home/Tests/Doubles/HomeServiceProtocolSpy.swift index c801368..a98bf23 100644 --- a/Projects/Home/Tests/Doubles/HomeServiceProtocolSpy.swift +++ b/Projects/Home/Tests/Doubles/HomeServiceProtocolSpy.swift @@ -7,6 +7,8 @@ // import Foundation +import HomeInterfaces + @testable import Home @MainActor diff --git a/Projects/Home/Tests/Doubles/HomeViewModelCoordinatorDelegateSpy.swift b/Projects/Home/Tests/Doubles/HomeViewModelCoordinatorDelegateSpy.swift index 8ca5226..851c331 100644 --- a/Projects/Home/Tests/Doubles/HomeViewModelCoordinatorDelegateSpy.swift +++ b/Projects/Home/Tests/Doubles/HomeViewModelCoordinatorDelegateSpy.swift @@ -7,6 +7,8 @@ // import Foundation +import HomeInterfaces + @testable import Home @MainActor diff --git a/Projects/Home/Tests/Doubles/HomeViewModelSpy.swift b/Projects/Home/Tests/Doubles/HomeViewModelSpy.swift index 28f4feb..7f94512 100644 --- a/Projects/Home/Tests/Doubles/HomeViewModelSpy.swift +++ b/Projects/Home/Tests/Doubles/HomeViewModelSpy.swift @@ -7,6 +7,8 @@ // import Foundation +import HomeInterfaces + @testable import Home @MainActor diff --git a/Projects/Home/Tests/Service/HomeServiceTests.swift b/Projects/Home/Tests/Service/HomeServiceTests.swift index a809a58..728d73c 100644 --- a/Projects/Home/Tests/Service/HomeServiceTests.swift +++ b/Projects/Home/Tests/Service/HomeServiceTests.swift @@ -6,8 +6,10 @@ // // -import Testing +import HomeInterfaces import Foundation +import Testing + @testable import Home @Suite diff --git a/Projects/Home/Tests/View/HomeViewControllerTests.swift b/Projects/Home/Tests/View/HomeViewControllerTests.swift index 27f39ce..6489f1b 100644 --- a/Projects/Home/Tests/View/HomeViewControllerTests.swift +++ b/Projects/Home/Tests/View/HomeViewControllerTests.swift @@ -6,8 +6,10 @@ // // +import HomeInterfaces import Testing import UIKit + @testable import Home @MainActor diff --git a/Projects/Home/Tests/ViewModel/HomeViewModelTests.swift b/Projects/Home/Tests/ViewModel/HomeViewModelTests.swift index ff84313..9b182c0 100644 --- a/Projects/Home/Tests/ViewModel/HomeViewModelTests.swift +++ b/Projects/Home/Tests/ViewModel/HomeViewModelTests.swift @@ -6,8 +6,10 @@ // // -import Testing import Foundation +import HomeInterfaces +import Testing + @testable import Home @MainActor diff --git a/Projects/Navigation/Testing/CoordinatorSpy.swift b/Projects/Navigation/Testing/CoordinatorSpy.swift index 2c0ee6f..0aa20d9 100644 --- a/Projects/Navigation/Testing/CoordinatorSpy.swift +++ b/Projects/Navigation/Testing/CoordinatorSpy.swift @@ -20,7 +20,7 @@ public final class CoordinatorSpy: Coordinator { public var navigationController: UINavigationController public init(parentCoordinator: Coordinator? = nil, - children: [Coordinator], + children: [Coordinator] = [], navigationController: UINavigationController) { self.parentCoordinator = parentCoordinator self.children = children diff --git a/Tuist/Package.swift b/Tuist/Package.swift index f545677..9cc58a7 100644 --- a/Tuist/Package.swift +++ b/Tuist/Package.swift @@ -5,7 +5,11 @@ import PackageDescription import ProjectDescription let packageSettings = PackageSettings( - productTypes: [:] + productTypes: [ + "Swinject": .framework, + "NetworkingInterfaces": .framework, + "Networking": .framework + ] ) #endif diff --git a/Workspace.swift b/Workspace.swift index de4324c..cd635ed 100644 --- a/Workspace.swift +++ b/Workspace.swift @@ -7,7 +7,8 @@ let workspace = Workspace( "./Projects/App", "./Projects/DependencyInjection", "./Projects/DesignSystem", - "./Projects/Home" + "./Projects/Home", + "./Projects/Detail" ], schemes: [], generationOptions: .options(autogeneratedWorkspaceSchemes: .disabled)