diff --git a/.env.sample b/.env.sample
new file mode 100644
index 0000000..f36d295
--- /dev/null
+++ b/.env.sample
@@ -0,0 +1,2 @@
+SECRET=
+REST_API_ENDPOINT=
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..5e4c93c
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,4 @@
+# Team
+# @minhnimble is the Engineering Lead
+# @nkhanh44 is the Team Lead
+* @nkhanh44 @Thieurom @doannimble @minhnimble
diff --git a/.github/ISSUE_TEMPLATE/bug_template.md b/.github/ISSUE_TEMPLATE/bug_template.md
index 18943b8..5eb84c3 100644
--- a/.github/ISSUE_TEMPLATE/bug_template.md
+++ b/.github/ISSUE_TEMPLATE/bug_template.md
@@ -7,12 +7,12 @@ labels: "type : bug"
## Issue
-Describe the issue you are facing. Show us the implementation: screenshots, GIFs, etc.
-
+Describe the issue you are facing. Show us the implementation: screenshots, gif, etc.
+
## Expected
-Describe what should be the correct behavior.
-
+Describe what should be the correct behaviour.
+
## Steps to reproduce
1.
diff --git a/.github/ISSUE_TEMPLATE/chore_template.md b/.github/ISSUE_TEMPLATE/chore_template.md
index 31da9ba..bb36ec2 100644
--- a/.github/ISSUE_TEMPLATE/chore_template.md
+++ b/.github/ISSUE_TEMPLATE/chore_template.md
@@ -1,14 +1,14 @@
---
name: "Chore"
-about: "Open a chore issue for a minor update."
+about: "Open a Chore for minor update."
title: "Update "
labels: "type : chore"
---
## Why
-Describe the update in detail and why it is needed.
-
+Describe the update details and why it's needed.
+
## Who Benefits?
Describe who will be the beneficiaries e.g. everyone, specific chapters, clients...
diff --git a/.github/ISSUE_TEMPLATE/feature_template.md b/.github/ISSUE_TEMPLATE/feature_template.md
index 3b009df..5a26eb9 100644
--- a/.github/ISSUE_TEMPLATE/feature_template.md
+++ b/.github/ISSUE_TEMPLATE/feature_template.md
@@ -7,8 +7,8 @@ labels: "type : feature"
## Why
-Describe the big picture of the feature and why it is needed.
-
+Describe the big picture of the feature and why it's needed.
+
## Who Benefits?
Describe who will be the beneficiaries e.g. everyone, specific chapters, clients...
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 00c4951..9c1062a 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -2,12 +2,15 @@
## What happened 👀
-Provide a description of the **changes** this pull request brings to the codebase. Additionally, when the pull request is still being worked on, a checklist of the planned changes is welcome to track progress.
+Describe the big picture of your changes here to communicate to the team why we should accept this pull request.
## Insight 📝
-Describe in detail why this solution is the most appropriate, which solution you tried but did not go with, and how to test the changes. References to relevant documentation are welcome as well.
+Describe in details how to test the changes, which solution you tried but did not go with, referenced documentation is
+welcome as well.
## Proof Of Work 📹
-Show us the implementation: screenshots, GIFs, etc.
+Show us the implementation: screenshots, gif, etc.
+
+
diff --git a/.github/PULL_REQUEST_TEMPLATE/release_template.md b/.github/PULL_REQUEST_TEMPLATE/release_template.md
index 59eb299..3a1e424 100644
--- a/.github/PULL_REQUEST_TEMPLATE/release_template.md
+++ b/.github/PULL_REQUEST_TEMPLATE/release_template.md
@@ -1,14 +1,12 @@
-Link to the milestone on Github e.g. https://github.com/nimblehq/git-templates/milestone/41?closed=1
-or
-Link to the project management tool for the release
+Link to the milestone on Github e.g. https://github.com/nimblehq/survey-flutter/milestone/41?closed=1
+or Link to the project management tool for the release
## Features
Provide the ID and title of the issue in the section for each type (feature, chore and bug). The link is optional.
-- [sc-1234] As a user, I can log in
-or
-- [[sc-1234](https://app.shortcut.com/nimblehq/story/1234)] As a user, I can log in
+- [#1] As a user, I can log in or
+- [[#1](https://github.com/nimblehq/survey-flutter/issues/1)] As a user, I can log in
## Chores
- Same structure as in ## Feature
diff --git a/.github/wiki/.keep b/.github/wiki/.keep
deleted file mode 100644
index e69de29..0000000
diff --git a/.github/workflows/android_deploy_production.yml b/.github/workflows/android_deploy_production.yml
new file mode 100644
index 0000000..e83bd7b
--- /dev/null
+++ b/.github/workflows/android_deploy_production.yml
@@ -0,0 +1,51 @@
+name: Android - Deploy Production build to Firebase
+
+on:
+ push:
+ branches:
+ - main
+
+jobs:
+ build_and_deploy_android:
+ name: Build & Deploy Android
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - name: Check out
+ uses: actions/checkout@v3
+
+ - name: Set up Java JDK
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'adopt'
+ java-version: '11'
+
+ - name: Set up Flutter environment
+ uses: subosito/flutter-action@v2
+ with:
+ channel: 'stable'
+ flutter-version: '3.10.5'
+
+ - name: Get Flutter dependencies
+ run: flutter pub get
+
+ - name: Run code generator
+ run: flutter packages pub run build_runner build --delete-conflicting-outputs
+
+ - name: Set up .env
+ env:
+ ENV_PRODUCTION: ${{ secrets.ENV_PRODUCTION }}
+ run: |
+ echo $ENV_PRODUCTION > .env
+
+ # App Bundle requires Firebase connected to Play Store to upload https://appdistribution.page.link/KPoa
+ - name: Build Android apk
+ run: flutter build apk --flavor production --debug --build-number $GITHUB_RUN_NUMBER
+
+ - name: Deploy Android Production to Firebase
+ uses: wzieba/Firebase-Distribution-Github-Action@v1.5.0
+ with:
+ appId: ${{ secrets.FIREBASE_ANDROID_APP_ID_PRODUCTION }}
+ serviceCredentialsFileContent: ${{ secrets.FIREBASE_DISTRIBUTION_CREDENTIAL_JSON }}
+ groups: ${{ vars.FIREBASE_DISTRIBUTION_TESTER_GROUPS }}
+ file: build/app/outputs/flutter-apk/app-production-debug.apk
diff --git a/.github/workflows/android_deploy_production_to_playstore.yml b/.github/workflows/android_deploy_production_to_playstore.yml
new file mode 100644
index 0000000..91a6307
--- /dev/null
+++ b/.github/workflows/android_deploy_production_to_playstore.yml
@@ -0,0 +1,52 @@
+name: Android - Deploy Production build to Play Store
+
+on:
+ push:
+ branches:
+ - main
+
+jobs:
+ build_and_deploy_android:
+ name: Build & Deploy Android
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - name: Check out
+ uses: actions/checkout@v3
+
+ - name: Set up Java JDK
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'adopt'
+ java-version: '11'
+
+ - name: Set up Flutter environment
+ uses: subosito/flutter-action@v2
+ with:
+ channel: 'stable'
+ flutter-version: '3.10.5'
+
+ - name: Get Flutter dependencies
+ run: flutter pub get
+
+ - name: Run code generator
+ run: flutter packages pub run build_runner build --delete-conflicting-outputs
+
+ - name: Set up .env
+ env:
+ ENV_PRODUCTION: ${{ secrets.ENV_PRODUCTION }}
+ run: |
+ echo $ENV_PRODUCTION > .env
+
+ - name: Build Production App Bundle
+ run: flutter build appbundle --flavor production --release --build-number $GITHUB_RUN_NUMBER
+
+ - name: Upload Android Production Release bundle to Play Store
+ uses: r0adkll/upload-google-play@v1
+ with:
+ serviceAccountJson: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
+ packageName: co.nimblehq.khanhthieu.survey
+ releaseFile: build/app/outputs/bundle/productionRelease/app-production-release.aab
+ track: internal
+ userFraction: 1.0
+ whatsNewDirectory: .github/workflows/whatsnew
diff --git a/.github/workflows/android_deploy_staging.yml b/.github/workflows/android_deploy_staging.yml
new file mode 100644
index 0000000..99379e0
--- /dev/null
+++ b/.github/workflows/android_deploy_staging.yml
@@ -0,0 +1,51 @@
+name: Android - Deploy Staging build to Firebase
+
+on:
+ push:
+ branches:
+ - develop
+
+jobs:
+ build_and_deploy_android:
+ name: Build & Deploy Android
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - name: Check out
+ uses: actions/checkout@v3
+
+ - name: Set up Java JDK
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'adopt'
+ java-version: '11'
+
+ - name: Set up Flutter environment
+ uses: subosito/flutter-action@v2
+ with:
+ channel: 'stable'
+ flutter-version: '3.10.5'
+
+ - name: Get Flutter dependencies
+ run: flutter pub get
+
+ - name: Run code generator
+ run: flutter packages pub run build_runner build --delete-conflicting-outputs
+
+ - name: Set up .env.staging
+ env:
+ ENV_STAGING: ${{ secrets.ENV_STAGING }}
+ run: |
+ echo $ENV_STAGING > .env.staging
+
+ # App Bundle requires Firebase connected to Play Store to upload https://appdistribution.page.link/KPoa
+ - name: Build Android apk
+ run: flutter build apk --flavor staging --debug --build-number $GITHUB_RUN_NUMBER
+
+ - name: Deploy Android Staging to Firebase
+ uses: wzieba/Firebase-Distribution-Github-Action@v1.5.0
+ with:
+ appId: ${{ secrets.FIREBASE_ANDROID_APP_ID_STAGING }}
+ serviceCredentialsFileContent: ${{ secrets.FIREBASE_STAGING_DISTRIBUTION_CREDENTIAL_JSON }}
+ groups: ${{ vars.FIREBASE_DISTRIBUTION_TESTER_GROUPS }}
+ file: build/app/outputs/flutter-apk/app-staging-debug.apk
diff --git a/.github/workflows/bump_version.yml b/.github/workflows/bump_version.yml
new file mode 100644
index 0000000..b08316d
--- /dev/null
+++ b/.github/workflows/bump_version.yml
@@ -0,0 +1,49 @@
+name: Bump Version
+
+on:
+ workflow_dispatch:
+ inputs:
+ newVersion:
+ description: "New version"
+ required: true
+ type: string
+
+jobs:
+ bump_version:
+ name: Bump version
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ steps:
+ - name: Check out
+ uses: actions/checkout@v3
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Set new version
+ run: |
+ perl -i -pe 's/^(version:\s+\d+\.\d+\.\d+\+)(\d+)$/"version: ${{ github.event.inputs.newVersion }}+".($2+1)/e' ./pubspec.yaml
+
+ - name: Create pull request
+ uses: peter-evans/create-pull-request@v4
+ with:
+ assignees: ${{ secrets.GITHUB_USER }}
+ token: ${{ secrets.WIKI_ACTION_TOKEN }}
+ commit-message: Bump version to ${{ github.event.inputs.newVersion }}
+ committer: Nimble Bot
+ branch: chore/bump-version-to-${{ github.event.inputs.newVersion }}
+ delete-branch: true
+ title: '[Chore] Bump version to ${{ github.event.inputs.newVersion }}'
+ labels: |
+ type : chore
+ body: |
+ ## What happened 👀
+
+ Bump version to ${{ github.event.inputs.newVersion }}
+
+ ## Insight 📝
+
+ Automatically created by the Bump Version workflow.
+
+ ## Proof Of Work 📹
+
+ On the Files changed tab
diff --git a/.github/workflows/ios_deploy_production_to_testflight.yml b/.github/workflows/ios_deploy_production_to_testflight.yml
new file mode 100644
index 0000000..c19d190
--- /dev/null
+++ b/.github/workflows/ios_deploy_production_to_testflight.yml
@@ -0,0 +1,69 @@
+name: iOS - Deploy Production build to TestFlight
+on:
+ push:
+ branches:
+ - main
+
+jobs:
+ build_and_upload_production_to_testflight:
+ name: Build and upload iOS Production build to TestFlight
+ runs-on: macOS-latest
+ steps:
+ - name: Check out
+ uses: actions/checkout@v3
+
+ - name: Install SSH key
+ uses: webfactory/ssh-agent@v0.8.0
+ with:
+ ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+
+ - name: Set up Flutter environment
+ uses: subosito/flutter-action@v2
+ with:
+ channel: 'stable'
+ flutter-version: '3.10.5'
+ - run: flutter --version
+
+ - name: Set up deployment environment
+ env:
+ ENV_PRODUCTION: ${{ secrets.ENV_PRODUCTION }}
+ run: echo "$ENV_PRODUCTION" > .env
+
+ - name: Get Flutter dependencies
+ run: flutter pub get
+
+ - name: Run code generator
+ run: flutter packages pub run build_runner build --delete-conflicting-outputs
+
+ - name: Cache Ruby gems
+ uses: actions/cache@v3
+ id: bunlderCache
+ with:
+ path: ios/vendor/bundle
+ key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
+ restore-keys: ${{ runner.os }}-gems-
+
+ - name: Cache Pods
+ uses: actions/cache@v3
+ id: cocoapodCache
+ with:
+ path: ios/Pods
+ key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
+ restore-keys: ${{ runner.os }}-pods-
+
+ - name: Install iOS dependencies
+ run: cd ios && bundle install --path vendor/bundle && bundle exec pod install
+
+ - name: Sync certificates and profiles
+ env:
+ MATCH_PASSWORD: ${{ secrets.MATCH_PASSPHRASE }}
+ run: cd ios && bundle exec fastlane sync_appstore_production_signing
+
+ - name: Build and Deploy to TestFlight
+ env:
+ BUILD_NUMBER: ${{ github.run_number }}
+ TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+ APPSTORE_CONNECT_API_KEY_ID: ${{ secrets.APPSTORE_CONNECT_API_KEY_ID }}
+ APPSTORE_CONNECT_ISSUER_ID: ${{ secrets.APPSTORE_CONNECT_ISSUER_ID }}
+ APPSTORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APPSTORE_CONNECT_API_KEY_CONTENT }}
+ run: cd ios && bundle exec fastlane build_and_upload_production_to_testflight
diff --git a/.github/workflows/ios_deploy_staging_to_testflight.yml b/.github/workflows/ios_deploy_staging_to_testflight.yml
new file mode 100644
index 0000000..0d5b78d
--- /dev/null
+++ b/.github/workflows/ios_deploy_staging_to_testflight.yml
@@ -0,0 +1,69 @@
+name: iOS - Deploy Staging build to TestFlight
+on:
+ push:
+ branches:
+ - develop
+
+jobs:
+ build_and_upload_staging_to_testflight:
+ name: Build and upload iOS Staging build to TestFlight
+ runs-on: macOS-latest
+ steps:
+ - name: Check out
+ uses: actions/checkout@v3
+
+ - name: Install SSH key
+ uses: webfactory/ssh-agent@v0.8.0
+ with:
+ ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
+
+ - name: Set up Flutter environment
+ uses: subosito/flutter-action@v2
+ with:
+ channel: 'stable'
+ flutter-version: '3.10.5'
+ - run: flutter --version
+
+ - name: Set up deployment environment
+ env:
+ ENV_STAGING: ${{ secrets.ENV_STAGING }}
+ run: echo "$ENV_STAGING" > .env.staging
+
+ - name: Get Flutter dependencies
+ run: flutter pub get
+
+ - name: Run code generator
+ run: flutter packages pub run build_runner build --delete-conflicting-outputs
+
+ - name: Cache Ruby gems
+ uses: actions/cache@v3
+ id: bunlderCache
+ with:
+ path: ios/vendor/bundle
+ key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
+ restore-keys: ${{ runner.os }}-gems-
+
+ - name: Cache Pods
+ uses: actions/cache@v3
+ id: cocoapodCache
+ with:
+ path: ios/Pods
+ key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
+ restore-keys: ${{ runner.os }}-pods-
+
+ - name: Install iOS dependencies
+ run: cd ios && bundle install --path vendor/bundle && bundle exec pod install
+
+ - name: Sync certificates and profiles
+ env:
+ MATCH_PASSWORD: ${{ secrets.MATCH_PASSPHRASE }}
+ run: cd ios && bundle exec fastlane sync_appstore_staging_signing
+
+ - name: Build and Deploy to TestFlight
+ env:
+ BUILD_NUMBER: ${{ github.run_number }}
+ TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+ APPSTORE_CONNECT_API_KEY_ID: ${{ secrets.APPSTORE_CONNECT_API_KEY_ID }}
+ APPSTORE_CONNECT_ISSUER_ID: ${{ secrets.APPSTORE_CONNECT_ISSUER_ID }}
+ APPSTORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APPSTORE_CONNECT_API_KEY_CONTENT }}
+ run: cd ios && bundle exec fastlane build_and_upload_staging_to_testflight
diff --git a/.github/workflows/publish_wiki.yml b/.github/workflows/publish_wiki.yml
deleted file mode 100644
index 6016ebc..0000000
--- a/.github/workflows/publish_wiki.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-# For setup instruction, refer to https://github.com/nimblehq/github-actions-workflows/blob/main/.github/workflows/publish_wiki.yml
-name: Publish Wiki
-
-on:
- push:
- paths:
- - .github/wiki/**
- branches:
- - develop
-
-jobs:
- publish:
- name: Publish Wiki
- uses: nimblehq/github-actions-workflows/.github/workflows/publish_wiki.yml@0.1.0
- with:
- USER_NAME: github-wiki-workflow
- USER_EMAIL: ${{ secrets.GH_EMAIL }}
- secrets:
- USER_TOKEN: ${{ secrets.GH_TOKEN }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..4e31b05
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,48 @@
+name: CI
+on:
+ # Trigger the workflow on push or pull request,
+ # but push action is only for the feature branch
+ pull_request:
+ types: [ opened, synchronize, edited, reopened ]
+ push:
+ branches-ignore:
+ - develop
+ - 'release/**'
+jobs:
+ lint_and_test:
+ name: Static code analyze & Unit test
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - name: Check out
+ uses: actions/checkout@v3
+
+ - name: Set up Flutter environment
+ uses: subosito/flutter-action@v2
+ with:
+ channel: 'stable'
+ flutter-version: '3.10.5'
+
+ - name: Get Flutter dependencies
+ run: flutter pub get
+
+ - name: Run code generator
+ run: flutter packages pub run build_runner build --delete-conflicting-outputs
+
+ - name: Check for any formatting issues in the code
+ run: dart format --set-exit-if-changed .
+
+ - name: Statically analyze the Dart code for any errors
+ run: flutter analyze .
+
+ - name: Run widget tests, unit tests
+ run: flutter test --machine --coverage
+
+ - name: Upload coverage to codecov
+ uses: codecov/codecov-action@v2
+ with:
+ files: ./coverage/lcov.info
+ flags: unittests # optional
+ token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
+ fail_ci_if_error: false
+ verbose: true
diff --git a/.github/workflows/whatsnew/whatsnew-en-US b/.github/workflows/whatsnew/whatsnew-en-US
new file mode 100644
index 0000000..6230feb
--- /dev/null
+++ b/.github/workflows/whatsnew/whatsnew-en-US
@@ -0,0 +1,3 @@
+
+Enter or paste your release notes for en-US here
+
diff --git a/.gitignore b/.gitignore
index 2f2567c..d4d72fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,36 +1,63 @@
-*.gem
-*.rbc
-/.config
-/.idea
-/coverage/
-/InstalledFiles
-/node_modules
-/pkg/
-/spec/reports/
-/spec/examples.txt
-/test/tmp/
-/test/version_tmp/
-/tmp/
-
# Used by dotenv library to load environment variables.
-# .env
-
-## Documentation cache and generated files:
-/.yardoc/
-/_yardoc/
-/doc/
-/rdoc/
-
-## Environment normalization:
-/.bundle/
-/vendor/bundle
-/lib/bundler/man/
-
-# for a library or gem, you might want to ignore these files since the code is
-# intended to run in multiple environments; otherwise, check them in:
-# Gemfile.lock
-# .ruby-version
-# .ruby-gemset
-
-# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
-.rvmrc
+.env
+.env.staging
+
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+.vscode/
+
+# Flutter version manager related
+.fvm/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+**/ios/.envfile
+**/ios/Flutter/tmp.xcconfig
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+/build/
+
+# Web related
+lib/generated_plugin_registrant.dart
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
+
+# Flutter generated files
+*.g.dart
+*.gen.dart
+*.config.dart
+*.freezed.dart
+*.mocks.dart
diff --git a/.metadata b/.metadata
new file mode 100644
index 0000000..56bfc2c
--- /dev/null
+++ b/.metadata
@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: f4abaa0735eba4dfd8f33f73363911d63931fe03
+ channel: stable
+
+project_type: app
diff --git a/README.md b/README.md
index 3352876..4ede7cf 100644
--- a/README.md
+++ b/README.md
@@ -1,32 +1,74 @@
# Survey Flutter
+[![codecov](https://codecov.io/gh/nimblehq/survey-flutter/branch/main/graph/badge.svg?token=ATUNXDX218)](https://codecov.io/gh/nimblehq/survey-flutter)
-## Usage
+## Prerequisite
-Clone the repository
+- Flutter 3.10.5
+- Flutter version manager (recommend): [fvm](https://fvm.app/)
+
+## Getting Started
+
+### Usage
+
+Checkout the repository
`git clone git@github.com:nimblehq/flutter-ic-khanh-thieu.git`
+### Setup
+
+- Create these `.env` files in the root directory according to the flavors and add the required
+environment variables. The example environment variable is in `.env.sample`.
+
+ - Staging: `.env.staging`
+
+ - Production: `.env`
+
+### Run
+
+- Run code generator for JSON models, DI dependencies, etc:
+
+ - `$ fvm flutter packages pub run build_runner build --delete-conflicting-outputs`
+
+- Run the app with the desired app flavor:
+
+ - `$ fvm flutter run --flavor staging`
+ - `$ fvm flutter run --flavor production`
+
+- Check code formatting & static code analyzing:
+
+ - `$ dart format --set-exit-if-changed .`
+ - `$ fvm flutter analyze .`
+
+### Test
+
+- Run unit testing:
+
+ - `$ fvm flutter test`
+ - `$ fvm flutter test --machine --coverage`
+
+- Run integration testing:
+
+ - `$ fvm flutter drive --driver=test_driver/integration_test.dart --target=integration_test/{test_file}.dart --flavor staging`
+
+ - For example:
+
+ `$ fvm flutter drive --driver=test_driver/integration_test.dart --target=integration_test/my_home_page_test.dart --flavor staging`
+
## License
-This project is Copyright (c) 2014 and onwards Nimble. It is free software and may be redistributed under the terms specified in the [LICENSE] file.
+This project is Copyright (c) 2014 and onwards. It is free software,
+and may be redistributed under the terms specified in the [LICENSE] file.
[LICENSE]: /LICENSE
## About
-
-
-
+
+![Nimble](https://assets.nimblehq.co/logo/dark/logo-dark-text-160.png)
This project is maintained and funded by Nimble.
-We ❤️ open source and do our part in sharing our work with the community!
+We love open source and do our part in sharing our work with the community!
See [our other projects][community] or [hire our team][hire] to help build your product.
-Want to join? [Check out our Jobs][jobs]!
-
[community]: https://github.com/nimblehq
[hire]: https://nimblehq.co/
-[jobs]: https://jobs.nimblehq.co/
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..8ae8663
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,38 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at
+ # https://dart-lang.github.io/linter/lints/index.html.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
+
+analyzer:
+ exclude: [
+ lib/**.g.dart,
+ lib/**.gen.dart,
+ lib/**.config.dart,
+ lib/**.freezed.dart,
+ test/**.mocks.dart
+ ]
diff --git a/android/.gitignore b/android/.gitignore
new file mode 100644
index 0000000..0a741cb
--- /dev/null
+++ b/android/.gitignore
@@ -0,0 +1,11 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+key.properties
diff --git a/android/app/build.gradle b/android/app/build.gradle
new file mode 100644
index 0000000..36b4e74
--- /dev/null
+++ b/android/app/build.gradle
@@ -0,0 +1,91 @@
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader('UTF-8') { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterRoot = localProperties.getProperty('flutter.sdk')
+if (flutterRoot == null) {
+ throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+ flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+ flutterVersionName = '1.0'
+}
+
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
+
+project.ext.envConfigFiles = [
+ stagingdebug: ".env.staging",
+ stagingrelease: ".env.staging",
+ productiondebug: ".env",
+ productionrelease: ".env"
+]
+
+apply from: project(':flutter_config').projectDir.getPath() + "/dotenv.gradle"
+
+android {
+ namespace "co.nimblehq.khanhthieu.survey"
+ compileSdkVersion flutter.compileSdkVersion
+ ndkVersion flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ }
+
+ defaultConfig {
+ applicationId "co.nimblehq.khanhthieu.survey"
+ minSdkVersion 23
+ targetSdkVersion flutter.targetSdkVersion
+ versionCode flutterVersionCode.toInteger()
+ versionName flutterVersionName
+ resValue "string", "build_config_package", "co.nimblehq.khanhthieu.survey"
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig signingConfigs.debug
+ }
+ }
+
+ flavorDimensions "stage"
+ productFlavors {
+ production {
+ applicationId "co.nimblehq.khanhthieu.survey"
+ dimension "stage"
+ }
+ staging {
+ dimension "stage"
+ applicationId "co.nimblehq.khanhthieu.survey.staging"
+ }
+ }
+}
+
+flutter {
+ source '../..'
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..98fd6e4
--- /dev/null
+++ b/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/kotlin/co/nimblehq/khanhthieu/survey/MainActivity.kt b/android/app/src/main/kotlin/co/nimblehq/khanhthieu/survey/MainActivity.kt
new file mode 100644
index 0000000..143e6fb
--- /dev/null
+++ b/android/app/src/main/kotlin/co/nimblehq/khanhthieu/survey/MainActivity.kt
@@ -0,0 +1,6 @@
+package co.nimblehq.khanhthieu.survey
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity() {
+}
diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000..f74085f
--- /dev/null
+++ b/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..db77bb4
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..17987b7
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09d4391
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d5f1c8d
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..06952be
--- /dev/null
+++ b/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..b6b5101
--- /dev/null
+++ b/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Survey Flutter
+
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..cb1ef88
--- /dev/null
+++ b/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/android/app/src/staging/res/values/strings.xml b/android/app/src/staging/res/values/strings.xml
new file mode 100644
index 0000000..33999d3
--- /dev/null
+++ b/android/app/src/staging/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Survey Flutter Staging
+
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..f7eb7f6
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,31 @@
+buildscript {
+ ext.kotlin_version = '1.7.10'
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:7.3.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(':app')
+}
+
+tasks.register("clean", Delete) {
+ delete rootProject.buildDir
+}
diff --git a/android/gradle.properties b/android/gradle.properties
new file mode 100644
index 0000000..94adc3a
--- /dev/null
+++ b/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx1536M
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..3c472b9
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
diff --git a/android/settings.gradle b/android/settings.gradle
new file mode 100644
index 0000000..44e62bc
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1,11 @@
+include ':app'
+
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
+
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
+
+def flutterSdkPath = properties.getProperty("flutter.sdk")
+assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
diff --git a/assets/colors/colors.xml b/assets/colors/colors.xml
new file mode 100644
index 0000000..29ab301
--- /dev/null
+++ b/assets/colors/colors.xml
@@ -0,0 +1,4 @@
+
+
+ #201547
+
diff --git a/assets/fonts/neuzeit.otf b/assets/fonts/neuzeit.otf
new file mode 100644
index 0000000..d55be30
Binary files /dev/null and b/assets/fonts/neuzeit.otf differ
diff --git a/assets/images/nimble_logo.png b/assets/images/nimble_logo.png
new file mode 100644
index 0000000..0e33df4
Binary files /dev/null and b/assets/images/nimble_logo.png differ
diff --git a/assets/svg/flutter_logo.svg b/assets/svg/flutter_logo.svg
new file mode 100644
index 0000000..49d0302
--- /dev/null
+++ b/assets/svg/flutter_logo.svg
@@ -0,0 +1,10 @@
+
diff --git a/build.yaml b/build.yaml
new file mode 100644
index 0000000..4a1f92c
--- /dev/null
+++ b/build.yaml
@@ -0,0 +1,7 @@
+targets:
+ $default:
+ builders:
+ json_serializable:
+ options:
+ # Full FieldRename's options, refer https://github.com/google/json_serializable.dart/blob/2185e8b80d8d0c12e2adbf897d920b6f5725cded/json_annotation/lib/src/json_serializable.dart#L16-L32
+ field_rename: "snake"
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000..de405b8
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,25 @@
+codecov:
+ bot: [bot_username] # For the private repository, set up a TeamBot https://docs.codecov.com/docs/team-bot, e.g., bob
+ require_ci_to_pass: yes
+
+coverage:
+ status:
+ project: off
+ patch: off
+
+parsers:
+ gcov:
+ branch_detection:
+ conditional: yes
+ loop: yes
+ method: no
+ macro: no
+
+comment:
+ layout: "reach,diff,flags,files,tree"
+ behavior: default
+ require_changes: no
+
+ignore:
+ - "lib/di"
+ - "lib/gen"
diff --git a/integration_test/my_home_page_test.dart b/integration_test/my_home_page_test.dart
new file mode 100644
index 0000000..7b4f558
--- /dev/null
+++ b/integration_test/my_home_page_test.dart
@@ -0,0 +1,20 @@
+import 'package:flutter/material.dart';
+import 'package:survey_flutter/main.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+
+import 'utils/test_util.dart';
+
+void main() {
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+ testWidgets('My Home Page widget', (WidgetTester tester) async {
+ await tester
+ .pumpWidget(TestUtil.pumpWidgetWithShellApp(const HomeScreen()));
+ await tester.pumpAndSettle();
+
+ expect(
+ find.widgetWithText(AppBar, 'Survey Flutter testing'), findsOneWidget);
+ expect(find.text('This is only for testing'), findsOneWidget);
+ });
+}
diff --git a/integration_test/real_app_test.dart b/integration_test/real_app_test.dart
new file mode 100644
index 0000000..abe57bf
--- /dev/null
+++ b/integration_test/real_app_test.dart
@@ -0,0 +1,18 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+
+import 'utils/test_util.dart';
+
+void main() {
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+ testWidgets('Real App', (WidgetTester tester) async {
+ await tester.pumpWidget(TestUtil.pumpWidgetWithRealApp('/'));
+ await tester.pumpAndSettle();
+
+ expect(
+ find.widgetWithText(AppBar, 'Survey Flutter testing'), findsOneWidget);
+ expect(find.text('This is only for testing'), findsOneWidget);
+ });
+}
diff --git a/integration_test/utils/test_util.dart b/integration_test/utils/test_util.dart
new file mode 100644
index 0000000..b1ac297
--- /dev/null
+++ b/integration_test/utils/test_util.dart
@@ -0,0 +1,35 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_config/flutter_config.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:survey_flutter/main.dart';
+import 'package:package_info_plus/package_info_plus.dart';
+
+class TestUtil {
+ /// This is useful when we test the whole app with the real configs(styling,
+ /// localization, routes, etc)
+ static Widget pumpWidgetWithRealApp(String initialRoute) {
+ _initDependencies();
+ return MyApp();
+ }
+
+ /// We normally use this function to test a specific [widget] without
+ /// considering much about theming.
+ static Widget pumpWidgetWithShellApp(Widget widget) {
+ _initDependencies();
+ return MaterialApp(
+ localizationsDelegates: AppLocalizations.localizationsDelegates,
+ supportedLocales: AppLocalizations.supportedLocales,
+ home: widget,
+ );
+ }
+
+ static void _initDependencies() {
+ PackageInfo.setMockInitialValues(
+ appName: 'Survey Flutter testing',
+ packageName: '',
+ version: '',
+ buildNumber: '',
+ buildSignature: '');
+ FlutterConfig.loadValueForTesting({'SECRET': 'This is only for testing'});
+ }
+}
diff --git a/ios/.gitignore b/ios/.gitignore
new file mode 100644
index 0000000..aa44815
--- /dev/null
+++ b/ios/.gitignore
@@ -0,0 +1,43 @@
+**/dgph
+*.mode1v3
+*.mode2v3
+*.moved-aside
+*.pbxuser
+*.perspectivev3
+**/*sync/
+.sconsign.dblite
+.tags*
+**/.vagrant/
+**/DerivedData/
+Icon?
+**/Pods/
+**/.symlinks/
+profile
+xcuserdata
+**/.generated/
+Flutter/App.framework
+Flutter/Flutter.framework
+Flutter/Flutter.podspec
+Flutter/Generated.xcconfig
+Flutter/ephemeral/
+Flutter/app.flx
+Flutter/app.zip
+Flutter/flutter_assets/
+Flutter/flutter_export_environment.sh
+Flutter/tmp.xcconfig
+Flutter/.last_build_id
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+Build/
+DerivedData/
+fastlane/README.md
+fastlane/report.xml
+.envfile
+.bundle
+vendor/bundle
+
+# Exceptions to above rules.
+!default.mode1v3
+!default.mode2v3
+!default.pbxuser
+!default.perspectivev3
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 0000000..9625e10
--- /dev/null
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ App
+ CFBundleIdentifier
+ io.flutter.flutter.app
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ App
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ MinimumOSVersion
+ 11.0
+
+
diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig
new file mode 100644
index 0000000..51a7451
--- /dev/null
+++ b/ios/Flutter/Debug.xcconfig
@@ -0,0 +1,3 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include "Generated.xcconfig"
+#include? "tmp.xcconfig"
diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000..d9de94c
--- /dev/null
+++ b/ios/Flutter/Release.xcconfig
@@ -0,0 +1,3 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include "Generated.xcconfig"
+#include? "tmp.xcconfig"
diff --git a/ios/Gemfile b/ios/Gemfile
new file mode 100644
index 0000000..b38f3c1
--- /dev/null
+++ b/ios/Gemfile
@@ -0,0 +1,7 @@
+source "https://rubygems.org"
+
+gem "fastlane"
+gem "cocoapods"
+
+plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
+eval_gemfile(plugins_path) if File.exist?(plugins_path)
diff --git a/ios/Gemfile.lock b/ios/Gemfile.lock
new file mode 100644
index 0000000..b962cea
--- /dev/null
+++ b/ios/Gemfile.lock
@@ -0,0 +1,286 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ CFPropertyList (3.0.6)
+ rexml
+ activesupport (6.1.5)
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ tzinfo (~> 2.0)
+ zeitwerk (~> 2.3)
+ addressable (2.8.4)
+ public_suffix (>= 2.0.2, < 6.0)
+ algoliasearch (1.27.5)
+ httpclient (~> 2.8, >= 2.8.3)
+ json (>= 1.5.1)
+ artifactory (3.0.15)
+ atomos (0.1.3)
+ aws-eventstream (1.2.0)
+ aws-partitions (1.796.0)
+ aws-sdk-core (3.180.1)
+ aws-eventstream (~> 1, >= 1.0.2)
+ aws-partitions (~> 1, >= 1.651.0)
+ aws-sigv4 (~> 1.5)
+ jmespath (~> 1, >= 1.6.1)
+ aws-sdk-kms (1.71.0)
+ aws-sdk-core (~> 3, >= 3.177.0)
+ aws-sigv4 (~> 1.1)
+ aws-sdk-s3 (1.132.0)
+ aws-sdk-core (~> 3, >= 3.179.0)
+ aws-sdk-kms (~> 1)
+ aws-sigv4 (~> 1.6)
+ aws-sigv4 (1.6.0)
+ aws-eventstream (~> 1, >= 1.0.2)
+ babosa (1.0.4)
+ claide (1.1.0)
+ cocoapods (1.11.3)
+ addressable (~> 2.8)
+ claide (>= 1.0.2, < 2.0)
+ cocoapods-core (= 1.11.3)
+ cocoapods-deintegrate (>= 1.0.3, < 2.0)
+ cocoapods-downloader (>= 1.4.0, < 2.0)
+ cocoapods-plugins (>= 1.0.0, < 2.0)
+ cocoapods-search (>= 1.0.0, < 2.0)
+ cocoapods-trunk (>= 1.4.0, < 2.0)
+ cocoapods-try (>= 1.1.0, < 2.0)
+ colored2 (~> 3.1)
+ escape (~> 0.0.4)
+ fourflusher (>= 2.3.0, < 3.0)
+ gh_inspector (~> 1.0)
+ molinillo (~> 0.8.0)
+ nap (~> 1.0)
+ ruby-macho (>= 1.0, < 3.0)
+ xcodeproj (>= 1.21.0, < 2.0)
+ cocoapods-core (1.11.3)
+ activesupport (>= 5.0, < 7)
+ addressable (~> 2.8)
+ algoliasearch (~> 1.0)
+ concurrent-ruby (~> 1.1)
+ fuzzy_match (~> 2.0.4)
+ nap (~> 1.0)
+ netrc (~> 0.11)
+ public_suffix (~> 4.0)
+ typhoeus (~> 1.0)
+ cocoapods-deintegrate (1.0.5)
+ cocoapods-downloader (1.6.1)
+ cocoapods-plugins (1.0.0)
+ nap
+ cocoapods-search (1.0.1)
+ cocoapods-trunk (1.6.0)
+ nap (>= 0.8, < 2.0)
+ netrc (~> 0.11)
+ cocoapods-try (1.2.0)
+ colored (1.2)
+ colored2 (3.1.2)
+ commander (4.6.0)
+ highline (~> 2.0.0)
+ concurrent-ruby (1.1.10)
+ 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)
+ dotenv (2.8.1)
+ emoji_regex (3.2.3)
+ escape (0.0.4)
+ ethon (0.15.0)
+ ffi (>= 1.15.0)
+ excon (0.100.0)
+ faraday (1.10.3)
+ faraday-em_http (~> 1.0)
+ faraday-em_synchrony (~> 1.0)
+ faraday-excon (~> 1.1)
+ faraday-httpclient (~> 1.0)
+ faraday-multipart (~> 1.0)
+ faraday-net_http (~> 1.0)
+ faraday-net_http_persistent (~> 1.0)
+ faraday-patron (~> 1.0)
+ faraday-rack (~> 1.0)
+ faraday-retry (~> 1.0)
+ ruby2_keywords (>= 0.0.4)
+ faraday-cookie_jar (0.0.7)
+ faraday (>= 0.8.0)
+ http-cookie (~> 1.0.0)
+ faraday-em_http (1.0.0)
+ faraday-em_synchrony (1.0.0)
+ faraday-excon (1.1.0)
+ faraday-httpclient (1.0.1)
+ faraday-multipart (1.0.4)
+ multipart-post (~> 2)
+ faraday-net_http (1.0.1)
+ faraday-net_http_persistent (1.2.0)
+ faraday-patron (1.0.0)
+ faraday-rack (1.0.0)
+ faraday-retry (1.0.3)
+ faraday_middleware (1.2.0)
+ faraday (~> 1.0)
+ fastimage (2.2.7)
+ fastlane (2.214.0)
+ CFPropertyList (>= 2.3, < 4.0.0)
+ addressable (>= 2.8, < 3.0.0)
+ artifactory (~> 3.0)
+ aws-sdk-s3 (~> 1.0)
+ babosa (>= 1.0.3, < 2.0.0)
+ bundler (>= 1.12.0, < 3.0.0)
+ colored
+ commander (~> 4.6)
+ dotenv (>= 2.1.1, < 3.0.0)
+ emoji_regex (>= 0.1, < 4.0)
+ excon (>= 0.71.0, < 1.0.0)
+ faraday (~> 1.0)
+ faraday-cookie_jar (~> 0.0.6)
+ faraday_middleware (~> 1.0)
+ fastimage (>= 2.1.0, < 3.0.0)
+ gh_inspector (>= 1.1.2, < 2.0.0)
+ google-apis-androidpublisher_v3 (~> 0.3)
+ google-apis-playcustomapp_v1 (~> 0.1)
+ google-cloud-storage (~> 1.31)
+ highline (~> 2.0)
+ json (< 3.0.0)
+ jwt (>= 2.1.0, < 3)
+ mini_magick (>= 4.9.4, < 5.0.0)
+ multipart-post (>= 2.0.0, < 3.0.0)
+ naturally (~> 2.2)
+ optparse (~> 0.1.1)
+ plist (>= 3.1.0, < 4.0.0)
+ rubyzip (>= 2.0.0, < 3.0.0)
+ security (= 0.1.3)
+ simctl (~> 1.6.3)
+ terminal-notifier (>= 2.0.0, < 3.0.0)
+ terminal-table (>= 1.4.5, < 2.0.0)
+ tty-screen (>= 0.6.3, < 1.0.0)
+ tty-spinner (>= 0.8.0, < 1.0.0)
+ word_wrap (~> 1.0.0)
+ xcodeproj (>= 1.13.0, < 2.0.0)
+ xcpretty (~> 0.3.0)
+ xcpretty-travis-formatter (>= 0.0.3)
+ fastlane-plugin-firebase_app_distribution (0.5.0)
+ ffi (1.15.5)
+ fourflusher (2.3.1)
+ fuzzy_match (2.0.4)
+ gh_inspector (1.1.3)
+ google-apis-androidpublisher_v3 (0.46.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-core (0.11.1)
+ addressable (~> 2.5, >= 2.5.1)
+ googleauth (>= 0.16.2, < 2.a)
+ httpclient (>= 2.8.1, < 3.a)
+ mini_mime (~> 1.0)
+ representable (~> 3.0)
+ retriable (>= 2.0, < 4.a)
+ rexml
+ webrick
+ google-apis-iamcredentials_v1 (0.17.0)
+ 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-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)
+ addressable (~> 2.8)
+ digest-crc (~> 0.4)
+ google-apis-iamcredentials_v1 (~> 0.1)
+ google-apis-storage_v1 (~> 0.19.0)
+ google-cloud-core (~> 1.6)
+ googleauth (>= 0.16.2, < 2.a)
+ mini_mime (~> 1.0)
+ googleauth (1.7.0)
+ faraday (>= 0.17.3, < 3.a)
+ jwt (>= 1.4, < 3.0)
+ memoist (~> 0.16)
+ multi_json (~> 1.11)
+ os (>= 0.9, < 2.0)
+ signet (>= 0.16, < 2.a)
+ highline (2.0.3)
+ http-cookie (1.0.5)
+ domain_name (~> 0.5)
+ httpclient (2.8.3)
+ i18n (1.10.0)
+ concurrent-ruby (~> 1.0)
+ jmespath (1.6.2)
+ json (2.6.3)
+ jwt (2.7.1)
+ memoist (0.16.2)
+ mini_magick (4.12.0)
+ mini_mime (1.1.2)
+ minitest (5.15.0)
+ molinillo (0.8.0)
+ multi_json (1.15.0)
+ multipart-post (2.3.0)
+ nanaimo (0.3.0)
+ nap (1.1.0)
+ naturally (2.2.1)
+ netrc (0.11.0)
+ optparse (0.1.1)
+ os (1.1.4)
+ plist (3.7.0)
+ public_suffix (4.0.7)
+ rake (13.0.6)
+ representable (3.2.0)
+ declarative (< 0.1.0)
+ trailblazer-option (>= 0.1.1, < 0.2.0)
+ uber (< 0.2.0)
+ retriable (3.1.2)
+ rexml (3.2.6)
+ rouge (2.0.7)
+ ruby-macho (2.5.1)
+ ruby2_keywords (0.0.5)
+ rubyzip (2.3.2)
+ security (0.1.3)
+ signet (0.17.0)
+ addressable (~> 2.8)
+ faraday (>= 0.17.5, < 3.a)
+ jwt (>= 1.5, < 3.0)
+ multi_json (~> 1.10)
+ simctl (1.6.10)
+ CFPropertyList
+ naturally
+ terminal-notifier (2.0.0)
+ terminal-table (1.8.0)
+ unicode-display_width (~> 1.1, >= 1.1.1)
+ trailblazer-option (0.1.2)
+ tty-cursor (0.7.1)
+ tty-screen (0.8.1)
+ tty-spinner (0.9.3)
+ tty-cursor (~> 0.7)
+ typhoeus (1.4.0)
+ ethon (>= 0.9.0)
+ tzinfo (2.0.4)
+ concurrent-ruby (~> 1.0)
+ uber (0.1.0)
+ unf (0.1.4)
+ unf_ext
+ unf_ext (0.0.8.2)
+ unicode-display_width (1.8.0)
+ webrick (1.8.1)
+ word_wrap (1.0.0)
+ xcodeproj (1.22.0)
+ CFPropertyList (>= 2.3.3, < 4.0)
+ atomos (~> 0.1.3)
+ claide (>= 1.0.2, < 2.0)
+ colored2 (~> 3.1)
+ nanaimo (~> 0.3.0)
+ rexml (~> 3.2.4)
+ xcpretty (0.3.0)
+ rouge (~> 2.0.7)
+ xcpretty-travis-formatter (1.0.1)
+ xcpretty (~> 0.2, >= 0.0.7)
+ zeitwerk (2.5.4)
+
+PLATFORMS
+ arm64-darwin-21
+
+DEPENDENCIES
+ cocoapods
+ fastlane
+ fastlane-plugin-firebase_app_distribution
+
+BUNDLED WITH
+ 2.3.10
diff --git a/ios/Podfile b/ios/Podfile
new file mode 100644
index 0000000..87905db
--- /dev/null
+++ b/ios/Podfile
@@ -0,0 +1,95 @@
+# Uncomment this line to define a global platform for your project
+platform :ios, '11.0'
+
+# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
+ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+
+project 'Runner', {
+ 'Debug' => :debug,
+ 'Profile' => :release,
+ 'Release' => :release,
+}
+
+def flutter_root
+ generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
+ unless File.exist?(generated_xcode_build_settings_path)
+ raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
+ end
+
+ File.foreach(generated_xcode_build_settings_path) do |line|
+ matches = line.match(/FLUTTER_ROOT\=(.*)/)
+ return matches[1].strip if matches
+ end
+ raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
+end
+
+require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
+
+flutter_ios_podfile_setup
+
+target 'Runner' do
+ use_frameworks!
+ use_modular_headers!
+
+ flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+ target.build_configurations.each do |config|
+ # TODO You can enable the permissions needed here.
+ # permission, just remove the `#` character in front so it looks like this:
+ #
+ # ## dart: PermissionGroup.camera
+ #'PERMISSION_CAMERA=1'
+ #
+ # Preprocessor definitions can be found in: https://github.com/Baseflow/flutter-permission-handler/blob/master/permission_handler/ios/Classes/PermissionHandlerEnums.h
+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
+ '$(inherited)',
+
+ ## dart: PermissionGroup.calendar
+ # 'PERMISSION_EVENTS=1',
+
+ ## dart: PermissionGroup.reminders
+ # 'PERMISSION_REMINDERS=1',
+
+ ## dart: PermissionGroup.contacts
+ # 'PERMISSION_CONTACTS=1',
+
+ ## dart: PermissionGroup.camera
+ # 'PERMISSION_CAMERA=1',
+
+ ## dart: PermissionGroup.microphone
+ # 'PERMISSION_MICROPHONE=1',
+
+ ## dart: PermissionGroup.speech
+ # 'PERMISSION_SPEECH_RECOGNIZER=1',
+
+ ## dart: PermissionGroup.photos
+ # 'PERMISSION_PHOTOS=1',
+
+ ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
+ # 'PERMISSION_LOCATION=1',
+
+ ## dart: PermissionGroup.notification
+ # 'PERMISSION_NOTIFICATIONS=1',
+
+ ## dart: PermissionGroup.mediaLibrary
+ # 'PERMISSION_MEDIA_LIBRARY=1',
+
+ ## dart: PermissionGroup.sensors
+ # 'PERMISSION_SENSORS=1',
+
+ ## dart: PermissionGroup.bluetooth
+ # 'PERMISSION_BLUETOOTH=1',
+
+ ## dart: PermissionGroup.appTrackingTransparency
+ # 'PERMISSION_APP_TRACKING_TRANSPARENCY=1',
+
+ ## dart: PermissionGroup.criticalAlerts
+ # 'PERMISSION_CRITICAL_ALERTS=1'
+ ]
+ end
+ end
+end
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
new file mode 100644
index 0000000..52f2618
--- /dev/null
+++ b/ios/Podfile.lock
@@ -0,0 +1,40 @@
+PODS:
+ - Flutter (1.0.0)
+ - flutter_config (0.0.1):
+ - Flutter
+ - integration_test (0.0.1):
+ - Flutter
+ - package_info_plus (0.4.5):
+ - Flutter
+ - permission_handler_apple (9.1.1):
+ - Flutter
+
+DEPENDENCIES:
+ - Flutter (from `Flutter`)
+ - flutter_config (from `.symlinks/plugins/flutter_config/ios`)
+ - integration_test (from `.symlinks/plugins/integration_test/ios`)
+ - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
+ - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
+
+EXTERNAL SOURCES:
+ Flutter:
+ :path: Flutter
+ flutter_config:
+ :path: ".symlinks/plugins/flutter_config/ios"
+ integration_test:
+ :path: ".symlinks/plugins/integration_test/ios"
+ package_info_plus:
+ :path: ".symlinks/plugins/package_info_plus/ios"
+ permission_handler_apple:
+ :path: ".symlinks/plugins/permission_handler_apple/ios"
+
+SPEC CHECKSUMS:
+ Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
+ flutter_config: 2226c1df19c78fe34a05eb7f1363445f18e76fc1
+ integration_test: 13825b8a9334a850581300559b8839134b124670
+ package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
+ permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
+
+PODFILE CHECKSUM: 632d6ac0b577d6e268ff7a13a105bbc4f7941989
+
+COCOAPODS: 1.12.0
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..9b975e9
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,887 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 54;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+ 9E13C213DE87A62BCC821C12 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3107420F64BBC761070D93C8 /* Pods_Runner.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 97C146ED1CF9000F007C117D;
+ remoteInfo = Runner;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 0C710016458F636F32E0F552 /* Pods-Runner.staging debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.staging debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.staging debug.xcconfig"; sourceTree = ""; };
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 3107420F64BBC761070D93C8 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 4CECC584E22FC1C9758915C4 /* Pods-Runner.production release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.production release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.production release.xcconfig"; sourceTree = ""; };
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
+ 90B63561D33F88987137327F /* Pods-Runner.production debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.production debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.production debug.xcconfig"; sourceTree = ""; };
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
+ 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ CD053C9523AC5A7DD2AB8FAD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
+ D32392E07C4AF4A06B44E524 /* Pods-Runner.staging release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.staging release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.staging release.xcconfig"; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 97C146EB1CF9000F007C117D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 9E13C213DE87A62BCC821C12 /* Pods_Runner.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 0B24DA943B3930869C992E6C /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 3107420F64BBC761070D93C8 /* Pods_Runner.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 331C8082294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXGroup;
+ children = (
+ 331C807B294A618700263BE5 /* RunnerTests.swift */,
+ );
+ path = RunnerTests;
+ sourceTree = "";
+ };
+ 531D1DC7D3465B4ECDFD13A2 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 0C710016458F636F32E0F552 /* Pods-Runner.staging debug.xcconfig */,
+ 90B63561D33F88987137327F /* Pods-Runner.production debug.xcconfig */,
+ D32392E07C4AF4A06B44E524 /* Pods-Runner.staging release.xcconfig */,
+ 4CECC584E22FC1C9758915C4 /* Pods-Runner.production release.xcconfig */,
+ CD053C9523AC5A7DD2AB8FAD /* Pods-Runner.profile.xcconfig */,
+ );
+ path = Pods;
+ sourceTree = "";
+ };
+ 9740EEB11CF90186004384FC /* Flutter */ = {
+ isa = PBXGroup;
+ children = (
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */,
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */,
+ );
+ name = Flutter;
+ sourceTree = "";
+ };
+ 97C146E51CF9000F007C117D = {
+ isa = PBXGroup;
+ children = (
+ 9740EEB11CF90186004384FC /* Flutter */,
+ 97C146F01CF9000F007C117D /* Runner */,
+ 97C146EF1CF9000F007C117D /* Products */,
+ 331C8082294A63A400263BE5 /* RunnerTests */,
+ 531D1DC7D3465B4ECDFD13A2 /* Pods */,
+ 0B24DA943B3930869C992E6C /* Frameworks */,
+ );
+ sourceTree = "";
+ };
+ 97C146EF1CF9000F007C117D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146EE1CF9000F007C117D /* Runner.app */,
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 97C146F01CF9000F007C117D /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146FA1CF9000F007C117D /* Main.storyboard */,
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */,
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+ 97C147021CF9000F007C117D /* Info.plist */,
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+ );
+ path = Runner;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 331C8080294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
+ buildPhases = (
+ 331C807D294A63A400263BE5 /* Sources */,
+ 331C807F294A63A400263BE5 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */,
+ );
+ name = RunnerTests;
+ productName = RunnerTests;
+ productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 97C146ED1CF9000F007C117D /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ 942778B383ADFC3A413E79B9 /* [CP] Check Pods Manifest.lock */,
+ 9740EEB61CF901F6004384FC /* Run Script */,
+ 97C146EA1CF9000F007C117D /* Sources */,
+ 97C146EB1CF9000F007C117D /* Frameworks */,
+ 97C146EC1CF9000F007C117D /* Resources */,
+ 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ F60C678E026E9519492B4B1A /* [CP] Embed Pods Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ productName = Runner;
+ productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 97C146E61CF9000F007C117D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 1300;
+ ORGANIZATIONNAME = "";
+ TargetAttributes = {
+ 331C8080294A63A400263BE5 = {
+ CreatedOnToolsVersion = 14.0;
+ TestTargetID = 97C146ED1CF9000F007C117D;
+ };
+ 97C146ED1CF9000F007C117D = {
+ CreatedOnToolsVersion = 7.3.1;
+ LastSwiftMigration = 1100;
+ };
+ };
+ };
+ buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 97C146E51CF9000F007C117D;
+ productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 97C146ED1CF9000F007C117D /* Runner */,
+ 331C8080294A63A400263BE5 /* RunnerTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 331C807F294A63A400263BE5 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EC1CF9000F007C117D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
+ };
+ 942778B383ADFC3A413E79B9 /* [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";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-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;
+ };
+ 9740EEB61CF901F6004384FC /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
+ };
+ F60C678E026E9519492B4B1A /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 331C807D294A63A400263BE5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EA1CF9000F007C117D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 97C146ED1CF9000F007C117D /* Runner */;
+ targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C146FB1CF9000F007C117D /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C147001CF9000F007C117D /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 249021D3217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Profile;
+ };
+ 249021D4217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "Survey Flutter Staging";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 4TWS7E2EPE;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = co.nimblehq.khanhthieu.survey.staging;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "match AdHoc co.nimblehq.khanhthieu.survey.staging";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Profile;
+ };
+ 331C8088294A63A400263BE5 /* Staging Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = co.nimblehq.khanhthieu.survey.staging.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = "Staging Debug";
+ };
+ 331C8089294A63A400263BE5 /* Staging Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = co.nimblehq.khanhthieu.survey.staging.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = "Staging Release";
+ };
+ 331C808A294A63A400263BE5 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = co.nimblehq.khanhthieu.survey.staging.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Profile;
+ };
+ 97C147031CF9000F007C117D /* Staging Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = "Staging Debug";
+ };
+ 97C147041CF9000F007C117D /* Staging Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = "Staging Release";
+ };
+ 97C147061CF9000F007C117D /* Staging Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "Survey Flutter Staging";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 4TWS7E2EPE;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = co.nimblehq.khanhthieu.survey.staging;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "match AdHoc co.nimblehq.khanhthieu.survey.staging";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Staging Debug";
+ };
+ 97C147071CF9000F007C117D /* Staging Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "Survey Flutter Staging";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_IDENTITY = "iPhone Distribution";
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 4TWS7E2EPE;
+ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4TWS7E2EPE;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = co.nimblehq.khanhthieu.survey.staging;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "match AppStore co.nimblehq.khanhthieu.survey.staging";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore co.nimblehq.khanhthieu.survey.staging";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Staging Release";
+ };
+ FE1173222A57CA84003AD5BD /* Production Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = "Production Debug";
+ };
+ FE1173232A57CA84003AD5BD /* Production Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "Survey Flutter";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 4TWS7E2EPE;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = co.nimblehq.khanhthieu.survey;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "match AppStore co.nimblehq.khanhthieu.survey";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Production Debug";
+ };
+ FE1173242A57CA84003AD5BD /* Production Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = co.nimblehq.khanhthieu.survey.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = "Production Debug";
+ };
+ FE1173252A57CABB003AD5BD /* Production Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = "Production Release";
+ };
+ FE1173262A57CABB003AD5BD /* Production Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "Survey Flutter";
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_IDENTITY = "iPhone Distribution";
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 4TWS7E2EPE;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = co.nimblehq.khanhthieu.survey;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "match AppStore co.nimblehq.khanhthieu.survey";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Production Release";
+ };
+ FE1173272A57CABB003AD5BD /* Production Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = co.nimblehq.khanhthieu.survey.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = "Production Release";
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 331C8088294A63A400263BE5 /* Staging Debug */,
+ FE1173242A57CA84003AD5BD /* Production Debug */,
+ 331C8089294A63A400263BE5 /* Staging Release */,
+ FE1173272A57CABB003AD5BD /* Production Release */,
+ 331C808A294A63A400263BE5 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Staging Release";
+ };
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147031CF9000F007C117D /* Staging Debug */,
+ FE1173222A57CA84003AD5BD /* Production Debug */,
+ 97C147041CF9000F007C117D /* Staging Release */,
+ FE1173252A57CABB003AD5BD /* Production Release */,
+ 249021D3217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Staging Release";
+ };
+ 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147061CF9000F007C117D /* Staging Debug */,
+ FE1173232A57CA84003AD5BD /* Production Debug */,
+ 97C147071CF9000F007C117D /* Staging Release */,
+ FE1173262A57CABB003AD5BD /* Production Release */,
+ 249021D4217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Staging Release";
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/production.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/production.xcscheme
new file mode 100644
index 0000000..d9fe1de
--- /dev/null
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/production.xcscheme
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/staging.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/staging.xcscheme
new file mode 100644
index 0000000..0baeaae
--- /dev/null
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/staging.xcscheme
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..21a3cc1
--- /dev/null
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
new file mode 100644
index 0000000..70693e4
--- /dev/null
+++ b/ios/Runner/AppDelegate.swift
@@ -0,0 +1,13 @@
+import UIKit
+import Flutter
+
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ GeneratedPluginRegistrant.register(with: self)
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+}
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..d36b1fa
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+ "images" : [
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "83.5x83.5",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-83.5x83.5@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "1024x1024",
+ "idiom" : "ios-marketing",
+ "filename" : "Icon-App-1024x1024@1x.png",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 0000000..dc9ada4
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 0000000..7353c41
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 0000000..797d452
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 0000000..6ed2d93
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 0000000..4cd7b00
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 0000000..fe73094
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 0000000..321773c
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 0000000..797d452
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 0000000..502f463
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 0000000..0ec3034
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 0000000..0ec3034
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 0000000..e9f5fea
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 0000000..84ac32a
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 0000000..8953cba
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 0000000..0467bf1
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 0000000..0bedcf2
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 0000000..89c2725
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..f2e259c
--- /dev/null
+++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f3c2851
--- /dev/null
+++ b/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
new file mode 100644
index 0000000..6ba70e7
--- /dev/null
+++ b/ios/Runner/Info.plist
@@ -0,0 +1,53 @@
+
+
+
+
+ ITSAppUsesNonExemptEncryption
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ $(APP_DISPLAY_NAME)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ survey_flutter
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+ CADisableMinimumFrameDurationOnPhone
+
+ UIApplicationSupportsIndirectInputEvents
+
+
+
diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 0000000..308a2a5
--- /dev/null
+++ b/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1 @@
+#import "GeneratedPluginRegistrant.h"
diff --git a/ios/RunnerTests/RunnerTests.swift b/ios/RunnerTests/RunnerTests.swift
new file mode 100644
index 0000000..86a7c3b
--- /dev/null
+++ b/ios/RunnerTests/RunnerTests.swift
@@ -0,0 +1,12 @@
+import Flutter
+import UIKit
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+ func testExample() {
+ // If you add code to the Runner application, consider adding tests here.
+ // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+ }
+
+}
diff --git a/ios/fastlane/Constants/Constants.rb b/ios/fastlane/Constants/Constants.rb
new file mode 100644
index 0000000..e3cce3f
--- /dev/null
+++ b/ios/fastlane/Constants/Constants.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+class Constants
+ #################
+ #### PROJECT ####
+ #################
+
+ # Workspace path
+ def self.WORKSPACE_PATH
+ './Runner.xcworkspace'
+ end
+
+ # Project path
+ def self.PROJECT_PATH
+ './Runner.xcodeproj'
+ end
+
+ # bundle ID for Staging app
+ def self.BUNDLE_ID_STAGING
+ 'co.nimblehq.khanhthieu.survey.staging'
+ end
+
+ # bundle ID for Production app
+ def self.BUNDLE_ID_PRODUCTION
+ 'co.nimblehq.khanhthieu.survey'
+ end
+
+ #################
+ #### BUILDING ###
+ #################
+
+ # a derived data path
+ def self.DERIVED_DATA_PATH
+ './DerivedData'
+ end
+
+ # a build path
+ def self.BUILD_PATH
+ './Build'
+ end
+
+ #################
+ #### KEYCHAIN ####
+ #################
+
+ # Keychain name
+ def self.KEYCHAIN_NAME
+ 'github_action_keychain'
+ end
+
+ def self.KEYCHAIN_PASSWORD
+ 'password'
+ end
+
+ #################
+ ### ARCHIVING ###
+ #################
+ # an staging environment scheme name
+ def self.SCHEME_NAME_STAGING
+ 'staging'
+ end
+
+ # a Production environment scheme name
+ def self.SCHEME_NAME_PRODUCTION
+ 'production'
+ end
+
+ # an staging product name
+ def self.PRODUCT_NAME_STAGING
+ 'Survey Flutter Staging'
+ end
+
+ # a staging TestFlight product name
+ def self.PRODUCT_NAME_STAGING_TEST_FLIGHT
+ 'Survey Flutter Staging'
+ end
+
+ # a Production product name
+ def self.PRODUCT_NAME_PRODUCTION
+ 'Survey Flutter'
+ end
+
+ # a main target name
+ def self.MAIN_TARGET_NAME
+ 'Runner'
+ end
+end
diff --git a/ios/fastlane/Constants/Environments.rb b/ios/fastlane/Constants/Environments.rb
new file mode 100644
index 0000000..7aa5872
--- /dev/null
+++ b/ios/fastlane/Constants/Environments.rb
@@ -0,0 +1,49 @@
+class Environments
+ def self.CI
+ ENV['CI']
+ end
+
+ def self.BUILD_NUMBER
+ ENV["BUILD_NUMBER"]
+ end
+
+ def self.MANUAL_VERSION
+ ENV['MANUAL_VERSION']
+ end
+
+ def self.FASTLANE_USER
+ ENV['FASTLANE_USER']
+ end
+
+ def self.TEAM_ID
+ ENV['TEAM_ID']
+ end
+
+ def self.APPSTORE_CONNECT_API_KEY_ID
+ ENV['APPSTORE_CONNECT_API_KEY_ID']
+ end
+
+ def self.APPSTORE_CONNECT_ISSUER_ID
+ ENV['APPSTORE_CONNECT_ISSUER_ID']
+ end
+
+ def self.APPSTORE_CONNECT_API_KEY_CONTENT
+ ENV['APPSTORE_CONNECT_API_KEY_CONTENT']
+ end
+
+ #################
+ ### Firebase ###
+ #################
+
+ def self.FIREBASE_CLI_TOKEN
+ ENV['FIREBASE_CLI_TOKEN']
+ end
+
+ def self.FIREBASE_APP_ID_STAGING
+ ENV['FIREBASE_APP_ID_STAGING']
+ end
+
+ def self.FIREBASE_TESTER_GROUPS
+ ENV['FIREBASE_DISTRIBUTION_TESTER_GROUPS']
+ end
+end
diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile
new file mode 100644
index 0000000..f03576d
--- /dev/null
+++ b/ios/fastlane/Fastfile
@@ -0,0 +1,186 @@
+# frozen_string_literal: true
+
+require './Constants/Constants'
+require './Constants/Environments'
+require './Managers/BuildManager'
+require './Managers/DistributionManager'
+require './Managers/MatchManager'
+
+ENV["FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT"] = "180"
+
+builder = BuildManager.new(fastlane: self)
+
+distribution_manager = DistributionManager.new(
+ fastlane: self,
+ build_path: Constants.BUILD_PATH,
+ firebase_token: Environments.FIREBASE_CLI_TOKEN
+)
+
+match_manager = MatchManager.new(
+ fastlane: self,
+ keychain_name: Constants.KEYCHAIN_NAME,
+ keychain_password: Constants.KEYCHAIN_PASSWORD,
+ is_ci: Environments.CI
+)
+
+before_all do
+ ensure_bundle_exec
+end
+
+default_platform(:ios)
+
+platform :ios do
+
+ # Code Sign
+
+ desc 'Sync AppStore Staging match signing'
+ lane :sync_appstore_staging_signing do
+ match_manager.sync_app_store_signing(app_identifier: [Constants.BUNDLE_ID_STAGING])
+ end
+
+ desc 'Sync AppStore Production match signing'
+ lane :sync_appstore_production_signing do
+ match_manager.sync_app_store_signing(app_identifier: [Constants.BUNDLE_ID_PRODUCTION])
+ end
+
+ desc 'Sync Adhoc Staging match signing'
+ lane :sync_adhoc_staging_signing do
+ match_manager.sync_adhoc_signing(app_identifier: [Constants.BUNDLE_ID_STAGING])
+ end
+
+ desc 'Register new devices'
+ lane :register_new_device do
+ device_name = prompt(text: 'Enter the device name: ')
+ device_udid = prompt(text: 'Enter the device UDID: ')
+ device_hash = {}
+ device_hash[device_name] = device_udid
+ register_devices(devices: device_hash)
+ match(force: true)
+ end
+
+ # Testflight
+
+ desc 'Build and upload Staging app to Test Flight'
+ lane :build_and_upload_staging_to_testflight do
+ set_app_version
+ bump_build
+ builder.build_app_store(
+ Constants.SCHEME_NAME_STAGING,
+ Constants.PRODUCT_NAME_STAGING,
+ Constants.BUNDLE_ID_STAGING,
+ false
+ )
+ set_appstore_connect_api_key
+ distribution_manager.upload_to_testflight(
+ product_name: Constants.PRODUCT_NAME_STAGING,
+ bundle_identifier: Constants.BUNDLE_ID_STAGING
+ )
+ end
+
+ desc 'Build and upload Production app to Test Flight'
+ lane :build_and_upload_production_to_testflight do
+ set_app_version
+ bump_build
+ builder.build_app_store(
+ Constants.SCHEME_NAME_PRODUCTION,
+ Constants.PRODUCT_NAME_PRODUCTION,
+ Constants.BUNDLE_ID_PRODUCTION,
+ false
+ )
+ set_appstore_connect_api_key
+ distribution_manager.upload_to_testflight(
+ product_name: Constants.PRODUCT_NAME_PRODUCTION,
+ bundle_identifier: Constants.BUNDLE_ID_PRODUCTION
+ )
+ end
+
+ # AppStore
+
+ desc 'Build and upload Staging app to App Store Connect'
+ lane :build_and_upload_app_store_connect_app do
+ set_app_version
+ bump_build
+ builder.build_app_store(
+ Constants.SCHEME_NAME_STAGING,
+ Constants.PRODUCT_NAME_STAGING,
+ Constants.BUNDLE_ID_STAGING,
+ false
+ )
+ upload_build_to_app_store_connect
+ end
+
+ desc 'upload develop build to App Store Connect'
+ private_lane :upload_build_to_app_store_connect do
+ distribution_manager.upload_to_app_store_connect(
+ product_name: Constants.PRODUCT_NAME_STAGING,
+ bundle_identifier: Constants.BUNDLE_ID_STAGING
+ )
+ end
+
+ # Firebase
+ desc 'Build and upload Staging app to Firebase'
+ lane :build_and_upload_staging_app do
+ build_and_upload_to_firebase(
+ scheme_name: Constants.SCHEME_NAME_STAGING,
+ product_name: Constants.PRODUCT_NAME_STAGING,
+ bundle_id: Constants.BUNDLE_ID_STAGING,
+ app_id: Environments.FIREBASE_APP_ID_STAGING
+ )
+ end
+
+ desc 'build and upload app to Firebase'
+ private_lane :build_and_upload_to_firebase do |options|
+ set_app_version
+ bump_build
+ builder.build_ad_hoc(
+ options[:scheme_name],
+ options[:product_name],
+ options[:bundle_id]
+ )
+ upload_build_to_firebase(
+ product_name: options[:product_name],
+ firebase_app_id: options[:app_id],
+ tester_groups: Environments.FIREBASE_TESTER_GROUPS
+ )
+ end
+
+ # Private helper lanes
+
+ desc 'check if any specific version number in build environment'
+ private_lane :set_app_version do
+ # Set up env var MANUAL_VERSION if we need to override the version number
+ if (Environments.MANUAL_VERSION || '') != ''
+ increment_version_number(
+ version_number: Environments.MANUAL_VERSION
+ )
+ end
+ end
+
+ desc 'set build number'
+ private_lane :bump_build do
+ increment_build_number(
+ build_number: Environments.BUILD_NUMBER,
+ xcodeproj: Constants.PROJECT_PATH
+ )
+ end
+
+ desc 'upload develop build to Firebase app distribution'
+ private_lane :upload_build_to_firebase do |options|
+ distribution_manager.upload_to_firebase(
+ product_name: options[:product_name],
+ firebase_app_id: options[:firebase_app_id],
+ tester_groups: options[:tester_groups],
+ notes: ""
+ )
+ end
+
+ desc 'set App Store Connect API Key'
+ private_lane :set_appstore_connect_api_key do
+ app_store_connect_api_key(
+ key_id: Environments.APPSTORE_CONNECT_API_KEY_ID,
+ issuer_id: Environments.APPSTORE_CONNECT_ISSUER_ID,
+ key_content: Environments.APPSTORE_CONNECT_API_KEY_CONTENT,
+ is_key_content_base64: true
+ )
+ end
+end
diff --git a/ios/fastlane/Gymfile b/ios/fastlane/Gymfile
new file mode 100644
index 0000000..9bf3f0b
--- /dev/null
+++ b/ios/fastlane/Gymfile
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+clean(true)
+export_team_id(Environments.TEAM_ID)
+output_directory(Constants.BUILD_PATH) # .ipa
+build_path(Constants.BUILD_PATH) # .xcarchive is stored
+derived_data_path(Constants.DERIVED_DATA_PATH) # .app
diff --git a/ios/fastlane/Managers/BuildManager.rb b/ios/fastlane/Managers/BuildManager.rb
new file mode 100644
index 0000000..d3f61d9
--- /dev/null
+++ b/ios/fastlane/Managers/BuildManager.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+class BuildManager
+ def initialize(fastlane:)
+ @fastlane = fastlane
+ end
+
+ def build_app_store(scheme, product_name, bundle_identifier, include_bitcode)
+ @fastlane.gym(
+ scheme: scheme,
+ export_method: 'app-store',
+ export_options: {
+ provisioningProfiles: {
+ @bundle_identifier_staging.to_s => "match AppStore #{bundle_identifier}"
+ }
+ },
+ include_bitcode: include_bitcode,
+ output_name: product_name
+ )
+ end
+
+ def build_ad_hoc(scheme, product_name, bundle_identifier)
+ @fastlane.gym(
+ scheme: scheme,
+ export_method: 'ad-hoc',
+ export_options: {
+ provisioningProfiles: {
+ @bundle_identifier_staging.to_s => "match Adhoc #{bundle_identifier}"
+ }
+ },
+ include_bitcode: false,
+ output_name: product_name,
+ disable_xcpretty: true
+ )
+ end
+end
diff --git a/ios/fastlane/Managers/DistributionManager.rb b/ios/fastlane/Managers/DistributionManager.rb
new file mode 100644
index 0000000..a0c6ee7
--- /dev/null
+++ b/ios/fastlane/Managers/DistributionManager.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+class DistributionManager
+ def initialize(fastlane:, build_path:, firebase_token:)
+ @fastlane = fastlane
+ @build_path = build_path
+ @firebase_token = firebase_token
+ end
+
+ def upload_to_testflight(product_name:, bundle_identifier:)
+ @fastlane.pilot(
+ ipa: "#{@build_path}/#{product_name}.ipa",
+ app_identifier: bundle_identifier,
+ notify_external_testers: false,
+ skip_waiting_for_build_processing: true
+ )
+ end
+
+ def upload_to_app_store_connect(product_name:, bundle_identifier:)
+ @fastlane.deliver(
+ ipa: "#{@build_path}/#{product_name}.ipa",
+ app_identifier: bundle_identifier,
+ force: true,
+ skip_metadata: true,
+ skip_screenshots: true,
+ run_precheck_before_submit: false
+ )
+ end
+
+ def upload_to_firebase(product_name:, firebase_app_id:, notes:, tester_groups:)
+ ipa_path = "#{@build_path}/#{product_name}.ipa"
+ @fastlane.firebase_app_distribution(
+ app: firebase_app_id,
+ ipa_path: ipa_path,
+ groups: tester_groups,
+ firebase_cli_token: @firebase_token,
+ release_notes: notes
+ )
+ end
+end
diff --git a/ios/fastlane/Managers/MatchManager.rb b/ios/fastlane/Managers/MatchManager.rb
new file mode 100644
index 0000000..a32cb63
--- /dev/null
+++ b/ios/fastlane/Managers/MatchManager.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+class MatchManager
+ def initialize(
+ fastlane:,
+ keychain_name:,
+ keychain_password:,
+ is_ci:
+ )
+ @fastlane = fastlane
+ @keychain_name = keychain_name
+ @keychain_password = keychain_password
+ @is_ci = is_ci
+ end
+
+ def sync_adhoc_signing(app_identifier:)
+ if @is_ci
+ create_ci_keychain
+ @fastlane.match(
+ type: 'adhoc',
+ keychain_name: @keychain_name,
+ keychain_password: @keychain_password,
+ app_identifier: app_identifier,
+ readonly: true
+ )
+ else
+ @fastlane.match(type: 'adhoc', app_identifier: app_identifier, readonly: true)
+ end
+ end
+
+ def sync_app_store_signing(app_identifier:)
+ if @is_ci
+ create_ci_keychain
+ @fastlane.match(
+ type: 'appstore',
+ keychain_name: @keychain_name,
+ keychain_password: @keychain_password,
+ app_identifier: app_identifier,
+ readonly: true
+ )
+ else
+ @fastlane.match(type: 'appstore', app_identifier: app_identifier, readonly: true)
+ end
+ end
+
+ def create_ci_keychain
+ @fastlane.create_keychain(
+ name: @keychain_name,
+ password: @keychain_password,
+ default_keychain: true,
+ unlock: true,
+ timeout: 3600,
+ lock_when_sleeps: false
+ )
+ end
+end
diff --git a/ios/fastlane/Matchfile b/ios/fastlane/Matchfile
new file mode 100644
index 0000000..1ae56cd
--- /dev/null
+++ b/ios/fastlane/Matchfile
@@ -0,0 +1,15 @@
+git_url("git@github.com:nimblehq/match-certificates.git")
+
+storage_mode("git")
+
+# type("appstore") # The default type, can be: appstore, adhoc, enterprise or development
+
+# app_identifier(["tools.fastlane.app", "tools.fastlane.app2"])
+# username("user@fastlane.tools") # Your Apple Developer Portal username
+
+# For all available options run `fastlane match --help`
+# Remove the # in the beginning of the line to enable the other options
+
+# The docs are available on https://docs.fastlane.tools/actions/match
+readonly(true)
+force(false)
diff --git a/ios/fastlane/Pluginfile b/ios/fastlane/Pluginfile
new file mode 100644
index 0000000..b18539b
--- /dev/null
+++ b/ios/fastlane/Pluginfile
@@ -0,0 +1,5 @@
+# Autogenerated by fastlane
+#
+# Ensure this file is checked in to source control!
+
+gem 'fastlane-plugin-firebase_app_distribution'
diff --git a/l10n.yaml b/l10n.yaml
new file mode 100644
index 0000000..15338f2
--- /dev/null
+++ b/l10n.yaml
@@ -0,0 +1,3 @@
+arb-dir: lib/l10n
+template-arb-file: app_en.arb
+output-localization-file: app_localizations.dart
diff --git a/lib/api/api_service.dart b/lib/api/api_service.dart
new file mode 100644
index 0000000..2840b69
--- /dev/null
+++ b/lib/api/api_service.dart
@@ -0,0 +1,14 @@
+import 'package:dio/dio.dart';
+import 'package:survey_flutter/model/response/user_response.dart';
+import 'package:retrofit/retrofit.dart';
+
+part 'api_service.g.dart';
+
+@RestApi()
+abstract class ApiService {
+ factory ApiService(Dio dio, {String baseUrl}) = _ApiService;
+
+ // TODO add API endpoint
+ @GET('users')
+ Future> getUsers();
+}
diff --git a/lib/api/exception/network_exceptions.dart b/lib/api/exception/network_exceptions.dart
new file mode 100644
index 0000000..9bc1e0c
--- /dev/null
+++ b/lib/api/exception/network_exceptions.dart
@@ -0,0 +1,171 @@
+import 'dart:io';
+
+import 'package:dio/dio.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part 'network_exceptions.freezed.dart';
+
+@freezed
+class NetworkExceptions with _$NetworkExceptions {
+ const factory NetworkExceptions.requestCancelled() = RequestCancelled;
+
+ const factory NetworkExceptions.unauthorisedRequest() = UnauthorisedRequest;
+
+ const factory NetworkExceptions.badRequest() = BadRequest;
+
+ const factory NetworkExceptions.notFound(String reason) = NotFound;
+
+ const factory NetworkExceptions.methodNotAllowed() = MethodNotAllowed;
+
+ const factory NetworkExceptions.notAcceptable() = NotAcceptable;
+
+ const factory NetworkExceptions.requestTimeout() = RequestTimeout;
+
+ const factory NetworkExceptions.receiveTimeout() = ReceiveTimeout;
+
+ const factory NetworkExceptions.sendTimeout() = SendTimeout;
+
+ const factory NetworkExceptions.conflict() = Conflict;
+
+ const factory NetworkExceptions.internalServerError() = InternalServerError;
+
+ const factory NetworkExceptions.notImplemented() = NotImplemented;
+
+ const factory NetworkExceptions.serviceUnavailable() = ServiceUnavailable;
+
+ const factory NetworkExceptions.noInternetConnection() = NoInternetConnection;
+
+ const factory NetworkExceptions.formatException() = FormatException;
+
+ const factory NetworkExceptions.unableToProcess() = UnableToProcess;
+
+ const factory NetworkExceptions.defaultError(String error) = DefaultError;
+
+ const factory NetworkExceptions.unexpectedError() = UnexpectedError;
+
+ static NetworkExceptions fromDioException(error) {
+ if (error is Exception) {
+ try {
+ NetworkExceptions networkExceptions;
+ if (error is DioError) {
+ switch (error.type) {
+ case DioErrorType.cancel:
+ networkExceptions = const NetworkExceptions.requestCancelled();
+ break;
+ case DioErrorType.connectionTimeout:
+ networkExceptions = const NetworkExceptions.requestTimeout();
+ break;
+ case DioErrorType.unknown:
+ networkExceptions =
+ const NetworkExceptions.noInternetConnection();
+ break;
+ case DioErrorType.receiveTimeout:
+ networkExceptions = const NetworkExceptions.receiveTimeout();
+ break;
+ case DioErrorType.sendTimeout:
+ networkExceptions = const NetworkExceptions.sendTimeout();
+ break;
+ case DioErrorType.badResponse:
+ switch (error.response?.statusCode) {
+ case 400:
+ networkExceptions = const NetworkExceptions.badRequest();
+ break;
+ case 401:
+ networkExceptions =
+ const NetworkExceptions.unauthorisedRequest();
+ break;
+ case 403:
+ networkExceptions =
+ const NetworkExceptions.unauthorisedRequest();
+ break;
+ case 404:
+ networkExceptions =
+ const NetworkExceptions.notFound("Not found");
+ break;
+ case 409:
+ networkExceptions = const NetworkExceptions.conflict();
+ break;
+ case 408:
+ networkExceptions = const NetworkExceptions.requestTimeout();
+ break;
+ case 500:
+ networkExceptions =
+ const NetworkExceptions.internalServerError();
+ break;
+ case 503:
+ networkExceptions =
+ const NetworkExceptions.serviceUnavailable();
+ break;
+ default:
+ var responseCode = error.response?.statusCode;
+ networkExceptions = NetworkExceptions.defaultError(
+ "Received invalid status code: $responseCode",
+ );
+ }
+ break;
+ default:
+ networkExceptions = const NetworkExceptions.unexpectedError();
+ break;
+ }
+ } else if (error is SocketException) {
+ networkExceptions = const NetworkExceptions.noInternetConnection();
+ } else {
+ networkExceptions = const NetworkExceptions.unexpectedError();
+ }
+ return networkExceptions;
+ } on FormatException catch (_) {
+ return const NetworkExceptions.formatException();
+ } catch (_) {
+ return const NetworkExceptions.unexpectedError();
+ }
+ } else {
+ if (error.toString().contains("is not a subtype of")) {
+ return const NetworkExceptions.unableToProcess();
+ } else {
+ return const NetworkExceptions.unexpectedError();
+ }
+ }
+ }
+
+ static String getErrorMessage(NetworkExceptions networkExceptions) {
+ var errorMessage = "";
+ networkExceptions.when(notImplemented: () {
+ errorMessage = "Not Implemented";
+ }, requestCancelled: () {
+ errorMessage = "Request Cancelled";
+ }, internalServerError: () {
+ errorMessage = "Internal Server Error";
+ }, notFound: (String reason) {
+ errorMessage = reason;
+ }, serviceUnavailable: () {
+ errorMessage = "Service unavailable";
+ }, methodNotAllowed: () {
+ errorMessage = "Method not allowed";
+ }, badRequest: () {
+ errorMessage = "Bad request";
+ }, unauthorisedRequest: () {
+ errorMessage = "Unauthorised request";
+ }, unexpectedError: () {
+ errorMessage = "Unexpected error occurred";
+ }, requestTimeout: () {
+ errorMessage = "Connection request timeout";
+ }, noInternetConnection: () {
+ errorMessage = "No internet connection";
+ }, conflict: () {
+ errorMessage = "Error due to a conflict";
+ }, sendTimeout: () {
+ errorMessage = "Send timeout in connection with API server";
+ }, receiveTimeout: () {
+ errorMessage = "Receive timeout in connection with API server";
+ }, unableToProcess: () {
+ errorMessage = "Unable to process the data";
+ }, defaultError: (String error) {
+ errorMessage = error;
+ }, formatException: () {
+ errorMessage = "Unexpected error occurred";
+ }, notAcceptable: () {
+ errorMessage = "Not acceptable";
+ });
+ return errorMessage;
+ }
+}
diff --git a/lib/api/repository/credential_repository.dart b/lib/api/repository/credential_repository.dart
new file mode 100644
index 0000000..436a0b3
--- /dev/null
+++ b/lib/api/repository/credential_repository.dart
@@ -0,0 +1,22 @@
+import 'package:survey_flutter/api/api_service.dart';
+import 'package:survey_flutter/api/exception/network_exceptions.dart';
+import 'package:survey_flutter/model/response/user_response.dart';
+
+abstract class CredentialRepository {
+ Future> getUsers();
+}
+
+class CredentialRepositoryImpl extends CredentialRepository {
+ final ApiService _apiService;
+
+ CredentialRepositoryImpl(this._apiService);
+
+ @override
+ Future> getUsers() async {
+ try {
+ return await _apiService.getUsers();
+ } catch (exception) {
+ throw NetworkExceptions.fromDioException(exception);
+ }
+ }
+}
diff --git a/lib/di/interceptor/app_interceptor.dart b/lib/di/interceptor/app_interceptor.dart
new file mode 100644
index 0000000..83dc509
--- /dev/null
+++ b/lib/di/interceptor/app_interceptor.dart
@@ -0,0 +1,69 @@
+import 'dart:io';
+
+import 'package:dio/dio.dart';
+
+class AppInterceptor extends Interceptor {
+ final bool _requireAuthenticate;
+ final Dio _dio;
+
+ AppInterceptor(
+ this._requireAuthenticate,
+ this._dio,
+ );
+
+ @override
+ Future onRequest(
+ RequestOptions options, RequestInterceptorHandler handler) async {
+ if (_requireAuthenticate) {
+ // TODO header authorization here
+ // options.headers
+ // .putIfAbsent(HEADER_AUTHORIZATION, () => "");
+ }
+ return super.onRequest(options, handler);
+ }
+
+ @override
+ void onError(DioError err, ErrorInterceptorHandler handler) {
+ final statusCode = err.response?.statusCode;
+ if ((statusCode == HttpStatus.forbidden ||
+ statusCode == HttpStatus.unauthorized) &&
+ _requireAuthenticate) {
+ _doRefreshToken(err, handler);
+ } else {
+ handler.next(err);
+ }
+ }
+
+ Future _doRefreshToken(
+ DioError err,
+ ErrorInterceptorHandler handler,
+ ) async {
+ try {
+ // TODO Request new token
+
+ // if (result is Success) {
+ // TODO Update new token header
+ // err.requestOptions.headers[_headerAuthorization] = newToken;
+
+ // Create request with new access token
+ final options = Options(
+ method: err.requestOptions.method,
+ headers: err.requestOptions.headers);
+ final newRequest = await _dio.request(
+ "${err.requestOptions.baseUrl}${err.requestOptions.path}",
+ options: options,
+ data: err.requestOptions.data,
+ queryParameters: err.requestOptions.queryParameters);
+ handler.resolve(newRequest);
+ // } else {
+ // handler.next(err);
+ // }
+ } catch (exception) {
+ if (exception is DioError) {
+ handler.next(exception);
+ } else {
+ handler.next(err);
+ }
+ }
+ }
+}
diff --git a/lib/di/provider/dio_provider.dart b/lib/di/provider/dio_provider.dart
new file mode 100644
index 0000000..311db6c
--- /dev/null
+++ b/lib/di/provider/dio_provider.dart
@@ -0,0 +1,39 @@
+import 'package:dio/dio.dart';
+import 'package:flutter/foundation.dart';
+import 'package:survey_flutter/di/interceptor/app_interceptor.dart';
+
+const String headerContentType = 'Content-Type';
+const String defaultContentType = 'application/json; charset=utf-8';
+
+class DioProvider {
+ Dio? _dio;
+
+ Dio getDio() {
+ _dio ??= _createDio();
+ return _dio!;
+ }
+
+ Dio _createDio({bool requireAuthenticate = false}) {
+ final dio = Dio();
+ final appInterceptor = AppInterceptor(
+ requireAuthenticate,
+ dio,
+ );
+ final interceptors = [];
+ interceptors.add(appInterceptor);
+ if (!kReleaseMode) {
+ interceptors.add(LogInterceptor(
+ request: true,
+ responseBody: true,
+ requestBody: true,
+ requestHeader: true,
+ ));
+ }
+
+ return dio
+ ..options.connectTimeout = const Duration(seconds: 3000)
+ ..options.receiveTimeout = const Duration(seconds: 5000)
+ ..options.headers = {headerContentType: defaultContentType}
+ ..interceptors.addAll(interceptors);
+ }
+}
diff --git a/lib/env.dart b/lib/env.dart
new file mode 100644
index 0000000..fd49d95
--- /dev/null
+++ b/lib/env.dart
@@ -0,0 +1,7 @@
+import 'package:flutter_config/flutter_config.dart';
+
+class Env {
+ static String get restApiEndpoint {
+ return FlutterConfig.get('REST_API_ENDPOINT');
+ }
+}
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
new file mode 100644
index 0000000..f19b50b
--- /dev/null
+++ b/lib/l10n/app_en.arb
@@ -0,0 +1,3 @@
+{
+ "hello": "Hello!"
+}
diff --git a/lib/l10n/app_th.arb b/lib/l10n/app_th.arb
new file mode 100644
index 0000000..245defa
--- /dev/null
+++ b/lib/l10n/app_th.arb
@@ -0,0 +1,3 @@
+{
+ "hello": "สวัสดี"
+}
diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb
new file mode 100644
index 0000000..221dec8
--- /dev/null
+++ b/lib/l10n/app_vi.arb
@@ -0,0 +1,3 @@
+{
+ "hello": "Xin chào!"
+}
diff --git a/lib/main.dart b/lib/main.dart
new file mode 100644
index 0000000..402e02a
--- /dev/null
+++ b/lib/main.dart
@@ -0,0 +1,111 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_config/flutter_config.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:survey_flutter/gen/assets.gen.dart';
+import 'package:go_router/go_router.dart';
+import 'package:package_info_plus/package_info_plus.dart';
+
+void main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+ await FlutterConfig.loadEnvVariables();
+ runApp(MyApp());
+}
+
+const routePathRootScreen = '/';
+const routePathSecondScreen = 'second';
+
+class MyApp extends StatelessWidget {
+ MyApp({Key? key}) : super(key: key);
+
+ final GoRouter _router = GoRouter(
+ routes: [
+ GoRoute(
+ path: routePathRootScreen,
+ builder: (BuildContext context, GoRouterState state) =>
+ const HomeScreen(),
+ routes: [
+ GoRoute(
+ path: routePathSecondScreen,
+ builder: (BuildContext context, GoRouterState state) =>
+ const SecondScreen(),
+ ),
+ ],
+ ),
+ ],
+ );
+
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp.router(
+ theme: ThemeData(
+ primarySwatch: Colors.blue,
+ brightness: Brightness.light,
+ fontFamily: Assets.fonts.neuzeit,
+ ),
+ localizationsDelegates: AppLocalizations.localizationsDelegates,
+ supportedLocales: AppLocalizations.supportedLocales,
+ routeInformationProvider: _router.routeInformationProvider,
+ routeInformationParser: _router.routeInformationParser,
+ routerDelegate: _router.routerDelegate,
+ );
+ }
+}
+
+class HomeScreen extends StatelessWidget {
+ const HomeScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: FutureBuilder(
+ future: PackageInfo.fromPlatform(),
+ builder: (context, snapshot) {
+ return snapshot.hasData
+ ? Text(snapshot.data?.appName ?? "")
+ : const SizedBox.shrink();
+ }),
+ ),
+ body: Center(
+ child: Column(
+ children: [
+ const SizedBox(height: 24),
+ FractionallySizedBox(
+ widthFactor: 0.5,
+ child: Image.asset(
+ Assets.images.nimbleLogo.path,
+ fit: BoxFit.fitWidth,
+ ),
+ ),
+ const SizedBox(height: 24),
+ Text(AppLocalizations.of(context)!.hello),
+ Text(
+ FlutterConfig.get('SECRET'),
+ style: const TextStyle(color: Colors.black, fontSize: 24),
+ ),
+ const SizedBox(height: 24),
+ ElevatedButton(
+ onPressed: () => context.go('/$routePathSecondScreen'),
+ child: const Text("Navigate to Second Screen"),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+class SecondScreen extends StatelessWidget {
+ const SecondScreen({
+ Key? key,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text("Second Screen"),
+ ),
+ );
+ }
+}
diff --git a/lib/model/response/user_response.dart b/lib/model/response/user_response.dart
new file mode 100644
index 0000000..6e95125
--- /dev/null
+++ b/lib/model/response/user_response.dart
@@ -0,0 +1,16 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'user_response.g.dart';
+
+@JsonSerializable()
+class UserResponse {
+ final String email;
+ final String username;
+
+ UserResponse(this.email, this.username);
+
+ factory UserResponse.fromJson(Map json) =>
+ _$UserResponseFromJson(json);
+
+ Map toJson() => _$UserResponseToJson(this);
+}
diff --git a/lib/usecases/base/base_use_case.dart b/lib/usecases/base/base_use_case.dart
new file mode 100644
index 0000000..3ec78dc
--- /dev/null
+++ b/lib/usecases/base/base_use_case.dart
@@ -0,0 +1,17 @@
+part 'use_case_result.dart';
+
+abstract class BaseUseCase {
+ const BaseUseCase();
+}
+
+abstract class UseCase extends BaseUseCase> {
+ const UseCase() : super();
+
+ Future> call(P params);
+}
+
+abstract class NoParamsUseCase extends BaseUseCase> {
+ const NoParamsUseCase() : super();
+
+ Future> call();
+}
diff --git a/lib/usecases/base/use_case_result.dart b/lib/usecases/base/use_case_result.dart
new file mode 100644
index 0000000..456111c
--- /dev/null
+++ b/lib/usecases/base/use_case_result.dart
@@ -0,0 +1,23 @@
+part of 'base_use_case.dart';
+
+abstract class Result {
+ Result._();
+}
+
+class Success extends Result {
+ final T value;
+
+ Success(this.value) : super._();
+}
+
+class UseCaseException implements Exception {
+ final dynamic actualException;
+
+ UseCaseException(this.actualException);
+}
+
+class Failed extends Result {
+ final UseCaseException exception;
+
+ Failed(this.exception) : super._();
+}
diff --git a/lib/utils/wrappers/permission_wrapper.dart b/lib/utils/wrappers/permission_wrapper.dart
new file mode 100644
index 0000000..954a8ea
--- /dev/null
+++ b/lib/utils/wrappers/permission_wrapper.dart
@@ -0,0 +1,28 @@
+import 'package:permission_handler/permission_handler.dart'
+ as permission_handler;
+
+abstract class PermissionWrapper {
+ Future requestCameraPermission();
+
+ Future isCameraPermissionDenied();
+
+ Future isCameraPermissionPermanentlyDenied();
+}
+
+class PermissionWrapperImpl extends PermissionWrapper {
+ @override
+ Future requestCameraPermission() {
+ return permission_handler.Permission.camera.request().then(
+ (status) => status == permission_handler.PermissionStatus.granted);
+ }
+
+ @override
+ Future isCameraPermissionDenied() {
+ return permission_handler.Permission.camera.isDenied;
+ }
+
+ @override
+ Future isCameraPermissionPermanentlyDenied() {
+ return permission_handler.Permission.camera.isPermanentlyDenied;
+ }
+}
diff --git a/pubspec.lock b/pubspec.lock
new file mode 100644
index 0000000..f12a004
--- /dev/null
+++ b/pubspec.lock
@@ -0,0 +1,846 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+ _fe_analyzer_shared:
+ dependency: transitive
+ description:
+ name: _fe_analyzer_shared
+ sha256: "405666cd3cf0ee0a48d21ec67e65406aad2c726d9fa58840d3375e7bdcd32a07"
+ url: "https://pub.dev"
+ source: hosted
+ version: "60.0.0"
+ analyzer:
+ dependency: transitive
+ description:
+ name: analyzer
+ sha256: "1952250bd005bacb895a01bf1b4dc00e3ba1c526cf47dca54dfe24979c65f5b3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.12.0"
+ args:
+ dependency: transitive
+ description:
+ name: args
+ sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1"
+ async:
+ dependency: transitive
+ description:
+ name: async
+ sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.11.0"
+ boolean_selector:
+ dependency: transitive
+ description:
+ name: boolean_selector
+ sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.1"
+ build:
+ dependency: transitive
+ description:
+ name: build
+ sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ build_config:
+ dependency: transitive
+ description:
+ name: build_config
+ sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
+ build_daemon:
+ dependency: transitive
+ description:
+ name: build_daemon
+ sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.0"
+ build_resolvers:
+ dependency: transitive
+ description:
+ name: build_resolvers
+ sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.0"
+ build_runner:
+ dependency: "direct dev"
+ description:
+ name: build_runner
+ sha256: "220ae4553e50d7c21a17c051afc7b183d28a24a420502e842f303f8e4e6edced"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.4"
+ build_runner_core:
+ dependency: transitive
+ description:
+ name: build_runner_core
+ sha256: "30859c90e9ddaccc484f56303931f477b1f1ba2bab74aa32ed5d6ce15870f8cf"
+ url: "https://pub.dev"
+ source: hosted
+ version: "7.2.8"
+ built_collection:
+ dependency: transitive
+ description:
+ name: built_collection
+ sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.1.1"
+ built_value:
+ dependency: transitive
+ description:
+ name: built_value
+ sha256: "2f17434bd5d52a26762043d6b43bb53b3acd029b4d9071a329f46d67ef297e6d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "8.5.0"
+ characters:
+ dependency: transitive
+ description:
+ name: characters
+ sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.0"
+ checked_yaml:
+ dependency: transitive
+ description:
+ name: checked_yaml
+ sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.3"
+ clock:
+ dependency: transitive
+ description:
+ name: clock
+ sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
+ code_builder:
+ dependency: transitive
+ description:
+ name: code_builder
+ sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.4.0"
+ collection:
+ dependency: transitive
+ description:
+ name: collection
+ sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.17.1"
+ color:
+ dependency: transitive
+ description:
+ name: color
+ sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.0"
+ convert:
+ dependency: transitive
+ description:
+ name: convert
+ sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.1"
+ crypto:
+ dependency: transitive
+ description:
+ name: crypto
+ sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.3"
+ dart_style:
+ dependency: transitive
+ description:
+ name: dart_style
+ sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.1"
+ dartx:
+ dependency: transitive
+ description:
+ name: dartx
+ sha256: "45d7176701f16c5a5e00a4798791c1964bc231491b879369c818dd9a9c764871"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
+ dio:
+ dependency: "direct main"
+ description:
+ name: dio
+ sha256: "347d56c26d63519552ef9a569f2a593dda99a81fdbdff13c584b7197cfe05059"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.1.2"
+ fake_async:
+ dependency: transitive
+ description:
+ name: fake_async
+ sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.1"
+ ffi:
+ dependency: transitive
+ description:
+ name: ffi
+ sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.2"
+ file:
+ dependency: transitive
+ description:
+ name: file
+ sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.1.4"
+ fixnum:
+ dependency: transitive
+ description:
+ name: fixnum
+ sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
+ flutter:
+ dependency: "direct main"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_config:
+ dependency: "direct main"
+ description:
+ name: flutter_config
+ sha256: a07e6156bb6e776e29c6357be433155acda87d1dab1a3f787a72091a1b71ffbf
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.2"
+ flutter_driver:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_gen_core:
+ dependency: transitive
+ description:
+ name: flutter_gen_core
+ sha256: e8637dd6a59860f89e5e71be0a27101ec32dad1a0ed7fd879fd23b6e91d5004d
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.3.1"
+ flutter_gen_runner:
+ dependency: "direct dev"
+ description:
+ name: flutter_gen_runner
+ sha256: "7de1bf4fc0439be0fef3178b6423d5c7f1f9f3a38a7c6fafe75d7f70ff4856d7"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.3.1"
+ flutter_lints:
+ dependency: "direct dev"
+ description:
+ name: flutter_lints
+ sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.1"
+ flutter_localizations:
+ dependency: "direct main"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_svg:
+ dependency: "direct main"
+ description:
+ name: flutter_svg
+ sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.7"
+ flutter_test:
+ dependency: "direct dev"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_web_plugins:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ freezed:
+ dependency: "direct dev"
+ description:
+ name: freezed
+ sha256: "2edb9ef971d0f803860ecd9084afd48c717d002141ad77b69be3e976bee7190e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.4"
+ freezed_annotation:
+ dependency: "direct main"
+ description:
+ name: freezed_annotation
+ sha256: aeac15850ef1b38ee368d4c53ba9a847e900bb2c53a4db3f6881cbb3cb684338
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.0"
+ frontend_server_client:
+ dependency: transitive
+ description:
+ name: frontend_server_client
+ sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.0"
+ fuchsia_remote_debug_protocol:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ glob:
+ dependency: transitive
+ description:
+ name: glob
+ sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.1"
+ go_router:
+ dependency: "direct main"
+ description:
+ name: go_router
+ sha256: b33a88c67816312597e5e0f5906c5139a0b9bd9bb137346e872c788da7af8ea0
+ url: "https://pub.dev"
+ source: hosted
+ version: "9.0.3"
+ graphs:
+ dependency: transitive
+ description:
+ name: graphs
+ sha256: "772db3d53d23361d4ffcf5a9bb091cf3ee9b22f2be52cd107cd7a2683a89ba0e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.0"
+ http:
+ dependency: transitive
+ description:
+ name: http
+ sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.13.6"
+ http_multi_server:
+ dependency: transitive
+ description:
+ name: http_multi_server
+ sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.1"
+ http_parser:
+ dependency: transitive
+ description:
+ name: http_parser
+ sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.2"
+ integration_test:
+ dependency: "direct dev"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ intl:
+ dependency: "direct main"
+ description:
+ name: intl
+ sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.18.0"
+ io:
+ dependency: transitive
+ description:
+ name: io
+ sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
+ js:
+ dependency: transitive
+ description:
+ name: js
+ sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.6.7"
+ json_annotation:
+ dependency: "direct main"
+ description:
+ name: json_annotation
+ sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.8.1"
+ json_serializable:
+ dependency: "direct dev"
+ description:
+ name: json_serializable
+ sha256: "43793352f90efa5d8b251893a63d767b2f7c833120e3cc02adad55eefec04dc7"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.6.2"
+ lints:
+ dependency: transitive
+ description:
+ name: lints
+ sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.0"
+ logging:
+ dependency: transitive
+ description:
+ name: logging
+ sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
+ matcher:
+ dependency: transitive
+ description:
+ name: matcher
+ sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.12.15"
+ material_color_utilities:
+ dependency: transitive
+ description:
+ name: material_color_utilities
+ sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.2.0"
+ meta:
+ dependency: transitive
+ description:
+ name: meta
+ sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.9.1"
+ mime:
+ dependency: transitive
+ description:
+ name: mime
+ sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
+ mockito:
+ dependency: "direct dev"
+ description:
+ name: mockito
+ sha256: dd61809f04da1838a680926de50a9e87385c1de91c6579629c3d1723946e8059
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.4.0"
+ package_config:
+ dependency: transitive
+ description:
+ name: package_config
+ sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.0"
+ package_info_plus:
+ dependency: "direct main"
+ description:
+ name: package_info_plus
+ sha256: d39e8fbff4c5aef4592737e25ad6ac500df006ce7a7a8e1f838ce1256e167542
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.0"
+ package_info_plus_platform_interface:
+ dependency: transitive
+ description:
+ name: package_info_plus_platform_interface
+ sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.1"
+ path:
+ dependency: transitive
+ description:
+ name: path
+ sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.8.3"
+ path_parsing:
+ dependency: transitive
+ description:
+ name: path_parsing
+ sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
+ permission_handler:
+ dependency: "direct main"
+ description:
+ name: permission_handler
+ sha256: "63e5216aae014a72fe9579ccd027323395ce7a98271d9defa9d57320d001af81"
+ url: "https://pub.dev"
+ source: hosted
+ version: "10.4.3"
+ permission_handler_android:
+ dependency: transitive
+ description:
+ name: permission_handler_android
+ sha256: "2ffaf52a21f64ac9b35fe7369bb9533edbd4f698e5604db8645b1064ff4cf221"
+ url: "https://pub.dev"
+ source: hosted
+ version: "10.3.3"
+ permission_handler_apple:
+ dependency: transitive
+ description:
+ name: permission_handler_apple
+ sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
+ url: "https://pub.dev"
+ source: hosted
+ version: "9.1.4"
+ permission_handler_platform_interface:
+ dependency: transitive
+ description:
+ name: permission_handler_platform_interface
+ sha256: "7c6b1500385dd1d2ca61bb89e2488ca178e274a69144d26bbd65e33eae7c02a9"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.11.3"
+ permission_handler_windows:
+ dependency: transitive
+ description:
+ name: permission_handler_windows
+ sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.3"
+ petitparser:
+ dependency: transitive
+ description:
+ name: petitparser
+ sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.4.0"
+ platform:
+ dependency: transitive
+ description:
+ name: platform
+ sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.0"
+ plugin_platform_interface:
+ dependency: transitive
+ description:
+ name: plugin_platform_interface
+ sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ pool:
+ dependency: transitive
+ description:
+ name: pool
+ sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.5.1"
+ process:
+ dependency: transitive
+ description:
+ name: process
+ sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.2.4"
+ pub_semver:
+ dependency: transitive
+ description:
+ name: pub_semver
+ sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ pubspec_parse:
+ dependency: transitive
+ description:
+ name: pubspec_parse
+ sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.3"
+ retrofit:
+ dependency: "direct main"
+ description:
+ name: retrofit
+ sha256: "5eedbd8f73697f190dabc88520e0bcf2d3b2d9b9ad5c837f1dbb3ee6172d7709"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.1"
+ retrofit_generator:
+ dependency: "direct dev"
+ description:
+ name: retrofit_generator
+ sha256: "6dde5588800930fe6863df24022a88df8cb971f93cf5413adb2e5a05f4df4a9d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "7.0.0"
+ shelf:
+ dependency: transitive
+ description:
+ name: shelf
+ sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.1"
+ shelf_web_socket:
+ dependency: transitive
+ description:
+ name: shelf_web_socket
+ sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
+ sky_engine:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.99"
+ source_gen:
+ dependency: transitive
+ description:
+ name: source_gen
+ sha256: "373f96cf5a8744bc9816c1ff41cf5391bbdbe3d7a96fe98c622b6738a8a7bd33"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.2"
+ source_helper:
+ dependency: transitive
+ description:
+ name: source_helper
+ sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.3"
+ source_span:
+ dependency: transitive
+ description:
+ name: source_span
+ sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.9.1"
+ stack_trace:
+ dependency: transitive
+ description:
+ name: stack_trace
+ sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.11.0"
+ stream_channel:
+ dependency: transitive
+ description:
+ name: stream_channel
+ sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.1"
+ stream_transform:
+ dependency: transitive
+ description:
+ name: stream_transform
+ sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.0"
+ string_scanner:
+ dependency: transitive
+ description:
+ name: string_scanner
+ sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.0"
+ sync_http:
+ dependency: transitive
+ description:
+ name: sync_http
+ sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.1"
+ term_glyph:
+ dependency: transitive
+ description:
+ name: term_glyph
+ sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
+ test_api:
+ dependency: transitive
+ description:
+ name: test_api
+ sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.5.1"
+ time:
+ dependency: transitive
+ description:
+ name: time
+ sha256: "83427e11d9072e038364a5e4da559e85869b227cf699a541be0da74f14140124"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.3"
+ timing:
+ dependency: transitive
+ description:
+ name: timing
+ sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
+ tuple:
+ dependency: transitive
+ description:
+ name: tuple
+ sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.1"
+ typed_data:
+ dependency: transitive
+ description:
+ name: typed_data
+ sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.2"
+ vector_graphics:
+ dependency: transitive
+ description:
+ name: vector_graphics
+ sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.7"
+ vector_graphics_codec:
+ dependency: transitive
+ description:
+ name: vector_graphics_codec
+ sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.7"
+ vector_graphics_compiler:
+ dependency: transitive
+ description:
+ name: vector_graphics_compiler
+ sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.7"
+ vector_math:
+ dependency: transitive
+ description:
+ name: vector_math
+ sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ vm_service:
+ dependency: transitive
+ description:
+ name: vm_service
+ sha256: f6deed8ed625c52864792459709183da231ebf66ff0cf09e69b573227c377efe
+ url: "https://pub.dev"
+ source: hosted
+ version: "11.3.0"
+ watcher:
+ dependency: transitive
+ description:
+ name: watcher
+ sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
+ web_socket_channel:
+ dependency: transitive
+ description:
+ name: web_socket_channel
+ sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ webdriver:
+ dependency: transitive
+ description:
+ name: webdriver
+ sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.2"
+ win32:
+ dependency: transitive
+ description:
+ name: win32
+ sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.1.4"
+ xml:
+ dependency: transitive
+ description:
+ name: xml
+ sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.3.0"
+ yaml:
+ dependency: transitive
+ description:
+ name: yaml
+ sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.2"
+sdks:
+ dart: ">=3.0.0 <4.0.0"
+ flutter: ">=3.7.0-0"
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..78ced7d
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,96 @@
+name: survey_flutter
+description: A new Flutter project.
+# The following line prevents the package from being accidentally published to
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+
+# The following defines the version and build number for your application.
+# A version number is three numbers separated by dots, like 1.2.43
+# followed by an optional build number separated by a +.
+# Both the version and the builder number may be overridden in flutter
+# build by specifying --build-name and --build-number, respectively.
+# In Android, build-name is used as versionName while build-number used as versionCode.
+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
+# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
+# Read more about iOS versioning at
+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+# In Windows, build-name is used as the major, minor, and patch parts
+# of the product and file versions while build-number is used as the build suffix.
+version: 0.1.0+1
+
+environment:
+ sdk: '>=3.0.0 <4.0.0'
+
+# Dependencies specify other packages that your package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
+dependencies:
+ dio: ^5.1.2
+ flutter:
+ sdk: flutter
+ flutter_config: ^2.0.2
+ flutter_localizations:
+ sdk: flutter
+ flutter_svg: ^2.0.7
+ freezed_annotation: ^2.2.0
+ go_router: ^9.0.3
+ intl: ^0.18.0
+ json_annotation: ^4.8.1
+ package_info_plus: ^4.0.0
+ permission_handler: ^10.2.0
+ retrofit: ^4.0.1
+
+dev_dependencies:
+ build_runner: ^2.4.4
+ flutter_gen_runner: ^5.3.1
+ flutter_lints: ^2.0.1
+ flutter_test:
+ sdk: flutter
+ freezed: ^2.3.4
+ integration_test:
+ sdk: flutter
+ json_serializable: ^6.6.2
+ mockito: ^5.4.0
+ retrofit_generator: ^7.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+ generate: true
+
+ # The following line ensures that the Material Icons font is
+ # included with your application, so that you can use the icons in
+ # the material Icons class.
+ uses-material-design: true
+
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/assets-and-images/#resolution-aware
+ #
+ # For details regarding adding assets from package dependencies, see
+ # https://flutter.dev/assets-and-images/#from-packages
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.dev/custom-fonts/#from-packages
+ assets:
+ - assets/
+ - assets/svg/
+ - assets/images/
+ - assets/fonts/
+
+ fonts:
+ - family: neuzeit
+ fonts:
+ - asset: assets/fonts/neuzeit.otf
+
+flutter_gen:
+ integrations:
+ flutter_svg: true
+
+ colors:
+ inputs:
+ - assets/colors/colors.xml
diff --git a/test/api/repository/credential_repository_test.dart b/test/api/repository/credential_repository_test.dart
new file mode 100644
index 0000000..38a97ee
--- /dev/null
+++ b/test/api/repository/credential_repository_test.dart
@@ -0,0 +1,40 @@
+import 'package:survey_flutter/api/exception/network_exceptions.dart';
+import 'package:survey_flutter/api/repository/credential_repository.dart';
+import 'package:survey_flutter/model/response/user_response.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/mockito.dart';
+
+import '../../mocks/generate_mocks.mocks.dart';
+
+void main() {
+ group('CredentialRepository', () {
+ MockApiService mockApiService = MockApiService();
+ late CredentialRepository repository;
+
+ setUp(() {
+ repository = CredentialRepositoryImpl(mockApiService);
+ });
+ test(
+ "When getting user list successfully, it emits corresponding user list",
+ () async {
+ when(mockApiService.getUsers()).thenAnswer((_) async => [
+ UserResponse('test@email.com', 'test_user'),
+ ]);
+
+ final result = await repository.getUsers();
+ expect(result.length, 1);
+ expect(result[0].email, 'test@email.com');
+ expect(result[0].username, 'test_user');
+ });
+
+ test("When getting user list failed, it returns NetworkExceptions error",
+ () async {
+ when(mockApiService.getUsers()).thenThrow(MockDioError());
+
+ expect(
+ () => repository.getUsers(),
+ throwsA(isA()),
+ );
+ });
+ });
+}
diff --git a/test/mocks/generate_mocks.dart b/test/mocks/generate_mocks.dart
new file mode 100644
index 0000000..39497e6
--- /dev/null
+++ b/test/mocks/generate_mocks.dart
@@ -0,0 +1,11 @@
+import 'package:dio/dio.dart';
+import 'package:survey_flutter/api/api_service.dart';
+import 'package:mockito/annotations.dart';
+
+@GenerateMocks([
+ ApiService,
+ DioError,
+])
+main() {
+ // empty class to generate mock repository classes
+}
diff --git a/test_driver/integration_test.dart b/test_driver/integration_test.dart
new file mode 100644
index 0000000..b38629c
--- /dev/null
+++ b/test_driver/integration_test.dart
@@ -0,0 +1,3 @@
+import 'package:integration_test/integration_test_driver.dart';
+
+Future main() => integrationDriver();