├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .metadata ├── .vscode └── launch.json ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── flutter_avancado │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── 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 │ │ │ └── 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 ├── lib ├── data │ ├── cache │ │ ├── cache.dart │ │ ├── fetch_secure_cache_storage.dart │ │ └── save_secure_cache_storage.dart │ ├── http │ │ ├── http.dart │ │ ├── http_client.dart │ │ └── http_error.dart │ ├── models │ │ ├── models.dart │ │ └── remote_account_model.dart │ └── usecases │ │ ├── authentication │ │ ├── authentication.dart │ │ └── remote_authentication.dart │ │ ├── load_current_account │ │ ├── load_current_account.dart │ │ └── local_load_current_account.dart │ │ ├── save_current_account │ │ ├── local_save_current_account.dart │ │ └── save_current_account.dart │ │ └── usecases.dart ├── domain │ ├── entities │ │ ├── account_entity.dart │ │ └── entities.dart │ ├── helpers │ │ ├── domain_error.dart │ │ └── helpers.dart │ └── usecases │ │ ├── authentication.dart │ │ ├── load_current_account.dart │ │ ├── save_current_account.dart │ │ └── usecases.dart ├── infra │ ├── cache │ │ ├── cache.dart │ │ └── local_storage_adpter.dart │ └── http │ │ ├── http.dart │ │ └── http_adpter.dart ├── main.dart ├── main │ ├── builders │ │ ├── builders.dart │ │ └── validation_builder.dart │ └── factories │ │ ├── cache │ │ ├── cache.dart │ │ └── local_storage_adpter_factory.dart │ │ ├── factories.dart │ │ ├── http │ │ ├── api_url_factory.dart │ │ ├── http.dart │ │ └── http_client_factory.dart │ │ ├── pages │ │ ├── login │ │ │ ├── login.dart │ │ │ ├── login_page_factory.dart │ │ │ ├── login_presenter_factory.dart │ │ │ └── login_validation_factory.dart │ │ ├── pages.dart │ │ └── splash │ │ │ ├── splash.dart │ │ │ ├── splash_page_factory.dart │ │ │ └── splash_presenter_factory.dart │ │ └── usecases │ │ ├── authentication_factory.dart │ │ ├── load_current_account_factory.dart │ │ ├── save_current_account_factory.dart │ │ └── usecases.dart ├── presentation │ ├── presenters │ │ ├── getx_login_presenter.dart │ │ ├── getx_splash_presenter.dart │ │ ├── presenters.dart │ │ └── stream_login_presenter.dart │ └── protocols │ │ ├── protocols.dart │ │ └── validation.dart ├── ui │ └── pages │ │ ├── login │ │ ├── login_page.dart │ │ └── login_presenter.dart │ │ ├── pages.dart │ │ └── splash │ │ ├── splash_page.dart │ │ └── splash_presenter.dart ├── utils │ └── i18n │ │ ├── i18n.dart │ │ ├── resources.dart │ │ └── strings │ │ ├── en_us.dart │ │ ├── pt_br.dart │ │ ├── strings.dart │ │ └── translations.dart └── validation │ ├── protocols │ ├── field_validation.dart │ └── protocols.dart │ └── validators │ ├── email_validation.dart │ ├── required_field_validation.dart │ ├── validation_composite.dart │ └── validators.dart ├── metrics ├── base.css ├── index.html ├── lib │ ├── data │ │ ├── cache │ │ │ ├── cache.html │ │ │ ├── fetch_secure_cache_storage.html │ │ │ ├── index.html │ │ │ └── save_secure_cache_storage.html │ │ ├── http │ │ │ ├── http.html │ │ │ ├── http_client.html │ │ │ ├── http_error.html │ │ │ └── index.html │ │ ├── models │ │ │ ├── index.html │ │ │ ├── models.html │ │ │ └── remote_account_model.html │ │ └── usecases │ │ │ ├── authentication │ │ │ ├── authentication.html │ │ │ ├── index.html │ │ │ └── remote_authentication.html │ │ │ ├── index.html │ │ │ ├── load_current_account │ │ │ ├── index.html │ │ │ ├── load_current_account.html │ │ │ └── local_load_current_account.html │ │ │ ├── save_current_account │ │ │ ├── index.html │ │ │ ├── local_save_current_account.html │ │ │ └── save_current_account.html │ │ │ └── usecases.html │ ├── domain │ │ ├── entities │ │ │ ├── account_entity.html │ │ │ ├── entities.html │ │ │ └── index.html │ │ ├── helpers │ │ │ ├── domain_error.html │ │ │ ├── helpers.html │ │ │ └── index.html │ │ └── usecases │ │ │ ├── authentication.html │ │ │ ├── index.html │ │ │ ├── load_current_account.html │ │ │ ├── save_current_account.html │ │ │ └── usecases.html │ ├── index.html │ ├── infra │ │ ├── cache │ │ │ ├── cache.html │ │ │ ├── index.html │ │ │ └── local_storage_adpter.html │ │ └── http │ │ │ ├── http.html │ │ │ ├── http_adpter.html │ │ │ └── index.html │ ├── main.html │ ├── main │ │ ├── builders │ │ │ ├── builders.html │ │ │ ├── index.html │ │ │ └── validation_builder.html │ │ └── factories │ │ │ ├── cache │ │ │ ├── cache.html │ │ │ ├── index.html │ │ │ └── local_storage_adpter_factory.html │ │ │ ├── factories.html │ │ │ ├── http │ │ │ ├── api_url_factory.html │ │ │ ├── http.html │ │ │ ├── http_client_factory.html │ │ │ └── index.html │ │ │ ├── index.html │ │ │ ├── pages │ │ │ ├── index.html │ │ │ ├── login │ │ │ │ ├── index.html │ │ │ │ ├── login.html │ │ │ │ ├── login_page_factory.html │ │ │ │ ├── login_presenter_factory.html │ │ │ │ └── login_validation_factory.html │ │ │ ├── pages.html │ │ │ └── splash │ │ │ │ ├── index.html │ │ │ │ ├── splash.html │ │ │ │ ├── splash_page_factory.html │ │ │ │ └── splash_presenter_factory.html │ │ │ └── usecases │ │ │ ├── authentication_factory.html │ │ │ ├── index.html │ │ │ ├── load_current_account_factory.html │ │ │ ├── save_current_account_factory.html │ │ │ └── usecases.html │ ├── presentation │ │ ├── presenters │ │ │ ├── getx_login_presenter.html │ │ │ ├── getx_splash_presenter.html │ │ │ ├── index.html │ │ │ ├── presenters.html │ │ │ └── stream_login_presenter.html │ │ └── protocols │ │ │ ├── index.html │ │ │ ├── protocols.html │ │ │ └── validation.html │ ├── ui │ │ └── pages │ │ │ ├── index.html │ │ │ ├── login │ │ │ ├── index.html │ │ │ ├── login_page.html │ │ │ └── login_presenter.html │ │ │ ├── pages.html │ │ │ └── splash │ │ │ ├── index.html │ │ │ ├── splash_page.html │ │ │ └── splash_presenter.html │ ├── utils │ │ └── i18n │ │ │ ├── i18n.html │ │ │ ├── index.html │ │ │ ├── resources.html │ │ │ └── strings │ │ │ ├── en_us.html │ │ │ ├── index.html │ │ │ ├── pt_br.html │ │ │ ├── strings.html │ │ │ └── translations.html │ └── validation │ │ ├── protocols │ │ ├── field_validation.html │ │ ├── index.html │ │ └── protocols.html │ │ └── validators │ │ ├── email_validation.html │ │ ├── index.html │ │ ├── required_field_validation.html │ │ ├── validation_composite.html │ │ └── validators.html ├── main.css ├── normalize.css └── variables.css ├── pubspec.lock ├── pubspec.yaml ├── requirements ├── cache │ └── fetch_secure_cache.md ├── http │ └── http_responses.md ├── login │ ├── login.feature │ ├── login_page.md │ ├── login_presenter.md │ └── remote_authentication_use_case.md ├── splash │ ├── splash_page.md │ └── splash_presenter.md └── use_cases │ ├── local_load_current_account.md │ └── local_save_current_account.md ├── sonar-project.properties └── test ├── data └── usecases │ ├── authentication │ └── remote_authentication_test.dart │ ├── load_current_account │ └── load_current_account_test.dart │ └── save_current_account │ └── local_save_current_account_test.dart ├── infra ├── cache │ └── local_storage_adpter_test.dart └── http │ └── http_adpter_test.dart ├── main └── factories │ └── pages │ └── login │ └── login_validation_factory_test.dart ├── presentation └── presenters │ ├── getx_login_presenter_test.dart │ ├── getx_splash_presenter_test.dart │ └── stream_login_presenter_test.dart ├── ui └── page │ ├── login_page_test.dart │ └── splash_page_test.dart └── validation └── validators ├── email_validation_test.dart ├── required_field_validation_test.dart └── validation_composite_test.dart /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Flutter CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | 13 | - uses: actions/checkout@v1 14 | - uses: actions/setup-java@v1 15 | with: 16 | java-version: '12.x' 17 | 18 | - uses: subosito/flutter-action@master 19 | with: 20 | channel: 'beta' 21 | 22 | - run: flutter pub get 23 | - run: flutter format --set-exit-if-changed . 24 | - run: flutter analyze . 25 | - run: flutter test 26 | - run: flutter pub run dart_code_metrics:metrics --reporter=github lib 27 | - run: flutter build apk 28 | - uses: actions/upload-artifact@v1 29 | with: 30 | name: release-apk 31 | path: build/app/outputs/apk/release/app-release.apk 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Exceptions to above rules. 44 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 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 and should not be manually edited. 5 | 6 | version: 7 | revision: 216dee60c0cc9449f0b29bcf922974d612263e24 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use o IntelliSense para aprender sobre possíveis atributos. 3 | // Passe o mouse para ver as descrições dos atributos existentes. 4 | // Para obter mais informações, visite: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Flutter: Run all Tests", 9 | "type": "dart", 10 | "request": "launch", 11 | "program": "./test/" 12 | }, 13 | ] 14 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Project 2 | ![Flutter CI](https://github.com/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/workflows/Flutter%20CI/badge.svg) 3 | 4 | - [X] Clean Archtecture 5 | - [X] Design Patterns 6 | - [X] Adapter 7 | - [X] Builder 8 | - [X] Singleton 9 | - [X] Decorator 10 | - [X] Solid 11 | - [X] TDD (Unit Test, Widget Test) 12 | - [X] BDD 13 | - [X] GitHub Actions (CI/CD) 14 | - [X] Check Format 15 | - [X] Check Analyze 16 | - [X] Check Test 17 | - [X] Generate Dart Code Metrics 18 | - [X] Build APK release 19 | - [X] Custom Analysis Options (Lint) 20 | - [X] SonarQube Configuration 21 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | plugins: 3 | - dart_code_metrics 4 | 5 | dart_code_metrics: 6 | anti-patterns: 7 | - long-method 8 | - long-parameter-list 9 | metrics: 10 | cyclomatic-complexity: 25 11 | maximum-nesting-level: 5 12 | number-of-parameters: 4 13 | source-lines-of-code: 50 14 | metrics-exclude: 15 | - test/** 16 | rules: 17 | - no-boolean-literal-compare 18 | - no-empty-block 19 | - prefer-trailing-comma 20 | - prefer-conditional-expressions 21 | - no-equal-then-else -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.example.flutter_avancado" 42 | minSdkVersion 18 43 | targetSdkVersion 30 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | } 47 | 48 | buildTypes { 49 | release { 50 | // TODO: Add your own signing config for the release build. 51 | // Signing with the debug keys for now, so `flutter run --release` works. 52 | signingConfig signingConfigs.debug 53 | } 54 | } 55 | } 56 | 57 | flutter { 58 | source '../..' 59 | } 60 | 61 | dependencies { 62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 63 | } 64 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/flutter_avancado/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.flutter_avancado 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /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 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 3 | #include "Generated.xcconfig" 4 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 3 | #include "Generated.xcconfig" 4 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.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 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - flutter_secure_storage (3.3.1): 4 | - Flutter 5 | 6 | DEPENDENCIES: 7 | - Flutter (from `Flutter`) 8 | - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) 9 | 10 | EXTERNAL SOURCES: 11 | Flutter: 12 | :path: Flutter 13 | flutter_secure_storage: 14 | :path: ".symlinks/plugins/flutter_secure_storage/ios" 15 | 16 | SPEC CHECKSUMS: 17 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 18 | flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec 19 | 20 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c 21 | 22 | COCOAPODS: 1.9.1 23 | -------------------------------------------------------------------------------- /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.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/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeividWillyan/Flutter-TDD_Clean-Architecture_Design-Patterns_SOLID/10eab991994e9a0a03b13a4bd9e6e73227777183/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 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_avancado 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/data/cache/cache.dart: -------------------------------------------------------------------------------- 1 | export './save_secure_cache_storage.dart'; 2 | export './fetch_secure_cache_storage.dart'; 3 | -------------------------------------------------------------------------------- /lib/data/cache/fetch_secure_cache_storage.dart: -------------------------------------------------------------------------------- 1 | abstract class FetchSecureCacheStorage { 2 | Future fetchSecure(String key); 3 | } 4 | -------------------------------------------------------------------------------- /lib/data/cache/save_secure_cache_storage.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | 3 | abstract class SaveSecureCacheStorage { 4 | Future saveSecure({@required String key, @required String value}); 5 | } 6 | -------------------------------------------------------------------------------- /lib/data/http/http.dart: -------------------------------------------------------------------------------- 1 | export './http_client.dart'; 2 | export './http_error.dart'; 3 | -------------------------------------------------------------------------------- /lib/data/http/http_client.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | 3 | abstract class HttpClient { 4 | Future request({ 5 | @required String url, 6 | @required String method, 7 | Map body, 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /lib/data/http/http_error.dart: -------------------------------------------------------------------------------- 1 | enum HttpError { 2 | badRequest, 3 | notFound, 4 | serverError, 5 | unauthorized, 6 | forbidden, 7 | invalidData, 8 | } 9 | -------------------------------------------------------------------------------- /lib/data/models/models.dart: -------------------------------------------------------------------------------- 1 | export './remote_account_model.dart'; 2 | -------------------------------------------------------------------------------- /lib/data/models/remote_account_model.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/entities/entities.dart'; 2 | 3 | import '../http/http.dart'; 4 | 5 | class RemoteAccountModel { 6 | final String accessToken; 7 | 8 | RemoteAccountModel(this.accessToken); 9 | 10 | factory RemoteAccountModel.fromMap(Map map) { 11 | if (!map.containsKey('accessToken')) { 12 | throw HttpError.invalidData; 13 | } 14 | return RemoteAccountModel(map['accessToken']); 15 | } 16 | 17 | AccountEntity toEntity() => AccountEntity(accessToken); 18 | } 19 | -------------------------------------------------------------------------------- /lib/data/usecases/authentication/authentication.dart: -------------------------------------------------------------------------------- 1 | export './remote_authentication.dart'; 2 | -------------------------------------------------------------------------------- /lib/data/usecases/authentication/remote_authentication.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | 3 | import '../../../domain/entities/entities.dart'; 4 | import '../../../domain/helpers/helpers.dart'; 5 | import '../../../domain/usecases/usecases.dart'; 6 | 7 | import '../../http/http.dart'; 8 | import '../../models/models.dart'; 9 | 10 | class RemoteAuthentication implements Authentication { 11 | final HttpClient httpClient; 12 | final String url; 13 | RemoteAuthentication({@required this.httpClient, @required this.url}); 14 | 15 | @override 16 | Future auth(AuthenticationParams params) async { 17 | try { 18 | final result = await httpClient.request( 19 | url: url, 20 | method: 'post', 21 | body: RemoteAuthenticationParams.fromDomain(params).toMap(), 22 | ); 23 | return RemoteAccountModel.fromMap(result).toEntity(); 24 | } on HttpError catch (error) { 25 | throw error == HttpError.unauthorized 26 | ? DomainError.invalidCredentials 27 | : DomainError.unexpected; 28 | } 29 | } 30 | } 31 | 32 | class RemoteAuthenticationParams { 33 | final String email; 34 | final String password; 35 | 36 | RemoteAuthenticationParams({ 37 | @required this.email, 38 | @required this.password, 39 | }); 40 | 41 | factory RemoteAuthenticationParams.fromDomain(AuthenticationParams params) => 42 | RemoteAuthenticationParams(email: params.email, password: params.secret); 43 | 44 | Map toMap() => {'email': email, 'password': password}; 45 | } 46 | -------------------------------------------------------------------------------- /lib/data/usecases/load_current_account/load_current_account.dart: -------------------------------------------------------------------------------- 1 | export './local_load_current_account.dart'; 2 | -------------------------------------------------------------------------------- /lib/data/usecases/load_current_account/local_load_current_account.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | 3 | import '../../../domain/entities/entities.dart'; 4 | import '../../../domain/helpers/helpers.dart'; 5 | import '../../../domain/usecases/usecases.dart'; 6 | 7 | import '../../cache/cache.dart'; 8 | 9 | class LocalLoadCurrentAccount implements LoadCurrentAccount { 10 | final FetchSecureCacheStorage fetchSecureCacheStorage; 11 | LocalLoadCurrentAccount({@required this.fetchSecureCacheStorage}); 12 | 13 | Future load() async { 14 | try { 15 | final token = await fetchSecureCacheStorage.fetchSecure('token'); 16 | return AccountEntity(token); 17 | } catch (error) { 18 | throw DomainError.unexpected; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/data/usecases/save_current_account/local_save_current_account.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | 3 | import '../../../domain/entities/entities.dart'; 4 | import '../../../domain/helpers/helpers.dart'; 5 | import '../../../domain/usecases/usecases.dart'; 6 | 7 | import '../../cache/cache.dart'; 8 | 9 | class LocalSaveCurrentAccout implements SaveCurrentAccount { 10 | final SaveSecureCacheStorage saveSecureCacheStorage; 11 | LocalSaveCurrentAccout({@required this.saveSecureCacheStorage}); 12 | 13 | @override 14 | Future save(AccountEntity account) async { 15 | try { 16 | saveSecureCacheStorage.saveSecure(key: 'token', value: account.token); 17 | } catch (error) { 18 | throw DomainError.unexpected; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/data/usecases/save_current_account/save_current_account.dart: -------------------------------------------------------------------------------- 1 | export './local_save_current_account.dart'; 2 | -------------------------------------------------------------------------------- /lib/data/usecases/usecases.dart: -------------------------------------------------------------------------------- 1 | export 'authentication/authentication.dart'; 2 | export 'save_current_account/save_current_account.dart'; 3 | export 'load_current_account/load_current_account.dart'; 4 | -------------------------------------------------------------------------------- /lib/domain/entities/account_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class AccountEntity extends Equatable { 4 | final String token; 5 | 6 | AccountEntity(this.token); 7 | 8 | @override 9 | List get props => [token]; 10 | } 11 | -------------------------------------------------------------------------------- /lib/domain/entities/entities.dart: -------------------------------------------------------------------------------- 1 | export './account_entity.dart'; 2 | -------------------------------------------------------------------------------- /lib/domain/helpers/domain_error.dart: -------------------------------------------------------------------------------- 1 | enum DomainError { 2 | unexpected, 3 | invalidCredentials, 4 | } 5 | 6 | extension DomainErrorExtension on DomainError { 7 | String get description { 8 | switch (this) { 9 | case DomainError.invalidCredentials: 10 | return 'Credenciais inválidas.'; 11 | case DomainError.unexpected: 12 | return 'Algo de errado aconteceu. Tente novamento em breve.'; 13 | default: 14 | return 'Erro inesperado'; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/domain/helpers/helpers.dart: -------------------------------------------------------------------------------- 1 | export './domain_error.dart'; 2 | -------------------------------------------------------------------------------- /lib/domain/usecases/authentication.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:meta/meta.dart'; 3 | 4 | import '../entities/entities.dart'; 5 | 6 | abstract class Authentication { 7 | Future auth(AuthenticationParams params); 8 | } 9 | 10 | class AuthenticationParams extends Equatable { 11 | final String email; 12 | final String secret; 13 | 14 | AuthenticationParams({ 15 | @required this.email, 16 | @required this.secret, 17 | }); 18 | 19 | @override 20 | List get props => [email, secret]; 21 | } 22 | -------------------------------------------------------------------------------- /lib/domain/usecases/load_current_account.dart: -------------------------------------------------------------------------------- 1 | import '../entities/entities.dart'; 2 | 3 | abstract class LoadCurrentAccount { 4 | Future load(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/domain/usecases/save_current_account.dart: -------------------------------------------------------------------------------- 1 | import '../entities/entities.dart'; 2 | 3 | abstract class SaveCurrentAccount { 4 | Future save(AccountEntity account); 5 | } 6 | -------------------------------------------------------------------------------- /lib/domain/usecases/usecases.dart: -------------------------------------------------------------------------------- 1 | export './authentication.dart'; 2 | export './save_current_account.dart'; 3 | export './load_current_account.dart'; 4 | -------------------------------------------------------------------------------- /lib/infra/cache/cache.dart: -------------------------------------------------------------------------------- 1 | export './local_storage_adpter.dart'; 2 | -------------------------------------------------------------------------------- /lib/infra/cache/local_storage_adpter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_secure_storage/flutter_secure_storage.dart'; 2 | import 'package:meta/meta.dart'; 3 | 4 | import '../../data/cache/cache.dart'; 5 | 6 | class LocalStorageAdpter 7 | implements SaveSecureCacheStorage, FetchSecureCacheStorage { 8 | final FlutterSecureStorage secureStorage; 9 | LocalStorageAdpter({@required this.secureStorage}); 10 | 11 | @override 12 | Future saveSecure({ 13 | @required String key, 14 | @required String value, 15 | }) async => 16 | await secureStorage.write(key: key, value: value); 17 | 18 | @override 19 | Future fetchSecure(String key) async => 20 | await secureStorage.read(key: key); 21 | } 22 | -------------------------------------------------------------------------------- /lib/infra/http/http.dart: -------------------------------------------------------------------------------- 1 | export './http_adpter.dart'; 2 | -------------------------------------------------------------------------------- /lib/infra/http/http_adpter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:http/http.dart'; 3 | import 'package:meta/meta.dart'; 4 | 5 | import '../../data/http/http.dart'; 6 | 7 | class HttpAdpter implements HttpClient { 8 | final Client client; 9 | HttpAdpter(this.client); 10 | 11 | Future request({ 12 | @required String url, 13 | @required String method, 14 | Map body, 15 | }) async { 16 | final headers = { 17 | 'content-type': 'application/json', 18 | 'accept': 'application/json', 19 | }; 20 | final jsonBody = body != null ? jsonEncode(body) : null; 21 | var response = Response('', 500); 22 | try { 23 | if (method == 'post') { 24 | response = 25 | await client.post(Uri.parse(url), headers: headers, body: jsonBody); 26 | } 27 | } catch (error) { 28 | throw HttpError.serverError; 29 | } 30 | return _handleResponse(response); 31 | } 32 | 33 | Map _handleResponse(Response response) { 34 | if (response.statusCode == 200) { 35 | return response.body.isEmpty ? null : jsonDecode(response.body); 36 | } else if (response.statusCode == 204) { 37 | return null; 38 | } else if (response.statusCode == 400) { 39 | throw HttpError.badRequest; 40 | } else if (response.statusCode == 401) { 41 | throw HttpError.unauthorized; 42 | } else if (response.statusCode == 403) { 43 | throw HttpError.forbidden; 44 | } else if (response.statusCode == 404) { 45 | throw HttpError.notFound; 46 | } else { 47 | throw HttpError.serverError; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:get/get.dart'; 4 | 5 | import 'main/factories/factories.dart'; 6 | 7 | void main() { 8 | runApp(App()); 9 | } 10 | 11 | class App extends StatelessWidget { 12 | @override 13 | Widget build(BuildContext context) { 14 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark); 15 | 16 | return GetMaterialApp( 17 | title: 'Flutter Avaçado', 18 | theme: ThemeData( 19 | primaryColor: Colors.purple[600], 20 | primaryColorDark: Colors.purple[800], 21 | primaryColorLight: Colors.purple[400], 22 | accentColor: Colors.purple[600], 23 | backgroundColor: Colors.white, 24 | ), 25 | debugShowCheckedModeBanner: false, 26 | initialRoute: '/', 27 | getPages: [ 28 | GetPage(name: '/', page: makeSplashPage), 29 | GetPage(name: '/login', page: makeLoginPage), 30 | GetPage(name: '/surveys', page: () => Scaffold(body: Text('Enquetes'))), 31 | ], 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/main/builders/builders.dart: -------------------------------------------------------------------------------- 1 | export './validation_builder.dart'; 2 | -------------------------------------------------------------------------------- /lib/main/builders/validation_builder.dart: -------------------------------------------------------------------------------- 1 | import '../../validation/protocols/protocols.dart'; 2 | import '../../validation/validators/validators.dart'; 3 | 4 | class ValidationBuilder { 5 | static ValidationBuilder _instance; 6 | ValidationBuilder._(); 7 | 8 | String fieldName; 9 | List validations = []; 10 | 11 | static ValidationBuilder field(String fieldName) { 12 | _instance = ValidationBuilder._(); 13 | _instance.fieldName = fieldName; 14 | return _instance; 15 | } 16 | 17 | ValidationBuilder required() { 18 | validations.add(RequiredFieldValidation(fieldName)); 19 | return this; 20 | } 21 | 22 | ValidationBuilder email() { 23 | validations.add(EmailValidation(fieldName)); 24 | return this; 25 | } 26 | 27 | List build() => validations; 28 | } 29 | -------------------------------------------------------------------------------- /lib/main/factories/cache/cache.dart: -------------------------------------------------------------------------------- 1 | export './local_storage_adpter_factory.dart'; 2 | -------------------------------------------------------------------------------- /lib/main/factories/cache/local_storage_adpter_factory.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_secure_storage/flutter_secure_storage.dart'; 2 | 3 | import '../../../infra/cache/cache.dart'; 4 | 5 | LocalStorageAdpter makeLocalStorageAdpter() => 6 | LocalStorageAdpter(secureStorage: FlutterSecureStorage()); 7 | -------------------------------------------------------------------------------- /lib/main/factories/factories.dart: -------------------------------------------------------------------------------- 1 | export './http/http.dart'; 2 | export './usecases/usecases.dart'; 3 | export './pages/pages.dart'; 4 | export './cache/cache.dart'; 5 | -------------------------------------------------------------------------------- /lib/main/factories/http/api_url_factory.dart: -------------------------------------------------------------------------------- 1 | String makeApiUrl(String path) => 'http://fordevs.herokuapp.com/api/$path'; 2 | -------------------------------------------------------------------------------- /lib/main/factories/http/http.dart: -------------------------------------------------------------------------------- 1 | export './http_client_factory.dart'; 2 | export './api_url_factory.dart'; 3 | -------------------------------------------------------------------------------- /lib/main/factories/http/http_client_factory.dart: -------------------------------------------------------------------------------- 1 | import 'package:http/http.dart'; 2 | 3 | import '../../../infra/http/http.dart'; 4 | 5 | HttpAdpter makeHttpAdpter() { 6 | final client = Client(); 7 | return HttpAdpter(client); 8 | } 9 | -------------------------------------------------------------------------------- /lib/main/factories/pages/login/login.dart: -------------------------------------------------------------------------------- 1 | export './login_page_factory.dart'; 2 | export './login_presenter_factory.dart'; 3 | export './login_validation_factory.dart'; 4 | -------------------------------------------------------------------------------- /lib/main/factories/pages/login/login_page_factory.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../../../ui/pages/pages.dart'; 4 | 5 | import './login.dart'; 6 | 7 | Widget makeLoginPage() => LoginPage(makeGetxLoginPresenter()); 8 | -------------------------------------------------------------------------------- /lib/main/factories/pages/login/login_presenter_factory.dart: -------------------------------------------------------------------------------- 1 | import '../../../../presentation/presenters/presenters.dart'; 2 | import '../../../../ui/pages/pages.dart'; 3 | 4 | import '../../factories.dart'; 5 | 6 | LoginPresenter makeStreamLoginPresenter() => StreamLoginPresenter( 7 | validation: makeLoginValidation(), 8 | authentication: makeAuthentication(), 9 | ); 10 | 11 | LoginPresenter makeGetxLoginPresenter() => GetxLoginPresenter( 12 | validation: makeLoginValidation(), 13 | authentication: makeAuthentication(), 14 | saveCurrentAccount: makeLocalSaveCurrentAccount(), 15 | ); 16 | -------------------------------------------------------------------------------- /lib/main/factories/pages/login/login_validation_factory.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_avancado/main/builders/builders.dart'; 2 | 3 | import '../../../../presentation/protocols/protocols.dart'; 4 | import '../../../../validation/validators/validators.dart'; 5 | 6 | Validation makeLoginValidation() => ValidationComposite(makeLoginValidations()); 7 | 8 | makeLoginValidations() => [ 9 | ...ValidationBuilder.field('email').required().email().build(), 10 | ...ValidationBuilder.field('password').required().build(), 11 | ]; 12 | -------------------------------------------------------------------------------- /lib/main/factories/pages/pages.dart: -------------------------------------------------------------------------------- 1 | export './login/login.dart'; 2 | export './splash/splash.dart'; 3 | -------------------------------------------------------------------------------- /lib/main/factories/pages/splash/splash.dart: -------------------------------------------------------------------------------- 1 | export 'splash_page_factory.dart'; 2 | export 'splash_presenter_factory.dart'; 3 | -------------------------------------------------------------------------------- /lib/main/factories/pages/splash/splash_page_factory.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../../../ui/pages/pages.dart'; 4 | 5 | import 'splash.dart'; 6 | 7 | Widget makeSplashPage() => SplashPage(presenter: makeGetxSplashPresenter()); 8 | -------------------------------------------------------------------------------- /lib/main/factories/pages/splash/splash_presenter_factory.dart: -------------------------------------------------------------------------------- 1 | import '../../../../presentation/presenters/presenters.dart'; 2 | import '../../../../ui/pages/pages.dart'; 3 | import '../../factories.dart'; 4 | 5 | SplashPresenter makeGetxSplashPresenter() => 6 | GetxSplashPresenter(loadCurrentAccount: makeLocalLoadCurrentAccount()); 7 | -------------------------------------------------------------------------------- /lib/main/factories/usecases/authentication_factory.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_avancado/data/usecases/usecases.dart'; 2 | import '../../../domain/usecases/usecases.dart'; 3 | 4 | import '../http/http.dart'; 5 | 6 | Authentication makeAuthentication() => RemoteAuthentication( 7 | httpClient: makeHttpAdpter(), 8 | url: makeApiUrl('login'), 9 | ); 10 | -------------------------------------------------------------------------------- /lib/main/factories/usecases/load_current_account_factory.dart: -------------------------------------------------------------------------------- 1 | import '../../../data/usecases/usecases.dart'; 2 | import '../../../domain/usecases/usecases.dart'; 3 | 4 | import '../factories.dart'; 5 | 6 | LoadCurrentAccount makeLocalLoadCurrentAccount() => 7 | LocalLoadCurrentAccount(fetchSecureCacheStorage: makeLocalStorageAdpter()); 8 | -------------------------------------------------------------------------------- /lib/main/factories/usecases/save_current_account_factory.dart: -------------------------------------------------------------------------------- 1 | import '../../../data/usecases/usecases.dart'; 2 | import '../../../domain/usecases/usecases.dart'; 3 | 4 | import '../factories.dart'; 5 | 6 | SaveCurrentAccount makeLocalSaveCurrentAccount() => 7 | LocalSaveCurrentAccout(saveSecureCacheStorage: makeLocalStorageAdpter()); 8 | -------------------------------------------------------------------------------- /lib/main/factories/usecases/usecases.dart: -------------------------------------------------------------------------------- 1 | export './authentication_factory.dart'; 2 | export './save_current_account_factory.dart'; 3 | export './load_current_account_factory.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/presenters/getx_login_presenter.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | import 'package:meta/meta.dart'; 3 | 4 | import '../../ui/pages/pages.dart'; 5 | 6 | import '../../domain/usecases/usecases.dart'; 7 | import '../../domain/helpers/helpers.dart'; 8 | 9 | import '../protocols/protocols.dart'; 10 | 11 | class GetxLoginPresenter extends GetxController implements LoginPresenter { 12 | final Validation validation; 13 | final Authentication authentication; 14 | final SaveCurrentAccount saveCurrentAccount; 15 | GetxLoginPresenter({ 16 | @required this.validation, 17 | @required this.authentication, 18 | @required this.saveCurrentAccount, 19 | }); 20 | 21 | String _email; 22 | String _password; 23 | var _emailError = RxString(); 24 | var _passwordError = RxString(); 25 | var _mainError = RxString(); 26 | var _isFormValid = false.obs; 27 | var _isLoading = false.obs; 28 | var _navigateTo = RxString(); 29 | 30 | Stream get emailErrorStream => _emailError.stream; 31 | Stream get passwordErrorStream => _passwordError.stream; 32 | Stream get mainErrorStream => _mainError.stream; 33 | Stream get isValidFormStream => _isFormValid.stream; 34 | Stream get isLoadingStream => _isLoading.stream; 35 | Stream get navigateToStream => _navigateTo.stream; 36 | 37 | void _validateForm() => _isFormValid.value = _emailError.value == null && 38 | _passwordError.value == null && 39 | _email != null && 40 | _password != null; 41 | 42 | void validateEmail(String email) { 43 | _email = email; 44 | _emailError.value = validation.validate(field: 'email', value: email); 45 | _validateForm(); 46 | } 47 | 48 | void validatePassword(String password) { 49 | _password = password; 50 | _passwordError.value = 51 | validation.validate(field: 'password', value: password); 52 | _validateForm(); 53 | } 54 | 55 | Future auth() async { 56 | try { 57 | _isLoading.value = true; 58 | final result = await authentication 59 | .auth(AuthenticationParams(email: _email, secret: _password)); 60 | await saveCurrentAccount.save(result); 61 | _navigateTo.value = '/surveys'; 62 | } on DomainError catch (error) { 63 | _mainError.value = error.description; 64 | _isLoading.value = false; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/presentation/presenters/getx_splash_presenter.dart: -------------------------------------------------------------------------------- 1 | import 'package:get/get.dart'; 2 | import 'package:meta/meta.dart'; 3 | 4 | import '../../domain/usecases/usecases.dart'; 5 | import '../../ui/pages/pages.dart'; 6 | 7 | class GetxSplashPresenter implements SplashPresenter { 8 | final LoadCurrentAccount loadCurrentAccount; 9 | GetxSplashPresenter({@required this.loadCurrentAccount}); 10 | 11 | var _navigateTo = RxString(); 12 | 13 | @override 14 | Future checkAccount({int durationInSeconds = 3}) async { 15 | await Future.delayed(Duration(seconds: durationInSeconds)); 16 | try { 17 | var account = await loadCurrentAccount.load(); 18 | _navigateTo.value = account.isNull ? '/login' : '/surveys'; 19 | } catch (error) { 20 | _navigateTo.value = '/login'; 21 | } 22 | } 23 | 24 | @override 25 | Stream get navigateToStream => _navigateTo.stream; 26 | } 27 | -------------------------------------------------------------------------------- /lib/presentation/presenters/presenters.dart: -------------------------------------------------------------------------------- 1 | export './stream_login_presenter.dart'; 2 | export './getx_login_presenter.dart'; 3 | export 'getx_splash_presenter.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/protocols/protocols.dart: -------------------------------------------------------------------------------- 1 | export './validation.dart'; 2 | -------------------------------------------------------------------------------- /lib/presentation/protocols/validation.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | 3 | abstract class Validation { 4 | validate({@required String field, @required String value}); 5 | } 6 | -------------------------------------------------------------------------------- /lib/ui/pages/login/login_presenter.dart: -------------------------------------------------------------------------------- 1 | abstract class LoginPresenter { 2 | Stream get emailErrorStream; 3 | Stream get passwordErrorStream; 4 | Stream get isValidFormStream; 5 | Stream get isLoadingStream; 6 | Stream get mainErrorStream; 7 | Stream get navigateToStream; 8 | 9 | void validateEmail(String email); 10 | void validatePassword(String password); 11 | void auth(); 12 | void dispose(); 13 | } 14 | -------------------------------------------------------------------------------- /lib/ui/pages/pages.dart: -------------------------------------------------------------------------------- 1 | export 'login/login_page.dart'; 2 | export 'login/login_presenter.dart'; 3 | export 'splash/splash_page.dart'; 4 | export 'splash/splash_presenter.dart'; 5 | -------------------------------------------------------------------------------- /lib/ui/pages/splash/splash_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get/get.dart'; 3 | 4 | import 'splash_presenter.dart'; 5 | 6 | class SplashPage extends StatelessWidget { 7 | final SplashPresenter presenter; 8 | SplashPage({this.presenter}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | presenter.checkAccount(); 13 | return Builder(builder: (context) { 14 | presenter.navigateToStream.listen((page) { 15 | if (page?.isNotEmpty == true) Get.offAllNamed(page); 16 | }); 17 | return Container( 18 | color: Colors.white, 19 | height: MediaQuery.of(context).size.height, 20 | width: MediaQuery.of(context).size.width, 21 | child: Center( 22 | child: CircularProgressIndicator(), 23 | ), 24 | ); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/ui/pages/splash/splash_presenter.dart: -------------------------------------------------------------------------------- 1 | abstract class SplashPresenter { 2 | Stream get navigateToStream; 3 | Future checkAccount({int durationInSeconds = 3}); 4 | } 5 | -------------------------------------------------------------------------------- /lib/utils/i18n/i18n.dart: -------------------------------------------------------------------------------- 1 | export 'resources.dart'; 2 | -------------------------------------------------------------------------------- /lib/utils/i18n/resources.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | import './strings/strings.dart'; 4 | 5 | class R { 6 | static Translations strings = PtBr(); 7 | 8 | static void load(Locale locale) { 9 | switch (locale.toString()) { 10 | case 'en_US': 11 | strings = EnUs(); 12 | break; 13 | default: 14 | strings = PtBr(); 15 | break; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/utils/i18n/strings/en_us.dart: -------------------------------------------------------------------------------- 1 | import 'translations.dart'; 2 | 3 | class EnUs implements Translations { 4 | @override 5 | String get addAccount => 'Add account'; 6 | } 7 | -------------------------------------------------------------------------------- /lib/utils/i18n/strings/pt_br.dart: -------------------------------------------------------------------------------- 1 | import 'translations.dart'; 2 | 3 | class PtBr implements Translations { 4 | @override 5 | String get addAccount => 'Criar conta'; 6 | } 7 | -------------------------------------------------------------------------------- /lib/utils/i18n/strings/strings.dart: -------------------------------------------------------------------------------- 1 | export 'en_us.dart'; 2 | export 'pt_br.dart'; 3 | export 'translations.dart'; 4 | -------------------------------------------------------------------------------- /lib/utils/i18n/strings/translations.dart: -------------------------------------------------------------------------------- 1 | abstract class Translations { 2 | String get addAccount; 3 | } 4 | -------------------------------------------------------------------------------- /lib/validation/protocols/field_validation.dart: -------------------------------------------------------------------------------- 1 | abstract class FieldValidation { 2 | String get field; 3 | String validate(String value); 4 | } 5 | -------------------------------------------------------------------------------- /lib/validation/protocols/protocols.dart: -------------------------------------------------------------------------------- 1 | export 'field_validation.dart'; 2 | -------------------------------------------------------------------------------- /lib/validation/validators/email_validation.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | import '../protocols/protocols.dart'; 4 | 5 | class EmailValidation extends Equatable implements FieldValidation { 6 | final String field; 7 | EmailValidation(this.field); 8 | 9 | @override 10 | String validate(String value) => 11 | value?.isNotEmpty != true || value.contains('@') 12 | ? null 13 | : 'Campo inválido.'; 14 | 15 | @override 16 | List get props => [field]; 17 | } 18 | -------------------------------------------------------------------------------- /lib/validation/validators/required_field_validation.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | import '../protocols/protocols.dart'; 4 | 5 | class RequiredFieldValidation extends Equatable implements FieldValidation { 6 | final String field; 7 | RequiredFieldValidation(this.field); 8 | 9 | @override 10 | String validate(String value) => 11 | value?.isNotEmpty == true ? null : 'Campo obrigatório.'; 12 | 13 | @override 14 | List get props => [field]; 15 | } 16 | -------------------------------------------------------------------------------- /lib/validation/validators/validation_composite.dart: -------------------------------------------------------------------------------- 1 | import '../../presentation/protocols/protocols.dart'; 2 | 3 | import '../protocols/protocols.dart'; 4 | 5 | class ValidationComposite implements Validation { 6 | final List validations; 7 | ValidationComposite(this.validations); 8 | 9 | @override 10 | validate({String field, String value}) { 11 | String error; 12 | for (var validation in validations.where((v) => v.field == field)) { 13 | error = validation.validate(value); 14 | if (error != null && error != '') return error; 15 | } 16 | return error; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/validation/validators/validators.dart: -------------------------------------------------------------------------------- 1 | export './required_field_validation.dart'; 2 | export './email_validation.dart'; 3 | export './validation_composite.dart'; 4 | -------------------------------------------------------------------------------- /metrics/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::before, 3 | *::after { 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | padding: var(--dart-code-metrics-body-padding); 9 | font-family: var(--dart-code-metrics-font-family); 10 | font-size: var(--dart-code-metrics-body-font-size); 11 | } 12 | 13 | table { 14 | width: 100%; 15 | margin: 0; 16 | border-spacing: 0; 17 | font-size: inherit; 18 | table-layout: fixed; 19 | } 20 | 21 | table td { 22 | vertical-align: top; 23 | } 24 | 25 | pre, 26 | code { 27 | margin: 0; 28 | } 29 | -------------------------------------------------------------------------------- /metrics/lib/data/cache/cache.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/cache/cache.dart

