diff --git a/.github/workflows/deploy_ios_firebase.yml b/.github/workflows/deploy_ios_firebase.yml index 8ff46f47..85edf70d 100644 --- a/.github/workflows/deploy_ios_firebase.yml +++ b/.github/workflows/deploy_ios_firebase.yml @@ -16,20 +16,6 @@ defaults: working-directory: iosApp jobs: - Lint: - name: lint - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Run SwiftLint - uses: norio-nomura/action-swiftlint@3.1.0 - with: - args: --strict - build: name: Build runs-on: macOS-latest @@ -49,6 +35,15 @@ jobs: # Set fetch-depth (default: 1) to get whole tree with: fetch-depth: 0 + submodules: recursive + + - name: Setup Konfig Properties + env: + KMM_KONFIG_PROPERTIES: ${{ secrets.KMM_KONFIG_PROPERTIES }} + run: | + cd ../buildSrc/src/main/kotlin/myPackage + touch BuildKonfig.kt + echo $KMM_KONFIG_PROPERTIES | base64 --decode > BuildKonfig.kt - name: Install SSH key uses: webfactory/ssh-agent@v0.5.4 diff --git a/.github/workflows/deploy_ios_release_firebase.yml b/.github/workflows/deploy_ios_release_firebase.yml index 211595c5..83e29a0e 100644 --- a/.github/workflows/deploy_ios_release_firebase.yml +++ b/.github/workflows/deploy_ios_release_firebase.yml @@ -16,20 +16,6 @@ defaults: working-directory: iosApp jobs: - Lint: - name: lint - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Run SwiftLint - uses: norio-nomura/action-swiftlint@3.1.0 - with: - args: --strict - build: name: Build runs-on: macOS-latest @@ -49,6 +35,15 @@ jobs: # Set fetch-depth (default: 1) to get whole tree with: fetch-depth: 0 + submodules: recursive + + - name: Setup Konfig Properties + env: + KMM_KONFIG_PROPERTIES: ${{ secrets.KMM_KONFIG_PROPERTIES }} + run: | + cd ../buildSrc/src/main/kotlin/appPackage + touch BuildKonfig.kt + echo $KMM_KONFIG_PROPERTIES | base64 --decode > BuildKonfig.kt - name: Install SSH key uses: webfactory/ssh-agent@v0.5.4 diff --git a/.github/workflows/ios_review_pull_request.yml b/.github/workflows/ios_review_pull_request.yml index 454ce576..e9d43880 100644 --- a/.github/workflows/ios_review_pull_request.yml +++ b/.github/workflows/ios_review_pull_request.yml @@ -41,6 +41,16 @@ jobs: - name: Checkout source code uses: actions/checkout@v2.3.2 + with: + submodules: recursive + + - name: Setup Konfig Properties + env: + KMM_KONFIG_PROPERTIES: ${{ secrets.KMM_KONFIG_PROPERTIES }} + run: | + cd ../buildSrc/src/main/kotlin/appPackage + touch BuildKonfig.kt + echo $KMM_KONFIG_PROPERTIES | base64 --decode > BuildKonfig.kt - name: Cache gems uses: actions/cache@v2 diff --git a/.github/workflows/kmm_review_pull_request.yml b/.github/workflows/kmm_review_pull_request.yml index da0b5c99..2843f6d6 100644 --- a/.github/workflows/kmm_review_pull_request.yml +++ b/.github/workflows/kmm_review_pull_request.yml @@ -22,6 +22,16 @@ jobs: - name: Checkout source code uses: actions/checkout@v2.3.2 + with: + submodules: recursive + + - name: Setup Konfig Properties + env: + KMM_KONFIG_PROPERTIES: ${{ secrets.KMM_KONFIG_PROPERTIES }} + run: | + cd buildSrc/src/main/kotlin/appPackage + touch BuildKonfig.kt + echo $KMM_KONFIG_PROPERTIES | base64 --decode > BuildKonfig.kt - name: Run Detekt run: ./gradlew shared:detekt diff --git a/.gitignore b/.gitignore index 9ce0922c..ca9cde12 100644 --- a/.gitignore +++ b/.gitignore @@ -89,4 +89,5 @@ iosApp/DerivedData # JetBrains IDEs .idea -**/GoogleService-*.plist +GoogleService-*.plist +buildSrc/src/main/kotlin/appPackage/BuildKonfig.kt diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..504423d3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "nimble-jsonapi-kotlin"] + path = nimble-jsonapi-kotlin + url = git@github.com:blyscuit/nimble-jsonapi-kotlin.git diff --git a/Dangerfile b/Dangerfile index 8afd2e9b..9ea330c7 100644 --- a/Dangerfile +++ b/Dangerfile @@ -22,7 +22,7 @@ Dir[detekt_dir].each do |file_name| end # Android Lint output check -lint_dir = "**/build/reports/lint-result-debug.xml" +lint_dir = "**/build/reports/lint-results-debug.xml" Dir[lint_dir].each do |file_name| android_lint.skip_gradle_task = true android_lint.report_file = file_name diff --git a/build.gradle.kts b/build.gradle.kts index 0e5dbcc4..0631326c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,17 +5,18 @@ buildscript { mavenCentral() } dependencies { - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10") - classpath("com.android.tools.build:gradle:7.2.2") - classpath("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.21.0") - classpath("org.jetbrains.kotlinx:kover:0.6.0") + classpath(Dependency.KOTLIN_GRADLE_PLUGIN) + classpath(Dependency.GRADLE) + classpath(Dependency.DETEKT) + classpath(Dependency.KOVER) + classpath(Dependency.KOTLIN_SERIALIZATION) + classpath(Dependency.BUILD_KONFIG) } } allprojects { apply { - plugin("jacoco") - plugin("kover") + plugin(Plugin.KOVER) } repositories { google() diff --git a/buildSrc/src/main/kotlin/appPackage/BuildKonfig.kt.example b/buildSrc/src/main/kotlin/appPackage/BuildKonfig.kt.example new file mode 100644 index 00000000..8423b3ac --- /dev/null +++ b/buildSrc/src/main/kotlin/appPackage/BuildKonfig.kt.example @@ -0,0 +1,10 @@ +object BuildKonfig { + const val CLIENT_ID = "" + const val CLIENT_SECRET = "" + const val STAGING_BASE_URL = "" + const val PRODUCTION_BASE_URL = "" + const val CLIENT_ID_STAGING = "" + const val CLIENT_SECRET_STAGING = "" + const val UI_TEST_EMAIL = "" + const val UI_TEST_PASSWORD = "" +} diff --git a/buildSrc/src/main/kotlin/appPackage/Dependency.kt b/buildSrc/src/main/kotlin/appPackage/Dependency.kt new file mode 100644 index 00000000..7ef15ec1 --- /dev/null +++ b/buildSrc/src/main/kotlin/appPackage/Dependency.kt @@ -0,0 +1,38 @@ +object Dependency { + + // Kotlin + const val KOTLIN_GRADLE_PLUGIN = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Version.KOTLIN}" + const val GRADLE = "com.android.tools.build:gradle:${Version.GRADLE}" + const val KOTLIN_SERIALIZATION = "org.jetbrains.kotlin:kotlin-serialization:${Version.KOTLIN}" + const val KOTLIN_TEST = "org.jetbrains.kotlin:kotlin-test:${Version.KOTLIN}" + + // Kotlinx + const val COROUTINES_CORE = "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Version.COROUTINES_CORE}" + const val KOVER = "org.jetbrains.kotlinx:kover:${Version.KOVER}" + const val KOTLINX_SERIALIZATION = "org.jetbrains.kotlinx:kotlinx-serialization-core:${Version.KOTLINX_SERIALIZATION}" + const val COROUTINES_TEST = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Version.COROUTINES_CORE}" + + // DETEKT + const val DETEKT = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:${Version.DETEKT}" + + // Ktor + const val KTOR_CORE = "io.ktor:ktor-client-core:${Version.KTOR}" + const val KTOR_SERIALIZATION = "io.ktor:ktor-client-serialization:${Version.KTOR}" + const val KTOR_LOGGING = "io.ktor:ktor-client-logging:${Version.KTOR}" + const val KTOR_CONTENT_NEGOTIATION = "io.ktor:ktor-client-content-negotiation:${Version.KTOR}" + const val KTOR_JSON = "io.ktor:ktor-serialization-kotlinx-json:${Version.KTOR}" + const val KTOR_ANDROID = "io.ktor:ktor-client-android:${Version.KTOR}" + const val KTOR_IOS = "io.ktor:ktor-client-ios:${Version.KTOR}" + const val KTOR_MOCK = "io.ktor:ktor-client-mock:${Version.KTOR}" + + // BuildKonfig + const val BUILD_KONFIG = "com.codingfeline.buildkonfig:buildkonfig-gradle-plugin:${Version.BUILD_KONFIG}" + + // Native Coroutines + const val NATIVE_COROUTINES = "com.rickclephas.kmp.nativecoroutines:${Version.NATIVE_COROUTINES_KOTLIN}" + + // Koin + const val KOIN = "io.insert-koin:koin-core:${Version.KOIN}" + const val KOIN_TEST = "io.insert-koin:koin-test:${Version.KOIN}" + const val KOIN_ANDROID = "io.insert-koin:koin-android:${Version.KOIN}" +} diff --git a/buildSrc/src/main/kotlin/appPackage/Module.kt b/buildSrc/src/main/kotlin/appPackage/Module.kt new file mode 100644 index 00000000..52a1c9c0 --- /dev/null +++ b/buildSrc/src/main/kotlin/appPackage/Module.kt @@ -0,0 +1,3 @@ +object Module { + const val JSONAPI_CORE = ":nimble-jsonapi-kotlin:core" +} diff --git a/buildSrc/src/main/kotlin/appPackage/Plugin.kt b/buildSrc/src/main/kotlin/appPackage/Plugin.kt new file mode 100644 index 00000000..e88443e0 --- /dev/null +++ b/buildSrc/src/main/kotlin/appPackage/Plugin.kt @@ -0,0 +1,16 @@ +object Plugin { + const val ANDROID_APPLICATION = "com.android.application" + const val GOOGLE_SERVICE = "com.google.gms.google-services" + const val ANDROID = "android" + + const val MULTIPLATFORM = "multiplatform" + const val COCOAPODS = "native.cocoapods" + const val ANDROID_LIBRARY = "com.android.library" + const val KOTLIN_SERIALIZATION = "plugin.serialization" + const val KOTLINX_SERIALIZATION = "kotlinx-serialization" + const val NATIVE_COROUTINES = "com.rickclephas.kmp.nativecoroutines" + const val BUILD_KONFIG = "com.codingfeline.buildkonfig" + + const val KOVER = "kover" + const val DETEKT = "io.gitlab.arturbosch.detekt" +} diff --git a/buildSrc/src/main/kotlin/appPackage/Versions.kt b/buildSrc/src/main/kotlin/appPackage/Versions.kt new file mode 100644 index 00000000..a16508ff --- /dev/null +++ b/buildSrc/src/main/kotlin/appPackage/Versions.kt @@ -0,0 +1,18 @@ +object Android { + const val COMPILE_SDK = 32 + const val TARGET_SDK = 32 + const val MIN_SDK = 26 +} + +object Version { + const val KOTLIN = "1.7.10" + const val GRADLE = "7.2.2" + const val COROUTINES_CORE = "1.6.4" + const val DETEKT = "1.21.0" + const val KTOR = "2.1.1" + const val KOVER = "0.6.0" + const val BUILD_KONFIG = "0.13.3" + const val KOTLINX_SERIALIZATION = "1.2.2" + const val NATIVE_COROUTINES_KOTLIN = "0.12.6-new-mm" + const val KOIN = "3.2.1" +} diff --git a/buildSrc/src/main/kotlin/myPackage/Versions.kt b/buildSrc/src/main/kotlin/myPackage/Versions.kt deleted file mode 100644 index 4189db85..00000000 --- a/buildSrc/src/main/kotlin/myPackage/Versions.kt +++ /dev/null @@ -1,5 +0,0 @@ -object Android { - const val COMPILE_SDK = 32 - const val TARGET_SDK = 32 - const val MIN_SDK = 26 -} diff --git a/gradle.properties b/gradle.properties index 3211eb81..0ad721b5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,4 +10,12 @@ android.useAndroidX=true #MPP kotlin.mpp.enableGranularSourceSetsMetadata=true kotlin.native.enableDependencyPropagation=false -kotlin.mpp.enableCInteropCommonization=true \ No newline at end of file +kotlin.mpp.enableCInteropCommonization=true + +# Support new memory manager iOS https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md#switch-to-the-new-mm +kotlin.native.cacheKind=none +kotlin.native.binary.memoryModel=experimental +kotlin.native.binary.freezing=disabled + +# Default flavor +buildkonfig.flavor=staging diff --git a/iosApp/Podfile b/iosApp/Podfile index 93e25b2e..a5461fae 100644 --- a/iosApp/Podfile +++ b/iosApp/Podfile @@ -34,6 +34,7 @@ target 'Survey' do # KMM platform :ios, '14.0' pod 'Shared', :path => '../shared' + pod 'KMPNativeCoroutinesCombine', '0.12.6' target 'SurveyTests' do inherit! :search_paths diff --git a/iosApp/Podfile.lock b/iosApp/Podfile.lock index 95eec489..2359acbe 100644 --- a/iosApp/Podfile.lock +++ b/iosApp/Podfile.lock @@ -43,6 +43,9 @@ PODS: - IQKeyboardManagerSwift (6.5.10) - KeychainAccess (4.2.2) - Kingfisher (7.3.2) + - KMPNativeCoroutinesCombine (0.12.6): + - KMPNativeCoroutinesCore (= 0.12.6) + - KMPNativeCoroutinesCore (0.12.6) - nanopb (2.30909.0): - nanopb/decode (= 2.30909.0) - nanopb/encode (= 2.30909.0) @@ -71,6 +74,7 @@ DEPENDENCIES: - IQKeyboardManagerSwift - KeychainAccess - Kingfisher + - KMPNativeCoroutinesCombine (= 0.12.6) - Nimble - NimbleExtension (from `https://github.com/nimblehq/NimbleExtension`, branch `master`) - Quick @@ -97,6 +101,8 @@ SPEC REPOS: - IQKeyboardManagerSwift - KeychainAccess - Kingfisher + - KMPNativeCoroutinesCombine + - KMPNativeCoroutinesCore - nanopb - Nimble - PromisesObjC @@ -135,6 +141,8 @@ SPEC CHECKSUMS: IQKeyboardManagerSwift: 52962c76ab33532f15ad9f3ff4e5715eda5335bb KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51 Kingfisher: 0086ad83719761ba9b2cdaf6ef4d5b4878cbae23 + KMPNativeCoroutinesCombine: 9c82dee7ba35c6acff4b35a9757bfecae8b335fd + KMPNativeCoroutinesCore: 35da0312355f0e911cbb16923aea3389894affca nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 Nimble: 5316ef81a170ce87baf72dd961f22f89a602ff84 NimbleExtension: acad4290f27afd4241b1ea20f8597889085e2ce7 @@ -150,6 +158,6 @@ SPEC CHECKSUMS: SwiftLint: 32ee33ded0636d0905ef6911b2b67bbaeeedafa5 Wormholy: 3252bc3e55a1847ef9a0976c1377bd77bf3635fa -PODFILE CHECKSUM: 1b16a2203f7a7e5189b6a011d87018abda0e626b +PODFILE CHECKSUM: aa082789bfd369623586fbf76e18d6d90097562e COCOAPODS: 1.11.3 diff --git a/iosApp/Survey.xcodeproj/project.pbxproj b/iosApp/Survey.xcodeproj/project.pbxproj index ad80f5a4..3de29f1c 100644 --- a/iosApp/Survey.xcodeproj/project.pbxproj +++ b/iosApp/Survey.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0648A69CF16D7212BE561B24 /* Pods_Survey.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CC6B0AEB245ACFC2B78211FD /* Pods_Survey.framework */; }; 09495F5928F92A6F0036BDFB /* RouteCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09495F5828F92A6E0036BDFB /* RouteCoordinator.swift */; }; 09495F6628FF97080036BDFB /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09495F6528FF97070036BDFB /* SplashView.swift */; }; 09495F6828FF97490036BDFB /* ViewId+Splash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09495F6728FF97490036BDFB /* ViewId+Splash.swift */; }; @@ -34,18 +35,20 @@ 09636B3628D8285700A5CB97 /* KeyboardScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09636B3428D8284600A5CB97 /* KeyboardScreen.swift */; }; 09CE770C28E191B400EAA9EE /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE770B28E191B400EAA9EE /* AppCoordinator.swift */; }; 09CE770F28E1922000EAA9EE /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE770E28E1922000EAA9EE /* Screen.swift */; }; + 09CE773228E2ED2300EAA9EE /* LazyKoin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE772F28E2ED2300EAA9EE /* LazyKoin.swift */; }; + 09CE773328E2ED2300EAA9EE /* KoinApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE773028E2ED2300EAA9EE /* KoinApplication.swift */; }; + 09CE773428E2ED2300EAA9EE /* Typealias+Koin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE773128E2ED2300EAA9EE /* Typealias+Koin.swift */; }; + 36D8E5F2D1534EA3FBBD6E17 /* Pods_Survey_SurveyUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA38CB929B0BC4E980C6E56B /* Pods_Survey_SurveyUITests.framework */; }; 3D0ADA9FBBF8D55D5F00610F /* OptionalUnwrapSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1EE1175F99D55A95E0995E9 /* OptionalUnwrapSpec.swift */; }; 5BBBFAF49689F25A8C1D57AB /* AutoMockable.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88CA60577ABA5F7885E1DE7 /* AutoMockable.generated.swift */; }; 686B2C185816765B3E124776 /* IOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46885A08B19F8EB7FFC5117F /* IOSApp.swift */; }; 870924447B8C177450E77414 /* Optional+Unwrap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64ED519E814E897776076800 /* Optional+Unwrap.swift */; }; 8BCA1398DA19EF4389A3E41A /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B0838AE1612D331EDA8D771 /* LoginView.swift */; }; - 92B7D2DDF09B9C366DDD6817 /* Pods_Survey.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 089ECC4763AAFDC8739533DA /* Pods_Survey.framework */; }; CA1F500707F2936D39825740 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E078CC9F3CA35716784FF802 /* Assets.xcassets */; }; - DC389C03DE539589D071C045 /* Pods_Survey_SurveyUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F8D46A12D575264811B98CD /* Pods_Survey_SurveyUITests.framework */; }; + D30597C390B22AD47DBCC531 /* Pods_SurveyTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDDB0F584F870B0473D96D84 /* Pods_SurveyTests.framework */; }; EABA6D4F0FE97293430D3FC9 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71A1F95D20E1E58589F4CD31 /* Constants.swift */; }; EE08DEF68E0F23B6777E9BED /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CFE0E10E82DADFEF9BF954DF /* LaunchScreen.storyboard */; }; F860FAD5941956384AEA9646 /* Constants+API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 415CD22123B29DD0BC988641 /* Constants+API.swift */; }; - FDCB8CBF56F270DB4F375113 /* Pods_SurveyTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F257D186DF536348ACCA14C /* Pods_SurveyTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -99,7 +102,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 089ECC4763AAFDC8739533DA /* Pods_Survey.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Survey.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 02CB2FA1B2C1B7160CD97DB0 /* Pods-Survey.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey.debug production.xcconfig"; path = "Target Support Files/Pods-Survey/Pods-Survey.debug production.xcconfig"; sourceTree = ""; }; 09495F5828F92A6E0036BDFB /* RouteCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteCoordinator.swift; sourceTree = ""; }; 09495F6528FF97070036BDFB /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; 09495F6728FF97490036BDFB /* ViewId+Splash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewId+Splash.swift"; sourceTree = ""; }; @@ -123,39 +126,42 @@ 09636B3428D8284600A5CB97 /* KeyboardScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardScreen.swift; sourceTree = ""; }; 09CE770B28E191B400EAA9EE /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = ""; }; 09CE770E28E1922000EAA9EE /* Screen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Screen.swift; sourceTree = ""; }; - 0F8D46A12D575264811B98CD /* Pods_Survey_SurveyUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Survey_SurveyUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 09CE772F28E2ED2300EAA9EE /* LazyKoin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyKoin.swift; sourceTree = ""; }; + 09CE773028E2ED2300EAA9EE /* KoinApplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KoinApplication.swift; sourceTree = ""; }; + 09CE773128E2ED2300EAA9EE /* Typealias+Koin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Typealias+Koin.swift"; sourceTree = ""; }; 122A6B9F6217729620D91A43 /* DebugProduction.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DebugProduction.xcconfig; sourceTree = ""; }; 16E10E52E1F7EAF6527F4E27 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 198438883A4D493209169F74 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - 2106C5F403F5436FBC038C2A /* Pods-Survey-SurveyUITests.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey-SurveyUITests.debug staging.xcconfig"; path = "Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests.debug staging.xcconfig"; sourceTree = ""; }; + 2176112DD78B6A638C15C6A4 /* Pods-Survey-SurveyUITests.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey-SurveyUITests.release production.xcconfig"; path = "Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests.release production.xcconfig"; sourceTree = ""; }; 23540B51F2526F91AE40B8F6 /* DebugStaging.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DebugStaging.xcconfig; sourceTree = ""; }; 293DE1041DE212AA81536BDB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - 3A337C4EF84BE59D82017112 /* Pods-SurveyTests.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SurveyTests.release production.xcconfig"; path = "Target Support Files/Pods-SurveyTests/Pods-SurveyTests.release production.xcconfig"; sourceTree = ""; }; + 40B891DBA9094E7597989586 /* Pods-Survey.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey.release production.xcconfig"; path = "Target Support Files/Pods-Survey/Pods-Survey.release production.xcconfig"; sourceTree = ""; }; 415CD22123B29DD0BC988641 /* Constants+API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Constants+API.swift"; sourceTree = ""; }; 46885A08B19F8EB7FFC5117F /* IOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOSApp.swift; sourceTree = ""; }; - 58AD99B0287A208A13493277 /* Pods-Survey.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey.release staging.xcconfig"; path = "Target Support Files/Pods-Survey/Pods-Survey.release staging.xcconfig"; sourceTree = ""; }; + 4B2DC21647BE9A27FD8C4D38 /* Pods-Survey-SurveyUITests.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey-SurveyUITests.debug staging.xcconfig"; path = "Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests.debug staging.xcconfig"; sourceTree = ""; }; 5A115DAC86D72B7F2CCCC346 /* SurveyUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SurveyUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 5DC5042EEACFF3453748A140 /* Pods-SurveyTests.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SurveyTests.debug staging.xcconfig"; path = "Target Support Files/Pods-SurveyTests/Pods-SurveyTests.debug staging.xcconfig"; sourceTree = ""; }; - 60524548F2AA0B879E3FB975 /* Pods-SurveyTests.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SurveyTests.release staging.xcconfig"; path = "Target Support Files/Pods-SurveyTests/Pods-SurveyTests.release staging.xcconfig"; sourceTree = ""; }; + 5B09189EFBAED74B87FFD51C /* Pods-Survey-SurveyUITests.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey-SurveyUITests.release staging.xcconfig"; path = "Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests.release staging.xcconfig"; sourceTree = ""; }; 64ED519E814E897776076800 /* Optional+Unwrap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Unwrap.swift"; sourceTree = ""; }; - 6F257D186DF536348ACCA14C /* Pods_SurveyTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SurveyTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 71A1F95D20E1E58589F4CD31 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 727F7D83813FA7F64C222B0F /* SurveyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SurveyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 80CCFBE8728705C6D489C02A /* Pods-Survey.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey.debug production.xcconfig"; path = "Target Support Files/Pods-Survey/Pods-Survey.debug production.xcconfig"; sourceTree = ""; }; + 77BD984C9889C3D6A8589013 /* Pods-Survey-SurveyUITests.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey-SurveyUITests.debug production.xcconfig"; path = "Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests.debug production.xcconfig"; sourceTree = ""; }; + 78627BFEDE672E072407352A /* Pods-SurveyTests.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SurveyTests.debug staging.xcconfig"; path = "Target Support Files/Pods-SurveyTests/Pods-SurveyTests.debug staging.xcconfig"; sourceTree = ""; }; + 7B78A4DBF26AC066537DE552 /* Pods-SurveyTests.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SurveyTests.debug production.xcconfig"; path = "Target Support Files/Pods-SurveyTests/Pods-SurveyTests.debug production.xcconfig"; sourceTree = ""; }; 8B0838AE1612D331EDA8D771 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; - 9615F7DF0CBF64EC80A00FFC /* Pods-Survey.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey.debug staging.xcconfig"; path = "Target Support Files/Pods-Survey/Pods-Survey.debug staging.xcconfig"; sourceTree = ""; }; A0804CAD6C01AC6009D88A55 /* Survey.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Survey.app; sourceTree = BUILT_PRODUCTS_DIR; }; A88CA60577ABA5F7885E1DE7 /* AutoMockable.generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoMockable.generated.swift; sourceTree = ""; }; - B71711FE2E3E3A7F3B1656DD /* Pods-SurveyTests.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SurveyTests.debug production.xcconfig"; path = "Target Support Files/Pods-SurveyTests/Pods-SurveyTests.debug production.xcconfig"; sourceTree = ""; }; - BBC8C42B587DEC988A917995 /* Pods-Survey-SurveyUITests.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey-SurveyUITests.release staging.xcconfig"; path = "Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests.release staging.xcconfig"; sourceTree = ""; }; + CA38CB929B0BC4E980C6E56B /* Pods_Survey_SurveyUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Survey_SurveyUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CC6B0AEB245ACFC2B78211FD /* Pods_Survey.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Survey.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CD76687B09E0F20A7CC1C054 /* ReleaseStaging.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseStaging.xcconfig; sourceTree = ""; }; + CE01F88EFAB142FFEDAD27C0 /* Pods-SurveyTests.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SurveyTests.release staging.xcconfig"; path = "Target Support Files/Pods-SurveyTests/Pods-SurveyTests.release staging.xcconfig"; sourceTree = ""; }; CFE0E10E82DADFEF9BF954DF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; - D04D1F9B9BEAA709BA0D42D8 /* Pods-Survey.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey.release production.xcconfig"; path = "Target Support Files/Pods-Survey/Pods-Survey.release production.xcconfig"; sourceTree = ""; }; D1EE1175F99D55A95E0995E9 /* OptionalUnwrapSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalUnwrapSpec.swift; sourceTree = ""; }; D4B0B811035E1D25A7230EDA /* ReleaseProduction.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseProduction.xcconfig; sourceTree = ""; }; + D89EC4F54F2613A85BDB7490 /* Pods-Survey.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey.release staging.xcconfig"; path = "Target Support Files/Pods-Survey/Pods-Survey.release staging.xcconfig"; sourceTree = ""; }; E078CC9F3CA35716784FF802 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - E5DBA78E3F1F0BC6EF8CE435 /* Pods-Survey-SurveyUITests.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey-SurveyUITests.debug production.xcconfig"; path = "Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests.debug production.xcconfig"; sourceTree = ""; }; - EC3D340309A0B927607FCB47 /* Pods-Survey-SurveyUITests.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey-SurveyUITests.release production.xcconfig"; path = "Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests.release production.xcconfig"; sourceTree = ""; }; + EDDB0F584F870B0473D96D84 /* Pods_SurveyTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SurveyTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F362A50BFAC28BB3242E7D02 /* Pods-Survey.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Survey.debug staging.xcconfig"; path = "Target Support Files/Pods-Survey/Pods-Survey.debug staging.xcconfig"; sourceTree = ""; }; + F982C497B0BAD800BEEE69F2 /* Pods-SurveyTests.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SurveyTests.release production.xcconfig"; path = "Target Support Files/Pods-SurveyTests/Pods-SurveyTests.release production.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -163,7 +169,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DC389C03DE539589D071C045 /* Pods_Survey_SurveyUITests.framework in Frameworks */, + 36D8E5F2D1534EA3FBBD6E17 /* Pods_Survey_SurveyUITests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -171,7 +177,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - FDCB8CBF56F270DB4F375113 /* Pods_SurveyTests.framework in Frameworks */, + D30597C390B22AD47DBCC531 /* Pods_SurveyTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -179,7 +185,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 92B7D2DDF09B9C366DDD6817 /* Pods_Survey.framework in Frameworks */, + 0648A69CF16D7212BE561B24 /* Pods_Survey.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -346,6 +352,32 @@ path = Screens; sourceTree = ""; }; + 09CE772C28E2ED2300EAA9EE /* KMM */ = { + isa = PBXGroup; + children = ( + 09CE772D28E2ED2300EAA9EE /* DI */, + ); + path = KMM; + sourceTree = ""; + }; + 09CE772D28E2ED2300EAA9EE /* DI */ = { + isa = PBXGroup; + children = ( + 09CE772E28E2ED2300EAA9EE /* Koin */, + ); + path = DI; + sourceTree = ""; + }; + 09CE772E28E2ED2300EAA9EE /* Koin */ = { + isa = PBXGroup; + children = ( + 09CE772F28E2ED2300EAA9EE /* LazyKoin.swift */, + 09CE773028E2ED2300EAA9EE /* KoinApplication.swift */, + 09CE773128E2ED2300EAA9EE /* Typealias+Koin.swift */, + ); + path = Koin; + sourceTree = ""; + }; 0A2BA072E9C5F7AC2C58F613 /* Views */ = { isa = PBXGroup; children = ( @@ -630,18 +662,18 @@ CDEEF8AAA4DEE3D13E81B4CA /* Pods */ = { isa = PBXGroup; children = ( - 80CCFBE8728705C6D489C02A /* Pods-Survey.debug production.xcconfig */, - 9615F7DF0CBF64EC80A00FFC /* Pods-Survey.debug staging.xcconfig */, - D04D1F9B9BEAA709BA0D42D8 /* Pods-Survey.release production.xcconfig */, - 58AD99B0287A208A13493277 /* Pods-Survey.release staging.xcconfig */, - E5DBA78E3F1F0BC6EF8CE435 /* Pods-Survey-SurveyUITests.debug production.xcconfig */, - 2106C5F403F5436FBC038C2A /* Pods-Survey-SurveyUITests.debug staging.xcconfig */, - EC3D340309A0B927607FCB47 /* Pods-Survey-SurveyUITests.release production.xcconfig */, - BBC8C42B587DEC988A917995 /* Pods-Survey-SurveyUITests.release staging.xcconfig */, - B71711FE2E3E3A7F3B1656DD /* Pods-SurveyTests.debug production.xcconfig */, - 5DC5042EEACFF3453748A140 /* Pods-SurveyTests.debug staging.xcconfig */, - 3A337C4EF84BE59D82017112 /* Pods-SurveyTests.release production.xcconfig */, - 60524548F2AA0B879E3FB975 /* Pods-SurveyTests.release staging.xcconfig */, + 02CB2FA1B2C1B7160CD97DB0 /* Pods-Survey.debug production.xcconfig */, + F362A50BFAC28BB3242E7D02 /* Pods-Survey.debug staging.xcconfig */, + 40B891DBA9094E7597989586 /* Pods-Survey.release production.xcconfig */, + D89EC4F54F2613A85BDB7490 /* Pods-Survey.release staging.xcconfig */, + 77BD984C9889C3D6A8589013 /* Pods-Survey-SurveyUITests.debug production.xcconfig */, + 4B2DC21647BE9A27FD8C4D38 /* Pods-Survey-SurveyUITests.debug staging.xcconfig */, + 2176112DD78B6A638C15C6A4 /* Pods-Survey-SurveyUITests.release production.xcconfig */, + 5B09189EFBAED74B87FFD51C /* Pods-Survey-SurveyUITests.release staging.xcconfig */, + 7B78A4DBF26AC066537DE552 /* Pods-SurveyTests.debug production.xcconfig */, + 78627BFEDE672E072407352A /* Pods-SurveyTests.debug staging.xcconfig */, + F982C497B0BAD800BEEE69F2 /* Pods-SurveyTests.release production.xcconfig */, + CE01F88EFAB142FFEDAD27C0 /* Pods-SurveyTests.release staging.xcconfig */, ); path = Pods; sourceTree = ""; @@ -695,6 +727,7 @@ E8FA76B3139104BA8189B8C0 /* Helpers */ = { isa = PBXGroup; children = ( + 09CE772C28E2ED2300EAA9EE /* KMM */, 09636B0928D48CE800A5CB97 /* Typealiases */, 09636AF428D47A1400A5CB97 /* Rswift */, ); @@ -707,16 +740,16 @@ 2307BBF2D8DFC29AF96736C0 /* Project */, 586803EF3EEDDB6484551736 /* Products */, CDEEF8AAA4DEE3D13E81B4CA /* Pods */, - FDB868D00A4C85A94D4C4854 /* Frameworks */, + F5122D9908BA1C2E22CD8554 /* Frameworks */, ); sourceTree = ""; }; - FDB868D00A4C85A94D4C4854 /* Frameworks */ = { + F5122D9908BA1C2E22CD8554 /* Frameworks */ = { isa = PBXGroup; children = ( - 089ECC4763AAFDC8739533DA /* Pods_Survey.framework */, - 0F8D46A12D575264811B98CD /* Pods_Survey_SurveyUITests.framework */, - 6F257D186DF536348ACCA14C /* Pods_SurveyTests.framework */, + CC6B0AEB245ACFC2B78211FD /* Pods_Survey.framework */, + CA38CB929B0BC4E980C6E56B /* Pods_Survey_SurveyUITests.framework */, + EDDB0F584F870B0473D96D84 /* Pods_SurveyTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -728,13 +761,13 @@ isa = PBXNativeTarget; buildConfigurationList = EE7461BAE7F27A38307B4FA7 /* Build configuration list for PBXNativeTarget "SurveyTests" */; buildPhases = ( - 034AC668A4450EE0CC2BDB0C /* [CP] Check Pods Manifest.lock */, + AFAD5415A6206372006EA524 /* [CP] Check Pods Manifest.lock */, A3C000438E4A91EA9068C937 /* SwiftFormat */, C03FF37BE91C4D8F7B1BF409 /* Sources */, 2751CDD4E0F83EB33F8E0E63 /* Resources */, ED5D7924B0EF482201D78315 /* Embed Frameworks */, 827414FFCE0AB4A1BD5754FE /* Frameworks */, - 81210451CC60D3BF50F615CC /* [CP] Embed Pods Frameworks */, + 8C82E5B2DE581E5A93868983 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -750,7 +783,7 @@ isa = PBXNativeTarget; buildConfigurationList = 92C0E02BDF2B11A44FB6CEE3 /* Build configuration list for PBXNativeTarget "Survey" */; buildPhases = ( - 00C4F2BF495CC93434D88C10 /* [CP] Check Pods Manifest.lock */, + 4612813121F893C91047A851 /* [CP] Check Pods Manifest.lock */, B85F179315C39B4798E604CA /* Sourcery */, 364701D01D6D730E26E263DF /* R.swift */, 9BD4EA3F047610A3BE9C5FD8 /* SwiftLint */, @@ -760,7 +793,7 @@ E5AAC51FAA606E5E5C684F83 /* Embed Frameworks */, FF76644469CE368D62BA827C /* Frameworks */, CC99E871FA1DDA8C64075BC0 /* Copy GoogleService-Info.plist */, - D60FDB7DD662539066793513 /* [CP] Embed Pods Frameworks */, + C2351F7F86E8F4BC7B7489FE /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -775,12 +808,12 @@ isa = PBXNativeTarget; buildConfigurationList = 4B9656EA15699F2B52E542CF /* Build configuration list for PBXNativeTarget "SurveyUITests" */; buildPhases = ( - A5BF967BFC797E3043099984 /* [CP] Check Pods Manifest.lock */, + B4E7C52D5881E0B8B31A32C0 /* [CP] Check Pods Manifest.lock */, 2C88074C10C197AACF226D16 /* Sources */, A28FDEF2E9D4FC4AC656E20C /* Resources */, 1E7617E014B651634FB6C745 /* Embed Frameworks */, 00B8FFD04E77D1BF4EC64EEE /* Frameworks */, - 6E50CB2449E4288142DA9212 /* [CP] Embed Pods Frameworks */, + 10FA1D4794C5D7CDDA191CE9 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -858,48 +891,21 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 00C4F2BF495CC93434D88C10 /* [CP] Check Pods Manifest.lock */ = { + 10FA1D4794C5D7CDDA191CE9 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Survey-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 034AC668A4450EE0CC2BDB0C /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-SurveyTests-checkManifestLockResult.txt", + "${PODS_ROOT}/Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 364701D01D6D730E26E263DF /* R.swift */ = { @@ -916,7 +922,7 @@ outputFileListPaths = ( ); outputPaths = ( - $SRCROOT/$PROJECT_NAME/Sources/Supports/Helpers/Rswift/R.generated.swift, + "$SRCROOT/$PROJECT_NAME/Sources/Supports/Helpers/Rswift/R.generated.swift", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -940,24 +946,29 @@ shellPath = /bin/sh; shellScript = "if [ -z \"$CI\" ]; then\n \"${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat\" \"$SRCROOT\" --lint --lenient\nfi"; }; - 6E50CB2449E4288142DA9212 /* [CP] Embed Pods Frameworks */ = { + 4612813121F893C91047A851 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Survey-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Survey-SurveyUITests/Pods-Survey-SurveyUITests-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 81210451CC60D3BF50F615CC /* [CP] Embed Pods Frameworks */ = { + 8C82E5B2DE581E5A93868983 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1010,7 +1021,7 @@ shellPath = /bin/sh; shellScript = "if [ -z \"$CI\" ]; then\n \"${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat\" \"$SRCROOT\"\nfi"; }; - A5BF967BFC797E3043099984 /* [CP] Check Pods Manifest.lock */ = { + AFAD5415A6206372006EA524 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1025,14 +1036,14 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Survey-SurveyUITests-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-SurveyTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - B85F179315C39B4798E604CA /* Sourcery */ = { + B4E7C52D5881E0B8B31A32C0 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1040,17 +1051,21 @@ inputFileListPaths = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); - name = Sourcery; + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Survey-SurveyUITests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"$PODS_ROOT/Sourcery/bin/sourcery\""; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; - CC99E871FA1DDA8C64075BC0 /* Copy GoogleService-Info.plist */ = { + B85F179315C39B4798E604CA /* Sourcery */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1059,16 +1074,16 @@ ); inputPaths = ( ); - name = "Copy GoogleService-Info.plist"; + name = Sourcery; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "PATH_TO_GOOGLE_PLISTS=\"$SRCROOT/$PROJECT_NAME/Configurations/Plists/GoogleService\"\n\ncase \"${CONFIGURATION}\" in\n\"Debug Staging\" | \"Release Staging\" )\ncp -r \"$PATH_TO_GOOGLE_PLISTS/Staging/GoogleService-Info.plist\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist\"\n;;\n\"Debug Production\" | \"Release Production\" )\ncp -r \"$PATH_TO_GOOGLE_PLISTS/Production/GoogleService-Info.plist\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist\"\n;;\n*)\n;;\nesac"; + shellScript = "\"$PODS_ROOT/Sourcery/bin/sourcery\""; }; - D60FDB7DD662539066793513 /* [CP] Embed Pods Frameworks */ = { + C2351F7F86E8F4BC7B7489FE /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1085,6 +1100,24 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Survey/Pods-Survey-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + CC99E871FA1DDA8C64075BC0 /* Copy GoogleService-Info.plist */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Copy GoogleService-Info.plist"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "PATH_TO_GOOGLE_PLISTS=\"$SRCROOT/$PROJECT_NAME/Configurations/Plists/GoogleService\"\n\ncase \"${CONFIGURATION}\" in\n\"Debug Staging\" | \"Release Staging\" )\ncp -r \"$PATH_TO_GOOGLE_PLISTS/Staging/GoogleService-Info.plist\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist\"\n;;\n\"Debug Production\" | \"Release Production\" )\ncp -r \"$PATH_TO_GOOGLE_PLISTS/Production/GoogleService-Info.plist\" \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist\"\n;;\n*)\n;;\nesac"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -1100,12 +1133,15 @@ 09CE770C28E191B400EAA9EE /* AppCoordinator.swift in Sources */, 09636AFD28D484CA00A5CB97 /* R+SwiftUI.swift in Sources */, 09636B0F28D80B8500A5CB97 /* View+KeyboardDismiss.swift in Sources */, + 09CE773428E2ED2300EAA9EE /* Typealias+Koin.swift in Sources */, 09495F5928F92A6F0036BDFB /* RouteCoordinator.swift in Sources */, 09495F6828FF97490036BDFB /* ViewId+Splash.swift in Sources */, 09636B1728D815D100A5CB97 /* ViewId+Login.swift in Sources */, EABA6D4F0FE97293430D3FC9 /* Constants.swift in Sources */, + 09CE773328E2ED2300EAA9EE /* KoinApplication.swift in Sources */, 09636AF928D47A4D00A5CB97 /* Font+Extensions.swift in Sources */, 8BCA1398DA19EF4389A3E41A /* LoginView.swift in Sources */, + 09CE773228E2ED2300EAA9EE /* LazyKoin.swift in Sources */, 09636B1528D8148C00A5CB97 /* ViewId.swift in Sources */, 09CE770F28E1922000EAA9EE /* Screen.swift in Sources */, 09636B0B28D48CFD00A5CB97 /* Typealiases.swift in Sources */, @@ -1230,7 +1266,7 @@ }; 045748AB609BF8940D5B860C /* Release Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = EC3D340309A0B927607FCB47 /* Pods-Survey-SurveyUITests.release production.xcconfig */; + baseConfigurationReference = 2176112DD78B6A638C15C6A4 /* Pods-Survey-SurveyUITests.release production.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = SurveyUITests/Configurations/Plists/Info.plist; @@ -1252,7 +1288,7 @@ }; 060D9CDB5BA2CAAAD9160176 /* Release Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 60524548F2AA0B879E3FB975 /* Pods-SurveyTests.release staging.xcconfig */; + baseConfigurationReference = CE01F88EFAB142FFEDAD27C0 /* Pods-SurveyTests.release staging.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1276,7 +1312,7 @@ }; 06304D047007243CFFCF3F19 /* Debug Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = B71711FE2E3E3A7F3B1656DD /* Pods-SurveyTests.debug production.xcconfig */; + baseConfigurationReference = 7B78A4DBF26AC066537DE552 /* Pods-SurveyTests.debug production.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1301,7 +1337,7 @@ }; 150050B4F5856B8C680BA857 /* Release Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3A337C4EF84BE59D82017112 /* Pods-SurveyTests.release production.xcconfig */; + baseConfigurationReference = F982C497B0BAD800BEEE69F2 /* Pods-SurveyTests.release production.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1325,7 +1361,7 @@ }; 36C8BBE6758900279E460885 /* Debug Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9615F7DF0CBF64EC80A00FFC /* Pods-Survey.debug staging.xcconfig */; + baseConfigurationReference = F362A50BFAC28BB3242E7D02 /* Pods-Survey.debug staging.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1352,7 +1388,7 @@ }; 56F1F2B77E9ABF3E64283C8A /* Release Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = BBC8C42B587DEC988A917995 /* Pods-Survey-SurveyUITests.release staging.xcconfig */; + baseConfigurationReference = 5B09189EFBAED74B87FFD51C /* Pods-Survey-SurveyUITests.release staging.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = SurveyUITests/Configurations/Plists/Info.plist; @@ -1427,7 +1463,7 @@ }; 594596731BF36E1720EE07AF /* Debug Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2106C5F403F5436FBC038C2A /* Pods-Survey-SurveyUITests.debug staging.xcconfig */; + baseConfigurationReference = 4B2DC21647BE9A27FD8C4D38 /* Pods-Survey-SurveyUITests.debug staging.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = SurveyUITests/Configurations/Plists/Info.plist; @@ -1562,7 +1598,7 @@ }; AC120A27DC1EA6A67DE3DF1A /* Debug Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E5DBA78E3F1F0BC6EF8CE435 /* Pods-Survey-SurveyUITests.debug production.xcconfig */; + baseConfigurationReference = 77BD984C9889C3D6A8589013 /* Pods-Survey-SurveyUITests.debug production.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = SurveyUITests/Configurations/Plists/Info.plist; @@ -1585,7 +1621,7 @@ }; D18CE29614745C9A7FBE61AF /* Release Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D04D1F9B9BEAA709BA0D42D8 /* Pods-Survey.release production.xcconfig */; + baseConfigurationReference = 40B891DBA9094E7597989586 /* Pods-Survey.release production.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1611,7 +1647,7 @@ }; F4ABC77AA692EC7809953362 /* Release Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 58AD99B0287A208A13493277 /* Pods-Survey.release staging.xcconfig */; + baseConfigurationReference = D89EC4F54F2613A85BDB7490 /* Pods-Survey.release staging.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1637,7 +1673,7 @@ }; F877E3A3A3F9BA1A03E0315A /* Debug Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5DC5042EEACFF3453748A140 /* Pods-SurveyTests.debug staging.xcconfig */; + baseConfigurationReference = 78627BFEDE672E072407352A /* Pods-SurveyTests.debug staging.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1662,7 +1698,7 @@ }; FB8889C36C898572F57D8B34 /* Debug Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 80CCFBE8728705C6D489C02A /* Pods-Survey.debug production.xcconfig */; + baseConfigurationReference = 02CB2FA1B2C1B7160CD97DB0 /* Pods-Survey.debug production.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; diff --git a/iosApp/Survey/Sources/Supports/Helpers/KMM/DI/Koin/KoinApplication.swift b/iosApp/Survey/Sources/Supports/Helpers/KMM/DI/Koin/KoinApplication.swift new file mode 100644 index 00000000..55256287 --- /dev/null +++ b/iosApp/Survey/Sources/Supports/Helpers/KMM/DI/Koin/KoinApplication.swift @@ -0,0 +1,37 @@ +// +// KoinApplication.swift +// Survey +// +// Created by Bliss on 21/9/22. +// Copyright © 2022 Nimble. All rights reserved. +// + +import Shared + +extension KoinApplication { + + static let shared = companion.start() + + @discardableResult + static func start() -> KoinApplication { + shared + } +} + +extension KoinApplication { + + private static let keyPaths: [PartialKeyPath] = [] + + static func inject() -> T { + shared.inject() + } + + func inject() -> T { + for partialKeyPath in Self.keyPaths { + guard let keyPath = partialKeyPath as? KeyPath else { continue } + return koin[keyPath: keyPath] + } + + fatalError("\(T.self) is not registered with KoinApplication") + } +} diff --git a/iosApp/Survey/Sources/Supports/Helpers/KMM/DI/Koin/LazyKoin.swift b/iosApp/Survey/Sources/Supports/Helpers/KMM/DI/Koin/LazyKoin.swift new file mode 100644 index 00000000..8af1e1f5 --- /dev/null +++ b/iosApp/Survey/Sources/Supports/Helpers/KMM/DI/Koin/LazyKoin.swift @@ -0,0 +1,15 @@ +// +// LazyKoin.swift +// Survey +// +// Created by Bliss on 21/9/22. +// Copyright © 2022 Nimble. All rights reserved. +// + +@propertyWrapper +struct LazyKoin { + + lazy var wrappedValue: T = KoinApplication.shared.inject() + + init() {} +} diff --git a/iosApp/Survey/Sources/Supports/Helpers/KMM/DI/Koin/Typealias+Koin.swift b/iosApp/Survey/Sources/Supports/Helpers/KMM/DI/Koin/Typealias+Koin.swift new file mode 100644 index 00000000..2d452b0c --- /dev/null +++ b/iosApp/Survey/Sources/Supports/Helpers/KMM/DI/Koin/Typealias+Koin.swift @@ -0,0 +1,12 @@ +// swiftlint:disable:this file_name +// Typealias+Koin.swift +// Survey +// +// Created by Bliss on 21/9/22. +// Copyright © 2022 Nimble. All rights reserved. +// + +import Shared + +typealias KoinApplication = Koin_coreKoinApplication +typealias Koin = Koin_coreKoin diff --git a/nimble-jsonapi-kotlin b/nimble-jsonapi-kotlin new file mode 160000 index 00000000..04cf06cd --- /dev/null +++ b/nimble-jsonapi-kotlin @@ -0,0 +1 @@ +Subproject commit 04cf06cd7e72623e11f26dcf0c56356f576b1596 diff --git a/settings.gradle.kts b/settings.gradle.kts index 885794bc..04bd6f65 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,4 +8,5 @@ pluginManagement { rootProject.name = "Survey" include(":androidApp") -include(":shared") \ No newline at end of file +include(":shared") +include(":nimble-jsonapi-kotlin:core") diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index bbb1c1d3..e1de035c 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -1,10 +1,14 @@ +import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType plugins { - kotlin("multiplatform") - kotlin("native.cocoapods") - id("com.android.library") - id("io.gitlab.arturbosch.detekt") + kotlin(Plugin.MULTIPLATFORM) + kotlin(Plugin.COCOAPODS) + id(Plugin.ANDROID_LIBRARY) + id(Plugin.DETEKT) + kotlin(Plugin.KOTLIN_SERIALIZATION) + id(Plugin.NATIVE_COROUTINES).version(Version.NATIVE_COROUTINES_KOTLIN) + id(Plugin.BUILD_KONFIG) } version = "1.0" @@ -31,13 +35,33 @@ kotlin { } sourceSets { - val commonMain by getting + val commonMain by getting { + dependencies { + implementation(Dependency.KOTLINX_SERIALIZATION) + implementation(Dependency.KTOR_CORE) + implementation(Dependency.KTOR_SERIALIZATION) + implementation(Dependency.KTOR_LOGGING) + implementation(Dependency.KTOR_JSON) + implementation(Dependency.KTOR_CONTENT_NEGOTIATION) + implementation(Dependency.KTOR_MOCK) + implementation(Dependency.COROUTINES_TEST) + implementation(Dependency.KOIN) + implementation(Dependency.KOIN_TEST) + implementation(project(Module.JSONAPI_CORE)) + implementation(Dependency.KOTLIN_TEST) + } + } val commonTest by getting { dependencies { implementation(kotlin("test")) } } - val androidMain by getting + val androidMain by getting { + dependencies { + implementation(Dependency.KTOR_ANDROID) + implementation(Dependency.KOIN_ANDROID) + } + } val androidTest by getting val iosX64Main by getting val iosArm64Main by getting @@ -47,6 +71,9 @@ kotlin { iosX64Main.dependsOn(this) iosArm64Main.dependsOn(this) iosSimulatorArm64Main.dependsOn(this) + dependencies { + implementation(Dependency.KTOR_IOS) + } } val iosX64Test by getting val iosArm64Test by getting @@ -93,3 +120,61 @@ android { tasks.check { dependsOn(detekt) } + +buildkonfig { + packageName = "co.nimblehq.blisskmmic" + + defaultConfigs { + buildConfigField( + STRING, + "CLIENT_ID", + BuildKonfig.CLIENT_ID + ) + buildConfigField( + STRING, + "CLIENT_SECRET", + BuildKonfig.CLIENT_SECRET + ) + buildConfigField( + STRING, + "BASE_URL", + BuildKonfig.STAGING_BASE_URL + ) + } + + defaultConfigs("production") { + buildConfigField( + STRING, + "CLIENT_ID", + BuildKonfig.CLIENT_ID + ) + buildConfigField( + STRING, + "CLIENT_SECRET", + BuildKonfig.CLIENT_SECRET + ) + buildConfigField( + STRING, + "BASE_URL", + BuildKonfig.PRODUCTION_BASE_URL + ) + } + + defaultConfigs("staging") { + buildConfigField( + STRING, + "CLIENT_ID", + BuildKonfig.CLIENT_ID_STAGING + ) + buildConfigField( + STRING, + "CLIENT_SECRET", + BuildKonfig.CLIENT_SECRET_STAGING + ) + buildConfigField( + STRING, + "BASE_URL", + BuildKonfig.STAGING_BASE_URL + ) + } +} diff --git a/shared/src/androidMain/AndroidManifest.xml b/shared/src/androidMain/AndroidManifest.xml index d83490df..dcffe116 100644 --- a/shared/src/androidMain/AndroidManifest.xml +++ b/shared/src/androidMain/AndroidManifest.xml @@ -1,2 +1,5 @@ - \ No newline at end of file + + + diff --git a/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/data/network/core/NetworkClient.kt b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/data/network/core/NetworkClient.kt new file mode 100644 index 00000000..bb787f7c --- /dev/null +++ b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/data/network/core/NetworkClient.kt @@ -0,0 +1,54 @@ +package co.nimblehq.blisskmmic.data.network.core + +import co.nimblehq.jsonapi.json.JsonApi +import io.ktor.client.HttpClient +import io.ktor.client.call.* +import io.ktor.client.engine.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.plugins.logging.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.serialization.kotlinx.json.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.serialization.json.Json + +class NetworkClient { + + val client: HttpClient + + val json = Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + } + + constructor(engine: HttpClientEngine? = null) { + if (engine == null) { + client = HttpClient() { + install(Logging) + install(ContentNegotiation) { + json(json) + } + } + } else { + client = HttpClient(engine) { + install(Logging) + install(ContentNegotiation) { + json(json) + } + } + } + } + + @Suppress("EmptySecondaryConstructor") + constructor() : this(null) {} + + inline fun fetch(builder: HttpRequestBuilder) : Flow { + return flow { + val body = client.request(builder).bodyAsText() + val data = JsonApi(json).decodeFromJsonApiString(body) + emit(data) + } + } +} diff --git a/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/Koin.kt b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/Koin.kt new file mode 100644 index 00000000..1a9dcc3c --- /dev/null +++ b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/Koin.kt @@ -0,0 +1,17 @@ +package co.nimblehq.blisskmmic.di.koin + +import co.nimblehq.blisskmmic.di.koin.modules.networkModule +import co.nimblehq.blisskmmic.di.koin.modules.repositoryModule +import co.nimblehq.blisskmmic.di.koin.modules.useCaseModule +import org.koin.core.KoinApplication +import org.koin.core.context.startKoin + +fun initKoin() : KoinApplication { + val dataModules = listOf(networkModule, repositoryModule) + val domainModules = listOf(useCaseModule) + return startKoin { + modules( + domainModules + dataModules + ) + } +} diff --git a/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/extensions/Start.kt b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/extensions/Start.kt new file mode 100644 index 00000000..1a4f4a10 --- /dev/null +++ b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/extensions/Start.kt @@ -0,0 +1,10 @@ +package co.nimblehq.blisskmmic.di.koin.extensions + +import co.nimblehq.blisskmmic.data.network.core.NetworkClient +import co.nimblehq.blisskmmic.di.koin.initKoin +import org.koin.core.Koin +import org.koin.core.KoinApplication + +fun KoinApplication.Companion.start(): KoinApplication = initKoin() + +// TODO: Add injectable dependencies diff --git a/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/modules/NetworkModule.kt b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/modules/NetworkModule.kt new file mode 100644 index 00000000..f243c7ae --- /dev/null +++ b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/modules/NetworkModule.kt @@ -0,0 +1,8 @@ +package co.nimblehq.blisskmmic.di.koin.modules + +import co.nimblehq.blisskmmic.data.network.core.NetworkClient +import org.koin.dsl.module + +val networkModule = module { + single { NetworkClient() } +} diff --git a/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/modules/RepositoryModule.kt b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/modules/RepositoryModule.kt new file mode 100644 index 00000000..56a9ec24 --- /dev/null +++ b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/modules/RepositoryModule.kt @@ -0,0 +1,5 @@ +package co.nimblehq.blisskmmic.di.koin.modules + +import org.koin.dsl.module + +val repositoryModule = module {} diff --git a/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/modules/UseCaseModule.kt b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/modules/UseCaseModule.kt new file mode 100644 index 00000000..6a22ab7b --- /dev/null +++ b/shared/src/commonMain/kotlin/co/nimblehq/blisskmmic/di/koin/modules/UseCaseModule.kt @@ -0,0 +1,5 @@ +package co.nimblehq.blisskmmic.di.koin.modules + +import org.koin.dsl.module + +val useCaseModule = module {} diff --git a/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/data/network/core/NetworkClientTest.kt b/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/data/network/core/NetworkClientTest.kt new file mode 100644 index 00000000..4d062edb --- /dev/null +++ b/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/data/network/core/NetworkClientTest.kt @@ -0,0 +1,27 @@ +package co.nimblehq.blisskmmic.data.network.core + +import co.nimblehq.blisskmmic.Greeting +import co.nimblehq.blisskmmic.helpers.mock.NetworkMockModel +import co.nimblehq.blisskmmic.helpers.mock.NETWORK_MOCK_MODEL_RESULT +import co.nimblehq.blisskmmic.helpers.mock.ktor.jsonMockEngine +import io.ktor.client.engine.mock.* +import io.ktor.client.request.* +import io.ktor.http.* +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class NetworkClientTest { + + val engine = jsonMockEngine(NETWORK_MOCK_MODEL_RESULT) + + @Test + fun testMockModel() = runTest { + val networkClient = NetworkClient(engine = engine) + networkClient + .fetch(HttpRequestBuilder()) + .collect { + assertEquals(it.title, "Hello") + } + } +} diff --git a/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/helpers/mock/NetworkMockModel.kt b/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/helpers/mock/NetworkMockModel.kt new file mode 100644 index 00000000..a2f12019 --- /dev/null +++ b/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/helpers/mock/NetworkMockModel.kt @@ -0,0 +1,21 @@ +package co.nimblehq.blisskmmic.helpers.mock + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +const val NETWORK_MOCK_MODEL_RESULT = """ + { + "data": { + "id": 20, + "type": "type", + "attributes": { + "title": "Hello" + } + } + } +""" + +@Serializable +data class NetworkMockModel( + val title: String +) diff --git a/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/helpers/mock/ktor/JsonMockEngine.kt b/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/helpers/mock/ktor/JsonMockEngine.kt new file mode 100644 index 00000000..ebbae89d --- /dev/null +++ b/shared/src/commonTest/kotlin/co/nimblehq/blisskmmic/helpers/mock/ktor/JsonMockEngine.kt @@ -0,0 +1,18 @@ +package co.nimblehq.blisskmmic.helpers.mock.ktor + +import co.nimblehq.blisskmmic.helpers.mock.NETWORK_MOCK_MODEL_RESULT +import io.ktor.client.engine.mock.* +import io.ktor.http.* + +fun jsonMockEngine( + jsonString: String, + statusCode: HttpStatusCode = HttpStatusCode.OK +): MockEngine { + return MockEngine { _ -> + respond( + content = jsonString, + status = statusCode, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } +}