diff --git a/.github/workflows/deploy_production.yml b/.github/workflows/deploy_production.yml new file mode 100644 index 00000000..b62c3b27 --- /dev/null +++ b/.github/workflows/deploy_production.yml @@ -0,0 +1,52 @@ +name: Deploy production app to Firebase App Distribution +on: + push: + branches: + - main + +jobs: + deploy_android: + name: Deploy Android app to Firebase App Distribution + runs-on: ubuntu-latest + timeout-minutes: 30 + environment: production + defaults: + run: + working-directory: ./sample + steps: + - name: Set up JDK + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '17' + + - name: Checkout source code + uses: actions/checkout@v3 + + - name: Cache Gradle + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches/modules-* + ~/.gradle/caches/jars-* + ~/.gradle/caches/build-cache-* + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Set up the necessary config + run: | + echo "${{ secrets.BUILD_KONFIG_PROPERTIES }}" > buildKonfig.properties + echo "${{ secrets.ANDROID_SIGNING_PROPERTIES }}" > signing.properties + echo "${{ secrets.ANDROID_RELEASE_KEYSTORE }}" | base64 --decode > config/release.keystore + + - name: Build production APK + run: ./gradlew assembleProductionRelease -PversionCode=$GITHUB_RUN_NUMBER + + - name: Deploy production to Firebase + uses: wzieba/Firebase-Distribution-Github-Action@v1.7.0 + with: + appId: ${{ vars.ANDROID_FIREBASE_APP_ID }} + serviceCredentialsFileContent: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_CREDENTIAL_FILE_CONTENT }} + groups: nimble + file: sample/android/build/outputs/apk/production/release/android-production-release.apk diff --git a/.github/workflows/deploy_staging.yml b/.github/workflows/deploy_staging.yml new file mode 100644 index 00000000..df6d7b5e --- /dev/null +++ b/.github/workflows/deploy_staging.yml @@ -0,0 +1,49 @@ +name: Deploy staging app to Firebase App Distribution +on: + push: + branches: + - develop + +jobs: + deploy_android: + name: Deploy Android app to Firebase App Distribution + runs-on: ubuntu-latest + timeout-minutes: 30 + environment: staging + defaults: + run: + working-directory: ./sample + steps: + - name: Set up JDK + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '17' + + - name: Checkout source code + uses: actions/checkout@v3 + + - name: Cache Gradle + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches/modules-* + ~/.gradle/caches/jars-* + ~/.gradle/caches/build-cache-* + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Set up the necessary config + run: echo "${{ secrets.BUILD_KONFIG_PROPERTIES }}" > buildKonfig.properties + + - name: Build staging APK + run: ./gradlew assembleStagingDebug -PversionCode=$GITHUB_RUN_NUMBER + + - name: Deploy staging to Firebase + uses: wzieba/Firebase-Distribution-Github-Action@v1.7.0 + with: + appId: ${{ vars.ANDROID_FIREBASE_APP_ID }} + serviceCredentialsFileContent: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_CREDENTIAL_FILE_CONTENT }} + groups: nimble + file: sample/android/build/outputs/apk/staging/debug/android-staging-debug.apk diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a48526cc..817faabb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,7 +1,12 @@ name: Code analysis, test and generate sample project on: pull_request: - types: [ opened, synchronize, reopened, ready_for_review ] + types: [ opened, edited, reopened, synchronize ] + push: + branches-ignore: + - main + - develop + - 'release/**' concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -100,8 +105,8 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - - name: Decode buildKonfig properties - run: echo ${{ secrets.BUILD_KONFIG_PROPERTIES }} | base64 --decode > buildKonfig.properties + - name: Set up the necessary config + run: echo "${{ secrets.BUILD_KONFIG_PROPERTIES }}" > buildKonfig.properties - name: Run Detekt run: ./gradlew detekt @@ -165,9 +170,9 @@ jobs: restore-keys: | ${{ runner.os }}-pods- - - name: Decode buildKonfig properties + - name: Set up the necessary config working-directory: ./sample - run: echo ${{ secrets.BUILD_KONFIG_PROPERTIES }} | base64 --decode > buildKonfig.properties + run: echo "${{ secrets.BUILD_KONFIG_PROPERTIES }}" > buildKonfig.properties - name: Generate KMM frameworks for Cocoapods run: | diff --git a/.gitignore b/.gitignore index 6b4bee79..8e2f43e5 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,9 @@ local.properties xcuserdata buildKonfig.properties +# Keystore +config/release.keystore + # iOS ios/Pods/ ios/fastlane/README.md diff --git a/.gitmodules b/.gitmodules index 8b88b8ad..b0c47177 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,4 +4,4 @@ [submodule "android"] path = android url = git@github.com:nimblehq/android-templates.git - branch = feature/replace-hilt-with-koin + branch = develop-koin diff --git a/README.md b/README.md index e2d04a41..ea4bef67 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ TODO ### Prerequisites - [JDK](https://www.oracle.com/java/technologies/javase-downloads.html): Java 17 +- [Kscript](https://github.com/holgerbrandl/kscript) v4.0.3 or later. - [Android Studio](https://developer.android.com/studio) with [Kotlin Multiplatform Mobile plugin](https://kotlinlang.org/docs/multiplatform-mobile-plugin-releases.html) - [Xcode](https://apps.apple.com/us/app/xcode/id497799835) 13.3+ @@ -28,13 +29,17 @@ Follow these steps to set up a new project from the template: 3. Generate the new project by running the following command: + `$ ./make.sh --bundle-id [BUNDLE_ID] --bundle-id-staging [BUNDLE_ID_STAGING] --project-name [PROJECT_NAME] --ios-version [IOS_VERSION]` + + For example, + `$ ./make.sh --bundle-id co.nimblehq.kmm.template --bundle-id-staging co.nimblehq.kmm.template.staging --project-name sample --ios-version 14.0` To skip CI/CD service generating from iOS script, export this CI env: `$ export CI=true` -The generated project is in the `/sample` folder and ready to build, run, and test 🎉 +The generated project is in the `[PROJECT_NAME]` folder (such as `/sample`) and ready to build, run, and test 🎉 ## Contributing diff --git a/android b/android index 5cb0ea45..7f0a2f60 160000 --- a/android +++ b/android @@ -1 +1 @@ -Subproject commit 5cb0ea459a57f9363406c5dddc1de0800c5e43e4 +Subproject commit 7f0a2f60cb4613639f5f4e4c0bdb9ba52cd21ed6 diff --git a/buildKonfig.properties b/buildKonfig.properties.sample similarity index 100% rename from buildKonfig.properties rename to buildKonfig.properties.sample diff --git a/custom/android/proguard-rules.pro b/custom/android/proguard-rules.pro index c4c23e09..cada5dea 100644 --- a/custom/android/proguard-rules.pro +++ b/custom/android/proguard-rules.pro @@ -60,3 +60,6 @@ #-keepnames class <1>$$serializer { # -keepnames suffices; class is kept when serializer() is kept. # static <1>$$serializer INSTANCE; #} + +# Suppress: Missing class org.slf4j.impl.StaticLoggerBinder while running R8 +-dontwarn org.slf4j.impl.StaticLoggerBinder diff --git a/make.sh b/make.sh index 51040e27..1ac64443 100755 --- a/make.sh +++ b/make.sh @@ -108,21 +108,26 @@ git reset --hard cd .. # Generate iOS module -sh make_ios.sh -b ${bundle_id_production} -s ${bundle_id_staging} -n ${project_name} -iv ${minimum_ios_version} +sh scripts/make_ios.sh -b ${bundle_id_production} -s ${bundle_id_staging} -n ${project_name} -iv ${minimum_ios_version} # Generate Android module -sh make_android.sh -b ${bundle_id_production} -n ${project_name} +sh scripts/make_android.sh -b ${bundle_id_production} -n ${project_name} -# Clone all project files to the "sample" directory -echo "=> Clone all project files to the "sample" directory" +# Clone all project files to the $project_name directory +echo "=> Clone all project files to the '$project_name' directory" rsync -av \ --exclude '.git' \ --exclude '.gitmodules' \ --exclude 'make.sh' \ - --exclude 'make_android.sh' \ - --exclude 'make_ios.sh' \ + --exclude 'CONTRIBUTING.md' \ + --exclude '/scripts' \ --exclude '/custom' \ --exclude '/android' \ + --exclude '/shared' \ --exclude '/sample' \ - ./ sample/ -rsync -av ./android/sample/app/ sample/android/ + --exclude '/'$project_name \ + ./ $project_name/ +rsync -av ./android/$project_name/app/ $project_name/android/ + +# Generate Shared module +kscript scripts/make_shared.kts package-name=${bundle_id_production} app-name=${project_name} diff --git a/sample/.github/workflows/deploy_production.yml b/sample/.github/workflows/deploy_production.yml new file mode 100644 index 00000000..b62c3b27 --- /dev/null +++ b/sample/.github/workflows/deploy_production.yml @@ -0,0 +1,52 @@ +name: Deploy production app to Firebase App Distribution +on: + push: + branches: + - main + +jobs: + deploy_android: + name: Deploy Android app to Firebase App Distribution + runs-on: ubuntu-latest + timeout-minutes: 30 + environment: production + defaults: + run: + working-directory: ./sample + steps: + - name: Set up JDK + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '17' + + - name: Checkout source code + uses: actions/checkout@v3 + + - name: Cache Gradle + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches/modules-* + ~/.gradle/caches/jars-* + ~/.gradle/caches/build-cache-* + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Set up the necessary config + run: | + echo "${{ secrets.BUILD_KONFIG_PROPERTIES }}" > buildKonfig.properties + echo "${{ secrets.ANDROID_SIGNING_PROPERTIES }}" > signing.properties + echo "${{ secrets.ANDROID_RELEASE_KEYSTORE }}" | base64 --decode > config/release.keystore + + - name: Build production APK + run: ./gradlew assembleProductionRelease -PversionCode=$GITHUB_RUN_NUMBER + + - name: Deploy production to Firebase + uses: wzieba/Firebase-Distribution-Github-Action@v1.7.0 + with: + appId: ${{ vars.ANDROID_FIREBASE_APP_ID }} + serviceCredentialsFileContent: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_CREDENTIAL_FILE_CONTENT }} + groups: nimble + file: sample/android/build/outputs/apk/production/release/android-production-release.apk diff --git a/sample/.github/workflows/deploy_staging.yml b/sample/.github/workflows/deploy_staging.yml new file mode 100644 index 00000000..df6d7b5e --- /dev/null +++ b/sample/.github/workflows/deploy_staging.yml @@ -0,0 +1,49 @@ +name: Deploy staging app to Firebase App Distribution +on: + push: + branches: + - develop + +jobs: + deploy_android: + name: Deploy Android app to Firebase App Distribution + runs-on: ubuntu-latest + timeout-minutes: 30 + environment: staging + defaults: + run: + working-directory: ./sample + steps: + - name: Set up JDK + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '17' + + - name: Checkout source code + uses: actions/checkout@v3 + + - name: Cache Gradle + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches/modules-* + ~/.gradle/caches/jars-* + ~/.gradle/caches/build-cache-* + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Set up the necessary config + run: echo "${{ secrets.BUILD_KONFIG_PROPERTIES }}" > buildKonfig.properties + + - name: Build staging APK + run: ./gradlew assembleStagingDebug -PversionCode=$GITHUB_RUN_NUMBER + + - name: Deploy staging to Firebase + uses: wzieba/Firebase-Distribution-Github-Action@v1.7.0 + with: + appId: ${{ vars.ANDROID_FIREBASE_APP_ID }} + serviceCredentialsFileContent: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_CREDENTIAL_FILE_CONTENT }} + groups: nimble + file: sample/android/build/outputs/apk/staging/debug/android-staging-debug.apk diff --git a/sample/.github/workflows/test.yml b/sample/.github/workflows/test.yml index a48526cc..817faabb 100644 --- a/sample/.github/workflows/test.yml +++ b/sample/.github/workflows/test.yml @@ -1,7 +1,12 @@ name: Code analysis, test and generate sample project on: pull_request: - types: [ opened, synchronize, reopened, ready_for_review ] + types: [ opened, edited, reopened, synchronize ] + push: + branches-ignore: + - main + - develop + - 'release/**' concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -100,8 +105,8 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - - name: Decode buildKonfig properties - run: echo ${{ secrets.BUILD_KONFIG_PROPERTIES }} | base64 --decode > buildKonfig.properties + - name: Set up the necessary config + run: echo "${{ secrets.BUILD_KONFIG_PROPERTIES }}" > buildKonfig.properties - name: Run Detekt run: ./gradlew detekt @@ -165,9 +170,9 @@ jobs: restore-keys: | ${{ runner.os }}-pods- - - name: Decode buildKonfig properties + - name: Set up the necessary config working-directory: ./sample - run: echo ${{ secrets.BUILD_KONFIG_PROPERTIES }} | base64 --decode > buildKonfig.properties + run: echo "${{ secrets.BUILD_KONFIG_PROPERTIES }}" > buildKonfig.properties - name: Generate KMM frameworks for Cocoapods run: | diff --git a/sample/.gitignore b/sample/.gitignore index 6b4bee79..8e2f43e5 100644 --- a/sample/.gitignore +++ b/sample/.gitignore @@ -49,6 +49,9 @@ local.properties xcuserdata buildKonfig.properties +# Keystore +config/release.keystore + # iOS ios/Pods/ ios/fastlane/README.md diff --git a/sample/CONTRIBUTING.md b/sample/CONTRIBUTING.md deleted file mode 100644 index 3f2bbf4b..00000000 --- a/sample/CONTRIBUTING.md +++ /dev/null @@ -1,29 +0,0 @@ -# Welcome to the KMM Templates contributing guide - -Thank you for investing your time in contributing to our project! :sparkles: - -## Getting started - -### Git Submodules - -- To add a submodule with default source branch (develop/main) - ``` - $ git submodule add - ``` - For example, - ``` - $ git submodule add git@github.com:nimblehq/android-templates.git android - ``` -- To add a submodule with a specific source branch - ``` - $ git submodule add -b - ``` - For example, - ``` - $ git submodule add -b feature/kmm-support-upgrade-to-gradle-8 git@github.com:nimblehq/android-templates.git android - ``` -- To remove a submodule - ``` - $ git rm android - ``` - Also, remove the cached repository of the submodule at `.git/modules/` if nescessary. diff --git a/sample/README.md b/sample/README.md index e2d04a41..ea4bef67 100644 --- a/sample/README.md +++ b/sample/README.md @@ -11,6 +11,7 @@ TODO ### Prerequisites - [JDK](https://www.oracle.com/java/technologies/javase-downloads.html): Java 17 +- [Kscript](https://github.com/holgerbrandl/kscript) v4.0.3 or later. - [Android Studio](https://developer.android.com/studio) with [Kotlin Multiplatform Mobile plugin](https://kotlinlang.org/docs/multiplatform-mobile-plugin-releases.html) - [Xcode](https://apps.apple.com/us/app/xcode/id497799835) 13.3+ @@ -28,13 +29,17 @@ Follow these steps to set up a new project from the template: 3. Generate the new project by running the following command: + `$ ./make.sh --bundle-id [BUNDLE_ID] --bundle-id-staging [BUNDLE_ID_STAGING] --project-name [PROJECT_NAME] --ios-version [IOS_VERSION]` + + For example, + `$ ./make.sh --bundle-id co.nimblehq.kmm.template --bundle-id-staging co.nimblehq.kmm.template.staging --project-name sample --ios-version 14.0` To skip CI/CD service generating from iOS script, export this CI env: `$ export CI=true` -The generated project is in the `/sample` folder and ready to build, run, and test 🎉 +The generated project is in the `[PROJECT_NAME]` folder (such as `/sample`) and ready to build, run, and test 🎉 ## Contributing diff --git a/sample/android/proguard-rules.pro b/sample/android/proguard-rules.pro index c4c23e09..cada5dea 100644 --- a/sample/android/proguard-rules.pro +++ b/sample/android/proguard-rules.pro @@ -60,3 +60,6 @@ #-keepnames class <1>$$serializer { # -keepnames suffices; class is kept when serializer() is kept. # static <1>$$serializer INSTANCE; #} + +# Suppress: Missing class org.slf4j.impl.StaticLoggerBinder while running R8 +-dontwarn org.slf4j.impl.StaticLoggerBinder diff --git a/sample/buildKonfig.properties.sample b/sample/buildKonfig.properties.sample new file mode 100644 index 00000000..9238fa78 --- /dev/null +++ b/sample/buildKonfig.properties.sample @@ -0,0 +1,4 @@ +# Staging env +STAGING_BASE_URL= +# Production env +PRODUCTION_BASE_URL= diff --git a/sample/ios/Gemfile.lock b/sample/ios/Gemfile.lock index 6b650dae..6e04be28 100644 --- a/sample/ios/Gemfile.lock +++ b/sample/ios/Gemfile.lock @@ -3,7 +3,7 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (7.1.1) + activesupport (7.1.2) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -18,42 +18,42 @@ GEM algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) - arkana (1.5.0) + arkana (1.6.0) dotenv (~> 2.7) rainbow (~> 3.1.1) yaml (~> 0.2) artifactory (3.0.15) atomos (0.1.3) - aws-eventstream (1.2.0) - aws-partitions (1.843.0) - aws-sdk-core (3.185.1) - aws-eventstream (~> 1, >= 1.0.2) + aws-eventstream (1.3.0) + aws-partitions (1.863.0) + aws-sdk-core (3.190.0) + aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.5) + aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.72.0) - aws-sdk-core (~> 3, >= 3.184.0) + aws-sdk-kms (1.74.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.136.0) - aws-sdk-core (~> 3, >= 3.181.0) + aws-sdk-s3 (1.141.0) + aws-sdk-core (~> 3, >= 3.189.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.6) - aws-sigv4 (1.6.1) + aws-sigv4 (~> 1.8) + aws-sigv4 (1.8.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) - base64 (0.1.1) + base64 (0.2.0) bigdecimal (3.1.4) claide (1.1.0) claide-plugins (0.9.2) cork nap open4 (~> 1.3) - cocoapods (1.14.2) + cocoapods (1.14.3) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.14.2) + cocoapods-core (= 1.14.3) cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 2.0) + cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) cocoapods-trunk (>= 1.6.0, < 2.0) @@ -66,7 +66,7 @@ GEM nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.14.2) + cocoapods-core (1.14.3) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -77,7 +77,7 @@ GEM public_suffix (~> 4.0) typhoeus (~> 1.0) cocoapods-deintegrate (1.0.5) - cocoapods-downloader (2.0) + cocoapods-downloader (2.1) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.1) @@ -93,7 +93,7 @@ GEM connection_pool (2.4.1) cork (0.3.0) colored2 (~> 3.1) - danger (9.3.2) + danger (9.4.1) claide (~> 1.0) claide-plugins (>= 0.9.2) colored2 (~> 3.1) @@ -104,13 +104,13 @@ GEM kramdown (~> 2.3) kramdown-parser-gfm (~> 1.0) no_proxy_fix - octokit (~> 6.0) + octokit (>= 6.0) terminal-table (>= 1, < 4) danger-plugin-api (1.0.0) danger (> 2.0) - danger-swiftformat (0.8.1) + danger-swiftformat (0.9.0) danger-plugin-api (~> 1.0) - danger-swiftlint (0.33.0) + danger-swiftlint (0.34.0) danger rake (> 10) thor (~> 0.19) @@ -123,16 +123,15 @@ GEM declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20231109) dotenv (2.8.1) - drb (2.1.1) + drb (2.2.0) ruby2_keywords emoji_regex (3.2.3) escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - excon (0.104.0) + excon (0.105.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -164,7 +163,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.7) - fastlane (2.216.0) + fastlane (2.217.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -213,7 +212,7 @@ GEM git (1.18.0) addressable (~> 2.8) rchardet (~> 1.8) - google-apis-androidpublisher_v3 (0.51.0) + google-apis-androidpublisher_v3 (0.53.0) google-apis-core (>= 0.11.0, < 2.a) google-apis-core (0.11.2) addressable (~> 2.5, >= 2.5.1) @@ -230,19 +229,19 @@ GEM google-apis-core (>= 0.11.0, < 2.a) google-apis-playcustomapp_v1 (0.13.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-storage_v1 (0.19.0) - google-apis-core (>= 0.9.0, < 2.a) + google-apis-storage_v1 (0.29.0) + google-apis-core (>= 0.11.0, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) google-cloud-errors (1.3.1) - google-cloud-storage (1.44.0) + google-cloud-storage (1.45.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.19.0) + google-apis-storage_v1 (~> 0.29.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) @@ -259,7 +258,7 @@ GEM i18n (1.14.1) concurrent-ruby (~> 1.0) jmespath (1.6.2) - json (2.6.3) + json (2.7.1) jwt (2.7.1) kramdown (2.4.0) rexml @@ -271,13 +270,13 @@ GEM molinillo (0.8.0) multi_json (1.15.0) multipart-post (2.3.0) - mutex_m (0.1.2) + mutex_m (0.2.0) nanaimo (0.3.0) nap (1.1.0) naturally (2.2.1) netrc (0.11.0) no_proxy_fix (0.1.2) - octokit (6.1.1) + octokit (8.0.0) faraday (>= 1, < 3) sawyer (~> 0.9) open4 (1.3.4) @@ -320,14 +319,11 @@ GEM tty-screen (0.8.1) tty-spinner (0.9.3) tty-cursor (~> 0.7) - typhoeus (1.4.0) + typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) unicode-display_width (2.5.0) webrick (1.8.1) word_wrap (1.0.0) @@ -350,7 +346,7 @@ GEM xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) xcresult (0.2.1) - yaml (0.2.1) + yaml (0.3.0) PLATFORMS x86_64-darwin-21 diff --git a/sample/ios/Podfile.lock b/sample/ios/Podfile.lock index 16b7978e..57e00ece 100644 --- a/sample/ios/Podfile.lock +++ b/sample/ios/Podfile.lock @@ -4,20 +4,20 @@ PODS: - ArkanaKeysInterfaces (1.0.0) - Differentiator (5.0.0) - Factory (2.3.1) - - Firebase/CoreOnly (10.17.0): - - FirebaseCore (= 10.17.0) - - Firebase/Crashlytics (10.17.0): + - Firebase/CoreOnly (10.18.0): + - FirebaseCore (= 10.18.0) + - Firebase/Crashlytics (10.18.0): - Firebase/CoreOnly - - FirebaseCrashlytics (~> 10.17.0) - - FirebaseCore (10.17.0): + - FirebaseCrashlytics (~> 10.18.0) + - FirebaseCore (10.18.0): - FirebaseCoreInternal (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - GoogleUtilities/Logger (~> 7.8) - - FirebaseCoreExtension (10.17.0): + - GoogleUtilities/Environment (~> 7.12) + - GoogleUtilities/Logger (~> 7.12) + - FirebaseCoreExtension (10.18.0): - FirebaseCore (~> 10.0) - - FirebaseCoreInternal (10.17.0): + - FirebaseCoreInternal (10.18.0): - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseCrashlytics (10.17.0): + - FirebaseCrashlytics (10.18.0): - FirebaseCore (~> 10.5) - FirebaseInstallations (~> 10.0) - FirebaseSessions (~> 10.5) @@ -25,12 +25,12 @@ PODS: - GoogleUtilities/Environment (~> 7.8) - nanopb (< 2.30910.0, >= 2.30908.0) - PromisesObjC (~> 2.1) - - FirebaseInstallations (10.17.0): + - FirebaseInstallations (10.18.0): - FirebaseCore (~> 10.0) - GoogleUtilities/Environment (~> 7.8) - GoogleUtilities/UserDefaults (~> 7.8) - PromisesObjC (~> 2.1) - - FirebaseSessions (10.17.0): + - FirebaseSessions (10.18.0): - FirebaseCore (~> 10.5) - FirebaseCoreExtension (~> 10.0) - FirebaseInstallations (~> 10.0) @@ -38,16 +38,16 @@ PODS: - GoogleUtilities/Environment (~> 7.10) - nanopb (< 2.30910.0, >= 2.30908.0) - PromisesSwift (~> 2.1) - - GoogleDataTransport (9.2.5): + - GoogleDataTransport (9.3.0): - GoogleUtilities/Environment (~> 7.7) - nanopb (< 2.30910.0, >= 2.30908.0) - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Environment (7.11.6): + - GoogleUtilities/Environment (7.12.0): - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.11.6): + - GoogleUtilities/Logger (7.12.0): - GoogleUtilities/Environment - - "GoogleUtilities/NSData+zlib (7.11.6)" - - GoogleUtilities/UserDefaults (7.11.6): + - "GoogleUtilities/NSData+zlib (7.12.0)" + - GoogleUtilities/UserDefaults (7.12.0): - GoogleUtilities/Logger - IQKeyboardManagerSwift (6.5.16) - KeychainAccess (4.2.2) @@ -57,11 +57,11 @@ PODS: - KIF/IdentifierTests (3.8.9): - KIF/Core - Kingfisher (7.10.0) - - nanopb (2.30909.0): - - nanopb/decode (= 2.30909.0) - - nanopb/encode (= 2.30909.0) - - nanopb/decode (2.30909.0) - - nanopb/encode (2.30909.0) + - nanopb (2.30909.1): + - nanopb/decode (= 2.30909.1) + - nanopb/encode (= 2.30909.1) + - nanopb/decode (2.30909.1) + - nanopb/encode (2.30909.1) - Nimble (13.0.0) - NimbleExtension (0.1.0) - PromisesObjC (2.3.1) @@ -96,8 +96,8 @@ PODS: - Sourcery (2.1.1): - Sourcery/CLI-Only (= 2.1.1) - Sourcery/CLI-Only (2.1.1) - - SwiftFormat/CLI (0.52.8) - - SwiftLint (0.53.0) + - SwiftFormat/CLI (0.52.10) + - SwiftLint (0.54.0) - Wormholy (1.7.0) - xcbeautify (0.17.0) @@ -183,20 +183,20 @@ SPEC CHECKSUMS: ArkanaKeysInterfaces: 81d21923368b058e2b6fd932ec96855166ef6d19 Differentiator: e8497ceab83c1b10ca233716d547b9af21b9344d Factory: 0aaf52d866846f0d50f42442cc39a91b8f6a07e0 - Firebase: f4ac0b02927af9253ae094d23deecf0890da7374 - FirebaseCore: 534544dd98cabcf4bf8598d88ec683b02319a528 - FirebaseCoreExtension: 47720bb330d7041047c0935a34a3a4b92f818074 - FirebaseCoreInternal: 2cf9202e226e3f78d2bf6d56c472686b935bfb7f - FirebaseCrashlytics: d78651ad7db206ef98269e103ac38d69d569200a - FirebaseInstallations: 9387bf15abfc69a714f54e54f74a251264fdb79b - FirebaseSessions: 49f39e5c10e3f9fdd38d01b748329bae2a2fa8ed - GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2 - GoogleUtilities: 202e7a9f5128accd11160fb9c19612de1911aa19 + Firebase: 414ad272f8d02dfbf12662a9d43f4bba9bec2a06 + FirebaseCore: 2322423314d92f946219c8791674d2f3345b598f + FirebaseCoreExtension: 62b201498aa10535801cdf3448c7f4db5e24ed80 + FirebaseCoreInternal: 8eb002e564b533bdcf1ba011f33f2b5c10e2ed4a + FirebaseCrashlytics: 86d5bce01f42fa1db265f87ff1d591f04db610ec + FirebaseInstallations: e842042ec6ac1fd2e37d7706363ebe7f662afea4 + FirebaseSessions: f90fe9212ee2818641eda051c0835c9c4e30d9ae + GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe + GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34 IQKeyboardManagerSwift: 12d89768845bb77b55cc092ecc2b1f9370f06b76 KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51 KIF: 7660c626b0f2d4562533590960db70a36d640558 Kingfisher: a18f05d3b6d37d8650ee4a3e61d57a28fc6207f6 - nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 + nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5 Nimble: 97d90931cca412a23224ff29e258809f75c258f7 NimbleExtension: acad4290f27afd4241b1ea20f8597889085e2ce7 PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 @@ -212,11 +212,11 @@ SPEC CHECKSUMS: RxTest: a23f26bb53a5e146a0a69db4f0fa0b69001ce7f4 SnapKit: e01d52ebb8ddbc333eefe2132acf85c8227d9c25 Sourcery: 3a6e2e9bd439caeee302e8150dc712d2f8ef45b3 - SwiftFormat: e60dbe6a704faf75f3089744e5f508aae0be4ad5 - SwiftLint: 5ce4d6a8ff83f1b5fd5ad5dbf30965d35af65e44 + SwiftFormat: ffd19286990ae717ca1729b853a75a439dfcf77a + SwiftLint: c1de071d9d08c8aba837545f6254315bc900e211 Wormholy: ab1c8c2f02f58587a0941deb0088555ffbf039a1 xcbeautify: 6e2f57af5c3a86d490376d5758030a8dcc201c1b PODFILE CHECKSUM: 85d4cae5e270d7a65db55a5c553c6c13b91a7b7f -COCOAPODS: 1.14.2 +COCOAPODS: 1.14.3 diff --git a/sample/ios/sample.xcodeproj/project.pbxproj b/sample/ios/sample.xcodeproj/project.pbxproj index 73fe7a96..cd9d5b39 100644 --- a/sample/ios/sample.xcodeproj/project.pbxproj +++ b/sample/ios/sample.xcodeproj/project.pbxproj @@ -7,25 +7,25 @@ objects = { /* Begin PBXBuildFile section */ + 0495CEC5165F98925D7CABA4 /* Pods_sample_sampleKIFUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6CBE779400F74BA80DF07EB /* Pods_sample_sampleKIFUITests.framework */; }; 0B975608DEB5FC5F00024E82 /* .gitkeep in Resources */ = {isa = PBXBuildFile; fileRef = EFE5D281FD0FFFF44FC92B04 /* .gitkeep */; }; 0FCD70BBC15623E2843E571B /* .gitkeep in Resources */ = {isa = PBXBuildFile; fileRef = E4C58806C2B28AED0873F8AF /* .gitkeep */; }; 18B4C2A55909888C5D0EDFDA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6432B427D5097BCF75C4B15E /* AppDelegate.swift */; }; 1F3B8CA45E426F2E4BA8A41C /* R.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EEB8F8EE4393D2D9AC51316 /* R.generated.swift */; }; 20FF012BAC088FFC92962E28 /* UIView+Subviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDBCDCBA1D855D7023A0342F /* UIView+Subviews.swift */; }; + 2D67B0DFE8E1CA3B5A07B5F0 /* Pods_sampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 355BE8BBCB766E70F98AC8A7 /* Pods_sampleTests.framework */; }; 33209CEB34C04BC32D0FFDD4 /* UseCaseFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CA52B4C8C3AF1CB2181C14D /* UseCaseFactoryProtocol.swift */; }; 3559AC5988194A4701902F80 /* .gitkeep in Resources */ = {isa = PBXBuildFile; fileRef = 302BB730B8D0BF901FF489B6 /* .gitkeep */; }; 53157A77A8B802D108AE9D73 /* Typealiases.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5B819017A28FE15B242BB5B /* Typealiases.swift */; }; 66C817ACCA7CE15ABF58BC06 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBD1568B768046A18E011F2C /* HomeViewController.swift */; }; 701258D40CE69EC8168A3D12 /* AutoMockable.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBF1B234787FCD92142B105D /* AutoMockable.generated.swift */; }; + 761252DDEFFFABC668A50FE0 /* Pods_sample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4596CBEDDB3EA5762654E780 /* Pods_sample.framework */; }; 7CF0F8933FB47F5D003383AA /* .gitkeep in Resources */ = {isa = PBXBuildFile; fileRef = 41210B648761A8DC4ABD3BB9 /* .gitkeep */; }; 7ED0E12DA355DEE8EED0B614 /* Color+Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = A29F97F67192DE9B66E872E6 /* Color+Application.swift */; }; 840CF0D3913B0069F0F2FF12 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D2F657F289C5314152FFCFA2 /* Assets.xcassets */; }; - 8A339C105AE529C0E00A1A84 /* Pods_sample_sampleKIFUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CAAF6ADA0D8AC3560AEACE7E /* Pods_sample_sampleKIFUITests.framework */; }; 8A43095CEA3F4C83584AB199 /* .gitkeep in Resources */ = {isa = PBXBuildFile; fileRef = 05F57F86A37A0E0B6CC54CB4 /* .gitkeep */; }; - 90A82EC9FD14E9B175C57A8F /* Pods_sampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E5F5668B0AD7E4C9A8128EBA /* Pods_sampleTests.framework */; }; 9726C56684473F7E78415A58 /* Navigator+Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = A64B0E7B034D526205048030 /* Navigator+Scene.swift */; }; 9ACA6A5E938E3365302C3749 /* Navigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C159B27C88C08E8AEB22AFD4 /* Navigator.swift */; }; - A42E84F5CF8BB978DF0AAD74 /* Pods_sample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0386D8BB0B951821215E276 /* Pods_sample.framework */; }; BA754F29AB917D745895322D /* Constants+API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 222B1BD9F71FF1797F160231 /* Constants+API.swift */; }; C152F2B63E42238BE4F20592 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F5C2293A2DB24CDCA81957 /* Constants.swift */; }; CA324314BE7318252E4D5D62 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6952456309E29C9609D23B3F /* LaunchScreen.storyboard */; }; @@ -88,48 +88,48 @@ /* Begin PBXFileReference section */ 04B8796D7472561BF8EB10A1 /* DebugProduction.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DebugProduction.xcconfig; sourceTree = ""; }; 05F57F86A37A0E0B6CC54CB4 /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = ""; }; - 0C3A7424697C1A1B954C0C6A /* Pods-sample.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample.release production.xcconfig"; path = "Target Support Files/Pods-sample/Pods-sample.release production.xcconfig"; sourceTree = ""; }; + 0BBA21280B9D11FA855F681B /* Pods-sampleTests.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sampleTests.release production.xcconfig"; path = "Target Support Files/Pods-sampleTests/Pods-sampleTests.release production.xcconfig"; sourceTree = ""; }; + 104124B136B5272470D331C9 /* Pods-sample.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample.debug production.xcconfig"; path = "Target Support Files/Pods-sample/Pods-sample.debug production.xcconfig"; sourceTree = ""; }; 18C176717B282B7A8842FC73 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 1EEB8F8EE4393D2D9AC51316 /* R.generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = R.generated.swift; sourceTree = ""; }; + 219FF6F9112AF3E91F07A91E /* Pods-sampleTests.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sampleTests.release staging.xcconfig"; path = "Target Support Files/Pods-sampleTests/Pods-sampleTests.release staging.xcconfig"; sourceTree = ""; }; 222B1BD9F71FF1797F160231 /* Constants+API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Constants+API.swift"; sourceTree = ""; }; + 2D0E7E2C5EE14CEBFC871796 /* Pods-sample-sampleKIFUITests.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample-sampleKIFUITests.release staging.xcconfig"; path = "Target Support Files/Pods-sample-sampleKIFUITests/Pods-sample-sampleKIFUITests.release staging.xcconfig"; sourceTree = ""; }; 302BB730B8D0BF901FF489B6 /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = ""; }; + 355BE8BBCB766E70F98AC8A7 /* Pods_sampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_sampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 41210B648761A8DC4ABD3BB9 /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = ""; }; 414B86B12605C252A692EA37 /* sampleKIFUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = sampleKIFUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 4596CBEDDB3EA5762654E780 /* Pods_sample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_sample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 562EF605C844B951CD47F38D /* Optional+Unwrap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Unwrap.swift"; sourceTree = ""; }; - 634D8AED806CAFA271D3C4A8 /* Pods-sampleTests.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sampleTests.debug staging.xcconfig"; path = "Target Support Files/Pods-sampleTests/Pods-sampleTests.debug staging.xcconfig"; sourceTree = ""; }; + 6202880F0852F9152109F11C /* Pods-sampleTests.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sampleTests.debug production.xcconfig"; path = "Target Support Files/Pods-sampleTests/Pods-sampleTests.debug production.xcconfig"; sourceTree = ""; }; 6432B427D5097BCF75C4B15E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 647A27AA39E9BC61DF5CC110 /* Pods-sample.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample.debug staging.xcconfig"; path = "Target Support Files/Pods-sample/Pods-sample.debug staging.xcconfig"; sourceTree = ""; }; 67C0EA707F4FBB459FEBA640 /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = ""; }; 6952456309E29C9609D23B3F /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; - 7A1E815D875486268C190447 /* Pods-sample-sampleKIFUITests.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample-sampleKIFUITests.debug production.xcconfig"; path = "Target Support Files/Pods-sample-sampleKIFUITests/Pods-sample-sampleKIFUITests.debug production.xcconfig"; sourceTree = ""; }; - 7C0049B84A46E01538565245 /* Pods-sample-sampleKIFUITests.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample-sampleKIFUITests.debug staging.xcconfig"; path = "Target Support Files/Pods-sample-sampleKIFUITests/Pods-sample-sampleKIFUITests.debug staging.xcconfig"; sourceTree = ""; }; + 7699F80647A1FC17D60855B2 /* Pods-sample-sampleKIFUITests.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample-sampleKIFUITests.release production.xcconfig"; path = "Target Support Files/Pods-sample-sampleKIFUITests/Pods-sample-sampleKIFUITests.release production.xcconfig"; sourceTree = ""; }; 82F5C2293A2DB24CDCA81957 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; - 8330189566A3A29C61BC7FF2 /* Pods-sample-sampleKIFUITests.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample-sampleKIFUITests.release production.xcconfig"; path = "Target Support Files/Pods-sample-sampleKIFUITests/Pods-sample-sampleKIFUITests.release production.xcconfig"; sourceTree = ""; }; 8CA52B4C8C3AF1CB2181C14D /* UseCaseFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UseCaseFactoryProtocol.swift; sourceTree = ""; }; - 910F16BA17F6D035249BF154 /* Pods-sample.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample.debug production.xcconfig"; path = "Target Support Files/Pods-sample/Pods-sample.debug production.xcconfig"; sourceTree = ""; }; - 95AA3E2E16A48DA59A6F4C9C /* Pods-sampleTests.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sampleTests.release production.xcconfig"; path = "Target Support Files/Pods-sampleTests/Pods-sampleTests.release production.xcconfig"; sourceTree = ""; }; - 9C9218B240549CFC08CB40C6 /* Pods-sample-sampleKIFUITests.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample-sampleKIFUITests.release staging.xcconfig"; path = "Target Support Files/Pods-sample-sampleKIFUITests/Pods-sample-sampleKIFUITests.release staging.xcconfig"; sourceTree = ""; }; + 90A2F4FF90AE0762AA3FCD4F /* Pods-sample-sampleKIFUITests.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample-sampleKIFUITests.debug staging.xcconfig"; path = "Target Support Files/Pods-sample-sampleKIFUITests/Pods-sample-sampleKIFUITests.debug staging.xcconfig"; sourceTree = ""; }; + 949E81C9A3D65DD3E2F9DB19 /* Pods-sample.release production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample.release production.xcconfig"; path = "Target Support Files/Pods-sample/Pods-sample.release production.xcconfig"; sourceTree = ""; }; A29F97F67192DE9B66E872E6 /* Color+Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Application.swift"; sourceTree = ""; }; A64B0E7B034D526205048030 /* Navigator+Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Navigator+Scene.swift"; sourceTree = ""; }; + A7CF0B04683C4F8EC5509BEE /* Pods-sample-sampleKIFUITests.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample-sampleKIFUITests.debug production.xcconfig"; path = "Target Support Files/Pods-sample-sampleKIFUITests/Pods-sample-sampleKIFUITests.debug production.xcconfig"; sourceTree = ""; }; ADE63A1C257C06E1D05C8136 /* DebugStaging.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DebugStaging.xcconfig; sourceTree = ""; }; + B6CBE779400F74BA80DF07EB /* Pods_sample_sampleKIFUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_sample_sampleKIFUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B7C41116D460DF2604302F21 /* Pods-sample.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample.debug staging.xcconfig"; path = "Target Support Files/Pods-sample/Pods-sample.debug staging.xcconfig"; sourceTree = ""; }; B8847183C3FF3D70FE4192CD /* sampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = sampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; BBD1568B768046A18E011F2C /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; }; BBF1B234787FCD92142B105D /* AutoMockable.generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoMockable.generated.swift; sourceTree = ""; }; BD9D9C9A495C5EA0AE9039C6 /* ReleaseProduction.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseProduction.xcconfig; sourceTree = ""; }; - C0386D8BB0B951821215E276 /* Pods_sample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_sample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C159B27C88C08E8AEB22AFD4 /* Navigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Navigator.swift; sourceTree = ""; }; - CAAF6ADA0D8AC3560AEACE7E /* Pods_sample_sampleKIFUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_sample_sampleKIFUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CD3A7C3AC94E15DEC4F12A85 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; CDBCDCBA1D855D7023A0342F /* UIView+Subviews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Subviews.swift"; sourceTree = ""; }; - D0878D95344DEB8A9B9FF7B9 /* Pods-sample.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample.release staging.xcconfig"; path = "Target Support Files/Pods-sample/Pods-sample.release staging.xcconfig"; sourceTree = ""; }; D2D7345A2017D2D372785123 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; D2F657F289C5314152FFCFA2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - D77A375C1C20601A88749631 /* Pods-sampleTests.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sampleTests.release staging.xcconfig"; path = "Target Support Files/Pods-sampleTests/Pods-sampleTests.release staging.xcconfig"; sourceTree = ""; }; + D8259AEE39D850B1D84C7D84 /* Pods-sample.release staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sample.release staging.xcconfig"; path = "Target Support Files/Pods-sample/Pods-sample.release staging.xcconfig"; sourceTree = ""; }; E4C58806C2B28AED0873F8AF /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = ""; }; - E5F5668B0AD7E4C9A8128EBA /* Pods_sampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_sampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + ECB02330D3B4769CB72B35EE /* Pods-sampleTests.debug staging.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sampleTests.debug staging.xcconfig"; path = "Target Support Files/Pods-sampleTests/Pods-sampleTests.debug staging.xcconfig"; sourceTree = ""; }; EFAE58D40BFE459B1184D994 /* KIF+Swift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KIF+Swift.swift"; sourceTree = ""; }; EFE5D281FD0FFFF44FC92B04 /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = ""; }; - F193E4BAA85237B1F637EB60 /* Pods-sampleTests.debug production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sampleTests.debug production.xcconfig"; path = "Target Support Files/Pods-sampleTests/Pods-sampleTests.debug production.xcconfig"; sourceTree = ""; }; F5B819017A28FE15B242BB5B /* Typealiases.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Typealiases.swift; sourceTree = ""; }; F854F7439696BB6B30145F6D /* ReleaseStaging.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseStaging.xcconfig; sourceTree = ""; }; F9816C413C0D0DD7B01BA9CE /* Navigator+Transition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Navigator+Transition.swift"; sourceTree = ""; }; @@ -141,7 +141,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 8A339C105AE529C0E00A1A84 /* Pods_sample_sampleKIFUITests.framework in Frameworks */, + 0495CEC5165F98925D7CABA4 /* Pods_sample_sampleKIFUITests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -149,7 +149,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 90A82EC9FD14E9B175C57A8F /* Pods_sampleTests.framework in Frameworks */, + 2D67B0DFE8E1CA3B5A07B5F0 /* Pods_sampleTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -157,7 +157,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A42E84F5CF8BB978DF0AAD74 /* Pods_sample.framework in Frameworks */, + 761252DDEFFFABC668A50FE0 /* Pods_sample.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -190,6 +190,26 @@ path = Modules; sourceTree = ""; }; + 12C5C0AF3364368EA87F3F19 /* Pods */ = { + isa = PBXGroup; + children = ( + 104124B136B5272470D331C9 /* Pods-sample.debug production.xcconfig */, + B7C41116D460DF2604302F21 /* Pods-sample.debug staging.xcconfig */, + 949E81C9A3D65DD3E2F9DB19 /* Pods-sample.release production.xcconfig */, + D8259AEE39D850B1D84C7D84 /* Pods-sample.release staging.xcconfig */, + A7CF0B04683C4F8EC5509BEE /* Pods-sample-sampleKIFUITests.debug production.xcconfig */, + 90A2F4FF90AE0762AA3FCD4F /* Pods-sample-sampleKIFUITests.debug staging.xcconfig */, + 7699F80647A1FC17D60855B2 /* Pods-sample-sampleKIFUITests.release production.xcconfig */, + 2D0E7E2C5EE14CEBFC871796 /* Pods-sample-sampleKIFUITests.release staging.xcconfig */, + 6202880F0852F9152109F11C /* Pods-sampleTests.debug production.xcconfig */, + ECB02330D3B4769CB72B35EE /* Pods-sampleTests.debug staging.xcconfig */, + 0BBA21280B9D11FA855F681B /* Pods-sampleTests.release production.xcconfig */, + 219FF6F9112AF3E91F07A91E /* Pods-sampleTests.release staging.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 2003C041305A8015968A9294 /* Plists */ = { isa = PBXGroup; children = ( @@ -261,9 +281,9 @@ 52B072A663159D9D007D540F /* Frameworks */ = { isa = PBXGroup; children = ( - C0386D8BB0B951821215E276 /* Pods_sample.framework */, - CAAF6ADA0D8AC3560AEACE7E /* Pods_sample_sampleKIFUITests.framework */, - E5F5668B0AD7E4C9A8128EBA /* Pods_sampleTests.framework */, + 4596CBEDDB3EA5762654E780 /* Pods_sample.framework */, + B6CBE779400F74BA80DF07EB /* Pods_sample_sampleKIFUITests.framework */, + 355BE8BBCB766E70F98AC8A7 /* Pods_sampleTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -298,7 +318,7 @@ 9B7CF20BE2915B62911C62AA /* Project */, 52B072A663159D9D007D540F /* Frameworks */, 372816F20EC291B850EECF1F /* Products */, - FC1F238147E07F8C039584C2 /* Pods */, + 12C5C0AF3364368EA87F3F19 /* Pods */, ); sourceTree = ""; }; @@ -543,26 +563,6 @@ path = Entities; sourceTree = ""; }; - FC1F238147E07F8C039584C2 /* Pods */ = { - isa = PBXGroup; - children = ( - 910F16BA17F6D035249BF154 /* Pods-sample.debug production.xcconfig */, - 647A27AA39E9BC61DF5CC110 /* Pods-sample.debug staging.xcconfig */, - 0C3A7424697C1A1B954C0C6A /* Pods-sample.release production.xcconfig */, - D0878D95344DEB8A9B9FF7B9 /* Pods-sample.release staging.xcconfig */, - 7A1E815D875486268C190447 /* Pods-sample-sampleKIFUITests.debug production.xcconfig */, - 7C0049B84A46E01538565245 /* Pods-sample-sampleKIFUITests.debug staging.xcconfig */, - 8330189566A3A29C61BC7FF2 /* Pods-sample-sampleKIFUITests.release production.xcconfig */, - 9C9218B240549CFC08CB40C6 /* Pods-sample-sampleKIFUITests.release staging.xcconfig */, - F193E4BAA85237B1F637EB60 /* Pods-sampleTests.debug production.xcconfig */, - 634D8AED806CAFA271D3C4A8 /* Pods-sampleTests.debug staging.xcconfig */, - 95AA3E2E16A48DA59A6F4C9C /* Pods-sampleTests.release production.xcconfig */, - D77A375C1C20601A88749631 /* Pods-sampleTests.release staging.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -570,7 +570,7 @@ isa = PBXNativeTarget; buildConfigurationList = 56FE2126489C1E87A2D918A3 /* Build configuration list for PBXNativeTarget "sample" */; buildPhases = ( - 67EDEE448585498C2FD57B0F /* [CP] Check Pods Manifest.lock */, + E67EA2C09944F600A7A4433F /* [CP] Check Pods Manifest.lock */, B2B621CC2B1F4F58601CD98D /* Sourcery */, 7EB246CFC1E0CCBA652DC37E /* R.swift */, CF26733D03C8D33F8823EE1F /* SwiftLint */, @@ -580,7 +580,7 @@ 494614C33B509301DBBDAD42 /* Embed Frameworks */, 89C77BA3C707AD804F79284B /* Frameworks */, 843C67A8A78058B8D8B3D11E /* Copy GoogleService-Info.plist */, - 134A96ED263C4F33CE62ECB2 /* [CP] Embed Pods Frameworks */, + FCE2330E514641FAF152E8EA /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -595,12 +595,12 @@ isa = PBXNativeTarget; buildConfigurationList = 31E84C030BDB7A39BCE38D8C /* Build configuration list for PBXNativeTarget "sampleKIFUITests" */; buildPhases = ( - B0E6B85B72D207AD7B3E752F /* [CP] Check Pods Manifest.lock */, + 76E5D1C42C0FCE74839E8756 /* [CP] Check Pods Manifest.lock */, 21ADDF0B071B770FFB6A086A /* Sources */, 43218B877C978B4CA5B93235 /* Resources */, 392BFB718CBF57CF0D23848E /* Embed Frameworks */, 29CEF4F9FF315D4254B8BC69 /* Frameworks */, - 97A76DC242D59CABE7E11EE0 /* [CP] Embed Pods Frameworks */, + B9AF22FB12EC568F35E452AE /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -616,13 +616,13 @@ isa = PBXNativeTarget; buildConfigurationList = C3875EBB5A0F6612B3515A13 /* Build configuration list for PBXNativeTarget "sampleTests" */; buildPhases = ( - 635D1B4A91DEAB1FC7934604 /* [CP] Check Pods Manifest.lock */, + 242CC2B9FEA66B6EC6746F60 /* [CP] Check Pods Manifest.lock */, 2F7B6AB35D89AA83D514ECC2 /* SwiftFormat */, 9344943859735CAEA8DDB048 /* Sources */, E472A2AC48FE9588146AB254 /* Resources */, 51D3263E7013F91DCDB0D884 /* Embed Frameworks */, 7A7AFF7C6576A774E896CA81 /* Frameworks */, - F38C0A58BFB49AA4680A0D97 /* [CP] Embed Pods Frameworks */, + D8AC8993FA1649A902943268 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -703,21 +703,26 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 134A96ED263C4F33CE62ECB2 /* [CP] Embed Pods Frameworks */ = { + 242CC2B9FEA66B6EC6746F60 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-sample/Pods-sample-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-sample/Pods-sample-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-sampleTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-sample/Pods-sample-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; }; 2F7B6AB35D89AA83D514ECC2 /* SwiftFormat */ = { @@ -738,7 +743,7 @@ shellPath = /bin/sh; shellScript = "if [ -z \"$CI\" ]; then\n \"${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat\" \"$SRCROOT\"\nfi"; }; - 635D1B4A91DEAB1FC7934604 /* [CP] Check Pods Manifest.lock */ = { + 76E5D1C42C0FCE74839E8756 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -753,38 +758,35 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-sampleTests-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-sample-sampleKIFUITests-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; }; - 67EDEE448585498C2FD57B0F /* [CP] Check Pods Manifest.lock */ = { + 7EB246CFC1E0CCBA652DC37E /* R.swift */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Check Pods Manifest.lock"; + name = R.swift; outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-sample-checkManifestLockResult.txt", + "$SRCROOT/$PROJECT_NAME/Sources/Supports/Helpers/Rswift/R.generated.swift", ); 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; + shellScript = "\"$PODS_ROOT/R.swift/rswift\" generate \"$SRCROOT/$PROJECT_NAME/Sources/Supports/Helpers/Rswift/R.generated.swift\""; }; - 7EB246CFC1E0CCBA652DC37E /* R.swift */ = { + 843C67A8A78058B8D8B3D11E /* Copy GoogleService-Info.plist */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -792,17 +794,16 @@ ); inputPaths = ( ); - name = R.swift; + name = "Copy GoogleService-Info.plist"; outputFileListPaths = ( ); outputPaths = ( - "$SRCROOT/$PROJECT_NAME/Sources/Supports/Helpers/Rswift/R.generated.swift", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"$PODS_ROOT/R.swift/rswift\" generate \"$SRCROOT/$PROJECT_NAME/Sources/Supports/Helpers/Rswift/R.generated.swift\""; + 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"; }; - 843C67A8A78058B8D8B3D11E /* Copy GoogleService-Info.plist */ = { + B2B621CC2B1F4F58601CD98D /* Sourcery */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -811,16 +812,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\""; }; - 97A76DC242D59CABE7E11EE0 /* [CP] Embed Pods Frameworks */ = { + B9AF22FB12EC568F35E452AE /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -837,7 +838,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-sample-sampleKIFUITests/Pods-sample-sampleKIFUITests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - B0E6B85B72D207AD7B3E752F /* [CP] Check Pods Manifest.lock */ = { + CF26733D03C8D33F8823EE1F /* SwiftLint */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -845,39 +846,34 @@ inputFileListPaths = ( ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Check Pods Manifest.lock"; + name = SwiftLint; outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-sample-sampleKIFUITests-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; + shellScript = "if [ -z \"$CI\" ]; then\n ${PODS_ROOT}/SwiftLint/swiftlint\nfi"; }; - B2B621CC2B1F4F58601CD98D /* Sourcery */ = { + D8AC8993FA1649A902943268 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-sampleTests/Pods-sampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); - name = Sourcery; + name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-sampleTests/Pods-sampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"$PODS_ROOT/Sourcery/bin/sourcery\""; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-sampleTests/Pods-sampleTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; }; - CF26733D03C8D33F8823EE1F /* SwiftLint */ = { + E67EA2C09944F600A7A4433F /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -885,15 +881,19 @@ inputFileListPaths = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); - name = SwiftLint; + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-sample-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ -z \"$CI\" ]; then\n ${PODS_ROOT}/SwiftLint/swiftlint\nfi"; + 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; }; EF3878B82E1CD4611A640906 /* SwiftFormat Lint */ = { isa = PBXShellScriptBuildPhase; @@ -913,21 +913,21 @@ shellPath = /bin/sh; shellScript = "if [ -z \"$CI\" ]; then\n \"${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat\" \"$SRCROOT\" --lint --lenient\nfi"; }; - F38C0A58BFB49AA4680A0D97 /* [CP] Embed Pods Frameworks */ = { + FCE2330E514641FAF152E8EA /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-sampleTests/Pods-sampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + "${PODS_ROOT}/Target Support Files/Pods-sample/Pods-sample-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-sampleTests/Pods-sampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + "${PODS_ROOT}/Target Support Files/Pods-sample/Pods-sample-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-sampleTests/Pods-sampleTests-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-sample/Pods-sample-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -989,7 +989,7 @@ /* Begin XCBuildConfiguration section */ 21ACBFF0B81C5FE1926420D2 /* Debug Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7A1E815D875486268C190447 /* Pods-sample-sampleKIFUITests.debug production.xcconfig */; + baseConfigurationReference = A7CF0B04683C4F8EC5509BEE /* Pods-sample-sampleKIFUITests.debug production.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1014,7 +1014,7 @@ }; 252EA76B363BC50D825D8BD6 /* Debug Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 634D8AED806CAFA271D3C4A8 /* Pods-sampleTests.debug staging.xcconfig */; + baseConfigurationReference = ECB02330D3B4769CB72B35EE /* Pods-sampleTests.debug staging.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1039,7 +1039,7 @@ }; 388E6BE620787A06CA1CA7EE /* Release Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D0878D95344DEB8A9B9FF7B9 /* Pods-sample.release staging.xcconfig */; + baseConfigurationReference = D8259AEE39D850B1D84C7D84 /* Pods-sample.release staging.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1063,7 +1063,7 @@ }; 38F81F703A83D6A307430059 /* Release Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 8330189566A3A29C61BC7FF2 /* Pods-sample-sampleKIFUITests.release production.xcconfig */; + baseConfigurationReference = 7699F80647A1FC17D60855B2 /* Pods-sample-sampleKIFUITests.release production.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1087,7 +1087,7 @@ }; 3BEDFE87FC2F0AE206422087 /* Release Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 95AA3E2E16A48DA59A6F4C9C /* Pods-sampleTests.release production.xcconfig */; + baseConfigurationReference = 0BBA21280B9D11FA855F681B /* Pods-sampleTests.release production.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1111,7 +1111,7 @@ }; 3E22885F8CD58F60301062E2 /* Release Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9C9218B240549CFC08CB40C6 /* Pods-sample-sampleKIFUITests.release staging.xcconfig */; + baseConfigurationReference = 2D0E7E2C5EE14CEBFC871796 /* Pods-sample-sampleKIFUITests.release staging.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1135,7 +1135,7 @@ }; 4C1D6824327C0FD7CA0FD5EA /* Release Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 0C3A7424697C1A1B954C0C6A /* Pods-sample.release production.xcconfig */; + baseConfigurationReference = 949E81C9A3D65DD3E2F9DB19 /* Pods-sample.release production.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1218,7 +1218,7 @@ }; 65EFF1C45B23F50B02803EAD /* Debug Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 647A27AA39E9BC61DF5CC110 /* Pods-sample.debug staging.xcconfig */; + baseConfigurationReference = B7C41116D460DF2604302F21 /* Pods-sample.debug staging.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1243,7 +1243,7 @@ }; 944F5AFF63FDFD18DB25D45F /* Debug Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 910F16BA17F6D035249BF154 /* Pods-sample.debug production.xcconfig */; + baseConfigurationReference = 104124B136B5272470D331C9 /* Pods-sample.debug production.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1268,7 +1268,7 @@ }; A6CE62F8A695FBBC221E4690 /* Debug Production */ = { isa = XCBuildConfiguration; - baseConfigurationReference = F193E4BAA85237B1F637EB60 /* Pods-sampleTests.debug production.xcconfig */; + baseConfigurationReference = 6202880F0852F9152109F11C /* Pods-sampleTests.debug production.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1293,7 +1293,7 @@ }; B7E6733E7030283A3E74681B /* Debug Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7C0049B84A46E01538565245 /* Pods-sample-sampleKIFUITests.debug staging.xcconfig */; + baseConfigurationReference = 90A2F4FF90AE0762AA3FCD4F /* Pods-sample-sampleKIFUITests.debug staging.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1371,7 +1371,7 @@ }; BD91BBB9D406D96A13EB8291 /* Release Staging */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D77A375C1C20601A88749631 /* Pods-sampleTests.release staging.xcconfig */; + baseConfigurationReference = 219FF6F9112AF3E91F07A91E /* Pods-sampleTests.release staging.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_IDENTITY = "iPhone Developer"; diff --git a/sample/settings.gradle.kts b/sample/settings.gradle.kts index dcc8f23e..c64ad0f2 100644 --- a/sample/settings.gradle.kts +++ b/sample/settings.gradle.kts @@ -14,6 +14,6 @@ dependencyResolutionManagement { } } -rootProject.name = "KMM_Template" +rootProject.name = "Sample" include(":android") include(":shared") diff --git a/make_android.sh b/scripts/make_android.sh similarity index 58% rename from make_android.sh rename to scripts/make_android.sh index e809a079..59c3c502 100644 --- a/make_android.sh +++ b/scripts/make_android.sh @@ -33,28 +33,31 @@ sed -i '' "/ buildProjectAndRunTests()*/d" scripts/new_project.kts kscript scripts/new_project.kts package-name=${bundle_id} app-name=${project_name} template=compose +# Convert bundle_id with dot to packake folder path, e.g., co.nimblehq.kmm.template -> co/nimblehq/kmm/template +package_path="${bundle_id//.//}" + # Correct dependencies -sed -i '' 's/Modules.DATA/Modules.SHARED/' sample/app/build.gradle.kts -sed -i '' "/implementation(project(Modules.DOMAIN))*/d" sample/app/build.gradle.kts -sed -i '' "/kover(project(Modules.DOMAIN))*/d" sample/app/build.gradle.kts +sed -i '' 's/Modules.DATA/Modules.SHARED/' $project_name/app/build.gradle.kts +sed -i '' "/implementation(project(Modules.DOMAIN))*/d" $project_name/app/build.gradle.kts +sed -i '' "/kover(project(Modules.DOMAIN))*/d" $project_name/app/build.gradle.kts # Correct imports -sed -i '' 's/import co.nimblehq.kmm.template.data.di.initKoin/import co.nimblehq.kmm.template.di.initKoin/' sample/app/src/main/java/co/nimblehq/kmm/template/MainApplication.kt +sed -i '' 's/import '$bundle_id'.data.di.initKoin/import '$bundle_id'.di.initKoin/' $project_name/app/src/main/java/$package_path/MainApplication.kt # Correct error mapping -sed -i '' 's/is ApiException -> error?.message/is ApiException -> message/' sample/app/src/main/java/co/nimblehq/kmm/template/ui/ErrorMapping.kt +sed -i '' 's/is ApiException -> error?.message/is ApiException -> message/' $project_name/app/src/main/java/$package_path/ui/ErrorMapping.kt # Remove unnecessary definition of BASE_API_URL -sed -i '' "/buildConfigField(\"String\", \"BASE_API_URL\"*/d" sample/app/build.gradle.kts -sed -i '' "/import co.nimblehq.kmm.template.BuildConfig*/d" sample/app/src/main/java/co/nimblehq/kmm/template/di/modules/AppModule.kt -sed -i '' "/import co.nimblehq.kmm.template.data.di.modules.BASE_API_URL*/d" sample/app/src/main/java/co/nimblehq/kmm/template/di/modules/AppModule.kt -sed -i '' "/import org.koin.core.qualifier.named*/d" sample/app/src/main/java/co/nimblehq/kmm/template/di/modules/AppModule.kt -sed -i '' "/ single(named(BASE_API_URL)) {\n*/d" sample/app/src/main/java/co/nimblehq/kmm/template/di/modules/AppModule.kt -sed -i '' "/ BuildConfig.BASE_API_URL\n*/d" sample/app/src/main/java/co/nimblehq/kmm/template/di/modules/AppModule.kt -sed -i '' "/ }\n*/d" sample/app/src/main/java/co/nimblehq/kmm/template/di/modules/AppModule.kt +sed -i '' "/buildConfigField(\"String\", \"BASE_API_URL\"*/d" $project_name/app/build.gradle.kts +sed -i '' "/import $bundle_id.BuildConfig*/d" $project_name/app/src/main/java/$package_path/di/modules/AppModule.kt +sed -i '' "/import $bundle_id.data.di.modules.BASE_API_URL*/d" $project_name/app/src/main/java/$package_path/di/modules/AppModule.kt +sed -i '' "/import org.koin.core.qualifier.named*/d" $project_name/app/src/main/java/$package_path/di/modules/AppModule.kt +sed -i '' "/ single(named(BASE_API_URL)) {\n*/d" $project_name/app/src/main/java/$package_path/di/modules/AppModule.kt +sed -i '' "/ BuildConfig.BASE_API_URL\n*/d" $project_name/app/src/main/java/$package_path/di/modules/AppModule.kt +sed -i '' "/ }\n*/d" $project_name/app/src/main/java/$package_path/di/modules/AppModule.kt # Overwrite custom files -rsync -av ../custom/android/ sample/app/ +rsync -av ../custom/android/ $project_name/app/ # Overwrite the Kover config for KMM perl -i -p0e 's/koverReport (.|\n)*}$/koverReport {\ @@ -81,6 +84,6 @@ perl -i -p0e 's/koverReport (.|\n)*}$/koverReport {\ }\ }\ }\ -}/g' sample/app/build.gradle.kts +}/g' $project_name/app/build.gradle.kts cd .. diff --git a/make_ios.sh b/scripts/make_ios.sh similarity index 100% rename from make_ios.sh rename to scripts/make_ios.sh diff --git a/scripts/make_shared.kts b/scripts/make_shared.kts new file mode 100644 index 00000000..6000d9ec --- /dev/null +++ b/scripts/make_shared.kts @@ -0,0 +1,221 @@ +import java.io.File + +object NewProject { + + private const val DELIMITER_ARGUMENT = "=" + + private const val KEY_APP_NAME = "app-name" + private const val KEY_PACKAGE_NAME = "package-name" + + private const val SCRIPTS_FOLDER_NAME = "scripts" + private const val SEPARATOR_DOT = "." + private const val SEPARATOR_MINUS = "-" + private const val SEPARATOR_SPACE = " " + + private const val TEMPLATE_APP_NAME = "KMM_Template" + private const val TEMPLATE_PACKAGE_NAME = "co.nimblehq.kmm.template" + + private val modules = listOf("shared") + + private val fileSeparator = File.separator + + private var appName: String = "" + set(value) { + field = if (value.contains(SEPARATOR_MINUS)) { + projectPath = value + value.replace(SEPARATOR_MINUS, SEPARATOR_SPACE).uppercaseEveryFirstCharacter() + } else { + value.uppercaseEveryFirstCharacter().also { + projectPath = it.getStringWithoutSpace() + } + } + } + + private var packageName = "" + + private var projectPath: String = "" + + private val rootPath: String + get() = System.getProperty("user.dir").let { userDir -> + if (userDir.endsWith("$fileSeparator$SCRIPTS_FOLDER_NAME")) { + userDir.substring(0, userDir.lastIndexOf(SCRIPTS_FOLDER_NAME)) + } else { + "$userDir$fileSeparator" + } + } + + private val templatePackageName + get() = TEMPLATE_PACKAGE_NAME + + private val templateAppName + get() = TEMPLATE_APP_NAME + + fun generate(args: Array) { + handleArguments(args) + initializeNewProjectFolder() + renamePackageNameFolders() + renamePackageNameWithinFiles() + renameAppName() + } + + private fun handleArguments(args: Array) { + args.forEach { arg -> + when { + arg.startsWith("$KEY_APP_NAME$DELIMITER_ARGUMENT") -> { + val (key, value) = arg.split(DELIMITER_ARGUMENT) + appName = value.trim() + } + arg.startsWith("$KEY_PACKAGE_NAME$DELIMITER_ARGUMENT") -> { + val (key, value) = arg.split(DELIMITER_ARGUMENT) + packageName = value.trim() + } + } + } + } + + private fun initializeNewProjectFolder() { + showMessage("=> 🐢 Initializing new project...") + modules.forEach { module -> + copyFiles(fromPath = rootPath + module, toPath = projectPath + fileSeparator + module) + } + } + + private fun renamePackageNameFolders() { + showMessage("=> 🔎 Renaming the package folders...") + modules.forEach { module -> + val srcPath = projectPath + fileSeparator + module + fileSeparator + "src" + File(srcPath) + .walk() + .maxDepth(2) + .filter { it.isDirectory } + .forEach { directory -> + val oldDirectory = File( + directory, templatePackageName.replace( + oldValue = SEPARATOR_DOT, + newValue = fileSeparator + ) + ) + if (oldDirectory.exists()) { + val newDirectory = File( + directory, packageName.replace( + oldValue = SEPARATOR_DOT, + newValue = fileSeparator + ) + ) + + val tempDirectory = File(directory, "temp_directory") + copyFiles( + fromPath = oldDirectory.absolutePath, + toPath = tempDirectory.absolutePath + ) + oldDirectory.parentFile?.parentFile?.deleteRecursively() + newDirectory.mkdirs() + copyFiles( + fromPath = tempDirectory.absolutePath, + toPath = newDirectory.absolutePath + ) + tempDirectory.deleteRecursively() + } + } + } + } + + private fun renamePackageNameWithinFiles() { + showMessage("=> 🔎 Renaming package name within files...") + File(projectPath) + .walk() + .filter { it.name.endsWithAny(".kt", ".xml", ".gradle.kts") } + .forEach { filePath -> + replace( + sourcePath = filePath.toString(), + oldValue = templatePackageName, + newValue = packageName + ) + } + } + + private fun copyFiles(fromPath: String, toPath: String) { + val targetFolder = File(toPath) + val sourceFolder = File(fromPath) + sourceFolder.copyRecursively(targetFolder, true) { file, exception -> + showMessage( + message = "${exception?.message ?: "Error copying files"}", + isError = true, + ) + return@copyRecursively OnErrorAction.TERMINATE + } + } + + private fun renameAppName() { + showMessage("=> 🔎 Renaming app name...") + File(projectPath) + .walk() + .filter { it.name == "strings.xml" } + .forEach { filePath -> + replace( + sourcePath = filePath.toString(), + oldValue = templateAppName, + newValue = appName + ) + } + File(projectPath) + .walk() + .filter { it.name == "settings.gradle.kts" } + .forEach { filePath -> + replace( + sourcePath = filePath.toString(), + oldValue = templateAppName, + newValue = appName + ) + } + } + + private fun replace(sourcePath: String, oldValue: String, newValue: String) { + val sourceFile = File(sourcePath) + var sourceText = sourceFile.readText() + sourceText = sourceText.replace(oldValue, newValue) + sourceFile.writeText(sourceText) + } + + private fun showMessage( + message: String, + exitAfterMessage: Boolean = false, + exitValue: Int = 0, + isError: Boolean = false, + ) { + println("\n${if (isError) "❌ " else ""}${message}\n") + if (exitAfterMessage) { + if (isError) { + exitWithError(exitValue) + } else { + System.exit(exitValue) + } + } + } + + private fun exitWithError(exitValue: Int = 0) { + if (projectPath.isNotBlank()) { + val file = File(projectPath) + if (file.exists()) { + file.deleteRecursively() + } + } + System.exit(exitValue) + } + + private fun String.uppercaseEveryFirstCharacter(): String { + return this.split(SEPARATOR_SPACE).joinToString(separator = SEPARATOR_SPACE) { string -> + string.replaceFirstChar { it.uppercase() } + } + } + + private fun String.getStringWithoutSpace(): String { + return this.replace(SEPARATOR_SPACE, "") + } + + private fun String.endsWithAny(vararg suffixes: String): Boolean { + return suffixes.any { endsWith(it) } + } +} + +NewProject.generate(args)