All files : lib/data/cache/cache.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
export './save_secure_cache_storage.dart';
2 | export './fetch_secure_cache_storage.dart';
3 | 
-------------------------------------------------------------------------------- /metrics/lib/data/cache/fetch_secure_cache_storage.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/cache/fetch_secure_cache_storage.dart

All files : lib/data/cache/fetch_secure_cache_storage.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
abstract class FetchSecureCacheStorage {
2 |   Future<String> fetchSecure(String key);
3 | }
4 | 
-------------------------------------------------------------------------------- /metrics/lib/data/cache/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/cache

All files : lib/data/cache

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
cache.dart00000
fetch_secure_cache_storage.dart00000
save_secure_cache_storage.dart00000
Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/data/http/http.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/http/http.dart

All files : lib/data/http/http.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
export './http_client.dart';
2 | export './http_error.dart';
3 | 
-------------------------------------------------------------------------------- /metrics/lib/data/http/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/http

All files : lib/data/http

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
http.dart00000
http_client.dart00000
http_error.dart00000
Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/data/models/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/models

All files : lib/data/models

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
models.dart00000
remote_account_model.dart308701
Cyclomatic complexity : 3
Lines of executable code : 0
Maintainability index : 43
Number of Arguments : 0
Maximum Nesting : 1
-------------------------------------------------------------------------------- /metrics/lib/data/models/models.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/models/models.dart

