diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..11ad474
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,23 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Run on dev",
+ "request": "launch",
+ "type": "dart",
+ "args": [
+ "--flavor",
+ "dev"
+ ]
+ },
+ {
+ "name": "Run on prod",
+ "request": "launch",
+ "type": "dart",
+ "args": [
+ "--flavor",
+ "prod"
+ ]
+ }
+ ]
+}
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..0d29021
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,28 @@
+# 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.dev/lints.
+ #
+ # 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
diff --git a/android/.gitignore b/android/.gitignore
new file mode 100644
index 0000000..6f56801
--- /dev/null
+++ b/android/.gitignore
@@ -0,0 +1,13 @@
+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
+**/*.keystore
+**/*.jks
diff --git a/android/app/build.gradle b/android/app/build.gradle
new file mode 100644
index 0000000..00a2aad
--- /dev/null
+++ b/android/app/build.gradle
@@ -0,0 +1,84 @@
+plugins {
+ id "com.android.application"
+ id "kotlin-android"
+ id "dev.flutter.flutter-gradle-plugin"
+}
+
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader('UTF-8') { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+ flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+ flutterVersionName = '1.0'
+}
+
+android {
+ namespace "com.example.flutter_ci_cd"
+ 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 {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId "com.example.flutter_ci_cd"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
+ minSdkVersion flutter.minSdkVersion
+ targetSdkVersion flutter.targetSdkVersion
+ versionCode flutterVersionCode.toInteger()
+ versionName flutterVersionName
+ }
+
+ 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 "app"
+
+ productFlavors {
+ dev {
+ dimension "app"
+ resValue "string", "app_name", "[Dev] Boilerplate"
+ versionNameSuffix "-dev"
+ applicationId "com.flutter.boilerplate.dev"
+ }
+ prod {
+ dimension "app"
+ resValue "string", "app_name", "Boilerplate"
+ versionNameSuffix "-pro"
+ applicationId "com.flutter.boilerplate"
+ }
+ }
+}
+
+flutter {
+ source '../..'
+}
+
+dependencies {}
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/com/flutter/boilerplate/flutter_boilerplate/MainActivity.kt b/android/app/src/main/kotlin/com/flutter/boilerplate/flutter_boilerplate/MainActivity.kt
new file mode 100644
index 0000000..a0196e9
--- /dev/null
+++ b/android/app/src/main/kotlin/com/flutter/boilerplate/flutter_boilerplate/MainActivity.kt
@@ -0,0 +1,6 @@
+package com.example.flutter_ci_cd
+
+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/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/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..55c4ca8
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1,20 @@
+pluginManagement {
+ def flutterSdkPath = {
+ def properties = new Properties()
+ file("local.properties").withInputStream { properties.load(it) }
+ def flutterSdkPath = properties.getProperty("flutter.sdk")
+ assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+ return flutterSdkPath
+ }
+ settings.ext.flutterSdkPath = flutterSdkPath()
+
+ includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
+
+ plugins {
+ id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
+ }
+}
+
+include ":app"
+
+apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle"
diff --git a/assets/color/colors.xml b/assets/color/colors.xml
new file mode 100644
index 0000000..bd03aba
--- /dev/null
+++ b/assets/color/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #F5CB84
+ #955E1C
+ #DF9527
+
diff --git a/assets/fonts/Exo2-VariableFont.ttf b/assets/fonts/Exo2-VariableFont.ttf
new file mode 100644
index 0000000..b97509d
Binary files /dev/null and b/assets/fonts/Exo2-VariableFont.ttf differ
diff --git a/assets/images/ic_launcher_dev.png b/assets/images/ic_launcher_dev.png
new file mode 100644
index 0000000..8cd44fa
Binary files /dev/null and b/assets/images/ic_launcher_dev.png differ
diff --git a/assets/images/ic_launcher_pro.png b/assets/images/ic_launcher_pro.png
new file mode 100644
index 0000000..52598e9
Binary files /dev/null and b/assets/images/ic_launcher_pro.png differ
diff --git a/assets/images/img_flutter_logo.png b/assets/images/img_flutter_logo.png
new file mode 100644
index 0000000..cfc0ee4
Binary files /dev/null and b/assets/images/img_flutter_logo.png differ
diff --git a/integration_test/features/main_home/main_home_page_test.dart b/integration_test/features/main_home/main_home_page_test.dart
new file mode 100644
index 0000000..ae67081
--- /dev/null
+++ b/integration_test/features/main_home/main_home_page_test.dart
@@ -0,0 +1,24 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_ci_cd/main.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ group(
+ 'MainHomePage test',
+ () {
+ testWidgets(
+ 'Bottom navigation bar test',
+ (widgetTester) async {
+ await widgetTester.pumpWidget(const MyApp());
+ final bottomNav = find.byType(BottomNavigationBar);
+ expect(bottomNav, findsOneWidget);
+
+ final homeTab = find.byIcon(Icons.home);
+ final personTab = find.byIcon(Icons.person);
+ expect(homeTab, findsOneWidget);
+ expect(personTab, findsOneWidget);
+ },
+ );
+ },
+ );
+}
diff --git a/integration_test/features/movie/movie_page_test.dart b/integration_test/features/movie/movie_page_test.dart
new file mode 100644
index 0000000..d6344f0
--- /dev/null
+++ b/integration_test/features/movie/movie_page_test.dart
@@ -0,0 +1,42 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_ci_cd/main.dart';
+import 'package:flutter_ci_cd/src/presentation/features/movie/view/pages/movie_detail_page.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ group('MoviePage test', () {
+ testWidgets('Test listview', (widgetTester) async {
+ await widgetTester.pumpWidget(const MyApp());
+ // Verify Loading indicator is present
+ final loadingProgress = find.byType(CircularProgressIndicator);
+ expect(loadingProgress, findsOneWidget);
+ await widgetTester.pumpAndSettle();
+ // Verify Loading indicator is disable
+ expect(loadingProgress, findsNothing);
+ // Verify list of movie is present.
+ final movieListView = find.byType(ListView);
+ expect(movieListView, findsOneWidget);
+
+ await widgetTester.dragUntilVisible(
+ find.text('12 Angry Men'), // what you want to find
+ find.byType(ListView), // widget you want to scroll
+ const Offset(-250, 0), // delta to move
+ );
+
+ // Verify first item of list of movie.
+ final firstMovieItem = find.text('The Shawshank Redemption');
+ expect(firstMovieItem, findsOneWidget);
+
+ final detailMoviePage = find.byType(MovieDetailPage);
+
+ expect(detailMoviePage, findsNothing);
+
+ // Click on item.
+ await widgetTester.tap(firstMovieItem);
+ await widgetTester.pumpAndSettle();
+
+ // Verify detail movie opened or not when click on item.
+ expect(detailMoviePage, findsOneWidget);
+ });
+ });
+}
diff --git a/ios/.gitignore b/ios/.gitignore
new file mode 100644
index 0000000..7a7f987
--- /dev/null
+++ b/ios/.gitignore
@@ -0,0 +1,34 @@
+**/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
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+
+# 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..ec97fc6
--- /dev/null
+++ b/ios/Flutter/Debug.xcconfig
@@ -0,0 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include "Generated.xcconfig"
diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000..c4855bf
--- /dev/null
+++ b/ios/Flutter/Release.xcconfig
@@ -0,0 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include "Generated.xcconfig"
diff --git a/ios/Podfile b/ios/Podfile
new file mode 100644
index 0000000..fdcc671
--- /dev/null
+++ b/ios/Podfile
@@ -0,0 +1,44 @@
+# 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__))
+ target 'RunnerTests' do
+ inherit! :search_paths
+ end
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+ end
+end
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..8917d90
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,1191 @@
+// !$*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 */; };
+/* 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 */
+ 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 = ""; };
+ 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 = ""; };
+ 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 = ""; };
+ 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 = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 97C146EB1CF9000F007C117D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 331C8082294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXGroup;
+ children = (
+ 331C807B294A618700263BE5 /* RunnerTests.swift */,
+ );
+ path = RunnerTests;
+ 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 */,
+ );
+ 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 = (
+ 9740EEB61CF901F6004384FC /* Run Script */,
+ 97C146EA1CF9000F007C117D /* Sources */,
+ 97C146EB1CF9000F007C117D /* Frameworks */,
+ 97C146EC1CF9000F007C117D /* Resources */,
+ 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ );
+ 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 = {
+ BuildIndependentTargetsInParallel = YES;
+ LastUpgradeCheck = 1430;
+ 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";
+ };
+ 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";
+ };
+/* 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-pro */ = {
+ 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-pro";
+ };
+ 249021D4217E4FDB00AE95B9 /* Profile-pro */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "[profile][pro] Boilerplate";
+ APP_DISPLAY_NAME_SHORT = boilerplate_profile_pro;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 3T7RS559P4;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_ci_cd;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Profile-pro";
+ };
+ 331C8088294A63A400263BE5 /* Debug-pro */ = {
+ 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 = com.flutter.boilerplate.flutterBoilerplate.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 = "Debug-pro";
+ };
+ 331C8089294A63A400263BE5 /* Release-pro */ = {
+ 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 = com.flutter.boilerplate.flutterBoilerplate.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = "Release-pro";
+ };
+ 331C808A294A63A400263BE5 /* Profile-pro */ = {
+ 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 = com.flutter.boilerplate.flutterBoilerplate.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = "Profile-pro";
+ };
+ 97C147031CF9000F007C117D /* Debug-pro */ = {
+ 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 = "Debug-pro";
+ };
+ 97C147041CF9000F007C117D /* Release-pro */ = {
+ 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 = "Release-pro";
+ };
+ 97C147061CF9000F007C117D /* Debug-pro */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "[debug][pro] Boilerplate";
+ APP_DISPLAY_NAME_SHORT = boilerplate_debug_pro;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 3T7RS559P4;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_ci_cd;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Debug-pro";
+ };
+ 97C147071CF9000F007C117D /* Release-pro */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "[release][pro] Boilerplate";
+ APP_DISPLAY_NAME_SHORT = boilerplate_release_pro;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 3T7RS559P4;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_ci_cd;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Release-pro";
+ };
+ BFC25EE42B2819B800B301FE /* Debug-stg */ = {
+ 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 = "Debug-stg";
+ };
+ BFC25EE52B2819B800B301FE /* Debug-stg */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "[debug][stg] Boilerplate";
+ APP_DISPLAY_NAME_SHORT = boilerplate_debug_stg;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 3T7RS559P4;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_ci_cd.stg;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Debug-stg";
+ };
+ BFC25EE62B2819B800B301FE /* Debug-stg */ = {
+ 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 = com.flutter.boilerplate.flutterBoilerplate.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 = "Debug-stg";
+ };
+ BFC25EE72B2819C100B301FE /* Release-stg */ = {
+ 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 = "Release-stg";
+ };
+ BFC25EE82B2819C100B301FE /* Release-stg */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "[release][stg] Boilerplate";
+ APP_DISPLAY_NAME_SHORT = boilerplate_release_stg;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 3T7RS559P4;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_ci_cd.stg;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Release-stg";
+ };
+ BFC25EE92B2819C100B301FE /* Release-stg */ = {
+ 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 = com.flutter.boilerplate.flutterBoilerplate.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = "Release-stg";
+ };
+ BFC25EEA2B2819C800B301FE /* Profile-stg */ = {
+ 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-stg";
+ };
+ BFC25EEB2B2819C800B301FE /* Profile-stg */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "[profile][stg] Boilerplate";
+ APP_DISPLAY_NAME_SHORT = boilerplate_profile_stg;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 3T7RS559P4;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_ci_cd.stg;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Profile-stg";
+ };
+ BFC25EEC2B2819C800B301FE /* Profile-stg */ = {
+ 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 = com.flutter.boilerplate.flutterBoilerplate.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = "Profile-stg";
+ };
+ BFFC463A2B2817B700D46E90 /* Debug-dev */ = {
+ 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 = "Debug-dev";
+ };
+ BFFC463B2B2817B700D46E90 /* Debug-dev */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "[debug][dev] Boilerplate";
+ APP_DISPLAY_NAME_SHORT = boilerplate_debug_dev;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 3T7RS559P4;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_ci_cd.dev;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Debug-dev";
+ };
+ BFFC463C2B2817B700D46E90 /* Debug-dev */ = {
+ 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 = com.flutter.boilerplate.flutterBoilerplate.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 = "Debug-dev";
+ };
+ BFFC463D2B2817C400D46E90 /* Release-dev */ = {
+ 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 = "Release-dev";
+ };
+ BFFC463E2B2817C400D46E90 /* Release-dev */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "[release][dev] Boilerplate";
+ APP_DISPLAY_NAME_SHORT = boilerplate_release_dev;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 3T7RS559P4;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_ci_cd.dev;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Release-dev";
+ };
+ BFFC463F2B2817C400D46E90 /* Release-dev */ = {
+ 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 = com.flutter.boilerplate.flutterBoilerplate.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = "Release-dev";
+ };
+ BFFC46402B2817D000D46E90 /* Profile-dev */ = {
+ 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-dev";
+ };
+ BFFC46412B2817D000D46E90 /* Profile-dev */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ APP_DISPLAY_NAME = "[profile][dev] Boilerplate";
+ APP_DISPLAY_NAME_SHORT = boilerplate_profile_dev;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 3T7RS559P4;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.flutter_ci_cd.dev;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = "Profile-dev";
+ };
+ BFFC46422B2817D000D46E90 /* Profile-dev */ = {
+ 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 = com.flutter.boilerplate.flutterBoilerplate.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = "Profile-dev";
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 331C8088294A63A400263BE5 /* Debug-pro */,
+ BFC25EE62B2819B800B301FE /* Debug-stg */,
+ BFFC463C2B2817B700D46E90 /* Debug-dev */,
+ 331C8089294A63A400263BE5 /* Release-pro */,
+ BFC25EE92B2819C100B301FE /* Release-stg */,
+ BFFC463F2B2817C400D46E90 /* Release-dev */,
+ 331C808A294A63A400263BE5 /* Profile-pro */,
+ BFFC46422B2817D000D46E90 /* Profile-dev */,
+ BFC25EEC2B2819C800B301FE /* Profile-stg */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-pro";
+ };
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147031CF9000F007C117D /* Debug-pro */,
+ BFC25EE42B2819B800B301FE /* Debug-stg */,
+ BFFC463A2B2817B700D46E90 /* Debug-dev */,
+ 97C147041CF9000F007C117D /* Release-pro */,
+ BFC25EE72B2819C100B301FE /* Release-stg */,
+ BFFC463D2B2817C400D46E90 /* Release-dev */,
+ 249021D3217E4FDB00AE95B9 /* Profile-pro */,
+ BFFC46402B2817D000D46E90 /* Profile-dev */,
+ BFC25EEA2B2819C800B301FE /* Profile-stg */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-pro";
+ };
+ 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147061CF9000F007C117D /* Debug-pro */,
+ BFC25EE52B2819B800B301FE /* Debug-stg */,
+ BFFC463B2B2817B700D46E90 /* Debug-dev */,
+ 97C147071CF9000F007C117D /* Release-pro */,
+ BFC25EE82B2819C100B301FE /* Release-stg */,
+ BFFC463E2B2817C400D46E90 /* Release-dev */,
+ 249021D4217E4FDB00AE95B9 /* Profile-pro */,
+ BFFC46412B2817D000D46E90 /* Profile-dev */,
+ BFC25EEB2B2819C800B301FE /* Profile-stg */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = "Release-pro";
+ };
+/* 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/dev.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/dev.xcscheme
new file mode 100644
index 0000000..d765486
--- /dev/null
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/dev.xcscheme
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/pro.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/pro.xcscheme
new file mode 100644
index 0000000..87131a0
--- /dev/null
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/pro.xcscheme
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/stg.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/stg.xcscheme
new file mode 100644
index 0000000..a00195e
--- /dev/null
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/stg.xcscheme
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..1d526a1
--- /dev/null
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
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..8210f60
--- /dev/null
+++ b/ios/Runner/Info.plist
@@ -0,0 +1,49 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ $(APP_DISPLAY_NAME)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(APP_DISPLAY_NAME_SHORT)
+ 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
+
+ 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/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart
new file mode 100644
index 0000000..23875c6
--- /dev/null
+++ b/lib/gen/assets.gen.dart
@@ -0,0 +1,110 @@
+/// GENERATED CODE - DO NOT MODIFY BY HAND
+/// *****************************************************
+/// FlutterGen
+/// *****************************************************
+
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use
+
+import 'package:flutter/widgets.dart';
+
+class $AssetsImagesGen {
+ const $AssetsImagesGen();
+
+ /// File path: assets/images/ic_launcher_dev.png
+ AssetGenImage get icLauncherDev =>
+ const AssetGenImage('assets/images/ic_launcher_dev.png');
+
+ /// File path: assets/images/ic_launcher_pro.png
+ AssetGenImage get icLauncherPro =>
+ const AssetGenImage('assets/images/ic_launcher_pro.png');
+
+ /// File path: assets/images/img_flutter_logo.png
+ AssetGenImage get imgFlutterLogo =>
+ const AssetGenImage('assets/images/img_flutter_logo.png');
+
+ /// List of all assets
+ List get values =>
+ [icLauncherDev, icLauncherPro, imgFlutterLogo];
+}
+
+class Assets {
+ Assets._();
+
+ static const $AssetsImagesGen images = $AssetsImagesGen();
+}
+
+class AssetGenImage {
+ const AssetGenImage(this._assetName);
+
+ final String _assetName;
+
+ Image image({
+ Key? key,
+ AssetBundle? bundle,
+ ImageFrameBuilder? frameBuilder,
+ ImageErrorWidgetBuilder? errorBuilder,
+ String? semanticLabel,
+ bool excludeFromSemantics = false,
+ double? scale,
+ double? width,
+ double? height,
+ Color? color,
+ Animation? opacity,
+ BlendMode? colorBlendMode,
+ BoxFit? fit,
+ AlignmentGeometry alignment = Alignment.center,
+ ImageRepeat repeat = ImageRepeat.noRepeat,
+ Rect? centerSlice,
+ bool matchTextDirection = false,
+ bool gaplessPlayback = false,
+ bool isAntiAlias = false,
+ String? package,
+ FilterQuality filterQuality = FilterQuality.low,
+ int? cacheWidth,
+ int? cacheHeight,
+ }) {
+ return Image.asset(
+ _assetName,
+ key: key,
+ bundle: bundle,
+ frameBuilder: frameBuilder,
+ errorBuilder: errorBuilder,
+ semanticLabel: semanticLabel,
+ excludeFromSemantics: excludeFromSemantics,
+ scale: scale,
+ width: width,
+ height: height,
+ color: color,
+ opacity: opacity,
+ colorBlendMode: colorBlendMode,
+ fit: fit,
+ alignment: alignment,
+ repeat: repeat,
+ centerSlice: centerSlice,
+ matchTextDirection: matchTextDirection,
+ gaplessPlayback: gaplessPlayback,
+ isAntiAlias: isAntiAlias,
+ package: package,
+ filterQuality: filterQuality,
+ cacheWidth: cacheWidth,
+ cacheHeight: cacheHeight,
+ );
+ }
+
+ ImageProvider provider({
+ AssetBundle? bundle,
+ String? package,
+ }) {
+ return AssetImage(
+ _assetName,
+ bundle: bundle,
+ package: package,
+ );
+ }
+
+ String get path => _assetName;
+
+ String get keyName => _assetName;
+}
diff --git a/lib/gen/colors.gen.dart b/lib/gen/colors.gen.dart
new file mode 100644
index 0000000..31bb100
--- /dev/null
+++ b/lib/gen/colors.gen.dart
@@ -0,0 +1,87 @@
+/// GENERATED CODE - DO NOT MODIFY BY HAND
+/// *****************************************************
+/// FlutterGen
+/// *****************************************************
+
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use
+
+import 'package:flutter/painting.dart';
+import 'package:flutter/material.dart';
+
+class ColorName {
+ ColorName._();
+
+ /// MaterialColor:
+ /// 50: #FFF2ECE4
+ /// 100: #FFDFCFBB
+ /// 200: #FFCAAF8E
+ /// 300: #FFB58E60
+ /// 400: #FFA5763E
+ /// 500: #FF955E1C
+ /// 600: #FF8D5619
+ /// 700: #FF824C15
+ /// 800: #FF784211
+ /// 900: #FF673109
+ static const MaterialColor cinnamon = MaterialColor(
+ 0xFF955E1C,
+ {
+ 50: Color(0xFFF2ECE4),
+ 100: Color(0xFFDFCFBB),
+ 200: Color(0xFFCAAF8E),
+ 300: Color(0xFFB58E60),
+ 400: Color(0xFFA5763E),
+ 500: Color(0xFF955E1C),
+ 600: Color(0xFF8D5619),
+ 700: Color(0xFF824C15),
+ 800: Color(0xFF784211),
+ 900: Color(0xFF673109),
+ },
+ );
+
+ /// Color: #F5CB84
+ static const Color milkTea = Color(0xFFF5CB84);
+
+ /// MaterialColor:
+ /// 50: #FFFBF2E5
+ /// 100: #FFF5DFBE
+ /// 200: #FFEFCA93
+ /// 300: #FFE9B568
+ /// 400: #FFE4A547
+ /// 500: #FFDF9527
+ /// 600: #FFDB8D23
+ /// 700: #FFD7821D
+ /// 800: #FFD27817
+ /// 900: #FFCA670E
+ static const MaterialColor yellowOcher = MaterialColor(
+ 0xFFDF9527,
+ {
+ 50: Color(0xFFFBF2E5),
+ 100: Color(0xFFF5DFBE),
+ 200: Color(0xFFEFCA93),
+ 300: Color(0xFFE9B568),
+ 400: Color(0xFFE4A547),
+ 500: Color(0xFFDF9527),
+ 600: Color(0xFFDB8D23),
+ 700: Color(0xFFD7821D),
+ 800: Color(0xFFD27817),
+ 900: Color(0xFFCA670E),
+ },
+ );
+
+ /// MaterialAccentColor:
+ /// 100: #FFFFE8E0
+ /// 200: #FFFFBCA3
+ /// 400: #FFFFA989
+ /// 700: #FFFF9E7A
+ static const MaterialAccentColor yellowOcherAccent = MaterialAccentColor(
+ 0xFFFFBCA3,
+ {
+ 100: Color(0xFFFFE8E0),
+ 200: Color(0xFFFFBCA3),
+ 400: Color(0xFFFFA989),
+ 700: Color(0xFFFF9E7A),
+ },
+ );
+}
diff --git a/lib/gen/fonts.gen.dart b/lib/gen/fonts.gen.dart
new file mode 100644
index 0000000..64e5f6d
--- /dev/null
+++ b/lib/gen/fonts.gen.dart
@@ -0,0 +1,15 @@
+/// GENERATED CODE - DO NOT MODIFY BY HAND
+/// *****************************************************
+/// FlutterGen
+/// *****************************************************
+
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use
+
+class FontFamily {
+ FontFamily._();
+
+ /// Font family: Exo
+ static const String exo = 'Exo';
+}
diff --git a/lib/main.dart b/lib/main.dart
new file mode 100644
index 0000000..e9f6bc8
--- /dev/null
+++ b/lib/main.dart
@@ -0,0 +1,25 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import 'gen/fonts.gen.dart';
+import 'src/presentation/router/app_router.dart';
+
+void main() {
+ runApp(const MyApp());
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return ProviderScope(
+ child: MaterialApp.router(
+ theme: ThemeData(
+ fontFamily: FontFamily.exo,
+ ),
+ routerConfig: AppRouter.routerConfig,
+ ),
+ );
+ }
+}
diff --git a/lib/src/data/data_sources/core/add_header_interceptor.dart b/lib/src/data/data_sources/core/add_header_interceptor.dart
new file mode 100644
index 0000000..24ef718
--- /dev/null
+++ b/lib/src/data/data_sources/core/add_header_interceptor.dart
@@ -0,0 +1,12 @@
+import 'package:dio/dio.dart';
+
+class AddHeaderInterceptor extends Interceptor {
+ final _authorization =
+ 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyZDQxYjkzZWRhNzI4YTRjM2M0OTJiY2IxMTdlYzBlZCIsInN1YiI6IjYyYTE2MDlmYzhmODU4MDA2NTI1Yjc3YyIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.kiLuMKecuutU2BuSjk0z65Wfo9M5IcmiSPerOL-jgJg';
+
+ @override
+ void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
+ super.onRequest(options, handler);
+ options.headers = {'Authorization': _authorization};
+ }
+}
diff --git a/lib/src/data/data_sources/core/endpoint.dart b/lib/src/data/data_sources/core/endpoint.dart
new file mode 100644
index 0000000..41d9a3e
--- /dev/null
+++ b/lib/src/data/data_sources/core/endpoint.dart
@@ -0,0 +1,9 @@
+import 'package:flutter/services.dart';
+
+class Endpoint {
+ static const _rootUrl = appFlavor == 'dev'
+ ? 'https://api.themoviedb.org/3'
+ : 'https://api.themoviedb.org/3';
+
+ static const String getTopRatedMovies = '$_rootUrl/movie/top_rated';
+}
diff --git a/lib/src/data/data_sources/movie/movie_data_source_provider.dart b/lib/src/data/data_sources/movie/movie_data_source_provider.dart
new file mode 100644
index 0000000..7108360
--- /dev/null
+++ b/lib/src/data/data_sources/movie/movie_data_source_provider.dart
@@ -0,0 +1,11 @@
+import 'package:dio/dio.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import 'movie_remote_data_source_impl.dart';
+
+final movieRemoteDataSourceProvider = Provider(
+ (ref) {
+ final dio = Dio();
+ return MovieRemoteDataSourceImpl(dio);
+ },
+);
diff --git a/lib/src/data/data_sources/movie/movie_remote_data_source.dart b/lib/src/data/data_sources/movie/movie_remote_data_source.dart
new file mode 100644
index 0000000..96cd7eb
--- /dev/null
+++ b/lib/src/data/data_sources/movie/movie_remote_data_source.dart
@@ -0,0 +1,7 @@
+import 'package:fpdart/fpdart.dart';
+
+import '../../response/movie/movie_response.dart';
+
+abstract class MovieDataSource {
+ Future>> fetchMovies();
+}
diff --git a/lib/src/data/data_sources/movie/movie_remote_data_source_impl.dart b/lib/src/data/data_sources/movie/movie_remote_data_source_impl.dart
new file mode 100644
index 0000000..2bd3a66
--- /dev/null
+++ b/lib/src/data/data_sources/movie/movie_remote_data_source_impl.dart
@@ -0,0 +1,29 @@
+import 'package:dio/dio.dart';
+import 'package:flutter_ci_cd/src/data/data_sources/core/add_header_interceptor.dart';
+import 'package:flutter_ci_cd/src/data/data_sources/core/endpoint.dart';
+import 'package:fpdart/fpdart.dart';
+
+import '../../response/movie/movie_response.dart';
+import 'movie_remote_data_source.dart';
+
+class MovieRemoteDataSourceImpl implements MovieDataSource {
+ final Dio dio;
+
+ MovieRemoteDataSourceImpl(this.dio);
+
+ @override
+ Future>> fetchMovies() async {
+ const url = Endpoint.getTopRatedMovies;
+ try {
+ dio.interceptors.add(AddHeaderInterceptor());
+ final response = await dio.get(url);
+ final mapFromJson = response.data['results'] as List;
+ final result = mapFromJson.map((e) {
+ return MovieResponse.fromJson(e);
+ }).toList();
+ return Right(result);
+ } on Exception catch (e) {
+ return Left(e);
+ }
+ }
+}
diff --git a/lib/src/data/repositories/movie/movie_repository_impl.dart b/lib/src/data/repositories/movie/movie_repository_impl.dart
new file mode 100644
index 0000000..d2547ed
--- /dev/null
+++ b/lib/src/data/repositories/movie/movie_repository_impl.dart
@@ -0,0 +1,16 @@
+import 'package:flutter_ci_cd/src/domain/repositories/movie/movie_repository.dart';
+import 'package:fpdart/fpdart.dart';
+
+import '../../data_sources/movie/movie_remote_data_source.dart';
+import '../../response/movie/movie_response.dart';
+
+class MovieRepositoryImpl implements MovieRepository {
+ final MovieDataSource dataSource;
+
+ MovieRepositoryImpl(this.dataSource);
+
+ @override
+ Future>> fetchMovies() {
+ return dataSource.fetchMovies();
+ }
+}
diff --git a/lib/src/data/repositories/movie/movie_repository_provider.dart b/lib/src/data/repositories/movie/movie_repository_provider.dart
new file mode 100644
index 0000000..a82998f
--- /dev/null
+++ b/lib/src/data/repositories/movie/movie_repository_provider.dart
@@ -0,0 +1,11 @@
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import '../../data_sources/movie/movie_data_source_provider.dart';
+import 'movie_repository_impl.dart';
+
+final movieRepositoryProvider = Provider(
+ (ref) {
+ final dataSource = ref.read(movieRemoteDataSourceProvider);
+ return MovieRepositoryImpl(dataSource);
+ },
+);
diff --git a/lib/src/data/response/core/data_mapper.dart b/lib/src/data/response/core/data_mapper.dart
new file mode 100644
index 0000000..b80a0e2
--- /dev/null
+++ b/lib/src/data/response/core/data_mapper.dart
@@ -0,0 +1,3 @@
+abstract class DataMapper {
+ T mapToModel();
+}
diff --git a/lib/src/data/response/movie/movie_response.dart b/lib/src/data/response/movie/movie_response.dart
new file mode 100644
index 0000000..68dd569
--- /dev/null
+++ b/lib/src/data/response/movie/movie_response.dart
@@ -0,0 +1,63 @@
+import 'package:flutter_ci_cd/src/domain/model/movie/movie_model.dart';
+
+import '../core/data_mapper.dart';
+
+class MovieResponse implements DataMapper {
+ bool? adult;
+ String? backdropPath;
+ List? genreIds;
+ int? id;
+ String? originalLanguage;
+ String? originalTitle;
+ String? overview;
+ double? popularity;
+ String? posterPath;
+ String? releaseDate;
+ String? title;
+ bool? video;
+ double? voteAverage;
+ int? voteCount;
+
+ MovieResponse({
+ this.adult,
+ this.backdropPath,
+ this.genreIds,
+ this.id,
+ this.originalLanguage,
+ this.originalTitle,
+ this.overview,
+ this.popularity,
+ this.posterPath,
+ this.releaseDate,
+ this.title,
+ this.video,
+ this.voteAverage,
+ this.voteCount,
+ });
+
+ MovieResponse.fromJson(Map json) {
+ adult = json['adult'];
+ backdropPath = json['backdrop_path'];
+ genreIds = json['genre_ids'].cast();
+ id = json['id'];
+ originalLanguage = json['original_language'];
+ originalTitle = json['original_title'];
+ overview = json['overview'];
+ popularity = json['popularity'];
+ posterPath = json['poster_path'];
+ releaseDate = json['release_date'];
+ title = json['title'];
+ video = json['video'];
+ voteAverage = json['vote_average'];
+ voteCount = json['vote_count'];
+ }
+
+ @override
+ MovieModel mapToModel() {
+ return MovieModel(
+ originalTitle: originalTitle ?? '',
+ overview: overview ?? '',
+ posterPath: 'https://image.tmdb.org/t/p/w220_and_h330_face$posterPath',
+ );
+ }
+}
diff --git a/lib/src/domain/model/movie/movie_model.dart b/lib/src/domain/model/movie/movie_model.dart
new file mode 100644
index 0000000..6bd5a6e
--- /dev/null
+++ b/lib/src/domain/model/movie/movie_model.dart
@@ -0,0 +1,11 @@
+class MovieModel {
+ String originalTitle;
+ String overview;
+ String posterPath;
+
+ MovieModel({
+ this.originalTitle = '',
+ this.overview = '',
+ this.posterPath = '',
+ });
+}
diff --git a/lib/src/domain/processors/movie/movie_processor.dart b/lib/src/domain/processors/movie/movie_processor.dart
new file mode 100644
index 0000000..1c2cd44
--- /dev/null
+++ b/lib/src/domain/processors/movie/movie_processor.dart
@@ -0,0 +1,7 @@
+import 'package:fpdart/fpdart.dart';
+
+import '../../model/movie/movie_model.dart';
+
+abstract class MovieProcessor {
+ Future>> fetchMovie();
+}
diff --git a/lib/src/domain/processors/movie/movie_processor_impl.dart b/lib/src/domain/processors/movie/movie_processor_impl.dart
new file mode 100644
index 0000000..87eb4c0
--- /dev/null
+++ b/lib/src/domain/processors/movie/movie_processor_impl.dart
@@ -0,0 +1,23 @@
+import 'package:flutter_ci_cd/src/domain/model/movie/movie_model.dart';
+import 'package:flutter_ci_cd/src/domain/repositories/movie/movie_repository.dart';
+import 'package:fpdart/fpdart.dart';
+
+import 'movie_processor.dart';
+
+class MovieProcessorImpl extends MovieProcessor {
+ final MovieRepository repository;
+
+ MovieProcessorImpl(this.repository);
+
+ @override
+ Future>> fetchMovie() async {
+ final response = await repository.fetchMovies();
+ return response.fold((left) {
+ return Left(left);
+ }, (right) {
+ final movies = [];
+ right.map((e) => movies.add(e.mapToModel())).toList();
+ return Right(movies);
+ });
+ }
+}
diff --git a/lib/src/domain/processors/movie/movie_processor_provider.dart b/lib/src/domain/processors/movie/movie_processor_provider.dart
new file mode 100644
index 0000000..e1d2246
--- /dev/null
+++ b/lib/src/domain/processors/movie/movie_processor_provider.dart
@@ -0,0 +1,10 @@
+import 'package:flutter_ci_cd/src/data/repositories/movie/movie_repository_provider.dart';
+import 'package:flutter_ci_cd/src/domain/processors/movie/movie_processor_impl.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+final movieProcessorProvider = Provider(
+ (ref) {
+ final repository = ref.read(movieRepositoryProvider);
+ return MovieProcessorImpl(repository);
+ },
+);
diff --git a/lib/src/domain/repositories/movie/movie_repository.dart b/lib/src/domain/repositories/movie/movie_repository.dart
new file mode 100644
index 0000000..6087d07
--- /dev/null
+++ b/lib/src/domain/repositories/movie/movie_repository.dart
@@ -0,0 +1,6 @@
+import 'package:flutter_ci_cd/src/data/response/movie/movie_response.dart';
+import 'package:fpdart/fpdart.dart';
+
+abstract class MovieRepository {
+ Future>> fetchMovies();
+}
diff --git a/lib/src/presentation/constants/app_strings.dart b/lib/src/presentation/constants/app_strings.dart
new file mode 100644
index 0000000..526c6a8
--- /dev/null
+++ b/lib/src/presentation/constants/app_strings.dart
@@ -0,0 +1,3 @@
+class AppStrings {
+ static const String kExample = 'Example boilerplate ';
+}
diff --git a/lib/src/presentation/constants/app_text_styles.dart b/lib/src/presentation/constants/app_text_styles.dart
new file mode 100644
index 0000000..dd8087e
--- /dev/null
+++ b/lib/src/presentation/constants/app_text_styles.dart
@@ -0,0 +1,16 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_ci_cd/gen/colors.gen.dart';
+
+class AppTextStyles {
+ static const sBlackSemiNormal = TextStyle(
+ color: Colors.black54,
+ fontWeight: FontWeight.w600,
+ fontSize: 14.0,
+ );
+
+ static const sMilkTeaSemiBig = TextStyle(
+ color: ColorName.milkTea,
+ fontWeight: FontWeight.w600,
+ fontSize: 20.0,
+ );
+}
diff --git a/lib/src/presentation/features/main_home/view/pages/main_home_page.dart b/lib/src/presentation/features/main_home/view/pages/main_home_page.dart
new file mode 100644
index 0000000..3f0940f
--- /dev/null
+++ b/lib/src/presentation/features/main_home/view/pages/main_home_page.dart
@@ -0,0 +1,51 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_ci_cd/src/presentation/router/app_router.dart';
+import 'package:go_router/go_router.dart';
+
+enum MainHomeType {
+ home,
+ profile,
+}
+
+class MainHomePage extends StatefulWidget {
+ const MainHomePage({
+ Key? key,
+ required this.child,
+ }) : super(key: key);
+ final Widget child;
+
+ @override
+ State createState() => _MainHomePageState();
+}
+
+class _MainHomePageState extends State {
+ final current = ValueNotifier(0);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ bottomNavigationBar: ListenableBuilder(
+ listenable: current,
+ builder: (context, child) {
+ return BottomNavigationBar(
+ items: const [
+ BottomNavigationBarItem(label: '', icon: Icon(Icons.home)),
+ BottomNavigationBarItem(label: '', icon: Icon(Icons.person)),
+ ],
+ onTap: (int index) {
+ if(index == 1){
+ context.push(AppRouter.profileChildTemp);
+ }else{
+ context.push(AppRouter.movie);
+ }
+ current.value = index;
+ },
+ selectedItemColor: Colors.red,
+ currentIndex: current.value,
+ );
+ }
+ ),
+ body: widget.child,
+ );
+ }
+}
diff --git a/lib/src/presentation/features/movie/controller/movie_controller.dart b/lib/src/presentation/features/movie/controller/movie_controller.dart
new file mode 100644
index 0000000..b8c748b
--- /dev/null
+++ b/lib/src/presentation/features/movie/controller/movie_controller.dart
@@ -0,0 +1,21 @@
+import 'dart:async';
+
+import 'package:flutter_ci_cd/src/domain/model/movie/movie_model.dart';
+import 'package:flutter_ci_cd/src/domain/processors/movie/movie_processor_provider.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+
+class MovieController extends AsyncNotifier> {
+ @override
+ Future> build() async {
+ final processor = ref.read(movieProcessorProvider);
+ final response = await processor.fetchMovie();
+ List result = [];
+ response.fold((l) {
+ // TODO: Handle exception.
+ }, (r) {
+ result.addAll(r);
+ });
+ return result;
+ }
+}
diff --git a/lib/src/presentation/features/movie/controller/movie_provider.dart b/lib/src/presentation/features/movie/controller/movie_provider.dart
new file mode 100644
index 0000000..4d3187b
--- /dev/null
+++ b/lib/src/presentation/features/movie/controller/movie_provider.dart
@@ -0,0 +1,11 @@
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import '../../../../domain/model/movie/movie_model.dart';
+import 'movie_controller.dart';
+
+final movieControllerProvider =
+ AsyncNotifierProvider>(
+ () {
+ return MovieController();
+ },
+);
diff --git a/lib/src/presentation/features/movie/view/pages/movie_detail_page.dart b/lib/src/presentation/features/movie/view/pages/movie_detail_page.dart
new file mode 100644
index 0000000..b8218dc
--- /dev/null
+++ b/lib/src/presentation/features/movie/view/pages/movie_detail_page.dart
@@ -0,0 +1,23 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_ci_cd/src/presentation/constants/app_text_styles.dart';
+
+class MovieDetailPage extends StatelessWidget {
+ const MovieDetailPage({
+ super.key,
+ required this.text,
+ });
+
+ final String text;
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Center(
+ child: Text(
+ text,
+ style: AppTextStyles.sBlackSemiNormal,
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/src/presentation/features/movie/view/pages/movie_page.dart b/lib/src/presentation/features/movie/view/pages/movie_page.dart
new file mode 100644
index 0000000..657281d
--- /dev/null
+++ b/lib/src/presentation/features/movie/view/pages/movie_page.dart
@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import '../../controller/movie_provider.dart';
+import '../widgets/movie_item.dart';
+
+class MoviePage extends ConsumerWidget {
+ const MoviePage({super.key});
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final state = ref.watch(movieControllerProvider);
+ return Scaffold(
+ body: state.when(
+ data: (data) => ListView.builder(
+ itemBuilder: (context, position) {
+ return MovieItem(movie: data[position]);
+ },
+ itemCount: data.length,
+ ),
+ error: (error, trace) => const SizedBox(),
+ loading: () => const Center(
+ child: CircularProgressIndicator(),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/src/presentation/features/movie/view/widgets/movie_item.dart b/lib/src/presentation/features/movie/view/widgets/movie_item.dart
new file mode 100644
index 0000000..2b46629
--- /dev/null
+++ b/lib/src/presentation/features/movie/view/widgets/movie_item.dart
@@ -0,0 +1,41 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_ci_cd/src/domain/model/movie/movie_model.dart';
+import 'package:flutter_ci_cd/src/presentation/constants/app_text_styles.dart';
+import 'package:go_router/go_router.dart';
+
+import '../../../../router/app_router.dart';
+
+class MovieItem extends StatelessWidget {
+ const MovieItem({
+ super.key,
+ required this.movie,
+ });
+
+ final MovieModel movie;
+
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTap: () {
+ context.push(AppRouter.movieDetail, extra: movie.overview);
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Image.network(movie.posterPath, fit: BoxFit.contain),
+ const SizedBox(height: 8.0),
+ Text(
+ movie.originalTitle,
+ style: AppTextStyles.sMilkTeaSemiBig,
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(height: 8.0),
+ Container(
+ color: Colors.black26,
+ height: 16.0,
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/src/presentation/router/app_router.dart b/lib/src/presentation/router/app_router.dart
new file mode 100644
index 0000000..f2b6c7c
--- /dev/null
+++ b/lib/src/presentation/router/app_router.dart
@@ -0,0 +1,54 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_ci_cd/src/presentation/features/main_home/view/pages/main_home_page.dart';
+import 'package:flutter_ci_cd/src/presentation/features/movie/view/pages/movie_detail_page.dart';
+import 'package:flutter_ci_cd/src/presentation/features/movie/view/pages/movie_page.dart';
+import 'package:go_router/go_router.dart';
+
+class AppRouter {
+ static const String details = 'details';
+ static const String movie = '/movie';
+ static const String movieDetail = '/movie/details';
+ static const String profileChildTemp = '/profile_child_temp';
+
+ static final _rootNavigatorKey = GlobalKey();
+ static final _shellNavigatorKey = GlobalKey();
+
+ static final routerConfig = GoRouter(
+ navigatorKey: _rootNavigatorKey,
+ initialLocation: movie,
+ routes: [
+ ShellRoute(
+ navigatorKey: _shellNavigatorKey,
+ builder: (context, state, child) {
+ return MainHomePage(child: child);
+ },
+ routes: [
+ GoRoute(
+ parentNavigatorKey: _shellNavigatorKey,
+ path: movie,
+ builder: (context, state) {
+ return const MoviePage();
+ },
+ routes: [
+ GoRoute(
+ path: details,
+ builder: (context, state) {
+ return MovieDetailPage(text: state.extra as String);
+ },
+ ),
+ ],
+ ),
+ GoRoute(
+ path: profileChildTemp,
+ builder: (context, state) {
+ return const Center(
+ child: Text('Profile child temp', key: Key('MyTextKey'),),
+ );
+ },
+ parentNavigatorKey: _shellNavigatorKey,
+ ),
+ ],
+ ),
+ ],
+ );
+}
diff --git a/lib/src/presentation/utils/value_notifier_extension.dart b/lib/src/presentation/utils/value_notifier_extension.dart
new file mode 100644
index 0000000..00ba389
--- /dev/null
+++ b/lib/src/presentation/utils/value_notifier_extension.dart
@@ -0,0 +1,15 @@
+import 'package:flutter/widgets.dart';
+
+extension ValueNotifierT on T {
+ ValueNotifier get obs => ValueNotifier(this);
+}
+
+extension ValueNotifierList on ValueNotifier> {
+ void addAll(List values) {
+ value = [...value, ...values];
+ }
+
+ void add(T newValue) {
+ value = [...value, newValue];
+ }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..fc8b08b
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,129 @@
+name: flutter_ci_cd
+description: A flutter boilerplate based on [Clean architecture]
+# 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: 1.0.0+1
+
+environment:
+ sdk: '>=3.1.5 <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:
+ flutter:
+ sdk: flutter
+
+
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ cupertino_icons: ^1.0.2
+
+ # Network, APIs...
+ dio: ^5.4.0
+
+ # Routing
+ go_router: ^13.0.0
+
+ # Data, object
+ fpdart: ^1.1.0
+
+ #Utils
+ logger: ^2.0.2+1
+
+ # Mocking data to writing test case
+ mockito: ^5.4.4
+
+ # State management
+ flutter_riverpod: ^2.4.9
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+ integration_test:
+ sdk: flutter
+
+ # Generate assets
+ flutter_gen_runner: ^5.3.2
+
+ # Generate code tool
+ build_runner: ^2.4.7
+
+ # Riverpod linter rules.
+ riverpod_lint: ^2.3.7
+
+
+ # The "flutter_lints" package below contains a set of recommended lints to
+ # encourage good coding practices. The lint set provided by the package is
+ # activated in the `analysis_options.yaml` file located at the root of your
+ # package. See that file for information about deactivating specific lint
+ # rules and activating additional ones.
+ flutter_lints: ^2.0.0
+
+
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+flutter_gen:
+ colors:
+ inputs:
+ - assets/color/colors.xml
+
+# The following section is specific to Flutter packages.
+flutter:
+
+ # 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
+
+ fonts:
+ - family: Exo
+ fonts:
+ - asset: assets/fonts/Exo2-VariableFont.ttf
+
+ assets:
+ - assets/images/
+
+ # To add assets to your application, add an assets section, like this:
+ # assets:
+ # - images/a_dot_burr.jpeg
+ # - images/a_dot_ham.jpeg
+
+ # 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
+
+ # To add custom fonts to your application, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.dev/custom-fonts/#from-packages
diff --git a/test/data/data_json_mock/movie_mock.dart b/test/data/data_json_mock/movie_mock.dart
new file mode 100644
index 0000000..b6fa875
--- /dev/null
+++ b/test/data/data_json_mock/movie_mock.dart
@@ -0,0 +1,21 @@
+final listOfMovieMock = {
+ 'results': [
+ {
+ "adult": false,
+ "backdrop_path": "/rSPw7tgCH9c6NqICZef4kZjFOQ5.jpg",
+ "genre_ids": [18, 80],
+ "id": 238,
+ "original_language": "en",
+ "original_title": "The Godfather",
+ "overview":
+ "Spanning the years 1945 to 1955, a chronicle of the fictional Italian-American Corleone crime family. When organized crime family patriarch, Vito Corleone barely survives an attempt on his life, his youngest son, Michael steps in to take care of the would-be killers, launching a campaign of bloody revenge.",
+ "popularity": 160.502,
+ "poster_path": "/3bhkrj58Vtu7enYsRolD1fZdja1.jpg",
+ "release_date": "1972-03-14",
+ "title": "The Godfather",
+ "video": false,
+ "vote_average": 8.7,
+ "vote_count": 19182
+ }
+ ]
+};
\ No newline at end of file
diff --git a/test/data/data_sources/movie/movie_remote_data_source_test.dart b/test/data/data_sources/movie/movie_remote_data_source_test.dart
new file mode 100644
index 0000000..a5840d2
--- /dev/null
+++ b/test/data/data_sources/movie/movie_remote_data_source_test.dart
@@ -0,0 +1,41 @@
+import 'package:dio/dio.dart';
+import 'package:flutter_ci_cd/src/data/data_sources/movie/movie_remote_data_source_impl.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:fpdart/fpdart.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+
+import '../../data_json_mock/movie_mock.dart';
+import 'movie_remote_data_source_test.mocks.dart';
+
+@GenerateNiceMocks([MockSpec()])
+void main() {
+ group('MovieDataSource', () {
+ MockDio mockDioClient = MockDio();
+ final dataSource = MovieRemoteDataSourceImpl(mockDioClient);
+ RequestOptions requestOptions = RequestOptions();
+ Response mockResponseSuccess = Response(
+ requestOptions: requestOptions,
+ statusCode: 200,
+ data: listOfMovieMock,
+ );
+
+ // Mock interceptor
+ final mockInterceptors = Interceptors();
+ when(mockDioClient.interceptors).thenReturn(mockInterceptors);
+
+ test('Fetch success', () async {
+ when(mockDioClient.get(any)).thenAnswer((_) async => mockResponseSuccess);
+ final actual = await dataSource.fetchMovies();
+ expect(actual, isA());
+ });
+
+ test('Fetch error', () async {
+ when(mockDioClient.get(any)).thenAnswer(
+ (_) async => throw DioException(requestOptions: requestOptions),
+ );
+ final actual = await dataSource.fetchMovies();
+ expect(actual, isA());
+ });
+ });
+}
diff --git a/test/data/data_sources/movie/movie_remote_data_source_test.mocks.dart b/test/data/data_sources/movie/movie_remote_data_source_test.mocks.dart
new file mode 100644
index 0000000..0c64767
--- /dev/null
+++ b/test/data/data_sources/movie/movie_remote_data_source_test.mocks.dart
@@ -0,0 +1,1052 @@
+// Mocks generated by Mockito 5.4.4 from annotations
+// in flutter_ci_cd/test/data/data_sources/movie/movie_remote_data_source_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i8;
+
+import 'package:dio/src/adapter.dart' as _i3;
+import 'package:dio/src/cancel_token.dart' as _i9;
+import 'package:dio/src/dio.dart' as _i7;
+import 'package:dio/src/dio_mixin.dart' as _i5;
+import 'package:dio/src/options.dart' as _i2;
+import 'package:dio/src/response.dart' as _i6;
+import 'package:dio/src/transformer.dart' as _i4;
+import 'package:mockito/mockito.dart' as _i1;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: deprecated_member_use
+// ignore_for_file: deprecated_member_use_from_same_package
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakeBaseOptions_0 extends _i1.SmartFake implements _i2.BaseOptions {
+ _FakeBaseOptions_0(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeHttpClientAdapter_1 extends _i1.SmartFake
+ implements _i3.HttpClientAdapter {
+ _FakeHttpClientAdapter_1(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeTransformer_2 extends _i1.SmartFake implements _i4.Transformer {
+ _FakeTransformer_2(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeInterceptors_3 extends _i1.SmartFake implements _i5.Interceptors {
+ _FakeInterceptors_3(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeResponse_4 extends _i1.SmartFake implements _i6.Response {
+ _FakeResponse_4(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+/// A class which mocks [Dio].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockDio extends _i1.Mock implements _i7.Dio {
+ @override
+ _i2.BaseOptions get options => (super.noSuchMethod(
+ Invocation.getter(#options),
+ returnValue: _FakeBaseOptions_0(
+ this,
+ Invocation.getter(#options),
+ ),
+ returnValueForMissingStub: _FakeBaseOptions_0(
+ this,
+ Invocation.getter(#options),
+ ),
+ ) as _i2.BaseOptions);
+
+ @override
+ set options(_i2.BaseOptions? _options) => super.noSuchMethod(
+ Invocation.setter(
+ #options,
+ _options,
+ ),
+ returnValueForMissingStub: null,
+ );
+
+ @override
+ _i3.HttpClientAdapter get httpClientAdapter => (super.noSuchMethod(
+ Invocation.getter(#httpClientAdapter),
+ returnValue: _FakeHttpClientAdapter_1(
+ this,
+ Invocation.getter(#httpClientAdapter),
+ ),
+ returnValueForMissingStub: _FakeHttpClientAdapter_1(
+ this,
+ Invocation.getter(#httpClientAdapter),
+ ),
+ ) as _i3.HttpClientAdapter);
+
+ @override
+ set httpClientAdapter(_i3.HttpClientAdapter? _httpClientAdapter) =>
+ super.noSuchMethod(
+ Invocation.setter(
+ #httpClientAdapter,
+ _httpClientAdapter,
+ ),
+ returnValueForMissingStub: null,
+ );
+
+ @override
+ _i4.Transformer get transformer => (super.noSuchMethod(
+ Invocation.getter(#transformer),
+ returnValue: _FakeTransformer_2(
+ this,
+ Invocation.getter(#transformer),
+ ),
+ returnValueForMissingStub: _FakeTransformer_2(
+ this,
+ Invocation.getter(#transformer),
+ ),
+ ) as _i4.Transformer);
+
+ @override
+ set transformer(_i4.Transformer? _transformer) => super.noSuchMethod(
+ Invocation.setter(
+ #transformer,
+ _transformer,
+ ),
+ returnValueForMissingStub: null,
+ );
+
+ @override
+ _i5.Interceptors get interceptors => (super.noSuchMethod(
+ Invocation.getter(#interceptors),
+ returnValue: _FakeInterceptors_3(
+ this,
+ Invocation.getter(#interceptors),
+ ),
+ returnValueForMissingStub: _FakeInterceptors_3(
+ this,
+ Invocation.getter(#interceptors),
+ ),
+ ) as _i5.Interceptors);
+
+ @override
+ void close({bool? force = false}) => super.noSuchMethod(
+ Invocation.method(
+ #close,
+ [],
+ {#force: force},
+ ),
+ returnValueForMissingStub: null,
+ );
+
+ @override
+ _i8.Future<_i6.Response> head(
+ String? path, {
+ Object? data,
+ Map? queryParameters,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #head,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #head,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #head,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> headUri(
+ Uri? uri, {
+ Object? data,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #headUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #headUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #headUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> get(
+ String? path, {
+ Object? data,
+ Map? queryParameters,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ _i2.ProgressCallback? onReceiveProgress,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #get,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #get,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #get,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> getUri(
+ Uri? uri, {
+ Object? data,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ _i2.ProgressCallback? onReceiveProgress,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #getUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #getUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> post(
+ String? path, {
+ Object? data,
+ Map? queryParameters,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ _i2.ProgressCallback? onSendProgress,
+ _i2.ProgressCallback? onReceiveProgress,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #post,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #post,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #post,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> postUri(
+ Uri? uri, {
+ Object? data,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ _i2.ProgressCallback? onSendProgress,
+ _i2.ProgressCallback? onReceiveProgress,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #postUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #postUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #postUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> put(
+ String? path, {
+ Object? data,
+ Map? queryParameters,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ _i2.ProgressCallback? onSendProgress,
+ _i2.ProgressCallback? onReceiveProgress,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #put,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #put,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #put,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> putUri(
+ Uri? uri, {
+ Object? data,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ _i2.ProgressCallback? onSendProgress,
+ _i2.ProgressCallback? onReceiveProgress,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #putUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #putUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #putUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> patch(
+ String? path, {
+ Object? data,
+ Map? queryParameters,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ _i2.ProgressCallback? onSendProgress,
+ _i2.ProgressCallback? onReceiveProgress,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #patch,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #patch,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #patch,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> patchUri(
+ Uri? uri, {
+ Object? data,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ _i2.ProgressCallback? onSendProgress,
+ _i2.ProgressCallback? onReceiveProgress,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #patchUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #patchUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #patchUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> delete(
+ String? path, {
+ Object? data,
+ Map? queryParameters,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #delete,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #delete,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #delete,
+ [path],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> deleteUri(
+ Uri? uri, {
+ Object? data,
+ _i2.Options? options,
+ _i9.CancelToken? cancelToken,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #deleteUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #deleteUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #deleteUri,
+ [uri],
+ {
+ #data: data,
+ #options: options,
+ #cancelToken: cancelToken,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> download(
+ String? urlPath,
+ dynamic savePath, {
+ _i2.ProgressCallback? onReceiveProgress,
+ Map? queryParameters,
+ _i9.CancelToken? cancelToken,
+ bool? deleteOnError = true,
+ String? lengthHeader = r'content-length',
+ Object? data,
+ _i2.Options? options,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #download,
+ [
+ urlPath,
+ savePath,
+ ],
+ {
+ #onReceiveProgress: onReceiveProgress,
+ #queryParameters: queryParameters,
+ #cancelToken: cancelToken,
+ #deleteOnError: deleteOnError,
+ #lengthHeader: lengthHeader,
+ #data: data,
+ #options: options,
+ },
+ ),
+ returnValue:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #download,
+ [
+ urlPath,
+ savePath,
+ ],
+ {
+ #onReceiveProgress: onReceiveProgress,
+ #queryParameters: queryParameters,
+ #cancelToken: cancelToken,
+ #deleteOnError: deleteOnError,
+ #lengthHeader: lengthHeader,
+ #data: data,
+ #options: options,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #download,
+ [
+ urlPath,
+ savePath,
+ ],
+ {
+ #onReceiveProgress: onReceiveProgress,
+ #queryParameters: queryParameters,
+ #cancelToken: cancelToken,
+ #deleteOnError: deleteOnError,
+ #lengthHeader: lengthHeader,
+ #data: data,
+ #options: options,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> downloadUri(
+ Uri? uri,
+ dynamic savePath, {
+ _i2.ProgressCallback? onReceiveProgress,
+ _i9.CancelToken? cancelToken,
+ bool? deleteOnError = true,
+ String? lengthHeader = r'content-length',
+ Object? data,
+ _i2.Options? options,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #downloadUri,
+ [
+ uri,
+ savePath,
+ ],
+ {
+ #onReceiveProgress: onReceiveProgress,
+ #cancelToken: cancelToken,
+ #deleteOnError: deleteOnError,
+ #lengthHeader: lengthHeader,
+ #data: data,
+ #options: options,
+ },
+ ),
+ returnValue:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #downloadUri,
+ [
+ uri,
+ savePath,
+ ],
+ {
+ #onReceiveProgress: onReceiveProgress,
+ #cancelToken: cancelToken,
+ #deleteOnError: deleteOnError,
+ #lengthHeader: lengthHeader,
+ #data: data,
+ #options: options,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #downloadUri,
+ [
+ uri,
+ savePath,
+ ],
+ {
+ #onReceiveProgress: onReceiveProgress,
+ #cancelToken: cancelToken,
+ #deleteOnError: deleteOnError,
+ #lengthHeader: lengthHeader,
+ #data: data,
+ #options: options,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> request(
+ String? url, {
+ Object? data,
+ Map? queryParameters,
+ _i9.CancelToken? cancelToken,
+ _i2.Options? options,
+ _i2.ProgressCallback? onSendProgress,
+ _i2.ProgressCallback? onReceiveProgress,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #request,
+ [url],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #cancelToken: cancelToken,
+ #options: options,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #request,
+ [url],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #cancelToken: cancelToken,
+ #options: options,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #request,
+ [url],
+ {
+ #data: data,
+ #queryParameters: queryParameters,
+ #cancelToken: cancelToken,
+ #options: options,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> requestUri(
+ Uri? uri, {
+ Object? data,
+ _i9.CancelToken? cancelToken,
+ _i2.Options? options,
+ _i2.ProgressCallback? onSendProgress,
+ _i2.ProgressCallback? onReceiveProgress,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #requestUri,
+ [uri],
+ {
+ #data: data,
+ #cancelToken: cancelToken,
+ #options: options,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #requestUri,
+ [uri],
+ {
+ #data: data,
+ #cancelToken: cancelToken,
+ #options: options,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #requestUri,
+ [uri],
+ {
+ #data: data,
+ #cancelToken: cancelToken,
+ #options: options,
+ #onSendProgress: onSendProgress,
+ #onReceiveProgress: onReceiveProgress,
+ },
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+
+ @override
+ _i8.Future<_i6.Response> fetch(_i2.RequestOptions? requestOptions) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #fetch,
+ [requestOptions],
+ ),
+ returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #fetch,
+ [requestOptions],
+ ),
+ )),
+ returnValueForMissingStub:
+ _i8.Future<_i6.Response>.value(_FakeResponse_4(
+ this,
+ Invocation.method(
+ #fetch,
+ [requestOptions],
+ ),
+ )),
+ ) as _i8.Future<_i6.Response>);
+}
diff --git a/test/data/models/movie/movie_response_test.dart b/test/data/models/movie/movie_response_test.dart
new file mode 100644
index 0000000..308f21c
--- /dev/null
+++ b/test/data/models/movie/movie_response_test.dart
@@ -0,0 +1,27 @@
+import 'package:flutter_ci_cd/src/data/response/movie/movie_response.dart';
+import 'package:flutter_ci_cd/src/domain/model/movie/movie_model.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import '../../data_json_mock/movie_mock.dart';
+
+void main() {
+ group('MovieResponse test', () {
+ final result = (listOfMovieMock['results'] as List)
+ .map((e) => MovieResponse.fromJson(e))
+ .toList();
+ test('[fromJson] function', () {
+ expect(result, isA>());
+ });
+
+ test('[mapToModel] function', () {
+ expect(result.first.mapToModel(), isA());
+
+ // Check [result.mapToModel().posterPath] is url.
+ final uri = Uri.parse(result.first.mapToModel().posterPath);
+ expect(
+ uri.isAbsolute,
+ true,
+ );
+ });
+ });
+}
diff --git a/test/data/repositories/movie/movie_repository_test.dart b/test/data/repositories/movie/movie_repository_test.dart
new file mode 100644
index 0000000..58e769b
--- /dev/null
+++ b/test/data/repositories/movie/movie_repository_test.dart
@@ -0,0 +1,36 @@
+import 'package:flutter_ci_cd/src/data/data_sources/movie/movie_remote_data_source_impl.dart';
+import 'package:flutter_ci_cd/src/data/repositories/movie/movie_repository_impl.dart';
+import 'package:flutter_ci_cd/src/data/response/movie/movie_response.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:fpdart/fpdart.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+
+import 'movie_repository_test.mocks.dart';
+
+@GenerateNiceMocks([MockSpec()])
+void main() {
+ group('MovieRepository', () {
+ final mockDataSource = MockMovieRemoteDataSourceImpl();
+ final repository = MovieRepositoryImpl(mockDataSource);
+ final mockDataSuccess =
+ Right>([MovieResponse()]);
+ final mockDataException = Left>(Exception());
+
+ test('Fetch success', () async {
+ provideDummy>>(mockDataSuccess);
+ when(mockDataSource.fetchMovies())
+ .thenAnswer((realInvocation) async => mockDataSuccess);
+ final actual = await repository.fetchMovies();
+ expect(actual, isA());
+ });
+
+ test('Fetch error', () async {
+ provideDummy>>(mockDataException);
+ when(mockDataSource.fetchMovies())
+ .thenAnswer((realInvocation) async => mockDataException);
+ final actual = await repository.fetchMovies();
+ expect(actual, isA());
+ });
+ });
+}
diff --git a/test/data/repositories/movie/movie_repository_test.mocks.dart b/test/data/repositories/movie/movie_repository_test.mocks.dart
new file mode 100644
index 0000000..b268d8b
--- /dev/null
+++ b/test/data/repositories/movie/movie_repository_test.mocks.dart
@@ -0,0 +1,84 @@
+// Mocks generated by Mockito 5.4.4 from annotations
+// in flutter_ci_cd/test/data/repositories/movie/movie_repository_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i4;
+
+import 'package:dio/dio.dart' as _i2;
+import 'package:flutter_ci_cd/src/data/data_sources/movie/movie_remote_data_source_impl.dart'
+ as _i3;
+import 'package:flutter_ci_cd/src/data/response/movie/movie_response.dart'
+ as _i6;
+import 'package:fpdart/fpdart.dart' as _i5;
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:mockito/src/dummies.dart' as _i7;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: deprecated_member_use
+// ignore_for_file: deprecated_member_use_from_same_package
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakeDio_0 extends _i1.SmartFake implements _i2.Dio {
+ _FakeDio_0(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+/// A class which mocks [MovieRemoteDataSourceImpl].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockMovieRemoteDataSourceImpl extends _i1.Mock
+ implements _i3.MovieRemoteDataSourceImpl {
+ @override
+ _i2.Dio get dio => (super.noSuchMethod(
+ Invocation.getter(#dio),
+ returnValue: _FakeDio_0(
+ this,
+ Invocation.getter(#dio),
+ ),
+ returnValueForMissingStub: _FakeDio_0(
+ this,
+ Invocation.getter(#dio),
+ ),
+ ) as _i2.Dio);
+
+ @override
+ _i4.Future<_i5.Either>> fetchMovies() =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #fetchMovies,
+ [],
+ ),
+ returnValue:
+ _i4.Future<_i5.Either>>.value(
+ _i7.dummyValue<_i5.Either>>(
+ this,
+ Invocation.method(
+ #fetchMovies,
+ [],
+ ),
+ )),
+ returnValueForMissingStub:
+ _i4.Future<_i5.Either>>.value(
+ _i7.dummyValue<_i5.Either>>(
+ this,
+ Invocation.method(
+ #fetchMovies,
+ [],
+ ),
+ )),
+ ) as _i4.Future<_i5.Either>>);
+}
diff --git a/test/domain/processor/movie/movie_processor_test.dart b/test/domain/processor/movie/movie_processor_test.dart
new file mode 100644
index 0000000..0cbc87d
--- /dev/null
+++ b/test/domain/processor/movie/movie_processor_test.dart
@@ -0,0 +1,52 @@
+import 'package:flutter_ci_cd/src/data/repositories/movie/movie_repository_impl.dart';
+import 'package:flutter_ci_cd/src/data/response/movie/movie_response.dart';
+import 'package:flutter_ci_cd/src/domain/model/movie/movie_model.dart';
+import 'package:flutter_ci_cd/src/domain/processors/movie/movie_processor_impl.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:fpdart/fpdart.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+
+import 'movie_processor_test.mocks.dart';
+
+@GenerateNiceMocks([MockSpec()])
+void main() {
+ group('MovieProcessor', () {
+ final mockRepository = MockMovieRepositoryImpl();
+ final processor = MovieProcessorImpl(mockRepository);
+ final mockRepositorySuccess =
+ Right>([MovieResponse()]);
+ final mockRepositoryFailed =
+ Left>(Exception());
+
+ test('Fetch & convert List to List success', () async {
+ // Mock the call [repository.fetchMovies] will return a type of Right>.
+ provideDummy>>(
+ mockRepositorySuccess);
+ when(mockRepository.fetchMovies())
+ .thenAnswer((realInvocation) async => mockRepositorySuccess);
+ final repositoryResult = await mockRepository.fetchMovies();
+ expect(repositoryResult, isA());
+ expect(repositoryResult.fold((l) => l, (r) => r), isA>());
+
+ // Check the result will return List.
+ final actual = await processor.fetchMovie();
+ expect(actual, isA());
+ expect(actual.fold((l) => l, (r) => r), isA>());
+ });
+
+ test('Fetch or convert has error', () async {
+ // Mock the call [repository.fetchMovies] will return a type of Left>.
+ when(mockRepository.fetchMovies())
+ .thenAnswer((realInvocation) async => mockRepositoryFailed);
+ final repositoryResult = await mockRepository.fetchMovies();
+ expect(repositoryResult, isA());
+ expect(repositoryResult.fold((l) => l, (r) => r), isA());
+
+ // Check the result is throw Exception.
+ final actual = await processor.fetchMovie();
+ expect(actual, isA());
+ expect(actual.fold((l) => l, (r) => r), isA());
+ });
+ });
+}
diff --git a/test/domain/processor/movie/movie_processor_test.mocks.dart b/test/domain/processor/movie/movie_processor_test.mocks.dart
new file mode 100644
index 0000000..d0c75a4
--- /dev/null
+++ b/test/domain/processor/movie/movie_processor_test.mocks.dart
@@ -0,0 +1,86 @@
+// Mocks generated by Mockito 5.4.4 from annotations
+// in flutter_ci_cd/test/domain/processor/movie/movie_processor_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i4;
+
+import 'package:flutter_ci_cd/src/data/data_sources/movie/movie_remote_data_source.dart'
+ as _i2;
+import 'package:flutter_ci_cd/src/data/repositories/movie/movie_repository_impl.dart'
+ as _i3;
+import 'package:flutter_ci_cd/src/data/response/movie/movie_response.dart'
+ as _i6;
+import 'package:fpdart/fpdart.dart' as _i5;
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:mockito/src/dummies.dart' as _i7;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: deprecated_member_use
+// ignore_for_file: deprecated_member_use_from_same_package
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakeMovieDataSource_0 extends _i1.SmartFake
+ implements _i2.MovieDataSource {
+ _FakeMovieDataSource_0(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+/// A class which mocks [MovieRepositoryImpl].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockMovieRepositoryImpl extends _i1.Mock
+ implements _i3.MovieRepositoryImpl {
+ @override
+ _i2.MovieDataSource get dataSource => (super.noSuchMethod(
+ Invocation.getter(#dataSource),
+ returnValue: _FakeMovieDataSource_0(
+ this,
+ Invocation.getter(#dataSource),
+ ),
+ returnValueForMissingStub: _FakeMovieDataSource_0(
+ this,
+ Invocation.getter(#dataSource),
+ ),
+ ) as _i2.MovieDataSource);
+
+ @override
+ _i4.Future<_i5.Either>> fetchMovies() =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #fetchMovies,
+ [],
+ ),
+ returnValue:
+ _i4.Future<_i5.Either>>.value(
+ _i7.dummyValue<_i5.Either>>(
+ this,
+ Invocation.method(
+ #fetchMovies,
+ [],
+ ),
+ )),
+ returnValueForMissingStub:
+ _i4.Future<_i5.Either>>.value(
+ _i7.dummyValue<_i5.Either>>(
+ this,
+ Invocation.method(
+ #fetchMovies,
+ [],
+ ),
+ )),
+ ) as _i4.Future<_i5.Either>>);
+}
diff --git a/test/presentation/features/main_home/main_home_view_test.dart b/test/presentation/features/main_home/main_home_view_test.dart
new file mode 100644
index 0000000..8eff1d3
--- /dev/null
+++ b/test/presentation/features/main_home/main_home_view_test.dart
@@ -0,0 +1,16 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_ci_cd/main.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ group('MainHomeView test', () {
+ testWidgets('Find a BottomNavigationBar widget', (widgetTester) async {
+ await widgetTester.pumpWidget(
+ const MyApp(),
+ );
+ await widgetTester.pumpAndSettle();
+ final bottomNav = find.byType(BottomNavigationBar);
+ expect(bottomNav, findsOneWidget);
+ });
+ });
+}
diff --git a/test/presentation/features/movie/movie_page_test.dart b/test/presentation/features/movie/movie_page_test.dart
new file mode 100644
index 0000000..49cdd8e
--- /dev/null
+++ b/test/presentation/features/movie/movie_page_test.dart
@@ -0,0 +1,25 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_ci_cd/src/presentation/features/movie/view/pages/movie_page.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ testWidgets('MoviePage test', (widgetTester) async {
+ await widgetTester.pumpWidget(
+ const ProviderScope(
+ child: MaterialApp(
+ home: MoviePage(),
+ ),
+ ),
+ );
+ final loading = find.byType(CircularProgressIndicator);
+ expect(loading, findsOneWidget);
+
+ // Call this to wait for the loading process to complete.
+ await widgetTester.pumpAndSettle();
+
+ expect(loading, findsNothing);
+ final listView = find.byType(ListView);
+ expect(listView, findsOneWidget);
+ });
+}
diff --git a/test/widget_test.dart b/test/widget_test.dart
new file mode 100644
index 0000000..2a2b819
--- /dev/null
+++ b/test/widget_test.dart
@@ -0,0 +1,8 @@
+// This is a basic Flutter widget test.
+//
+// To perform an interaction with a widget in your test, use the WidgetTester
+// utility in the flutter_test package. For example, you can send tap and scroll
+// gestures. You can also use WidgetTester to find child widgets in the widget
+// tree, read text, and verify that the values of widget properties are correct.
+
+void main() {}