├── .gitignore
├── .metadata
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── flutter_tdd_and_clean_architecture
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
├── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── RunnerTests
│ └── RunnerTests.swift
└── firebase_app_id_file.json
├── lib
├── main.dart
└── src
│ └── features
│ └── auth
│ ├── data
│ ├── data_sources
│ │ ├── auth_local_data_source.dart
│ │ ├── auth_remote_data_source.dart
│ │ ├── auth_remote_data_source_fake.dart
│ │ └── auth_remote_data_source_firebase.dart
│ ├── models
│ │ └── auth_user_model.dart
│ └── repositories
│ │ └── auth_repository_impl.dart
│ ├── domain
│ ├── entities
│ │ └── auth_user.dart
│ ├── repositories
│ │ └── auth_repository.dart
│ ├── use_cases
│ │ ├── sign_in_use_case.dart
│ │ ├── sign_out_use_case.dart
│ │ ├── sign_up_use_case.dart
│ │ └── stream_auth_user_use_case.dart
│ └── value_objects
│ │ ├── email.dart
│ │ ├── email.g.dart
│ │ ├── password.dart
│ │ └── password.g.dart
│ └── presentation
│ ├── blocs
│ ├── email_status.dart
│ ├── form_status.dart
│ ├── password_status.dart
│ ├── sign_in
│ │ ├── sign_in_cubit.dart
│ │ └── sign_in_state.dart
│ └── sign_up
│ │ ├── sign_up_cubit.dart
│ │ └── sign_up_state.dart
│ └── screens
│ ├── sign_in_screen.dart
│ └── sign_up_screen.dart
├── pubspec.lock
├── pubspec.yaml
├── screenshots
└── clean_architecture_course.png
├── test
└── src
│ └── features
│ └── auth
│ ├── data
│ ├── data_sources
│ │ ├── auth_local_data_source_test.dart
│ │ ├── auth_remote_data_source_firebase_test.dart
│ │ └── auth_remote_data_source_firebase_test.mocks.dart
│ ├── models
│ │ ├── auth_user_model_test.dart
│ │ └── auth_user_model_test.mocks.dart
│ └── repositories
│ │ ├── auth_repository_impl_test.dart
│ │ └── auth_repository_impl_test.mocks.dart
│ ├── domain
│ ├── entities
│ │ └── auth_user_test.dart
│ ├── use_cases
│ │ ├── sign_in_use_case_test.dart
│ │ ├── sign_in_use_case_test.mocks.dart
│ │ ├── sign_out_use_case_test.dart
│ │ ├── sign_out_use_case_test.mocks.dart
│ │ ├── sign_up_use_case_test.dart
│ │ ├── sign_up_use_case_test.mocks.dart
│ │ ├── stream_auth_user_use_case_test.dart
│ │ └── stream_auth_user_use_case_test.mocks.dart
│ └── value_objects
│ │ ├── email_test.dart
│ │ └── password_test.dart
│ └── presentation
│ ├── blocs
│ ├── sign_in
│ │ ├── sign_in_cubit_test.dart
│ │ ├── sign_in_cubit_test.mocks.dart
│ │ └── sign_in_state_test.dart
│ └── sign_up
│ │ ├── sign_up_cubit_test.dart
│ │ ├── sign_up_cubit_test.mocks.dart
│ │ └── sign_up_state_test.dart
│ └── screens
│ ├── sign_in_screen_test.dart
│ ├── sign_in_screen_test.mocks.dart
│ ├── sign_up_screen_test.dart
│ └── sign_up_screen_test.mocks.dart
└── web
├── favicon.png
├── icons
├── Icon-192.png
├── Icon-512.png
├── Icon-maskable-192.png
└── Icon-maskable-512.png
├── index.html
└── manifest.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Symbolication related
36 | app.*.symbols
37 |
38 | # Obfuscation related
39 | app.*.map.json
40 |
41 | # Android Studio will place build artifacts here
42 | /android/app/debug
43 | /android/app/profile
44 | /android/app/release
45 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled.
5 |
6 | version:
7 | revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
8 | channel: stable
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
17 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
18 | - platform: android
19 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
20 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
21 | - platform: ios
22 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
23 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
24 | - platform: linux
25 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
26 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
27 | - platform: macos
28 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
29 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
30 | - platform: web
31 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
32 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
33 | - platform: windows
34 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
35 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
36 |
37 | # User provided section
38 |
39 | # List of Local paths (relative to this file) that should be
40 | # ignored by the migrate tool.
41 | #
42 | # Files that are not part of the templates will be ignored by default.
43 | unmanaged_files:
44 | - 'lib/main.dart'
45 | - 'ios/Runner.xcodeproj/project.pbxproj'
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Clean Architecture with Firebase
2 |
3 | This project demonstrates the use of advanced topics such as Clean Architecture, Firebase integration, Bloc pattern for state management, and Hive for local storage.
4 |
5 | ## Structure
6 |
7 | The application follows the principles of Clean Architecture and is structured into three primary layers:
8 |
9 | - **Data Layer**: This layer includes the models, data sources (remote and local), and the repositories. It interacts with Firebase for remote data and Hive for local data.
10 |
11 | - **Domain Layer**: This layer contains the core business logic (use cases) and entity definitions.
12 |
13 | - **Presentation Layer**: This is where the UI-related logic resides. It uses Bloc for state management.
14 |
15 | The application has three main features/modules:
16 |
17 | - **Auth**: Deals with user authentication, both locally and remotely through Firebase.
18 |
19 | - **Feed** (not included in the preview): Handles the creation, fetching, and management of user posts.
20 |
21 | - **Chat** (not included in the preview): Manages real-time chat functionality between users.
22 |
23 | All modules follow the above-mentioned architectural layers and are organized accordingly within their respective directories.
24 |
25 | ## Usage
26 |
27 | - **User Authentication**: User can register, login and logout.
28 |
29 | - **Feed Posting**: Users can view posts. Coming soon: add and delete posts.
30 |
31 | - **Chat**: Users can chat with other users in real-time.
32 |
33 | Please note that the code is written in a way to be easily read, extended, and maintained. This is in line with the principles of Clean Architecture, which aims to separate concerns and make the codebase more understandable and flexible.
34 |
35 | ## Customization
36 |
37 | Feel free to customize the code to suit your needs. The codebase is modular and flexible, making it easy to add, remove, or modify features.
38 |
39 | ## Dependencies
40 |
41 | The application is built using various dependencies that aid in implementing its features:
42 |
43 | - Firebase Core, Firestore, and Auth for backend operations.
44 | - Hive for local database operations.
45 | - Bloc for state management.
46 | - Equatable, UUID, Built Value for data handling.
47 | - Google Fonts and Flex Color Scheme for UI styling.
48 | - Functional error handling with fpdart (not included in the preview)
49 | - And several other for testing and mocking.
50 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 |
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | // START: FlutterFire Configuration
26 | apply plugin: 'com.google.gms.google-services'
27 | // END: FlutterFire Configuration
28 | apply plugin: 'kotlin-android'
29 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
30 |
31 | android {
32 | namespace "com.example.flutter_clean_architecture_with_firebase"
33 | compileSdkVersion flutter.compileSdkVersion
34 | ndkVersion flutter.ndkVersion
35 |
36 | compileOptions {
37 | sourceCompatibility JavaVersion.VERSION_1_8
38 | targetCompatibility JavaVersion.VERSION_1_8
39 | }
40 |
41 | kotlinOptions {
42 | jvmTarget = '1.8'
43 | }
44 |
45 | sourceSets {
46 | main.java.srcDirs += 'src/main/kotlin'
47 | }
48 |
49 | defaultConfig {
50 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
51 | applicationId "com.example.flutter_clean_architecture_with_firebase"
52 | // You can update the following values to match your application needs.
53 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
54 | minSdkVersion flutter.minSdkVersion
55 | targetSdkVersion flutter.targetSdkVersion
56 | versionCode flutterVersionCode.toInteger()
57 | versionName flutterVersionName
58 | }
59 |
60 | buildTypes {
61 | release {
62 | // TODO: Add your own signing config for the release build.
63 | // Signing with the debug keys for now, so `flutter run --release` works.
64 | signingConfig signingConfigs.debug
65 | }
66 | }
67 | }
68 |
69 | flutter {
70 | source '../..'
71 | }
72 |
73 | dependencies {
74 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
75 | }
76 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
14 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/flutter_tdd_and_clean_architecture/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.flutter_clean_architecture_with_firebase
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.7.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.3.0'
10 | // START: FlutterFire Configuration
11 | classpath 'com.google.gms:google-services:4.3.10'
12 | // END: FlutterFire Configuration
13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | mavenCentral()
21 | }
22 | }
23 |
24 | rootProject.buildDir = '../build'
25 | subprojects {
26 | project.buildDir = "${rootProject.buildDir}/${project.name}"
27 | }
28 | subprojects {
29 | project.evaluationDependsOn(':app')
30 | }
31 |
32 | tasks.register("clean", Delete) {
33 | delete rootProject.buildDir
34 | }
35 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '11.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | target 'RunnerTests' do
36 | inherit! :search_paths
37 | end
38 | end
39 |
40 | post_install do |installer|
41 | installer.pods_project.targets.each do |target|
42 | flutter_additional_ios_build_settings(target)
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maxonflutter/Flutter-Clean-Architecture-With-Firebase/b49ed2200d1332aa3c473f5de943d0db2191af19/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | 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.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Flutter Tdd And Clean Architecture
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | flutter_clean_architecture_with_firebase
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UIViewControllerBasedStatusBarAppearance
45 |
46 | CADisableMinimumFrameDurationOnPhone
47 |
48 | UIApplicationSupportsIndirectInputEvents
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/ios/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/ios/firebase_app_id_file.json:
--------------------------------------------------------------------------------
1 | {
2 | "file_generated_by": "FlutterFire CLI",
3 | "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory",
4 | "GOOGLE_APP_ID": "1:386454341522:ios:c51154e06897c00796234b",
5 | "FIREBASE_PROJECT_ID": "flutter-tdd-clean-architecture",
6 | "GCM_SENDER_ID": "386454341522"
7 | }
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:firebase_core/firebase_core.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_bloc/flutter_bloc.dart';
6 |
7 | import 'firebase_options.dart';
8 | import 'src/features/auth/data/data_sources/auth_local_data_source.dart';
9 | import 'src/features/auth/data/data_sources/auth_remote_data_source.dart';
10 | import 'src/features/auth/data/data_sources/auth_remote_data_source_firebase.dart';
11 | import 'src/features/auth/data/repositories/auth_repository_impl.dart';
12 | import 'src/features/auth/domain/entities/auth_user.dart';
13 | import 'src/features/auth/domain/repositories/auth_repository.dart';
14 | import 'src/features/auth/presentation/screens/sign_in_screen.dart';
15 |
16 | typedef AppBuilder = Future Function();
17 |
18 | Future bootstrap(AppBuilder builder) async {
19 | WidgetsFlutterBinding.ensureInitialized();
20 | await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
21 | runApp(await builder());
22 | }
23 |
24 | void main() {
25 | bootstrap(
26 | () async {
27 | AuthLocalDataSource authLocalDataSource = AuthLocalDataSource();
28 | AuthRemoteDataSource authRemoteDataSource =
29 | AuthRemoteDataSourceFirebase();
30 |
31 | AuthRepository authRepository = AuthRepositoryImpl(
32 | localDataSource: authLocalDataSource,
33 | remoteDataSource: authRemoteDataSource,
34 | );
35 |
36 | return App(
37 | authRepository: authRepository,
38 | authUser: await authRepository.authUser.first,
39 | );
40 | },
41 | );
42 | }
43 |
44 | class App extends StatelessWidget {
45 | const App({
46 | super.key,
47 | required this.authRepository,
48 | this.authUser,
49 | });
50 |
51 | final AuthRepository authRepository;
52 | final AuthUser? authUser;
53 |
54 | @override
55 | Widget build(BuildContext context) {
56 | return MultiRepositoryProvider(
57 | providers: [
58 | RepositoryProvider.value(value: authRepository),
59 | ],
60 | child: MaterialApp(
61 | title: 'Clean Architecture',
62 | theme: ThemeData.light(useMaterial3: true),
63 | home: const SignInScreen(),
64 | ),
65 | );
66 | }
67 | }
68 |
69 | // class HomeScreen extends StatelessWidget {
70 | // const HomeScreen({super.key});
71 |
72 | // @override
73 | // Widget build(BuildContext context) {
74 | // return Scaffold(
75 | // appBar: AppBar(title: const Text('Clean Architecture')),
76 | // body: const Column(children: []),
77 | // );
78 | // }
79 | // }
80 |
--------------------------------------------------------------------------------
/lib/src/features/auth/data/data_sources/auth_local_data_source.dart:
--------------------------------------------------------------------------------
1 | class AuthLocalDataSource {
2 | AuthLocalDataSource() : authLocalDataSource = {};
3 |
4 | final Map authLocalDataSource;
5 |
6 | void write({required String key, T? value}) {
7 | authLocalDataSource[key] = value;
8 | }
9 |
10 | T? read({required String key}) {
11 | final value = authLocalDataSource[key];
12 | if (value is T) return value;
13 | return null;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/src/features/auth/data/data_sources/auth_remote_data_source.dart:
--------------------------------------------------------------------------------
1 | import '../models/auth_user_model.dart';
2 |
3 | abstract class AuthRemoteDataSource {
4 | Stream get user;
5 |
6 | Future signUpWithEmailAndPassword({
7 | required String email,
8 | required String password,
9 | });
10 |
11 | Future signInWithEmailAndPassword({
12 | required String email,
13 | required String password,
14 | });
15 |
16 | Future signOut();
17 | }
18 |
--------------------------------------------------------------------------------
/lib/src/features/auth/data/data_sources/auth_remote_data_source_fake.dart:
--------------------------------------------------------------------------------
1 | import '../models/auth_user_model.dart';
2 | import 'auth_remote_data_source.dart';
3 |
4 | class AuthRemoteDataSourceFake implements AuthRemoteDataSource {
5 | static const fakeUser = AuthUserModel(
6 | id: 'fake-user-id',
7 | email: 'fake-user-email',
8 | name: 'fake-user-name',
9 | );
10 |
11 | @override
12 | Stream get user {
13 | return Stream.value(fakeUser);
14 | }
15 |
16 | @override
17 | Future signUpWithEmailAndPassword({
18 | required String email,
19 | required String password,
20 | }) async {
21 | await Future.delayed(const Duration(seconds: 1));
22 | return fakeUser;
23 | }
24 |
25 | @override
26 | Future signInWithEmailAndPassword({
27 | required String email,
28 | required String password,
29 | }) async {
30 | await Future.delayed(const Duration(seconds: 1));
31 | return fakeUser;
32 | }
33 |
34 | @override
35 | Future signOut() async {
36 | throw UnimplementedError();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/src/features/auth/data/data_sources/auth_remote_data_source_firebase.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
2 |
3 | import '../models/auth_user_model.dart';
4 | import 'auth_remote_data_source.dart';
5 |
6 | class AuthRemoteDataSourceFirebase implements AuthRemoteDataSource {
7 | AuthRemoteDataSourceFirebase({
8 | firebase_auth.FirebaseAuth? firebaseAuth,
9 | }) : _firebaseAuth = firebaseAuth ?? firebase_auth.FirebaseAuth.instance;
10 |
11 | final firebase_auth.FirebaseAuth _firebaseAuth;
12 |
13 | @override
14 | Stream get user {
15 | return _firebaseAuth.authStateChanges().map((firebaseUser) {
16 | if (firebaseUser == null) {
17 | return null;
18 | }
19 | return AuthUserModel.fromFirebaseAuthUser(firebaseUser);
20 | });
21 | }
22 |
23 | @override
24 | Future signUpWithEmailAndPassword({
25 | required String email,
26 | required String password,
27 | }) async {
28 | try {
29 | firebase_auth.UserCredential credential =
30 | await _firebaseAuth.createUserWithEmailAndPassword(
31 | email: email,
32 | password: password,
33 | );
34 |
35 | if (credential.user == null) {
36 | throw Exception('Sign up failed: The user is null after sign up.');
37 | }
38 |
39 | return AuthUserModel.fromFirebaseAuthUser(credential.user!);
40 | } catch (error) {
41 | throw Exception('Sign up failed: $error');
42 | }
43 | }
44 |
45 | @override
46 | Future signInWithEmailAndPassword({
47 | required String email,
48 | required String password,
49 | }) async {
50 | try {
51 | firebase_auth.UserCredential credential =
52 | await _firebaseAuth.signInWithEmailAndPassword(
53 | email: email,
54 | password: password,
55 | );
56 |
57 | if (credential.user == null) {
58 | throw Exception('Sign in failed: The user is null after sign in.');
59 | }
60 |
61 | return AuthUserModel.fromFirebaseAuthUser(credential.user!);
62 | } catch (error) {
63 | throw Exception('Sign in failed: $error');
64 | }
65 | }
66 |
67 | @override
68 | Future signOut() async {
69 | try {
70 | await _firebaseAuth.signOut();
71 | } catch (error) {
72 | throw Exception('Sign out failed: $error');
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/lib/src/features/auth/data/models/auth_user_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:equatable/equatable.dart';
2 | import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
3 |
4 | import '../../domain/entities/auth_user.dart';
5 |
6 | class AuthUserModel extends Equatable {
7 | final String id;
8 | final String email;
9 | final String? name;
10 | final String? photoURL;
11 |
12 | const AuthUserModel({
13 | required this.id,
14 | required this.email,
15 | this.name,
16 | this.photoURL,
17 | });
18 |
19 | factory AuthUserModel.fromFirebaseAuthUser(
20 | firebase_auth.User firebaseUser,
21 | ) {
22 | return AuthUserModel(
23 | id: firebaseUser.uid,
24 | email: firebaseUser.email ?? '',
25 | name: firebaseUser.displayName,
26 | photoURL: firebaseUser.photoURL,
27 | );
28 | }
29 |
30 | // factory AuthUserModel.fromAnotherDataSourceAuthUser(
31 | // // ...
32 | // ) {
33 | // return AuthUserModel(
34 | // ...
35 | // );
36 | // }
37 |
38 | AuthUser toEntity() {
39 | return AuthUser(
40 | id: id,
41 | email: email,
42 | name: name,
43 | photoURL: photoURL,
44 | );
45 | }
46 |
47 | @override
48 | List