All files : lib/data/models/models.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './remote_account_model.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/data/usecases/authentication/authentication.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/usecases/authentication/authentication.dart

All files : lib/data/usecases/authentication/authentication.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './remote_authentication.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/data/usecases/authentication/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/usecases/authentication

All files : lib/data/usecases/authentication

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
authentication.dart00000
remote_authentication.dart508101
Cyclomatic complexity : 5
Lines of executable code : 0
Maintainability index : 40
Number of Arguments : 0
Maximum Nesting : 1
-------------------------------------------------------------------------------- /metrics/lib/data/usecases/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/usecases

All files : lib/data/usecases

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
usecases.dart00000
Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/data/usecases/load_current_account/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/usecases/load_current_account

All files : lib/data/usecases/load_current_account

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
load_current_account.dart00000
local_load_current_account.dart207202
Cyclomatic complexity : 2
Lines of executable code : 0
Maintainability index : 36
Number of Arguments : 0
Maximum Nesting : 1
-------------------------------------------------------------------------------- /metrics/lib/data/usecases/load_current_account/load_current_account.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/usecases/load_current_account/load_current_account.dart

All files : lib/data/usecases/load_current_account/load_current_account.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './local_load_current_account.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/data/usecases/save_current_account/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/usecases/save_current_account

All files : lib/data/usecases/save_current_account

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
local_save_current_account.dart207412
save_current_account.dart00000
Cyclomatic complexity : 2
Lines of executable code : 0
Maintainability index : 37
Number of Arguments : 1
Maximum Nesting : 1
-------------------------------------------------------------------------------- /metrics/lib/data/usecases/save_current_account/save_current_account.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/usecases/save_current_account/save_current_account.dart

All files : lib/data/usecases/save_current_account/save_current_account.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './local_save_current_account.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/data/usecases/usecases.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/data/usecases/usecases.dart

All files : lib/data/usecases/usecases.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
export 'authentication/authentication.dart';
2 | export 'save_current_account/save_current_account.dart';
3 | export 'load_current_account/load_current_account.dart';
4 | 
-------------------------------------------------------------------------------- /metrics/lib/domain/entities/entities.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/domain/entities/entities.dart

All files : lib/domain/entities/entities.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './account_entity.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/domain/entities/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/domain/entities

All files : lib/domain/entities

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
account_entity.dart109900
entities.dart00000
Cyclomatic complexity : 1
Lines of executable code : 0
Maintainability index : 49
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/domain/helpers/helpers.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/domain/helpers/helpers.dart

All files : lib/domain/helpers/helpers.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './domain_error.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/domain/helpers/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/domain/helpers

All files : lib/domain/helpers

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
domain_error.dart407401
helpers.dart00000
Cyclomatic complexity : 4
Lines of executable code : 0
Maintainability index : 37
Number of Arguments : 0
Maximum Nesting : 1
-------------------------------------------------------------------------------- /metrics/lib/domain/usecases/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/domain/usecases

All files : lib/domain/usecases

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
authentication.dart109700
load_current_account.dart00000
save_current_account.dart00000
usecases.dart00000
Cyclomatic complexity : 1
Lines of executable code : 0
Maintainability index : 24
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/domain/usecases/usecases.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/domain/usecases/usecases.dart

All files : lib/domain/usecases/usecases.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
export './authentication.dart';
2 | export './save_current_account.dart';
3 | export './load_current_account.dart';
4 | 
-------------------------------------------------------------------------------- /metrics/lib/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib

All files : lib

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
main.dart207711
Cyclomatic complexity : 2
Lines of executable code : 0
Maintainability index : 77
Number of Arguments : 1
Maximum Nesting : 1
-------------------------------------------------------------------------------- /metrics/lib/infra/cache/cache.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/infra/cache/cache.dart

All files : lib/infra/cache/cache.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './local_storage_adpter.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/infra/cache/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/infra/cache

All files : lib/infra/cache

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
cache.dart00000
local_storage_adpter.dart208520
Cyclomatic complexity : 2
Lines of executable code : 0
Maintainability index : 42
Number of Arguments : 1
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/infra/http/http.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/infra/http/http.dart

All files : lib/infra/http/http.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './http_adpter.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/infra/http/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/infra/http

All files : lib/infra/http

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
http.dart00000
http_adpter.dart1205923
Cyclomatic complexity : 12
Lines of executable code : 0
Maintainability index : 29
Number of Arguments : 1
Maximum Nesting : 2
-------------------------------------------------------------------------------- /metrics/lib/main/builders/builders.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/builders/builders.dart

All files : lib/main/builders/builders.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './validation_builder.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/main/builders/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/builders

All files : lib/main/builders

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
builders.dart00000
validation_builder.dart408801
Cyclomatic complexity : 4
Lines of executable code : 0
Maintainability index : 44
Number of Arguments : 0
Maximum Nesting : 1
-------------------------------------------------------------------------------- /metrics/lib/main/factories/cache/cache.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/cache/cache.dart

All files : lib/main/factories/cache/cache.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './local_storage_adpter_factory.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/main/factories/cache/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/cache

All files : lib/main/factories/cache

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
cache.dart00000
local_storage_adpter_factory.dart108800
Cyclomatic complexity : 1
Lines of executable code : 0
Maintainability index : 44
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/main/factories/factories.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/factories.dart

All files : lib/main/factories/factories.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
4
export './http/http.dart';
2 | export './usecases/usecases.dart';
3 | export './pages/pages.dart';
4 | export './cache/cache.dart';
5 | 
-------------------------------------------------------------------------------- /metrics/lib/main/factories/http/http.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/http/http.dart

All files : lib/main/factories/http/http.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
export './http_client_factory.dart';
2 | export './api_url_factory.dart';
3 | 
-------------------------------------------------------------------------------- /metrics/lib/main/factories/http/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/http

All files : lib/main/factories/http

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
api_url_factory.dart109910
http.dart00000
http_client_factory.dart108601
Cyclomatic complexity : 2
Lines of executable code : 0
Maintainability index : 62
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/main/factories/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories

All files : lib/main/factories

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
factories.dart00000
Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/main/factories/pages/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/pages

All files : lib/main/factories/pages

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
pages.dart00000
Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/main/factories/pages/login/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/pages/login

All files : lib/main/factories/pages/login

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
login.dart00000
login_page_factory.dart109700
login_presenter_factory.dart208000
login_validation_factory.dart208700
Cyclomatic complexity : 5
Lines of executable code : 0
Maintainability index : 66
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/main/factories/pages/login/login.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/pages/login/login.dart

All files : lib/main/factories/pages/login/login.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
export './login_page_factory.dart';
2 | export './login_presenter_factory.dart';
3 | export './login_validation_factory.dart';
4 | 
-------------------------------------------------------------------------------- /metrics/lib/main/factories/pages/pages.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/pages/pages.dart

All files : lib/main/factories/pages/pages.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
export './login/login.dart';
2 | export './splash/splash.dart';
3 | 
-------------------------------------------------------------------------------- /metrics/lib/main/factories/pages/splash/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/pages/splash

All files : lib/main/factories/pages/splash

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
splash.dart00000
splash_page_factory.dart109500
splash_presenter_factory.dart108800
Cyclomatic complexity : 2
Lines of executable code : 0
Maintainability index : 61
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/main/factories/pages/splash/splash.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/pages/splash/splash.dart

All files : lib/main/factories/pages/splash/splash.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
export 'splash_page_factory.dart';
2 | export 'splash_presenter_factory.dart';
3 | 
-------------------------------------------------------------------------------- /metrics/lib/main/factories/usecases/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/usecases

All files : lib/main/factories/usecases

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
authentication_factory.dart108500
load_current_account_factory.dart108800
save_current_account_factory.dart108800
usecases.dart00000
Cyclomatic complexity : 3
Lines of executable code : 0
Maintainability index : 65
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/main/factories/usecases/usecases.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/main/factories/usecases/usecases.dart

All files : lib/main/factories/usecases/usecases.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
export './authentication_factory.dart';
2 | export './save_current_account_factory.dart';
3 | export './load_current_account_factory.dart';
4 | 
-------------------------------------------------------------------------------- /metrics/lib/presentation/presenters/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/presentation/presenters

All files : lib/presentation/presenters

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
getx_login_presenter.dart1408700
getx_splash_presenter.dart408211
presenters.dart00000
stream_login_presenter.dart3508000
Cyclomatic complexity : 53
Lines of executable code : 0
Maintainability index : 62
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/presentation/presenters/presenters.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/presentation/presenters/presenters.dart

All files : lib/presentation/presenters/presenters.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
export './stream_login_presenter.dart';
2 | export './getx_login_presenter.dart';
3 | export 'getx_splash_presenter.dart';
4 | 
-------------------------------------------------------------------------------- /metrics/lib/presentation/protocols/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/presentation/protocols

All files : lib/presentation/protocols

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
protocols.dart00000
validation.dart00000
Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/presentation/protocols/protocols.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/presentation/protocols/protocols.dart

All files : lib/presentation/protocols/protocols.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export './validation.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/ui/pages/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/ui/pages

All files : lib/ui/pages

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
pages.dart00000
Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/ui/pages/login/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/ui/pages/login

All files : lib/ui/pages/login

FileCyclomatic complexity / violationsLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
login_page.dart25 / 107202
login_presenter.dart00000
Cyclomatic complexity / violations : 25 / 1
Lines of executable code : 0
Maintainability index : 36
Number of Arguments : 0
Maximum Nesting : 1
-------------------------------------------------------------------------------- /metrics/lib/ui/pages/pages.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/ui/pages/pages.dart

All files : lib/ui/pages/pages.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
4
export 'login/login_page.dart';
2 | export 'login/login_presenter.dart';
3 | export 'splash/splash_page.dart';
4 | export 'splash/splash_presenter.dart';
5 | 
-------------------------------------------------------------------------------- /metrics/lib/ui/pages/splash/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/ui/pages/splash

All files : lib/ui/pages/splash

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
splash_page.dart505613
splash_presenter.dart00000
Cyclomatic complexity : 5
Lines of executable code : 0
Maintainability index : 28
Number of Arguments : 1
Maximum Nesting : 2
-------------------------------------------------------------------------------- /metrics/lib/ui/pages/splash/splash_presenter.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/ui/pages/splash/splash_presenter.dart

All files : lib/ui/pages/splash/splash_presenter.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
4
abstract class SplashPresenter {
2 |   Stream get navigateToStream;
3 |   Future<void> checkAccount({int durationInSeconds = 3});
4 | }
5 | 
-------------------------------------------------------------------------------- /metrics/lib/utils/i18n/i18n.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/utils/i18n/i18n.dart

All files : lib/utils/i18n/i18n.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export 'resources.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/utils/i18n/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/utils/i18n

All files : lib/utils/i18n

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
i18n.dart00000
resources.dart307011
Cyclomatic complexity : 3
Lines of executable code : 0
Maintainability index : 35
Number of Arguments : 1
Maximum Nesting : 1
-------------------------------------------------------------------------------- /metrics/lib/utils/i18n/strings/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/utils/i18n/strings

All files : lib/utils/i18n/strings

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
en_us.dart109900
pt_br.dart109900
strings.dart00000
translations.dart00000
Cyclomatic complexity : 2
Lines of executable code : 0
Maintainability index : 49
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/utils/i18n/strings/strings.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/utils/i18n/strings/strings.dart

All files : lib/utils/i18n/strings/strings.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
export 'en_us.dart';
2 | export 'pt_br.dart';
3 | export 'translations.dart';
4 | 
-------------------------------------------------------------------------------- /metrics/lib/utils/i18n/strings/translations.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/utils/i18n/strings/translations.dart

All files : lib/utils/i18n/strings/translations.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
abstract class Translations {
2 |   String get addAccount;
3 | }
4 | 
-------------------------------------------------------------------------------- /metrics/lib/validation/protocols/field_validation.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/validation/protocols/field_validation.dart

All files : lib/validation/protocols/field_validation.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
4
abstract class FieldValidation {
2 |   String get field;
3 |   String validate(String value);
4 | }
5 | 
-------------------------------------------------------------------------------- /metrics/lib/validation/protocols/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/validation/protocols

All files : lib/validation/protocols

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
field_validation.dart00000
protocols.dart00000
Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
-------------------------------------------------------------------------------- /metrics/lib/validation/protocols/protocols.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/validation/protocols/protocols.dart

All files : lib/validation/protocols/protocols.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
export 'field_validation.dart';
2 | 
-------------------------------------------------------------------------------- /metrics/lib/validation/validators/index.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/validation/validators

All files : lib/validation/validators

FileCyclomatic complexityLines of executable codeMaintainability indexNumber of ArgumentsMaximum Nesting
email_validation.dart508810
required_field_validation.dart409210
validation_composite.dart406822
validators.dart00000
Cyclomatic complexity : 13
Lines of executable code : 0
Maintainability index : 62
Number of Arguments : 1
Maximum Nesting : 1
-------------------------------------------------------------------------------- /metrics/lib/validation/validators/validators.html: -------------------------------------------------------------------------------- 1 | Metrics report for lib/validation/validators/validators.dart

All files : lib/validation/validators/validators.dart

Cyclomatic complexity : 0
Lines of executable code : 0
Maintainability index : 0
Number of Arguments : 0
Maximum Nesting : 0
ComplexitySource code
1
2
3
export './required_field_validation.dart';
2 | export './email_validation.dart';
3 | export './validation_composite.dart';
4 | 
-------------------------------------------------------------------------------- /metrics/normalize.css: -------------------------------------------------------------------------------- 1 | /*! based on normalize.css v5.0.0 | MIT License | github.com/necolas */ 2 | 3 | /* Document ========================================================================== */ 4 | 5 | /* 6 | * 1. Correct the line height in all browsers. 7 | * 2. Prevent adjustments of font size after orientation changes in iOS. 8 | */ 9 | 10 | html { 11 | font-family: sans-serif; /* 1 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /* Sections ========================================================================== */ 16 | 17 | /* 18 | * Remove the margin in all browsers (opinionated). 19 | */ 20 | body { 21 | margin: 0; 22 | } 23 | 24 | h1, 25 | h2, 26 | h3, 27 | h4, 28 | h5, 29 | h6 { 30 | margin: 0; 31 | } 32 | 33 | p { 34 | margin: 0; 35 | } 36 | 37 | /* Grouping content ========================================================================== */ 38 | 39 | /* 40 | * 1. Add the correct box sizing in Firefox. 41 | * 2. Show the overflow in Edge and IE. 42 | */ 43 | hr { 44 | box-sizing: content-box; /* 1 */ 45 | height: 0; /* 1 */ 46 | overflow: visible; /* 2 */ 47 | } 48 | 49 | /** 50 | * 1. Correct the inheritance and scaling of font size in all browsers. 51 | * 2. Correct the odd `em` font sizing in all browsers. 52 | */ 53 | pre { 54 | font-family: monospace, monospace; /* 1 */ 55 | font-size: 1em; /* 2 */ 56 | } 57 | 58 | /* Text-level semantics ========================================================================== */ 59 | 60 | /* 61 | * Remove gaps in links underline in iOS 8+ and Safari 8+. 62 | */ 63 | a { 64 | -webkit-text-decoration-skip: objects; 65 | outline: none; 66 | } 67 | 68 | /* 69 | * Remove the outline on focused links when they are also active or hovered in all browsers (opinionated). 70 | */ 71 | a:active, 72 | a:hover { 73 | outline-width: 0; 74 | } 75 | 76 | /** 77 | * 1. Correct the inheritance and scaling of font size in all browsers. 78 | * 2. Correct the odd `em` font sizing in all browsers. 79 | */ 80 | code { 81 | font-family: monospace, monospace; /* 1 */ 82 | font-size: 1em; /* 2 */ 83 | } 84 | 85 | /* 86 | * Prevent text blurriness in Firefox on macOS 87 | * link: https://stackoverflow.com/a/44898465 88 | */ 89 | @supports (-moz-appearance: meterbar) and (background-blend-mode: difference, normal) { 90 | 91 | body { 92 | -moz-osx-font-smoothing: grayscale; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /requirements/cache/fetch_secure_cache.md: -------------------------------------------------------------------------------- 1 | # Fetch Secure Cache 2 | 3 | > ## Caso de sucesso 4 | 1. ✅ Solicitar dados de uma chave do cache seguro 5 | 2. ✅ Retornar o valor armazenado para aquela chave 6 | 7 | > ## Exeção - Erro ao carregar os dados do cache seguro 8 | 1. ✅ Deve repassar a exceção para quem chamou essa classe -------------------------------------------------------------------------------- /requirements/http/http_responses.md: -------------------------------------------------------------------------------- 1 | # HTTP 2 | 3 | > ## Sucesso 4 | 1. ✅ Request com verbo http válido (post) 5 | 2. ✅ Passar nos headers o content type JSON 6 | 3. ✅ Chamar request com body correto 7 | 4. ✅ Ok - 200 e resposta com dados 8 | 5. ✅ No content - 204 e resposta sem dados 9 | 10 | > ## Erros 11 | 1. ✅ Bad request - 400 12 | 2. ✅ Unauthorized - 401 13 | 3. ✅ Forbidden - 403 14 | 4. ✅ Not found - 404 15 | 5. ✅ Internal server error - 500 16 | 17 | > ## Exceção - Status code diferente dos citados acima 18 | 1. ✅ Internal server error - 500 19 | 20 | > ## Exceção - Http request deu alguma exceção 21 | 1. ✅ Internal server error - 500 22 | 23 | > ## Exceção - Verbo http inválido 24 | 1. ✅ Internal server error - 500 -------------------------------------------------------------------------------- /requirements/login/login.feature: -------------------------------------------------------------------------------- 1 | Feature: Login 2 | Como um cliente 3 | Quero poder acessar minha conta e me manter logado 4 | Para que eu possa ver e responder enquetes de forma rápida 5 | 6 | Cenário: Credenciais Válidas 7 | Dado que o cliente informou credenciais válidas 8 | Quando solicitar para fazer login 9 | Então o sistema deve enviar o usuário para a tela de pesquisas 10 | E manter o usuário conectado 11 | 12 | Cenário: Credenciais Inválidas 13 | Dado que o cliente informou credenciais inválidas 14 | Quando solicitar para fazer login 15 | Então o sistema deve retornar uma mensagem de erro -------------------------------------------------------------------------------- /requirements/login/login_page.md: -------------------------------------------------------------------------------- 1 | # Login Page 2 | 3 | > ## Regras 4 | 1. ✅ Os campos devem começar sem exibir mensagem de erro 5 | 2. ✅ O botão de fazer login deve começar desabilitado 6 | 3. ✅ Após digitar algo em um campo, a mensagem de erro só deve sumir se o campo for válido 7 | 4. ✅ Validar email quando o usuário digitar no campo 8 | 5. ✅ Mostrar mensagem de erro se o email for inválido 9 | 6. ✅ Remover mensagem de erro se o email for válido 10 | 7. ✅ Validar senha quando o usuário digitar no campo 11 | 8. ✅ Mostrar mensagem de erro se a senha for inválida 12 | 9. ✅ Remover mensagem de erro se a senha for válida 13 | 10. ✅ Habilitar o botão de fazer login se todos os campos forem válidos 14 | 11. ✅ Desabilitar o botão de fazer login se algum campo for inválido 15 | 12. ✅ Exibir loading no início da ação de login 16 | 13. ✅ Chamar metodo de autenticar 17 | 14. ✅ Exibir mensagem de erro caso o login falhe 18 | 15. ✅ Esconder loading no fim da ação de login 19 | 16. ✅ Fechar streams quando a página for encerrada -------------------------------------------------------------------------------- /requirements/login/login_presenter.md: -------------------------------------------------------------------------------- 1 | # Login Presenter 2 | 3 | > ## Regras 4 | 1. ✅ Chamar Validation ao alterar o email 5 | 2. ✅ Notificar o emailErrorStream com o mesmo erro do Validation, caso retorne erro 6 | 3. ✅ Notificar o emailErrorStream com null, caso o Validation não retorne erro 7 | 4. ✅ Não notificar o emailErrorStream se o valor for igual ao último 8 | 5. ✅ Notificar o isFormValidStream após alterar o email 9 | 6. ✅ Chamar Validation ao alterar a senha 10 | 7. ✅ Notificar o passwordErrorStream com o mesmo erro do Validation, caso retorne erro 11 | 8. ✅ Notificar o passwordErrorStream com null, caso o Validation não retorne erro 12 | 9. ✅ Não notificar o passwordErrorStream se o valor for igual ao último 13 | 10. ✅ Notificar o isFormValidStream após alterar a senha 14 | 11. ✅ Para o formulário estar válido todos os Streams de erro precisam estar null e todos os campos obrigatórios não podem estar vazios 15 | 12. ✅ Não notificar o isFormValidStream se o valor for igual ao último 16 | 13. ✅ Chamar o Authentication com email e senha corretos 17 | 14. ✅ Notificar o isLoadingStream como true antes de chamar o Authentication 18 | 15. ✅ Notificar o isLoadingStream como false no fim do Authentication 19 | 16. ✅ Notificar o mainErrorStream caso o Authentication retorne um DomainError 20 | 17. ✅ Fechar todos os Streams no dispose 21 | 18. ✅ Gravar o Account no cache em caso de sucesso 22 | 19. ✅ Levar o usuário pra tela de Enquetes em caso de sucesso 23 | 20. ✅ Notificar o mainErrorStream caso o SaveCurrentAccount retorne erro -------------------------------------------------------------------------------- /requirements/login/remote_authentication_use_case.md: -------------------------------------------------------------------------------- 1 | # Remote Authentication Use Case 2 | 3 | > ## Caso de sucesso 4 | 1. ✅ Sistema valida os dados 5 | 2. ✅ Sistema faz uma requisição para a URL da API de login 6 | 3. ✅ Sistema valida os dados recebidos da API 7 | 4. ✅ Sistema entrega os dados da conta do usuário 8 | 9 | > ## Exceção - URL inválida 10 | 1. ✅ Sistema retorna uma mensagem de erro inesperado 11 | 12 | > ## Exceção - Dados inválidos 13 | 1. ✅ Sistema retorna uma mensagem de erro inesperado 14 | 15 | > ## Exceção - Resposta inválida 16 | 1. ✅ Sistema retorna uma mensagem de erro inesperado 17 | 18 | > ## Exceção - Falha no servidor 19 | 1. ✅ Sistema retorna uma mensagem de erro inesperado 20 | 21 | > ## Exceção - Credenciais inválidas 22 | 1. ✅ Sistema retorna uma mensagem de erro informando que as credenciais estão erradas -------------------------------------------------------------------------------- /requirements/splash/splash_page.md: -------------------------------------------------------------------------------- 1 | # Splash Page 2 | 3 | > ## Regras 4 | 1. ✅ Mostrar loading ao iniciar a página 5 | 2. ✅ Chamar o carregar dados da conta atual 6 | 3. ✅ Navegar para a página correta ao final do carregamento -------------------------------------------------------------------------------- /requirements/splash/splash_presenter.md: -------------------------------------------------------------------------------- 1 | # Splash Presenter 2 | 3 | > ## Regras 4 | 1. ✅ Chamar o LoadCurrentAccount 5 | 2. ✅ Levar o usuário pra tela de Enquetes se tiver dados no cache 6 | 3. ✅ Levar o usuário pra tela de Login se não tiver dados no cache 7 | 4. ✅ Lever o usuário pra tela de Login e der erro ao carregar dados do cache -------------------------------------------------------------------------------- /requirements/use_cases/local_load_current_account.md: -------------------------------------------------------------------------------- 1 | # Local Load Current Account Use Case 2 | 3 | > ## Caso de sucesso 4 | 1. ✅ Sistema solicita o token de acesso do usuário gravado no Cache Seguro 5 | 2. ✅ Sistema retorna os dados da conta do usuário 6 | 7 | > ## Exeção - Falha ao gravar no cache 8 | 1. ✅ Sistema retorna uma mensagem de erro inesperado -------------------------------------------------------------------------------- /requirements/use_cases/local_save_current_account.md: -------------------------------------------------------------------------------- 1 | # Local Save Current Account Use Case 2 | 3 | > ## Caso de sucesso 4 | 1. ✅ Sistema grava o token de acesso do usuário no Cache de forma segura 5 | 6 | > ## Exeção - Falha ao gravar no cache 7 | 1. ✅ Sistema retorna uma mensagem de erro inesperado -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | # Project identification 2 | sonar.projectKey=flutter_rocks 3 | sonar.projectName=Flutter Rocks 4 | sonar.projectVersion=1.0 5 | 6 | sonar.host.url=http://host.docker.internal:9000 7 | sonar.login=admin 8 | sonar.password=123 9 | 10 | # Source code location. 11 | # Path is relative to the sonar-project.properties file. Defaults to . 12 | # Use commas to specify more than one folder. 13 | sonar.sources=lib 14 | sonar.tests=test 15 | 16 | # Encoding of the source code. Default is default system encoding. 17 | sonar.sourceEncoding=UTF-8 -------------------------------------------------------------------------------- /test/data/usecases/load_current_account/load_current_account_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:faker/faker.dart'; 2 | import 'package:flutter_avancado/data/cache/cache.dart'; 3 | import 'package:flutter_avancado/data/usecases/usecases.dart'; 4 | import 'package:flutter_avancado/domain/entities/entities.dart'; 5 | import 'package:flutter_avancado/domain/helpers/helpers.dart'; 6 | import 'package:mockito/mockito.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | class FetchSecureCacheStorageSpy extends Mock 10 | implements FetchSecureCacheStorage {} 11 | 12 | main() { 13 | LocalLoadCurrentAccount sut; 14 | FetchSecureCacheStorage fetchSecureCacheStorage; 15 | String token; 16 | 17 | mockSuccess() => when(fetchSecureCacheStorage.fetchSecure(any)) 18 | .thenAnswer((_) async => token); 19 | mockUnexpectedError() => 20 | when(fetchSecureCacheStorage.fetchSecure(any)).thenThrow(Exception()); 21 | 22 | setUp(() { 23 | fetchSecureCacheStorage = FetchSecureCacheStorageSpy(); 24 | sut = LocalLoadCurrentAccount( 25 | fetchSecureCacheStorage: fetchSecureCacheStorage, 26 | ); 27 | token = faker.guid.guid(); 28 | 29 | mockSuccess(); 30 | }); 31 | 32 | test('Should call FetchSecureCacheStorage with corrent values', () async { 33 | await sut.load(); 34 | 35 | verify(fetchSecureCacheStorage.fetchSecure('token')).called(1); 36 | }); 37 | 38 | test('Should return an AccountEntity', () async { 39 | final account = await sut.load(); 40 | 41 | expect(account, AccountEntity(token)); 42 | }); 43 | 44 | test( 45 | 'Should throw UnexpectedError if fetchSecureCacheStorage throws', 46 | () async { 47 | mockUnexpectedError(); 48 | 49 | final future = sut.load(); 50 | 51 | expect(future, throwsA(DomainError.unexpected)); 52 | }, 53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /test/data/usecases/save_current_account/local_save_current_account_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:faker/faker.dart'; 2 | import 'package:flutter_avancado/data/cache/cache.dart'; 3 | import 'package:flutter_avancado/data/usecases/usecases.dart'; 4 | import 'package:flutter_avancado/domain/entities/entities.dart'; 5 | import 'package:flutter_avancado/domain/helpers/helpers.dart'; 6 | import 'package:mockito/mockito.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | class SaveSecureCacheStorageSpy extends Mock implements SaveSecureCacheStorage { 10 | } 11 | 12 | void main() { 13 | SaveSecureCacheStorageSpy saveSecureCacheStorage; 14 | LocalSaveCurrentAccout sut; 15 | AccountEntity account; 16 | 17 | setUp(() { 18 | saveSecureCacheStorage = SaveSecureCacheStorageSpy(); 19 | sut = 20 | LocalSaveCurrentAccout(saveSecureCacheStorage: saveSecureCacheStorage); 21 | account = AccountEntity(faker.guid.guid()); 22 | }); 23 | 24 | test('Should call SaveSecureCacheStorage with correct values', () async { 25 | await sut.save(account); 26 | 27 | verify( 28 | saveSecureCacheStorage.saveSecure(key: 'token', value: account.token), 29 | ); 30 | }); 31 | 32 | test( 33 | 'Should throw UnexpectedError if SaveSecureCacheStorage throws', 34 | () async { 35 | when(saveSecureCacheStorage.saveSecure( 36 | key: anyNamed('key'), 37 | value: anyNamed('value'), 38 | )).thenThrow(Exception()); 39 | 40 | final result = sut.save(account); 41 | 42 | expect(result, throwsA(DomainError.unexpected)); 43 | }, 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /test/infra/cache/local_storage_adpter_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:faker/faker.dart'; 2 | import 'package:flutter_avancado/infra/cache/cache.dart'; 3 | import 'package:flutter_secure_storage/flutter_secure_storage.dart'; 4 | import 'package:mockito/mockito.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | class FlutterSecureStorageSpy extends Mock implements FlutterSecureStorage {} 8 | 9 | main() { 10 | FlutterSecureStorageSpy secureStorage; 11 | LocalStorageAdpter sut; 12 | String key; 13 | String value; 14 | setUp(() { 15 | secureStorage = FlutterSecureStorageSpy(); 16 | sut = LocalStorageAdpter(secureStorage: secureStorage); 17 | key = faker.lorem.word(); 18 | value = faker.guid.guid(); 19 | }); 20 | 21 | group('saveSecure', () { 22 | test('Should call save secure with correct values', () async { 23 | await sut.saveSecure(key: key, value: value); 24 | 25 | verify(secureStorage.write(key: key, value: value)); 26 | }); 27 | 28 | test('Should throw if save secure throws', () async { 29 | when(secureStorage.write(key: anyNamed('key'), value: anyNamed('value'))) 30 | .thenThrow(Exception()); 31 | 32 | final result = sut.saveSecure(key: key, value: value); 33 | 34 | expect(result, throwsA(TypeMatcher())); 35 | }); 36 | }); 37 | 38 | group('fetchSecure', () { 39 | test('Should call fetch secure with correct value', () async { 40 | await sut.fetchSecure(key); 41 | 42 | verify(secureStorage.read(key: key)).called(1); 43 | }); 44 | 45 | test('Should return correct value on success', () async { 46 | when(secureStorage.read(key: anyNamed('key'))) 47 | .thenAnswer((_) async => value); 48 | 49 | final result = await sut.fetchSecure(key); 50 | 51 | expect(result, value); 52 | }); 53 | 54 | test('Should throw if fetch secure throws', () async { 55 | when(secureStorage.read(key: anyNamed('key'))).thenThrow(Exception()); 56 | 57 | final result = sut.fetchSecure(key); 58 | 59 | expect(result, throwsA(TypeMatcher())); 60 | }); 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /test/main/factories/pages/login/login_validation_factory_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_avancado/main/factories/pages/login/login.dart'; 2 | import 'package:flutter_avancado/validation/validators/validators.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | void main() { 6 | test('Should return the correct validation', () { 7 | final validations = makeLoginValidations(); 8 | 9 | expect(validations, [ 10 | RequiredFieldValidation('email'), 11 | EmailValidation('email'), 12 | RequiredFieldValidation('password'), 13 | ]); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /test/presentation/presenters/getx_splash_presenter_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:faker/faker.dart'; 2 | import 'package:flutter_avancado/domain/entities/entities.dart'; 3 | import 'package:flutter_avancado/domain/usecases/usecases.dart'; 4 | import 'package:flutter_avancado/presentation/presenters/presenters.dart'; 5 | import 'package:mockito/mockito.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | class LoadCurrentAccountSpy extends Mock implements LoadCurrentAccount {} 9 | 10 | main() { 11 | LoadCurrentAccountSpy loadCurrentAccount; 12 | GetxSplashPresenter sut; 13 | 14 | mockLoadCurrentAccount({AccountEntity account}) => 15 | when(loadCurrentAccount.load()).thenAnswer((_) async => account); 16 | 17 | setUp(() { 18 | loadCurrentAccount = LoadCurrentAccountSpy(); 19 | sut = GetxSplashPresenter(loadCurrentAccount: loadCurrentAccount); 20 | 21 | mockLoadCurrentAccount(account: AccountEntity(faker.guid.guid())); 22 | }); 23 | 24 | test('Should call LoadCurrentAccount', () async { 25 | await sut.checkAccount(durationInSeconds: 0); 26 | 27 | verify(loadCurrentAccount.load()).called(1); 28 | }); 29 | 30 | test('Should go to surveys page on success', () async { 31 | sut.navigateToStream 32 | .listen(expectAsync1((page) => expect(page, '/surveys'))); 33 | 34 | await sut.checkAccount(durationInSeconds: 0); 35 | }); 36 | 37 | test('Should go to Login page on null result', () async { 38 | mockLoadCurrentAccount(account: null); 39 | 40 | sut.navigateToStream.listen(expectAsync1((page) => expect(page, '/login'))); 41 | 42 | await sut.checkAccount(durationInSeconds: 0); 43 | }); 44 | 45 | test('Should go to Login page on error', () async { 46 | when(loadCurrentAccount.load()).thenThrow(Exception()); 47 | 48 | sut.navigateToStream.listen(expectAsync1((page) => expect(page, '/login'))); 49 | 50 | await sut.checkAccount(durationInSeconds: 0); 51 | }); 52 | } 53 | -------------------------------------------------------------------------------- /test/ui/page/splash_page_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_avancado/ui/pages/pages.dart'; 5 | import 'package:flutter_test/flutter_test.dart'; 6 | import 'package:get/get.dart'; 7 | import 'package:mockito/mockito.dart'; 8 | 9 | class SplashPresenterSpy extends Mock implements SplashPresenter {} 10 | 11 | void main() { 12 | SplashPresenterSpy presenter; 13 | StreamController navigateToController; 14 | 15 | setUp(() { 16 | presenter = SplashPresenterSpy(); 17 | navigateToController = StreamController(); 18 | 19 | when(presenter.navigateToStream) 20 | .thenAnswer((_) => navigateToController.stream); 21 | }); 22 | 23 | tearDown(() { 24 | navigateToController.close(); 25 | }); 26 | 27 | loadPage(tester) async => await tester.pumpWidget( 28 | GetMaterialApp( 29 | initialRoute: '/', 30 | getPages: [ 31 | GetPage(name: '/', page: () => SplashPage(presenter: presenter)), 32 | GetPage( 33 | name: '/any_route', 34 | page: () => Material(child: Text('fake page')), 35 | ), 36 | ], 37 | ), 38 | ); 39 | 40 | testWidgets( 41 | "Should present spinner on page load", 42 | (WidgetTester tester) async { 43 | await loadPage(tester); 44 | 45 | expect(find.byType(CircularProgressIndicator), findsOneWidget); 46 | }, 47 | ); 48 | 49 | testWidgets( 50 | "Should call loadCurrentAccount in presenter", 51 | (WidgetTester tester) async { 52 | await loadPage(tester); 53 | 54 | verify(presenter.checkAccount()).called(1); 55 | }, 56 | ); 57 | 58 | testWidgets("Should change page", (WidgetTester tester) async { 59 | await loadPage(tester); 60 | 61 | navigateToController.add("/any_route"); 62 | await tester.pumpAndSettle(); 63 | 64 | expect(Get.currentRoute, "/any_route"); 65 | expect(find.text('fake page'), findsOneWidget); 66 | }); 67 | 68 | testWidgets("Should not change page", (WidgetTester tester) async { 69 | await loadPage(tester); 70 | 71 | navigateToController.add(''); 72 | await tester.pump(); 73 | expect(Get.currentRoute, '/'); 74 | 75 | navigateToController.add(null); 76 | await tester.pump(); 77 | expect(Get.currentRoute, '/'); 78 | }); 79 | } 80 | -------------------------------------------------------------------------------- /test/validation/validators/email_validation_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:faker/faker.dart'; 2 | import 'package:flutter_avancado/validation/validators/validators.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | main() { 6 | EmailValidation sut; 7 | 8 | setUp(() { 9 | sut = EmailValidation('any_field'); 10 | }); 11 | 12 | test('Should return null if email is empty', () { 13 | expect(sut.validate(''), isNull); 14 | }); 15 | 16 | test('Should return null if email is null', () { 17 | expect(sut.validate(null), isNull); 18 | }); 19 | 20 | test('Should return null if email is valid', () { 21 | expect(sut.validate(faker.internet.email()), isNull); 22 | }); 23 | 24 | test('Should return error if email is invalid', () { 25 | expect(sut.validate('email_invalid'), 'Campo inválido.'); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /test/validation/validators/required_field_validation_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_avancado/validation/validators/validators.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | RequiredFieldValidation sut; 6 | 7 | setUp(() { 8 | sut = RequiredFieldValidation('any_field'); 9 | }); 10 | 11 | test('Should return null if value is not empty', () { 12 | expect(sut.validate('any_value'), isNull); 13 | }); 14 | 15 | test('Should return error if value is empty', () { 16 | expect(sut.validate(''), 'Campo obrigatório.'); 17 | }); 18 | 19 | test('Should return error if value is null', () { 20 | expect(sut.validate(null), 'Campo obrigatório.'); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /test/validation/validators/validation_composite_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:mockito/mockito.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | import 'package:flutter_avancado/validation/protocols/protocols.dart'; 5 | import 'package:flutter_avancado/validation/validators/validators.dart'; 6 | 7 | class FieldValidationSpy extends Mock implements FieldValidation {} 8 | 9 | void main() { 10 | ValidationComposite sut; 11 | FieldValidationSpy validation1; 12 | FieldValidationSpy validation2; 13 | 14 | void mockValidation( 15 | FieldValidationSpy validation, 16 | String error, { 17 | String field = 'any_field', 18 | }) { 19 | when(validation.field).thenReturn(field); 20 | when(validation.validate(any)).thenReturn(error); 21 | } 22 | 23 | setUp(() { 24 | validation1 = FieldValidationSpy(); 25 | mockValidation(validation1, null); 26 | 27 | validation2 = FieldValidationSpy(); 28 | mockValidation(validation2, null); 29 | 30 | sut = ValidationComposite([validation1, validation2]); 31 | }); 32 | 33 | test('Shold return null if all validations returns null or empty', () { 34 | final error = sut.validate(field: 'any_field', value: 'any_value'); 35 | 36 | expect(error, null); 37 | }); 38 | 39 | test('Shold return primary error in ValidationComposite', () { 40 | mockValidation(validation1, 'error_1'); 41 | mockValidation(validation2, 'error_2', field: 'other_field'); 42 | 43 | final error = sut.validate(field: 'other_field', value: 'any_value'); 44 | 45 | expect(error, 'error_2'); 46 | }); 47 | } 48 | --------------------------------------------------------------------------------